OmniAICreator/Qiita-1.07M huggingface dataset:
コード(和音)を五線譜上に表示するWebアプリを作った(TypeScript+React+Redux)

# 作成物

https://botanic7arc.github.io/chord-on-staff/

## ソースコード

https://github.com/botanic7arc/chord-on-staff

# 使い方

コード名を入力すると五線譜上に音符が表示される。
入力欄の左の音符記号ボタンを押すとト音とへ音の切り替えが可能。

![新しいビデオ.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/792099/781343b6-a349-80cf-8dd7-5823fcc55cfa.gif)


## 動作確認済みOS

- Windows10(20H2)

## 動作確認済みブラウザ

- Microsoft Edge(Chromium)
- Google Chrome

# なぜ作ったか

ピアノの楽譜を作る際にギター譜に載っているコードをアルペジオにして(分解して)左手にあてると楽に楽譜が作れそうだと考えた。
しかし音楽理論が分からずコードも全然知らない、かつ検索しても見やすいコードのサイトが見当たらなかったため作成した。

# TypeScript+React+Reduxを使った理由

TypeScript+Reactを学習していて、ちょうど状態管理方法としてReduxなるものが使われていると知ったため。

# 動作内容概略

入力したコード名と一致するデータが存在すれば音符記号を表示させる。記号1つに対してcssを1つ割り当てることによってコードにおける音ごとの表示を可能にした。

# 工夫した点

## 画像を一枚も使用することなく実装した点

画像を使うと楽に作れると思ったが、画像を使ってしまうとプログラマーとして負けた気持ちになると何故か思ってしまったため、画像は使用していない。
ト音記号とへ音記号と音符と♯と♭は文字を使用し、五線譜はcanvasで描画している。

## コードを入力した時点で表示させるようにした点

Webアプリでは主にボタンを押した後に結果を表示させるような気がするが(偏見)、ボタンを押す手間がもったいないため、入力した時点で一致するコードが存在する場合に表示するようにした。

## ト音とへ音の切り替えボタン

最初はト音でしか考えていなかったが、ピアノの左手にあてるのであればへ音が必要だと気が付き、ボタンで切り替えられるようにした。

# 大変だった点

## Reduxの使用

今回初めてReduxを使ったのでまず概念を理解するのに苦労した。
[React + Redux + TypescriptでサンプルWebアプリ - Qiita](https://qiita.com/makishy/items/857bb838a2910eb34da3)
この記事をかなり参考にさせていただいた。

## CSSでの位置調整

約170個あるコードのそれぞれの音と記号に対する位置調整。170*1コードあたり大体4個の記号≒680個の位置調整を行っている。

# 実装しようと思えばまだ可能なこと

- 異名同音(F♯に対するG♭など[^1])の実装:労力と成果物が釣り合わない
- スマホ対応:CSSの対応のみでできそうだがPCが使えない状況で楽譜を作ることがない

# 今後勉強が必要な点
- tsxにおいて繰り返し処理を使いdiv要素を並列に結合する方法(分からなかったため今回は無理矢理switch文を使って結合)
- Reduxはstoreで一括状態管理するがコンポーネントへの受け渡しは引数(props)のバケツリレーでよいのか
- Reduxにおいて全て関数コンポーネントで実装する方法

# おわりに

取り掛かるまでは全くと言っていいほやる気がど出なかったが、始めてみれば特に問題なかった。やはり実際に始めることは大切だと感じた。
初めてWebアプリを作ってみたが、大体想像していたようなものが作成でき良かった。
便利そうなため可能であればReduxを使っていきたい。

# 参考文献

- [React + Redux + TypescriptでサンプルWebアプリ - Qiita](https://qiita.com/makishy/items/857bb838a2910eb34da3)
- [コード早見表 | シンコーミュージック・エンタテイメント  |  楽譜[スコア]・音楽書籍・雑誌の出版社](https://www.shinko-music.co.jp/reading_score_piano/p-3-2/)
- [コード一覧](https://www.ady.co.jp/song-chord/chorditiran.htm)
- [ReactアプリをGitHub Pages(Project Pages)で公開する - Qiita](https://qiita.com/EisKern/items/15dcf7864fa49df8f247)
- [GitHubのリポジトリにアクセス時に「remote: Support for password authentication was removed on August 13, 2021.」エラー - キリウ君が読まないノート](https://note.kiriukun.com/entry/20210904-github-password-authentication-was-removed)

[^1]: 異名同音と書いているが音楽理論的にはF♯とG♭はおそらく名前だけでなく音も異なる
【備忘録】ProtonでSteam以外のソフトを動かす方法

## Q. Protonとは

A. Steamを開発してるValveがWineをゲーム用に魔改造したやつ。
SteamでWinのみ対応のゲームをインストールして起動しようとするとこいつが使われる。
~~Wineみたいに単独でインストールすることはできない。~~
と思ったら普通にAURに単独であった。
一応この記事はSteamでインストールした場合を想定。

## 結論

```bash
$ cd [動かしたい.exeのあるフォルダ]
$ STEAM_COMPAT_CLIENT_INSTALL_PATH=[Steamのインストールされてるディレクトリ] STEAM_COMPAT_DATA_PATH=[Steamインストールされてるディレクトリ/steamapps/compatdata] [Protonのインストール先ディレクトリ]/proton run [動かしたいやつ.exe]
```

## 例

```bash
$ cd ~/Downloads
$ STEAM_COMPAT_CLIENT_INSTALL_PATH=~/.local/share/Steam/ STEAM_COMPAT_DATA_PATH=~/.local/share/Steam/steamapps/compatdata/ ~/.local/share/Steam/steamapps/common/Proton\ 6.3/proton run setup.exe
```

インストールされた.exeファイルは`STEAM_COMPAT_DATA_PATH/pfx/drive_c/` をCドライブ直下とした指定ディレクトリに入る

## 環境変数とか

### STEAM_COMPAT_CLIENT_INSTALL_PATH

Steamのいろんなファイルとかが入ってるディレクトリ。
多分どのディストリビューションも`~/.local/share/Steam/`だと思う
`~/.steam/steam`が上記ディレクトリのシンボリックリンクだったりしました。

### STEAM_COMPAT_DATA_PATH

これが一体何を指してるのかよくわからないが、多分Cドライブとかレジストリ設定の位置あたりを指定してるものと思われる。
`~/.local/share/Steam/steamapps/compatdata/`を指定したら動いた。
`~/proton`を指定しても動いた。

### Protonがインストールされてるフォルダ

Steam開いてライブラリからProton x.x(xはバージョン)を選択、右クリックして"Properties..."をクリックした後、"LOCAL FILES"タブ内にある"Move install folder..."を押せば規定のファイルマネージャーで該当ディレクトリに飛びます。
何故か私の環境だと日本語フォントインストールしても日本語が豆腐になるので日本語でなんて書いてあるかはわかりません。

### 参考文献

- [How do I use Proton for non-steam games? : linux_gaming](https://www.reddit.com/r/linux_gaming/comments/ol1vcr/how_do_i_use_proton_for_nonsteam_games/)
ネイティブ開発Ouclus Quest2

#１．事前準備
・Oculus Quest2の開発者モードを有効化
・ADBドライバのインストール
・Android Studioのセットアップ

以下の手順に従って事前準備を行う
https://developer.oculus.com/documentation/native/android/mobile-device-setup/
https://developer.oculus.com/documentation/native/android/mobile-studio-setup-android/

※注意点※
Android SDK Tool (Obsolete)をインストールする必要があるのですが、デフォルトではSDK Managerに表示されないのでインストールできません。
どうすればいいのかというと、SDK Managerの画面右下にあるHide Obsolete Pakeagesの☑を☐にすると表示されるのでインストールしてください。

#２．SDKのセットアップ
・Oculus OpenXRモバイルSDKのダウンロード
・Androidマニフェストの変更

以下の手順に従ってSDKをセットアップする
https://developer.oculus.com/documentation/native/android/mobile-openxr/

#３．Google Maven リポジトリをプロジェクトに追加
・build.gradleの変更

https://developer.android.com/studio/build/dependencies#google-maven

#３．Android Games ライブラリの依存関係を追加

・build.gradleの変更
・CMakeLists.txtの変更

以下の手順に従って依存関係を追加する
https://developer.android.com/studio/build/dependencies#google-maven
https://developer.android.com/jetpack/androidx/releases/games
https://developer.android.com/games/agdk/integrate-game-activity

続きは追って書きます。


https://developer.android.com/ndk
https://developer.android.com/jetpack
https://developer.android.com/games
右クリックからwslpathを実行

↓をshell:sendtoに設置するだけ

```wslpath.bat
@C:\Windows\System32\bash.exe -c "echo \"$(wslpath -a -u "%1")\" | /mnt/c/Windows/System32/clip.exe"
```

参考：https://qiita.com/nbhr/items/d23b381e905fd9f2b890
[Javascript] 比較演算子(===)を簡単にまとめる


===と==の違いがうろ覚えだったので、このちがいを復習。


<h2>1.==は「等価」を確認</h2>

==は「等価演算子」を表しており、***2つの値が等しいか***どうかを検証する。

```javascript
const a = 1
const b = 1
const c = 2
const d = "1"

console.log(a == b) //true
console.log(a == c) //false
console.log(a == d ) //true
```

==は「値」が同じかをみます。
aとdを比べる際は、文字列を数字に置き換えるため、同じとみなされます。



<h2>2.===は「厳密」に確認</h2>

＝＝＝は「厳密等価演算子」であり、2つの値に加えて、***2つの値の「データの型」***まで比較する。


```javascript
const a = 1 //数字
const b = "1"　//文字列

console.log(a == b) //true
console.log(a === b) //false

```

＝＝の等価演算子であれば、文字列を数値に変換し「変数の値だけを比較する」ためTRUEが返る。

一方で、＝＝＝の厳密等価演算子は、文字列を数値に変換することなく、それぞれの変数の「データの値と型が一致しているか」を比較する。そのために、数字と文字列をでちがうaとbはfalseになる。


<h3>Booleanは？？</h3>
==を使う際にはtrueは1に、falseは0に変換されます。
===を使う際は型も確認するため、true/false以外のものと比べると必ずfalseになります。

```javascript
console.log(true == 1) //true　trueは1に変換される
console.log(true === 1) //false 型も見ているため違うものとみなされる
console.log(false== 0) //true　falseは0に変換される
console.log(false === 0) //false　型も見ているため違うものとみなされる

```

<h3>Objectは？？</h3>

```javascript
console.log("test" == new String("test")) //true　
console.log("test" === new String("test")) //false 

```

プリミティブ型とString型の比較。
==では、String型がプリミティブ型に変換され、trueになる。


```javascriptrue　
console.log(new String("test") == new String("test")) //false 

```

上記は異なるオブジェクトの比較になるので、false





<h2>3.!=は(1)等価演算子の逆</h2>

!=は「不等価」と呼び、1の***等価演算子(==)の反対***。
２つの「値」を確認して等しくない場合にtrueが返る。

```javascript
const a = 1 
const b = 2

console.log(a != b) //true


```



<h2>4.!==は(2)厳密等価の逆</h2>

!==は「厳密不等価演算子」と呼び、2の***厳密等価演算子(===)の反対***の結果を返します。



```javascript
const a = 1 //数字
const b = "1"　//文字列

console.log(a != b) //false 値が一緒なので同じものとみなされてfalseとなる。
console.log(a !== b) //true 型も確認するため、違うものとみなされtrueが返る。

```
全てのTOPオペレーターの解像度を統一する

TextDATに以下のコードを書いて実行します。

```python:reso.py
thisPrj = parent().children

for op in thisPrj:
  if(op.family == 'TOP'):
      op.par.resolutionw = 1920;
      op.par.resolutionh = 1080;
```
Salesforce-Salescloudコンサルタント-合格体験記


<h3>はじめに</h3>
2021年8月に認定アドミニストレーターに合格し、
2021年9月19日にSalescloudコンサルタントに合格しました。

これからSalesforce上位試験を受験される方に役立つ情報となれば幸いです。

・学習教材、参考にしたサイト
・勉強時間
・所感

等を纏めた記事となっています。

<h3>学習教材</h3>
1.[Trailmix](https://trailhead.salesforce.com/ja/users/welcome4/trailmixes/certified-sales-cloud-consultant-ja)
2.[Salesforce公式_ポイントスタディ](https://trailhead.salesforce.com/ja/academy/classes/crt251-certification-preparation-for-sales-cloud-consultant/)
3.[Quizlet_問題演習(155問)](https://quizlet.com/jp/427664845/salescloud-%E3%82%B3%E3%83%B3%E3%82%B5%E3%83%AB%E3%82%BF%E3%83%B3%E3%83%88-flash-cards/)
4.[SFの一番星_問題演習](https://keneloper.com/)

<h3>勉強時間(25時間)</h3>
<h4>1.Trailmix 12時間</h4>
　実際に手を動かしながらTrailmixに取り組みました。
　Salesforce公式の資料の中に具体的な出題割合や問題の概要について説明されているので、
　Trailmixで学習する際に活用すると理解が深まります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1520342/481ceb5d-243d-587c-9ad3-3788661c731b.png)

<h4>2.ポイントスタディ　6時間</h4>
 Salesforce公式のポイントスタディで出題範囲を一通り復習しました。
セミナーの受講で効率的に試験範囲を網羅することはできますが、
これだけで合格は難しいと思います。（セミナーを見た後に結局Trailmixで勉強しました）

<h4>3.Quizlet演習問題 4時間</h4>
　Webサイトの問題集を２周しました。
　知らない語句を調べたり、SalesforceのHelpを活用しました。

<h4>4.SFの一番星 3時間</h4>
 Salesforceのヘルプなど、参考になりそうな箇所を確認して問題演習をしました。

<h3>所感</h3>
　アドミニストレーターよりかなり細かい内容が問われ、難しい印象でした。
　他の方の合格体験記でSalesforceのヘルプなど、　
　重箱の隅をつつくような問題が出題されると書いてあったので、
　出題割合が高い箇所については重点的に学習しました。
　勉強期間は２週間で、得点率６割強でギリギリ合格できました。。
Salesforce-DataLoader 挿入したデータの文字化け

<h2>インサートしたデータが正しく表示されない</h2>
Salesforceでユーザーの一括登録をする際に、
文字化けして正しくデータが表示されない問題について纏めました。
↓「田中」などの日本語をインサートするとこの様な状態になりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1520342/59f7eaca-7579-8a72-4365-7d984ccfe292.png)

<h2>解消方法</h2>
`①LANGUAGELOCALEKEY（言語情報）は「ja」に設定されているか`
　→ここは問題なく、「ja」を指定していました。

`②Bulk APIをオフにしているか`
　→普段、Buli APIでデータをインサートしていたのでオフにしました。
　　しかしそれでも解消されず、、↓に続きます。

`③DataLoaderの読み書き設定が「CSV.コンマ区切り(.CSV)」に対応しているか`
　　→ここが原因でした。
　　「CSV.コンマ区切り(.CSV)」を取り込む際は以下の設定をオフ（Check外す）にします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1520342/af5a2803-5e49-b65d-389b-ef307d5e1fcb.png)

以上の設定で正しくインサートされ、表示できるようになりました！
コミュニティサイトをPardotでトラッキングする方法

##最初に
エクスペリエンスビルダー内のコンポーネント[HTMLエディタ]で、scriptタグがサポートされておらず、困り果てた末、コミュニティ（質問広場）で質問させていただきました。
すると、すっっっっぐにご回答いただき、無事解決することができました:sunny:

教えていただいたサイトを参考にしつつ、自分でやってみた方法を書き留めておこうと思います:sunny:（備忘録的な）

参考にしたサイトは、最後に記載しています:sunny:

##Pardot側での操作
1. アプリケーションランチャーから[Pardotキャンペーン]を開く
2. 任意のPardotキャンペーン開き、[トラッキングコードを表示]を押す。
3. 表示されたトラッキングコードをコピーしておく。

##コミュニティサイト側での操作
1. エクスペリエンスビルダーの設定 ⇒ セキュリティとプライバシーの[コンテンツセキュリティポリシー(CSP)]のセキュリティレベルを「緩和されたCSP：インラインスクリプトと許可されたホストへのアクセスを許可」に変更する。
※デフォルトは「厳格なCSP：インラインスクリプトとすべてのホストへのアクセスをブロック(推奨)

2. 設定 ⇒ 詳細の[ヘッドマークアップを編集]を押下する。

3. [ヘッドマークアップ]にコピーしたトラッキングコードを貼り付ける。
⇒このとき、「リソースにアクセスできません。」のエラーが出てきても問題なし。

4. 設定⇒セキュリティとプライバシーのCSPエラーに表示されるURL(多分、pi.pardot.com/pd.js)の[URLを許可]を押す。
⇒このときも、エラーメッセージ出てくると思いますが、気にせずいきましょう。

5. 一回、エクスペリエンスビルダーを閉じて、Salesforceの設定の画面に戻る。（※）

6. もう一回、エクスペリエンスビルダーを開く。

7. CSPエラーに/analyticsのURLが増えてるのを確認して、[URLを許可]を押す。

8. エラーが出てこなくなったら完了。

（※）わざわざ開きなおさなくても、エクスペリエンスビルダー内で[更新]すればいいだけかもしれません、、。
その方法はやってみてないので、確証はないです()

##参考（英語）
私は試していませんが、コミュニティサイトにPardotフォームを埋め込む方法も記載されていました。

https://resonantdigitalsolutions.com/pardot-forms-salesforce-communities/
Ruby on Rails タスクモデルを作成する

#タスクモデルのひな形を作成する
・モデル作成のための便利なジェネレータを使う

```:ターミナル
#bin/rails g model [モデル名] [属性名:データ型　属性名:データ型 …] [オプション]
$ bin/rails g model Task name:srtring description:text
```
コマンドを実行すると、モデルのクラスファイル、マイグレーションファイル、モデルの自動テストのファイルのひな形が自動作成される、

| 生成されるものの種類 | 本筋でのファイルパス | 用途 |
|:-----------|------------:|:------------:|
| モデルクラスのソースコード |	app/models/task.rb |	Taskクラスの実装 |
| マイグレーションファイル | db/migrate/20210825131759_create_tass.rb | データベースにtasksテーブルを追加する |
| モデルの自動テスト | test/models/task_test.rb | Taskクラスについての自動テストの実装 |
| モデルの自動テストで使うfixtureファイル | test/fixtures/tasks.yml | Taskクラスについての自動テストのためのデータ投入の定義 |

#データベースにテーブルを追加する

・データベースにテーブルを追加するには、Railsの用意しているマイグレーションという仕組みを使う。
・generatorでTaskモデルを作成した際に作成されたdb/migrate/xxxxxxxxxxxxxx_create_tasks.rbは必要最低限の要件を満たしているので、このままマイグレーションを実行して、データベースにtasksテーブルを追加する。

```rb:db/migrate/xxxxxxxxxxxxxx_create_tasks.rb
class CreateTasks < ActiveRecord::Migration[5.2]
  def change
    create_table :tasks do |t|　→#tasksというテーブルを作る
      t.string :name　→#tasksというテーブルがnameのカラムを備えること
      t.text :description　→#tasksというテーブルがdescritionのカラムを備えること

      t.timestamps　→#打刻ようのカラムを持つこと　
    end
  end
end
```

```:ターミナル
#データベースにtaskテーブルを追加
% bin/rails db migrate
```

```rb:app/models/task.rb
#このファイルはクラスを定義している
class Task < ApplicationRecord
end
```

#コントローラーとビュー
 
コントローラやビューのひな形もジェネレータで作成することができる

```:ターミナル
#コントローラを作成する書式→bin/rails g controller コントローラー名 [アクション名 アクション名 …] [オプション]
$ bin/rails g controller tasks index show new edit
```

・アプリケーションは、URLとHTTPメソッドの組み合わせから、リクエストを処理すべきコントローラーとアクションを特定して(※この特定処理を「ルーティング」と呼ぶ)、特定したアクションに処理をさせ、結果のHTTPレスポンスを作ってプラウ座に返す。

***
###URLとHTTPメソッド
①リクエストを処理するコントローラとアクションは、ブラウザからのリクエストに含まれるURLとHTTPメソッドによって決定される。
②コントローラのアクションを設計する際には、入り口となるURLとHTTPメソッドを合わせて考える必要がある。
***********
・controllerジェネレータでアクションを指定すると、アクションと同名のビューも一緒に作ってくれます。
・HTTPメソッドがGETのアクションは同名のビューを使うことが多いので、HTTPメソッドがGETとなるアクション名をジェネレータコマンドの引数として指定するのが効率的。
・controllerジェネレータコマンドを実行すると「index」「show」「new」「edit」のアクションについて個別のルーティングを追加する。
・CRUDというよくあるパターンは、パターン通りのルーティングを一括で設定したいので、config/routes.rbから4つのアクションについての設定を消す。

```rb:config/routes.rb

#ここから消す
get 'tasks/index'
get 'tasks/show'
get 'tasks/new'
get 'tasks/edit'
#ここまで

#代わりに「resouces」メソッドを追加
resouces :tasks
#resourcesメソッドは(index,show,new,create,edit,update,destroy)に関するルーティングを一括で設定してくれる。
```

・アプリケーションの玄関口(ルートパス)にアクセスした時に、Railsのデフォルト画面ではなくタスク一覧が表示されるようにする

```rb:config/routes.rb
#追加
root to: 'tasks#index'
```
追加した結果のroutes.rb

```rb:config/routes.rb

Rails.application.routes.draw do
  root to: 'tasks#index' 
  resources :tasks
end
```
HTMLからXpathで必要な要素を切り抜く

# はじめに
色々調査をしている時に、HTMLから任意の要素を切り抜く必要があったので、やり方をメモ。

# 前提条件
- Mac OSX
- Chrome最新版

でのみ試しています。Windows, Linuxでもxmllintが入っていれば動くかと思います。

# 手順
## XPathの取得
* ブラウザ上で切り抜きたい要素を右クリック、「検証」を選択
* DevToolが表示されたら、そのElementsタブ内部で、要素を選択、右クリックで`Copy > Copy full XPath`を選択。切り取れたXPathは

```
/html/body/div/main/div[6]/div/table/tbody/tr[5]/td[2]
```
だったとする。このXPathをどこかにメモする。

## ブラウザのDevToolで動作を検証
ブラウザのコンソールから、以下のような形でXPathの動作検証ができる。

- Chrome で対象のサイトを開く
- デベロッパーツールからコンソールを開く

```
$x('/html/body/div/main/div[6]/div/table/tbody/tr/td[2]') 
```
のような感じに設定して、配列で`tr`を繰り返しパースして、`td`部のデータが取得できるか、などを確認する。

## ページの保存
DevToolからだとオブジェクトは取れるのだが、該当の文字列が取得できない。絞り込まれたオブジェクトを指定してコピー、テキストエディタなどに貼り付けても、空のオブジェクト配列しかとれなかった。

調べたところ、Mac OSXに標準で入っている`xmllint`を利用して文字列が取得できることがわかったので、以下のように対象HTMLをローカルにコピーして処理することにした。

* その要素が表示されているページで右クリック、`ページのソースを表示`
* Cmd + Sで保存ダイアログを表示、`ウェブページ、HTMLのみ`で保存。今回は、例えば`test.html`として保存する。

## xmllintコマンドの実行
次に、コマンドプロンプトを開き、`test.html`を保存したディレクトリに移動。XPathを以下のように変更

- 今回は、テーブルの全部`tr`の2番目(td[2])の要素のテキストを抜き出したかったので、保存していたXpathを以下のように変更してパースする。
- `test()`は、前の要素のテキストを抜き出すための関数になる。

```bash:変更したXPathを指定したxmllint
xmllint --html -xpath "/html/body/div/main/div[6]/div/table/tbody/tr/td[2]/text()" test.html
```
これを実行すると、テーブルの任意の部分のテキストが切り取れる。
Raspberry Pi 3+の設定（忘備録）番外編　Win32DiskImagerでディスクイメージ作成→環境復元

Win32DiskImagerでmicroSDのディスクイメージを取っておくと、途中で環境を以前に戻したい（もしくは環境を吹っ飛ばした）時にもとに戻すことができるので便利です。

Win32DiskImagerは日本語化できるので、こちらのサイトからファイルをダウンロードして配置しておきましょう。

https://donkichirou.okoshi-yasu.net/download/Win32DiskImager.html

# イメージファイル読み取り
カードリーダーにmicroSDを挿してWin32DiskImagerを起動します。**microSDを挿した際に「ドライブをフォーマットしますか？」と聞かれますが、うっかり「はい」と答えないようにしましょう。**
![win32DiskImager01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1207708/df7d0f87-8d6c-4237-d4f3-4311e4787489.jpeg)

ちなみにラズベリーパイから抜いたmicroSDカード64GBを「ディスクの管理」で見るとこのようなパーティッションになっています。
![win32DiskImager07.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1207708/39d20559-eaa1-0b28-d45e-462253587b5d.jpeg)

複数ドライブが選択できるようになっています。ディスクイメージはmicroSDカード1枚に対して1つ取ればいいので、選択するドライブは一つです。
![win32DiskImager02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1207708/e34c8c9e-2950-f633-2aa2-75ba80668881.jpeg)

保存した際のディスクイメージファイル名を設定し、「割り振られたパーティッションのみを読み取る」の**チェックが外れている事**を確認し、「書き込み」ボタンを押します。
![win32DiskImager03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1207708/99bf31c1-d939-d743-c3c2-e28ba61ac7b0.jpeg)

読み込みには少し時間がかかります。
![win32DiskImager04.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1207708/c8ff39d9-575f-9509-4ea6-0b463fd55d7b.jpeg)

読み込み完了時にはダイアログが出ます。
![win32DiskImager05.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1207708/915aadaf-7054-224f-f6b4-26f5c80185fe.jpeg)

こちらが64GBのmicroSDから取り出したディスクイメージファイルのプロパティです。ファイルサイズが64GBになっていることに注意してください。これでmicroSD内全てがバックアップされたことになります。
![win32DiskImager06.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1207708/91b0c846-0f3a-3b50-44a5-6a860be168c9.jpeg)

# イメージファイル書き込み
同一容量のmicroSDカードを「ディスクの管理」で見るとこのようになっています。このmicroSDに先ほどのディスクイメージを書き込みします。
![win32DiskImager08.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1207708/17fa1d7b-eb3f-88a5-ef8a-7a81707bb1f9.jpeg)

Win32DiskImagerで、イメージファイル名を選択。「書き込み」をクリックします。**「読み込み」を押さないように気を付けてください。**
![win32DiskImager09.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1207708/f080ff98-19c8-c164-008e-df213a5aed27.jpeg)

物理ドライブに書き込むときに警告文がでますがそのまま実行します。
![win32DiskImager10.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1207708/02dd1e5d-4a74-e911-f63e-d6aaed675875.jpeg)

書き込みが終わるまでしばらく待ちます。

書き込み完了時にはダイアログが出ます。そして**ほどなくして「フォーマットしますか？」というwindows側のダイアログ（先ほどイメージファイルを作成する際にカードリーダーにmicroSDを挿した時と同じ挙動）がでますが、うっかりはいとしないように気を付けてください。**
![win32DiskImager11.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1207708/9b12e08f-866d-f3f6-695d-9d5f8a9e0723.jpeg)

「ディスクの管理」でmicroSDカードの中を見てみましょう。先ほどイメージファイルを作成したmicroSDと同様になっていることがわかります。
![win32DiskImager12.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1207708/f6c86cb3-1c6d-18cb-deaf-cf34796383f8.jpeg)

これでイメージファイルからのラズベリーパイの環境復元が出来ました。以上。
GCEで自分のグローバルIP（外部IP）を取得する

## プライベートIP

```
curl -H "Metadata-Flavor: Google" "http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/ip"
```

## グローバルIP

```
curl -H "Metadata-Flavor: Google" "http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip"
```
SafariでSVGの端が欠ける

## 事象

SafariでSVGの端が欠ける。
iOS/Macどちらでも発生する。
Safari以外は大丈夫。
同じSVG、同じスタイルでも使われている場所によって欠けたり欠けなかったりする。
元のSVGを適当なビューアで見ても欠けているわけではない。
Illustratorで線の位置を外側にしてしまって、外側にはみ出した分欠けているとかではない。

## 原因

SafariはSVGタグに

```css
overflow-x: hidden;
overflow-y: hidden;
```

というスタイルをデフォルトで当てている。
（つまりimgタグで読み込んだSVGではこの事象は発生しない）
何かの拍子にSVGタグのボックス内をはみ出した場合、その部分が欠けてしまう。

## 対策

CSSでSVGタグのoverflow: hiddenを打ち消す。
Ruby on Rails アプリケーションの準備

#アプリケーションのひな形を作成する

```:ターミナル
$ rails new アプリケーション名 [オプション名]
```
rails newコマンドをバージョンを指定せずに実行すると、最新バージョンであるRails6系で作成が行われるので、Rails5系に指定したい場合は

```:ターミナル
$ rails _5.2.6_ new アプリケーション名
```

のようにバージョンを指定する必要がある。

```:ターミナル
$ cd アプリケーション名
```

でディレクトリに移動したら、データベースを制作する

```:ターミナル
$ bin/rails db:create
```

データベースが作成できればサーバーを起動出来るようになるので、サーバーを起動してみる
(※サーバーの停止は[Ctrl]キーを押したまま[C]キーを押す。停止するまで動作し続ける。)

```:ターミナル
$ bin/rails s
```

サーバを起動したら、プラウザを立ち上げてhttps://localhost3000にアクセスする。プラウザ上にRailsのデフォルトページが表示されていれば、正しくサーバが起動している。

#データベースの環境ごとの使いわけ
・Rilsではデフォルトで3種類の「環境」が用意されており、1つの環境に対して1つのデータベースを対応させる。

| 環境の種類 | 環境のシステム名 |　　　　　　　　　　用途 　　　　　　　　　　|
|:-----------|------------:|:------------:|
| 開発       | development | 開発時の動作確認を行う |
| テスト     | test      |　自動テストを行う |
| 本番      | production | ユーザーが利用可能な形で稼働させる |

・どの環境にどのようなデータベースを対応させるかはconfig/datebase.ymlに記述
・開発時は、基本的に開発・テストの2種類の環境を使う。
#slimを使えるようにする
slimとはHTMLをツリー構造として簡潔に表現できる別のテンプレートエンジン。※テンプレートエンジンとは、HTMLのテンプレート(ひな形)とそこに記述された動的な処置から、最終的なHTMLを生成するための仕組み。

・アプリケーションが利用するgemはGemfileに定義。エディタでアプリケーションフォルダ直下にあるGemfileを開いて最後の行にslim-railsとhtml2slimについての設定を加える。

```rb:Gemfile
gem 'slim-rails'
#Slimジェネレータを提供してくれるgem
gem 'html2slim'
#ERB形式のファイルをslim形式に変換してくれるerb2slimコマンドを提供してくれるgem
```
                      
・Gemfileの変更を保存したら、gemをインストール。

```:ターミナル
$ bundle
```
これで今後Railsのコマンドを通じて作成されるビュー層のテンプレートファイルは、Slim形式で作成されるようになったが、現時点では、app/views/layoutsディレクトリの中にERB形式のファイルが3つ存在するのでerb2slimコマンドを利用してSlimに変更する。

```:ターミナル
$ bundle exec erb2slim app/views/layouts/ —delete
```

#Bootstrapを導入する
手軽に程よく見栄えのよう画面を作成することができるため、Bootstrapというフロントフレームワークを利用する。※手軽に程よく見栄えの良い画面を作成することができるため、実際の開発現場でもBootstrapはしばしば利用されている。

```rb:Gemfile
#Gemfileの末尾に追記
gem 'bootstrap'
```

```:ターミナル
#Gemfileを保存したら、インストール
$ bundle
```

・Railsはアプリ全体で1つのCSSファイルを読み込むようになって位いるので、これから利用するBootstrapも、application.css から読み込むようにしていく。
・Slimと同じように、CSSにも効率よく表現できる形式としてSassがあるので、CSSファイル(application.css)を編集してSCSSファイル(application.scss)を作成する。

```:ターミナル
$ rm app/assets/stylesheets/application.css
```

・app/assets/stylesheets/application.scssを作成

```rb:app/assets/stylesheets/application.scss
@import "bootstrap"
```

これで画面をBootstrapのデザインが当たった状態にすることができる。

・レイアウトファイルapplication.html.slimにapplication.cssを読み込ませ、各画面のslimファイルに定義せずに全ての画面にBootstrapのデザインを反映させることができる。

#HTMLのtitleや、画面の見出しなどを整備しておく

```rb:app/views/layouts/application.html.slim
body
#ここから追記
  .app-title.navbar.navbar-expand-md.navbar-light.bg-light
    .navbar-brand Taskleaf
  .container
#ここまで
    = yield
```

#Railsのエラーメッセージを日本語で表示する

・Githubのrails-i18nリポジトリに翻訳された日本語翻訳ファイルがあるので、そのrawファイルをconfig/locales/ja.ymlとしてダウンロードする。

```:ターミナル
$ wget https://raw.githubusercontent.com/svenfuchs/rails-i18n/master/rails/locale/ja.yml -P config/locales
#wgetファイルがない場合は先にインストール
```

```rb:config/initializers/locale.rb
#デフォルトで日本語のコンテンツを使うようにアプリケーションの設定を変更する
Rails.application.config.i18n.default_locale = :ja
```
Pentaho Data Integration でCSVファイルを読み込む

バッチ処理でよくあるパターンとして、CSVファイルをインプットとして読み込むことが考えられますので、CSVファイルからデータを取得する際の方法をまとめました。

# 使用データ
今回は、政府CIOポータルで提供されているワクチン接種状況のオープンデータである、以下のCSVデータを使用したいと思います。
[都道府県別累積接種回数サマリー](https://vrs-data.cio.go.jp/vaccination/opendata/latest/summary_by_prefecture.csv)

中身は以下のとおりです。なお、文字コードはSJISでした。

```summary_by_prefecture.csv
date,prefecture_code,prefecture_name,count_first_or_mid_general,count_second_or_full_general
2021-09-29,01,北海道,3165775,2597047
2021-09-29,02,青森県,822507,680631
2021-09-29,03,岩手県,752279,615774
2021-09-29,04,宮城県,1458050,1196522
2021-09-29,05,秋田県,653724,544742
：
```

# テキストファイル入力
CSVファイルからデータを読み込むための機能として用意されているのがテキストファイル入力ステップです。
また、CSV入力ステップという機能もあり、こちらでもCSVファイルを読み込んでデータを取得することができます。
どちらもCSVファイルを読み込むことができますが、テキストファイル入力のほうが多機能なので、こちらを紹介したいと思います。
CSV入力ステップの優位性としては、テキストファイル入力よりも機能がシンプルなので、読み込み自体が多少早いということが挙げられます。
が、そこまで劇的な差は無いので、基本的にはテキストファイル入力を使用すれば問題ないかと思います。
以下、配置イメージです。
![pdi_csv01x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186651/1d1bdc3a-39c1-0378-ccae-075cd5234cde.png)

配置したテキストファイル入力ステップをダブルクリックすると以下のような画面が表示されます。
以下、読み込むファイルを指定する設定です。
![pdi_csv02x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186651/ac92b663-221e-1974-adf7-ead3a5224dba.png)

続いて、全般タブを選択して全体的な設定を行います。設定はファイルにあわせて変更していきます。
![pdi_csv03x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186651/21895355-904d-7a16-1b13-01d3e878ecc4.png)


最後に、各フィールドを設定します。設定完了後、OKボタンを押下することで設定が完了します。
![pdi_csv04x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186651/953f732f-a0e9-fcd9-cde7-8c13f9580326.png)

なお、プレビューすると以下のように確認することができます。
![pdi_csv05x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186651/82d929a5-2f9a-4ace-9b16-d1c84fd414f5.png)

# URLの直接指定
今回はローカルのCSVファイルを指定する例を紹介しておりますが、以下のように直接URLを指定することも可能です。
![pdi_csv06x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186651/d872afa7-5c95-cd24-0fd7-60980ad84980.png)

さらに、今回使用したデータは、毎日更新されているようなので、以下のようにTransformationの処理を作成して、毎日自動で実行するように設定しておけば、データの自動収集が可能となります。
![pdi_csv07x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186651/d8550dfe-d922-9ae2-d64f-6d8ac5aff60b.png)

極端な例ですが、2ステップでデータ収集機能を持つバッチ処理を作成することができます。

# データ抽出後の設定
CSVファイルからデータを抽出したあとは、文字列変換やソート、その他のデータと結合するなどのデータ加工を行って、上記のように最終的にDBへロードしたり、別の形式のファイルへ出力したりすることになります。
このあたりは、また別の記事でご紹介していきたいと思います。
【GAS】トリガーを決まった時刻に実行する

# やりたいこと
GASのトリガー（時間主導型）は、1時間毎に実行してはくれるものの、何分に実行など細かな設定はできません。なので、決まった時刻に実行するトリガーを別途用意して対応します。
この対応は検索すると色々なところに書かれてはいたのですが、まとめておくと便利そうだったので備忘録として投稿しておきます。

# 対応
まず毎時00分に実行する場合は、下記のsetNextTriggerを時間主導型のトリガー（1時間おき）にセットします。

```JavaScript
const mainTriggerName = "main"; //実行したい関数名。仮にmain()とします;

//===========================================================================================
// 1時間後の00分に次の実行トリガーをセットする(14:30に実行したら15:00にタイマーセット)
// この関数を1時間ごとのトリガーに指定して運用する
//===========================================================================================
function setNextTrigger(){

  const time = new Date();
  time.setHours(time.getHours() + 1);
  time.setMinutes(00);

  //過去のトリガーを削除
  removeTrigger(mainTriggerName);
  ScriptApp.newTrigger(mainTriggerName).timeBased().at(time).create();

}

//===========================================================================================
// トリガーを削除
//===========================================================================================
function removeTrigger(triggerName){
  const triggers = ScriptApp.getProjectTriggers();

  for(const trigger of triggers){

    if(trigger.getHandlerFunction() == triggerName){
      ScriptApp.deleteTrigger(trigger);
    }
  }  
}
```

ただトリガーは分までしか認識しないので、この場合でも0分の0秒ぴったりに実行してくれるわけではありません。
ぴったり実行したい場合は、1分前にトリガーをセットして0秒になるまでSleepが一般的だそうです。
というわけで書き直したものが下記です。

```JavaScript
const mainTriggerName = "mainTrigger";

//===========================================================================================
// 59分に次の実行トリガーをセットする(14:30に実行したら14:59にタイマーセット)
// この関数を1時間ごとのトリガーに指定して運用する
//===========================================================================================
function setNextTrigger(){

  const time = new Date();
  time.setMinutes(59);

  //過去のトリガーを削除
  removeTrigger(mainTriggerName);
  ScriptApp.newTrigger(mainTriggerName).timeBased().at(time).create();

}

//===========================================================================================
// 毎時59分に呼び出されるメイン処理のトリガー
//===========================================================================================
function mainTrigger(){
  //トリガーは毎時59分にセットされるため、00分00秒に処理を開始するまで待機
  const startTime = new Date();
  startTime.setMinutes(startTime.getMinutes() + 1);
  startTime.setSeconds(0);
  startTime.setMilliseconds(0);
  Utilities.sleep(startTime - new Date());

 main(); //メイン処理呼び出し。ここでは仮にmain()としています
}

//===========================================================================================
// トリガーを削除
//===========================================================================================
function removeTrigger(triggerName){
  const triggers = ScriptApp.getProjectTriggers();

  for(const trigger of triggers){

    if(trigger.getHandlerFunction() == triggerName){
      ScriptApp.deleteTrigger(trigger);
    }
  }  
}

```

これでmain()が毎時0分0秒に実行されるようセットできました。
ただこの方法だと最長1分近くSleepするため、トリガー実行可能時間6分のうちその分消費しても大丈夫な処理だけに入れることをおすすめします。
自宅SCMサーバー再構成　構築編13　Gitlabテスト用グループの作成


#旧式HPサーバーに CentOS7 をインストールしDockerコンテナ上でGitlabとRedmineを連携しSCM環境を再構築した際の備忘録（13）
##13.Gitlabグループの作成
###13-1.新規グループ作成
ブラウザで```127.0.0.1：9080```を開く
rootでGitlabへサインイン
![gitlabmenu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226547/1c2b9bdb-bab2-b0f1-8f3a-a9c886c73fac.png)から
![gitlaadmin.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226547/62cbdd41-02b0-ea7f-f092-4251eec7cb5d.png)を選択
```GROUPS```の```新規グループ```を選択


テスト用にGitAlignグループを作成
![gitaligngroups.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226547/0e47d9a7-6826-c04e-bc06-fcfd3e231141.png)
![gitaligngroups2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226547/7654f9d3-9788-cd05-7503-ef54f855d724.png)
![gitaligngroups3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226547/7b293527-9156-644e-ec37-86d2c7c64194.png)でグループ作成

###13-2.グループへユーザーの追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226547/182dcc27-21ef-3cd9-8aa9-9cb372f639a6.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226547/45b731fd-59d8-f3f8-bc8b-6f0ba70c8fde.png)
で```Gitalign01```　```Gitalign02```　を　```Maintainer```登録
【Unity】プロジェクトのルートの名前空間を指定する【Rider】

# はじめに

Riderの標準機能でルートの名前空間を指定した時に、設定が初期化されてしまう問題が発生しました。今回はその対処方法について紹介します。

恐らく他のエディタでも共通する話なのですが、今回はRiderを使っている前提で話します。


# 環境

- macOS 11.4（20F71）
- Unity 2020.3.11f1
    - JetBrains Rider Editor 3.0.7
- JetBrains Rider 2021.1.5

# 背景（発生した問題について）

Riderのコードインスペクションには、ディレクトリ構造と名前空間の不一致を検出してくれる機能があります。
![スクリーンショット 2021-09-30 13.14.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55365/4f68a57c-7e10-4b8e-13db-5ae42a0f69e8.png)

便利な機能なのですが、ディレクトリ構造と名前空間は必ずしも一致しません。プラットフォーム固有のディレクトリを省きたい事情や、C#のガイドラインに沿った下記のような名前空間にしたい場合があります。

```
<Company>.(<Product>|<Technology>)[.<Feature>][.<Subnamespace>]
```

https://docs.microsoft.com/ja-jp/dotnet/standard/design-guidelines/names-of-namespaces

そこでRiderには以下のように名前空間を調整する機能があるのですが、前者に関しては何故かコンパイルのタイミングなどで設定が初期化されてしまう問題がありました。

- ルートの名前空間を指定する
- 名前空間要素にしないディレクトリを指定する

https://pleiades.io/help/rider/Refactorings__Adjust_Namespaces.html


# 解決方法

該当プロジェクトの Assembly Definition Asset（asmdefファイル）の「Root Namespace」で指定すればOKです。

![スクリーンショット 2021-09-30 12.52.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55365/3bfb4afb-ae4d-92ff-ec2e-8a126435363f.png)

Assembly Definition Assetについては各自で調べてください。設定されていないプロジェクト（csproj）に関しては、やはりコンパイルの度にリセットされてしまうようです。

原因なのですが、Unityマニュアルを見ると対象となるcsprojはUnity側で制御しているような説明があります。恐らくこの辺りの仕組みが原因なのではないでしょうか

> Unity は自動的に Visual Studio .sln および .csproj ファイルを作成および維持します。誰が Unity 内でファイルを追加、名前変更、移動、削除を行なっても、Unity は .sln および .csproj ファイルを生成します。Visual Studio からのソリューションにもファイルを追加できます。Unity はこれらの新しいファイルをインポートし、次に Unity がプロジェクトファイルを再度作成すると、この新しいファイルを含めて、プロジェクトファイルを作成します。

https://docs.unity3d.com/ja/2018.4/Manual/VisualStudioIntegration.html

# 最後に

（RiderはUnityを前提としたIDEなのに、なんでこの挙動について書いてないんだろう・・・？）

Twitterやっているのでフォローしてくれると嬉しいです！

https://twitter.com/nkjzm


# 追記

Unity 2020.2 の新機能に書いてあることを教えてもらいました！

> アセンブリ定義の設定で Root Namespace が利用可能に
C# の名前空間は、コードを整理する効率的な方法を提供し、クラスの命名に関して他のパッケージやライブラリとの衝突を回避できます。Root Namespace が asmdef インスペクターの新しいフィールドとして利用できるようになり、Unity や Visual Studio と Rider で新しいスクリプトを作成するときに名前空間を自動的に追加するために使用されます。


https://unity.com/ja/releases/2020-2/programmer-tools#root-namespace-available-assembly-definition-settings
STM8のソフトウェアシリアルでHello Worldと出力 1000bps TX PD0


目的
つくれそうだから作ってみた。

x タイミング調整中?

x ALレジスターが1個だからたぶん遅い


```c++



//104 9600
//208 4800
//416 2400
//832 1200

#define UART_DELAY 9090 //  1/110
//#define UART_DELAY 832 //  1/1200
//#define UART_DELAY 832 //  1/1200
//#define UART_DELAY 96 //  1/9600

#define PD_ODR *(volatile uint8_t *)0x500F

#define  on1()   PD_ODR=0b00000001
#define  off1()  PD_ODR=0b00000000

//仮想シリアルへの一文字出力 9600bps
int pc_putc1(char ch) {

  on1();
  off1(); //START
  delay(1);

  if( ch & 0b00000001){
    on1();  /*ビットが1*/   
  } else {
    off1(); /*ビットが0*/ 
  }//end if
  delay(1); //0

  if( ch & 0b00000010){
    on1();  /*ビットが1*/   
  } else {
    off1(); /*ビットが0*/
  }//end if
  delay(1); //1
  
  if( ch & 0b00000100){
    on1();  /*ビットが1*/  
  } else {
    off1(); /*ビットが0*/
  }//end if
  delay(1); //2

  if( ch & 0b00001000){
    on1();  /*ビットが1*/   
  } else {
    off1(); /*ビットが0*/ 
  }//end if
  delay(1); //3

///44444444444444444444444444
  if( ch & 0b00010000){
    on1();  /*ビットが1*/ 
  } else {
    off1(); /*ビットが0*/ 
  }//end if
  delay(1); //4

  if( ch & 0b00100000){
    on1();  /*ビットが1*/   
  } else {
    off1(); /*ビットが0*/ 
  }//end if
  delay(1); //5

  if( ch & 0b01000000){
    on1();  /*ビットが1*/   
  } else {
    off1(); /*ビットが0*/
  }//end if
  delay(1); //6

  if( ch & 0b10000000){
    on1();  /*ビットが1*/  
  } else {
    off1(); /*ビットが0*/
  }//end if
  delay(1); //7
  
  on1(); //Stop
  delay(1);

}

void setup() {

  //仮想シリアルの出力ポート

  //ポートをhiにする 初期化
  pinMode(PD0, OUTPUT);
  on1();

}//setup

char *ss1; //文字のポインター
int  ii;   //ループカウンター

//無限ループ
void loop() {

  ss1="Hello World !\r\n";
  ii=0; //ループカウンター
  while(ss1[ii]!=0){

    //一文字出力
    pc_putc1(ss1[ii]);ii++;

  } //while

  //1秒の待ち
  delay(1000);
  
}//loop




```
react + typescript + laravelで管理画面作成

#成果物について
##使用技術について
フロントエンド：　react + typescript + tailwindCss
バックエンド　：　laravel

##コンテンツについて
予約機能があるHPの管理画面を作成
■具体的な機能
・予約日毎に予約者一覧が確認できる機能
・利用ユーザー毎にpdfの領収書をメールに添付して送信できる機能

###予約日毎に予約者一覧が確認できる機能について
日付選択欄にて、選択した日付の予約一覧を表示可能

<画面>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/637993/2975d70f-6826-a70d-0646-e29cd4507b09.png)

###利用ユーザー毎にpdfの領収書をメールに添付して送信できる機能について
■領収書送信対象者一覧画面
・日付選択欄・氏名入力欄にて、選択した条件のユーザー一覧を表示可能
・一覧のセルを押下すると、対応したユーザーの送信画面に遷移

<画面>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/637993/626b8ba9-5fc0-f08c-6475-4ce917dd6b65.png)

■領収書送信画面
・料金は動的に変更可能
・送信ボタンを押下すると、pdfの領収書をメールに添付して送信

<画面>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/637993/642850d4-0991-ee6a-06ff-71481809d7f2.png)
数式フィールドの文字数問題

[Answersで回答する時に使う情報のまとめに戻る](https://qiita.com/Keiji_otsubo/items/9e6e0e946826133eddc7)

基本的にはIF文(中身が同じフィールドをOR条件している場合)があれば、Caseに置き換えるのが定番です。

しかし、今回のケース

```
IF ( 
NOT ( ISBLANK (  Term_Length__c )),
( TCV_mf3__c / Term_Length__c ),
IF (
NOT ( ISBLANK (  Term_Length_Primary_Quote__c )),
( TCV_mf3__c / Term_Length_Primary_Quote__c ),
( TCV_mf3__c / 12 )))
```

う～ん、これは無理ですね。

解決策の道筋

```
TCV_mf3__c / BLANK VALUE(Term_Length__c , BLANKVALUE( Term_Length_Primary_Quote__c , 12 ))
```

[Formula "too big" error](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000ChzTTSAZ)
Vue3でpropsの値をCSSに渡す際に注意したいこと

## はじめに
久々に実装した際に、エラーも出力されず苦戦したので共有します。

## サンプルコード

```Sample.vue
<template>
  <span class="test" :style="styles">
    テスト
  </span>
</template>
<script lang="ts">
import { defineComponent, computed } from 'vue';

export default defineComponent({
  props: {
    color: { type: String, default: '#FFF' },
  },

  setup: (props) => {
    const styles = computed(() => ({
      '--color': props.color,
    }));

    return { styles };
  },
});
</script>

<style scoped>
.test {
  color: var(--icon-color);
}
</style>
```

ここで大事なのが、**propsを渡すクラスをつけている要素のstyleフィールドに対して、stylesをbind**している箇所です。

```Sample.vue
<span class="test" :style="styles">
```

これを忘れてしまうと、CSS内のvar変数に値が入らないので注意してください。

## 所感
自分の記憶や過去の自分のコードを信じるではなく、おかしいなと思ったら公式サイトをすぐに見に行ったほうが良いですね。

## 参考文献
- [Vue3公式](https://v3.ja.vuejs.org/guide/class-and-style.html#%E3%82%A4%E3%83%B3%E3%83%A9%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%82%A4%E3%83%AB%E3%81%AE%E3%83%8F%E3%82%99%E3%82%A4%E3%83%B3%E3%83%86%E3%82%99%E3%82%A3%E3%83%B3%E3%82%AF%E3%82%99)
laravelのwhere()で複数のカラムを指定したい

laravelのwhere()で複数のカラムを指定したいと思いましたがやり方がわからずに調べました。


##夢

```php
where(['login_id', 'ToUserId'],Auth::id())
```
どちらかのカラムに自分のIDが入っていたら取得する。
しかし、whereの第一引数には配列が指定できませんでした。

##解決策

```php
whereRaw('`login_id` = ? OR ToUserId = ?', [Auth::id(), Auth::id()])
```

綺麗ではないですが上記であれば取得可能です。
?の部分に第二引数で指定した配列が入ります。

##参考記事
https://www.ritolab.com/entry/93

##感想
むずい
古いUbuntuのアップデート方法

19.04のアップデートができなかったので、その時の記録です

古いUbuntuはアップデートができなかった
リポジトリリストのURLにアクセスしても目的のファイルがないから

なので、リポジトリのリストを変更する必要がある

/etc/apt/sources.list
を開いて

古いバージョンは
http://old-releases.ubuntu.com 
の中に入っているので以下を追加

 deb http://old-releases.ubuntu.com/ubuntu disco main restricted
 deb http://old-releases.ubuntu.com/ubuntu disco-updates main restricted 
 deb http://old-releases.ubuntu.com/ubuntu disco universe

参考
https://web2.official.jp/ubuntu-apt-get
ショートカットキーまとめ

エンジニアなら使ってて当たり前なショートカットキーまとめ


```
Ctrl + E ->カーソルが一番右にいく
Ctrl + A　　->カーソルが一番左にいく
Ctrl + N　　->カーソルが次の行にいく
Ctrl + P　　->カーソルが前の行にいく
Ctrl + F　　->カーソルが1文字進む
Ctrl + B ->カーソルが1文字戻る
Ctrl + D　　->カーソルの後ろの1文字を消す
Ctrl + H　　->カーソルの前の1文字を消す
Ctrl + K　　->カーソルの右側の文字を全て消す
```
エラー：NoMethodError: undefined method `〇〇=' for

## 環境
ruby 2.7.1
Rails 6.1.3.2
RSpec 3.10


## 状況
Rspec実行時に下記のエラーで怒られた


```
 NoMethodError:
       undefined method `article=' for #<XXXXX:0x000055d551353cd0>
       Did you mean?  article=
                      article
                      article_id=
```


```spec/factories/users.rb
FactoryBot.define do
  factory :user do
    name { "testuser1" }
    sequence(:email) { |n| "tester#{n}@example.com" }
    password { "testpassword" }
  end
end

```

```spec/factories/articles.rb
FactoryBot.define do
  factory :article do
    user
    title { "sampletitle" }
    content { "samplecontent" }
  end
end
```

```spec/factories/comments.rb
FactoryBot.define do
  factory :comment do
    user
    article
    content { "samplecomment" }
  end
end
```


## 原因
FactoryBotのアソシエーションで作成するデータがかぶっていた
（articleとcomment両方にアソシエーションとしてuserが定義されている）


## 解決方法
アソシエーションがかぶっているcommentのuserのアソシエーションの書き方を変える

```spec/factories/comments.rb
FactoryBot.define do
  factory :comment do
    user { article.user }　　#articleで作成されたuserを使う
    article
    content { "samplecomment" }
  end
end
```

## 参考

https://qiita.com/Ryoga_aoym/items/741c57e266a9d811a2d4
Telepresence 2 を試してみる part.1

# 概要
ローカル環境でKubernetes用のマイクロサービスを開発する際に便利なツール `Telepresence` がV2にアップデートされていたので試してみました。
たくさんの機能がありますが、今回は最も基礎的な使い方である `Telepresence Connect` を利用してみます。


# なぜTelepresenceを使いたいか？
kubernetesによるマイクロサービス環境を運用する中で課題の1つとなるのが、ローカル環境にてマイクロサービス間通信が必要な箇所の検証があります。
マイクロサービスAと通信を行うマイクロサービスBをローカル環境で開発する際に動作テスト等を行うためにローカルにある開発中のアプリとマイクロサービスAを通信させてテストしたいと思う事があります。
マイクロサービスAのmockにあたるdockerコンテナをローカル環境に稼働させる方法もありますが、DBを別途用意する必要やアプリバージョンの問題等で安定した開発環境にはなっておりません。

この問題を解決するためにTelepresenceが有効に利用できます。
Telepresenceを使うことでローカル環境からKubernetes内部のエンドポイントに対して疎通する事ができるため、アプリ開発を行う際の動作確認が手軽に実施できます。

ちなみに、Kubernetes内部のエンドポイントとは `my-svc.my-namespace.svc.cluster.local` にて定義されるkubernetesのServiceに対するエンドポイントです。
基本的にはKubernetes内部間の通信に使われるKubernetes内のDNSに定義されている名前なので外部から疎通する事はできません。

# Telepresence2を利用する前提条件
Telepresence2の内部にてkubectlコマンドでクラスターに接続を行います。
Telepresence2実行前にローカル環境のkubectlコマンドにて接続したいクラスターに接続できる状態になっている事を確認してください。

また、自身の利用できるアカウントが必要な権限を付与されている必要があります。
Telepresence2を利用するためには各リソースに対して下記の権限が必要となります。

| 対象リソース | 必要権限 |
|:-:|:-:|
| pods | get, list, create, watch, delete  |
| servuces | get, list, watch, update  |
| pods/portforward | create  |
| deployments | get, list, update |
| replicasets | get, list, update |
| statefulsets | get, list, update |
| hosts | * |
| mappings | * |
| endpoints | get, list, watch |
| namespaces | get, list, watch |
ref.https://www.getambassador.io/docs/telepresence/latest/reference/rbac/

# TelepresenceConnectを試してみる
## Telepresence2 のインストール
ローカル環境にてTelepresence2のインストールを行います。
brewを使ってインストールする事が可能です

```
$ brew install datawire/blackbird/telepresence
```

brewが無い環境であれば直接バイナリファイルをダウンロードして利用する事も可能です。

```
$ curl -fL https://app.getambassador.io/download/tel2/darwin/amd64/latest/telepresence -o /usr/local/bin/telepresence
$ chmod a+x /usr/local/bin/telepresence
```

## ローカル環境とk8sを接続する
connectコマンドを使ってローカル環境とk8s環境を接続する事ができます。

```
$ telepresence connect
```
*telepresence connectを行うとローカル環境にてDaemonが起動します。*

## ローカルからk8s上のエンドポイントを叩いてみる
```
$ curl "http://my-svc.my-namespace.svc.cluster.local/helth-check"
```
レスポンスが帰ってくれば成功です。
非常に簡単ですね。

## ローカル環境とk8sを接続を切る
quitコマンドを使ってローカル環境とk8s環境の接続を切る事ができます。

```
$ telepresence quit
```

# 感想
TelepresenceConnectとローカルからk8s上のエンドポイントを簡単に叩く事ができました。
アプリケーションの開発やマイクロサービス間の動作確認を行う上でとても便利になりそうです。

ただし、必要な権限が多いので注意が必要な印象を受けました。

Telepresence2は他にも様々な機能があるので調査次第part2を書きたいと思います。
日記；回すだけII ①CANopenの準備

###PC側のCANインターフェース
　入手性、日本法人があるなどの理由からIXXATのUSB-to_CAN V2 Compactをマルツで入手しました。付属のビューワcanAnalyser3 Miniでは、CANopenのプロトコルを見ることはできません。接続したPCのOSはWindows10 12H1です。

<img width="400" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/d4d49e9f-da3f-78bc-9047-23b9a0c19587.png">


　購入したモデルのCAN接続口は、一般的なDサブ9ピンです。130Ω（120Ωがなかったので）の終端を取り付けたケーブルを自作しました。終端は、モータ側にもつけています。まったく終端を入れないと、同期をとるためのスタッフィング信号のエラーが多発しました。CANopenの物理層はCANバスです。ツイストペア線で、複数の機器がぶら下がります。両端には終端抵抗を入れます。

<img width="700" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/bac86440-1327-808b-4924-3274c759ef9d.png">



　Windowsのドライバと同時にインストールされるcanAnalyser3 Miniの画面です。つながっていることの確認しかできません。この上のモデルだとCANopenのプロトコルに対応していますが、Digi-keyで調べたら20万円でした。

![2021-09-29 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/857ddbad-bcbb-d81f-a3d8-59a57cfb3ce3.png)

###使用したモータ
 　amazonでもステッピング・モータに対応したCANopenインターフェースが販売されていますが、動く確証がありません。Digi-keyで検索したら、TRINAMIC社のモータが１万７千円ぐらいからありました。これだけシリーズが用意されているのだからという理由で、一番小さなモデル**PD42-1270 CANopen**を購入しました。モータ自体は、ステッピング・モータでメジャーなNEMA17ライクです。CANopenのインターフェースは、モータの後ろ側に二つのねじで止められています。コンパクトです。
　取付金具はアマゾンにありました。
　　　``「RATTMMOTOR 取付角42ｍｍ ブラケット 取付金具 NEMA17ステッパーモーター用 L形 3Dプリンター部品 ネジ付き 3個入り」``
　10ピンのコネクタもアマゾンにありました。
　　　``「6セット10針100ミリ長さの線束単体で2.0ミリ間隔＋10針直コンセント6個（AWG#26）のJST PH」``
　　DB9のオス/メスのコネクタもアマゾンで入手しました。
　　　``「uxcell DB9 9ピンメス-オスコネクタ PCB実装 半田付けタイプ D-サブ」``




###接続
　10ピンのコネクタの配置です。電源は6～24Vなので、24Vと12Vで試しました。100rpm以上の速度でトルクに差が出ます。5V端子は出力です。特に何もつなぎません。

>**1** GND Supply and signal ground connection
>**2** +24V Supply voltage input (+6V to +28V DC)
>**3** CAN_H Differential CAN bus signal (non-inverting)
>**4** CAN_L Differential CAN bus signal (inverting)
>**5** GND Signal ground connection
>**6** +5V 5V output, 100mA maximum load, e.g. for end / home switch circuit or external encoder supply
>**7** HOME (GPI0) General purpose input 0, can be used as HOME switch input, also. Configurable as analog input AIN0 via software (+5V compatible, internal 10k pullup to +5V)
>**8** REFL (GPI1) General purpose input 1, can be used as left reference / stop switch input REFL / STOP_L, also. Configurable as incremental encoder input channel A via software (+5V TTL compatible, internal 10k pull-up to +5V)
>**9** REFR (GPI2) General purpose input 2, can be used as right reference / stop switch input REFR / STOP_R, also. Configurable as incremental encoder input channel B via software (+5V TTL compatible, internal 10k pull-up to +5V)
>**10** ENN (GPI3) ENABLE NOT input (active low) for driver stage, 0 = enabled, 1 = disabled (+5V TTL compatible, internal 10k pull-up to +5V)


　CANバスとは、CAN＿L、CAN＿H、GNDの3本でつなぎました。
　**7** HOME、**8** REFL、**9** REFRの3本にはマイクロスイッチをつなぎました。各信号は+5Vにプルアップされているので、スイッチがONになるとGNDとショートする配線です。**10** ENNは負論理なので、GNDに落として有効の状態にします。
　写真の電源ユニットは、12V-1.67Aです。

![IMGP0785.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/65123ced-a9d8-a9cd-d9ea-9404998353ff.png)

###CANopenの解説書
　1冊だけ見つけました。
　　　``Olaf Pfeiffer , Christian Keydel , Andrew Ayre、福島 E.文彦 (監修), シュタールジャパン (翻訳) ；CANおよびCANopenによる組み込みネットワーク、シュタールジャパン。``
Pry でサクッとベンチマーク


`.pryrc` に以下を追記すると、pry実行時にサクッとベンチマークがとれます。

```ruby
# ■ 使い方
# pry(main)> bench | {  [測定対象]  }
# pry(main)> bench | do
#  [測定対象]
# end
command_set = Pry::CommandSet.new do
  block_command('bench', "Use the Ruby benchmark to measure code blocks.", takes_block: true) do
    require 'benchmark'

    Benchmark.bm do |x|
      x.report do
        command_block.call
      end
    end
  end
end
Pry::Commands.import(command_set)
```
Zoomをサンドボックス化して起動する


## 手順

1. Zoom.pkgをhttps://zoom.us/downloadからダウンロードする
2. https://www.timdoug.com/unpkg/ を用いて展開する
3. Zoom/zoom.us.appを得る
4. `zoom.sh Zoom/zoom.us.app/Contents/MacOS/zoom.us`として起動する


```sh:zoom.sh
#!/bin/sh
sandbox-exec -p "
(version 1)
(allow default)
(deny file-write*)
(allow file-write*
    (subpath \"${HOME}/Library/Application Support/zoom.us\")
    (subpath \"${HOME}/Library/Logs/zoom.us\")
    (subpath \"${HOME}/Library/WebKit/us.zoom.xos\")
    (subpath \"${HOME}/Library/Caches/us.zoom.xos\")
    (subpath \"${HOME}/Library/Saved Application State/us.zoom.xos.savedState\")
    (subpath \"/private/var/tmp\")
    (subpath \"/private/tmp\")
    (subpath \"/tmp\")
    (subpath \"/private/var/folders\")
    (subpath \"/var/folders\")
)
(deny file* (regex #\"/id_rsa$\"))
(deny file* (regex #\"/id_dsa$\"))
(deny file* (regex #\"/id_ecdsa$\"))
(deny file* (regex #\"/id_ed25519$\"))
(deny file* (regex #\"\\.pem$\"))
" "$@"
```

(ところで$HOMEとか設定ファイルに書けないっぽいんですがなんとかなりませんかね、bashで逃げてますが。)

## 問題点

1. 初回起動時、ミーティングを開始できない不具合があるようですが再度起動すれば大丈夫です。
2. クラッシュが発生したと報告されるようですが無視すればよいです。

## あとがき

こういう記事はQiitaガイドライン的にどうなんだろうと思いましたが、少しZoomで検索したところまあ大丈夫の範疇みたい。
Android11でv1署名がサポートされなくなった

#経緯
jarsignerコマンドで署名して実機に`adb install`しようとしたらandroid11で下記のエラーが出た。

```
adb: failed to install hoge.apk: Failure [INSTALL_PARSE_FAILED_NO_CERTIFICATES: Scanning Failed.: No signature found in package of version 2 or newer for package jp.hogehoge]
```

エラーメッセージで調べると、v1署名のみのapkをandroid11にインストールしようとすると出るものらしい。

#対応
android11ではv1はサポートしないため、v2以降で署名する必要がある。
https://developer.android.com/about/versions/11/behavior-changes-11?hl=ja

v2署名をするためにはapksignerコマンドを使う。
https://developer.android.com/studio/command-line/apksigner?hl=ja

こんな感じ↓

```
$ apksigner sign --ks hoge.keystore {署名したいapkのパス}
```

#反省
２年前くらいから「apksigner使おうぜ！」みたいな記事を見てたけど放置した者の末路でした…
それなりに急いでたのでちょっと焦った件
自宅SCMサーバー再構成　構築編12　Gitlabテスト用ユーザーの作成



#旧式HPサーバーに CentOS7 をインストールしDockerコンテナ上でGitlabとRedmineを連携しSCM環境を再構築した際の備忘録（12）
##12.Gitlabユーザーの作成
###12-1.新規ユーザー作成
ブラウザで```127.0.0.1：9080```を開く
rootでGitlabへサインイン
![gitlabmenu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226547/1c2b9bdb-bab2-b0f1-8f3a-a9c886c73fac.png)から
![gitlaadmin.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226547/62cbdd41-02b0-ea7f-f092-4251eec7cb5d.png)を選択
```USERS```の```新規ユーザー```を選択
![gitalignuser1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226547/5823c28f-7312-190f-e985-16a78b5ea38b.png)

テスト用GitAlign01ユーザーを作成
※連携テスト用の為管理者で作成しました

![gitalignuser2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226547/d79ba135-3bf2-16b1-498a-3bcb73ce3dea.png)で新規ユーザー作成

![gitalignuser3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226547/43bc8fb3-92c0-2158-2c2a-e025c13faf4f.png)

###12-2.パスワードの付加
![gitalignuser4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226547/4060d8c9-9d86-20cf-5246-589febe520ad.png)
を押下し編集画面でパスワードを設定
![gitalignuser5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226547/d26453a1-fd34-1ccc-aa1d-6657ea2fbc1d.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226547/6b0e7cba-e901-e700-ca17-ea3829c49752.png)
で保存

※同様にユーザー```Gitalign02```も作成しておきます

次の工程

https://qiita.com/YCS_Project/items/26a31900140fc87b1311
VMWareからAzureに移行する際にポートが開いているにも関わらず開いていないと言われた場合の対処方法

#はじめに
エーティーエルシステムズ 森村です。

今回は、Azure Migrateツールを利用してVMWareからAzureに移行する際の手順の1つである、仮想マシンのレプリケート時に発生したエラー(110034)の対処方法について紹介します！

経緯として、私の所属するDS事業部の検証環境をVMWareからAzureに移行することになりました。
その際に、前述のようなエラーに衝突したものの、推奨される操作では解決できなかった&同様の問題を取り上げる文献が見つからなかったため、投稿に至りました。

同じ問題を抱えている方の手助けになればと思います。

**※免責事項(必ず、ご一読ください)**
本記事の情報により生じた、いかなる損害や損失についても、当社は一切の責任を負いかねます。
また、誤った情報が入り込んだり、情報が古くなったりすることもあります。必ずしも正確性を保証するものではありませんのでご了承ください。

#エラー内容
実際に発生したエラーは下記の通りです。
※ホスト名と仮想マシン名はダミーのものに差し替えてあります

**エラーID**
110034

**エラーメッセージ**
移行要件を取得できませんでした。

**プロバイダーエラーメッセージ**
The ESXi host 'host1.local' that virtual machine 'machine1' is running on is not reachable. 
Error message:No such host is known

**プロバイダーエラーから考えられる原因**
The port 902 is not open.

**プロバイダーエラーの推奨される操作**
Ensure that the port is open and then try again.

#原因
今回、検証サーバだったので設定を簡便にしていたため、DNSにGoogle DNS(8.8.8.8)を使用していたのですが、これが原因でvCenterからESXIのhost1.localが名前解決出来なかったようです…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1753781/c304c2ae-cc49-b129-f6bf-08b110bc3c2e.png)

図で表すと、このような状況になっていました。
![関係図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1753781/389db01f-9902-69f7-f974-66d43585d3dc.png)




#対処方法
アプライアンスサーバにあるhostsファイルにESXI(今回はhost1.local)を追加したところ、無事レプリケートが出来ました。
hostsファイルの場所：C:\windows\system32\drivers\etc\hosts
※ドメインはダミーのものに差し替えてあります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1753781/966b7b81-ccd0-0eca-129a-7e7b15a0f6b4.png)





#最後に
　最後まで読んでいただき、ありがとうございました！
　余談ですが、弊社は**facebook**もしております！よろしければご覧ください！
[![f_logo_RGB-Blue_64.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1661584/81cb9432-5fc7-7dfd-0155-15a602114fa2.png)](https://www.facebook.com/atlsystems)
ABC107 B - Candles diff 茶は焦るかも

https://atcoder.jp/contests/abc107/submissions/22307759

![abc107_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737344/7bee79b8-ff35-6b40-9ea9-2f4f4ad25b47.png)
![abc107_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737344/0f156fc2-34c1-e6c0-de46-ec74100c6ec3.png)
![abc107_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737344/7cebff39-8978-77ae-79ba-725d944bd410.png)
![abc107_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737344/94770990-9c37-5dc9-5e2e-86f1b8d1e9e9.png)

B 問題の diff 茶に初チャレンジ。
試験当日で、このレベルが来ると自分なら焦ると思います。

```Candles.py
H,W = map(int,input().split())
A = [list(input()) for _ in range(H)]
lisA = []
h = 0

for h in range(H):
    if A[h].count(".") != W:
        lisA.append(A[h])

#print(lisA,len(lisA))
memo = []
for w in range(W):
    cnt = 0
    for h in range(len(lisA)):
        #print(lisA[h][w],h,w)
        if lisA[h][w] == ".":
            cnt += 1
    if cnt == len(lisA):
        memo.append(w)

memo = set(memo)# <= ココ
ans =[]

for h in range(len(lisA)):
    ans.append([])
    for w in range(W):
        if w not in memo:# <= ココ
            ans[h].append(lisA[h][w])

#print(ans)
for i in range(len(ans)):
    print("".join(ans[i]))
```

in 演算子は set は計算量 O(1)。コメントの**"ココ"** をご覧ください。

https://takeg.hatenadiary.jp/entry/2019/06/02/172831