OmniAICreator/Qiita-1.07M huggingface dataset:
Wikiレンタルサービスをつくってみた

# はじめに
こんにちは、ぴたんです。
Wikiを無料で作成できるサービス、「WikiChree.COM」を数ヶ月前に作りました。

https://wikichree.com/

# サービスについて
WikiChree.COM以前はWikiCというサービスでした。
ソフトウェアにはPukiWikiを利用しており、PukiWikiはPHPで書かれた和製のCMSであり、Wikiを簡単に立てることができる便利なWebソフトウェアです。それをベースとしてWikiChreeのシステムを作りました。つまり、WikiChreeはほぼPukiWikiのレンタルサービスです。
コントロールパネルで設定を変更したりユーザーを追加できたりプラグイン導入できたりと割とカスタマイズできるようにしています。
サーバーにはCore Serverを使っています。

# お試しとサンプル
https://wikichree.com/TrialWiki/

https://wikichree.com/SampleWiki/

お試しとサンプルを載せています。

# 使い方
https://wikichree.com/Guide/

# 質問場所等
https://wikichree.com/forum/

https://discord.gg/nnC7wy25g7

Discordとフォーラムを設置しています。

プラグインの追加要望があれば以下のページでできます。

https://wikichree.com/SampleWiki/?%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3%E3%81%AE%E8%BF%BD%E5%8A%A0%E8%A6%81%E6%9C%9B

その他の要望はこちらでお願いしたいです。

https://wikichree.com/?%E8%A6%81%E6%9C%9B%E3%83%BB%E3%83%90%E3%82%B0%E5%A0%B1%E5%91%8A

# 苦労した点
PukiWikiの設定はpukiwiki.ini.phpで保存されています。
これでは、コントロールパネルで設定変更するには無理があります。
そのためpukiwikiの設定をjson化し、独自のコントロールパネルから設定を変更できるようにしました。

PukiWikiのコアの部分とデータの部分を分け、メンテナンスしやすくしました。
つまり、以下のサイトのWikiFarmということでしょうかね。

https://pukiwiki.osdn.jp/dev/?PukiWiki/WikiFarm

# おわりに
Wikiレンタルサービスをつくってて楽しかったです。
ただ、利用者はめちゃくちゃ少ないので使ってほしいところです。
ソリューションアーキテクト対策_オンプレからのデータ移行とデータ転送篇

## はじめに
試験勉強した際のメモを自分用に記事化。
内容は公式やBlack Beltの写経ですので目新しいことはありません:pray:

## オンプレからのデータ移行
### サーバー移行
#### AWS Application Migration Service(MGN)
VMwareなどのオンプレ・仮想インフラ・Azureなどの移行元環境からネットワークを経由してサーバーイメージを転送し、AWS環境へのサーバーの移行を実現するサービス。
ワークロードの転送を行うことができる。

旧称はAWS Server Migration Service(SMS)。現在は廃止。

### DB移行
#### AWS Database Migration Service(DMS)
広く使用されている商用およびオープンソースのほとんどのデータベースをAWSにデータ移行するサービス。

### 移行計画
### AWS Application Discovery Service(ADS)
オンプレミスサーバーのインベントリと動作を検出するために使用される。
このサービスは、AWSへの移行計画を作成するときに使う。
※実際にはサーバーにエージェントをインストールし、サーバーの利用情報を収集する

### データ転送・移行
#### AWS DataSync
オンプレミスストレージとEFSやFSxなどのファイルシステム間でデータを迅速かつ簡単に移動する際に利用するマネージド型のデータ転送サービス。
オープンソースと比べて最大10倍の速度で、アクティブなデータセットをAWS DirrectConnectまたはインターネット経由で転送できる。

## 大規模(エクサバイト規模)データ転送サービス
覚えられない。。w

### AWS Snowmobile
超大容量データをAWSに移動するために使用できるエクサバイト規模のデータ転送サービス。
トラック1台あたり100PBまで転送できる。DC全体のクラウド移行なんかもできる。

<img width="300" alt="スクリーンショット 2022-09-19 18.22.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278897/17997074-2d8d-05f2-0067-c6624e9ecba6.png">

### AWS Snowball
ペタバイト規模のデータ転送サービス。
現在はSnowballEdgeの利用が推奨されているため、利用することはない。

<img width="300" alt="スクリーンショット 2022-09-19 18.24.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278897/b80d6c68-60c4-29af-a182-d6fc62e88ee0.png">


### AWS Snowball Edge
統合されたストレージとコンピューティング機能を備えた100TBのデータ転送デバイス。
主にペタバイト規模のデータ移動に使用できる。エクサバイト規模のデータ転送は不可。

<img width="300" alt="スクリーンショット 2022-09-19 18.27.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278897/2fcf32e0-4337-ebf5-f756-c76fcb0d96b7.png">

ちなみにオプション？で容量が違う。
Snowball Edge Compute Optimized：42TB
Snowball Edge Storage Optimized：100TB(80TB)

## おわりに
引き続き追記します！

以上です。
レビュー機能（レビューを一覧表示させる）

mac OS バージョン11.6
エディタ…VScode
Rails 6.0.4

映画のレビュー機能に関する備忘録です。
レビューを一覧表示させることが目的で、レビューの投稿に関する記述は端折っています。
必要であれば別の記事で追記します。
![6df600d58c843b86d07be66a56a8373e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1962714/0e514943-ef56-6dfc-1a7a-4398d3f2a2c8.png)

# 1.モデル設計

![65c95b6e79bed96ec091f33cc49f179d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1962714/450d8ea4-1f9f-ac18-7f06-7e4a7ed04de4.png)
　・Userは多くのReviewを持ち、Movieも多くのReviewを持つことになる多対多の関係。
　・中間テーブルを作成して1つのレコード毎に、レビューの所有者（user_id）・映画（movie_id）・レビューの内容を格納するreview_textカラムを追加する。


```movie.rb
class Movie < ApplicationRecord
  has_many :reviews # Movie.commentsで、投稿が所有するコメントを取得できる
end
```

```user.rb
class User < ApplicationRecord
  has_many :reviews  #User.reviewsで、ユーザーの所有するコメントを取得できる
end
```

```review.rb
class Review < ApplicationRecord
   .
   .
   .
   belongs_to :user  　　#　Review.userでコメントの所有者を取得
   belongs_to :movie  #　Review.movieでそのコメントがされた投稿を取得
end
```

# 2.コントローラー設計
```movies_controller.rb
def show
    .
    .
    @reviews = @movie.reviews #　レビューを一覧表示
  end
```

```reviews_controller.rb
class ReviewsController < ApplicationController
  before_action :require_user_signed_in, only: [:create]
  def create
    @review = current_user.reviews.new(review_params) 
    @review.save
    redirect_to movie_path(@review.movie_id)
  end

  def new
    @review = Review.new
  end

  private
    def review_params
      params.require(:review).permit(:movie_id, :user_id, :text, :raty) 
    end
  end  
```

# 3.viewを編集

```html:movies/show.html.erb
    .
    .
    .
    <h1>レビュー一覧</h1>
<% @reviews.each do |review|%>
  <div class=card>
    <%= review.user.name %><br>
    <p>評価 :<%= review.raty %>点</p>
    <div id="star-rate<%= review.id %>"></div>    
    <script>
      $('#star-rate<%= review.id%>').raty({
        size      : 36,
        starOff   : '<%= asset_path('star-off.png') %>',
        starOn    : '<%= asset_path('star-on.png') %>',
        starHalf: '<%= asset_path('star-half.png') %>',
        readOnly: true,  //星を読み取り専用にする
        score: <%= review.raty %>,
      });
    </script>
    <p>内容:<%= review.text%></p>
  </div>
<% end %>
```



参考：https://qiita.com/kurawo___D/items/d2fefdd329f5310113aa
Windows 10のONLYOFFICE Desktop Editorsで自動音声認識を利用する方法

テキストを手入力することなく、ドキュメントに直接口述することができます。これは、Windows 10に内蔵された音声認識ツールを使って簡単に行うことができます。また、内蔵のデジタルアシスタントCortanaを使って、音声コマンドでテキストエディターを起動することも可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2655664/d21f667a-ef9e-a2b4-7596-f375d35502e2.png)

### 必要条件

* Windows 10以降
* PCに接続されたマイク
* [ONLYOFFICE Desktop Editors](https://www.onlyoffice.com/download-desktop.aspx?utm_source=qiita&utm_medium=article&utm_campaign=speechtotext)がPCにインストールされていること

### Windowsの設定を調整する

１．「スタート」→「設定」→「**プライバシー**」と進みます。
２． **音声起動**の項目を開きます。
３．「**音声起動を使用するアプリを許可する**」スイッチャーをオンにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2655664/4863aaea-2db9-d41c-38b3-ac248724a0ba.png)

４．「コルタナに『コルタナ』と応答」キーワードスイッチャーをオンにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2655664/284a19f7-92b9-79ef-6078-31df2c823b0e.png)

５．プライバシー設定で、「**スピーチ**」セクションを開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2655664/6662e681-270b-e7a9-b067-2a2f133bcd5d.png)

６．オンライン音声認識スイッチャーをオンにします。

### 文書にテキストを書き込む

１．Cortanaを起動します。スタート」→「すべてのアプリ」→「Cortana」。また、タスクバーの検索バー右のCortanaアイコンをクリックするか、Win+Cを押すか、「Cortana」と言っても起動できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2655664/40929a61-30d2-afce-f2a2-f43c8ff7b64a.png)

２．初めてCortanaを起動する場合は、MicrosoftアカウントでCortanaにサインインしてください。
３．設定によっては、マイクをクリックするか、「Cortana」と発言して、ONLYOFFICE Desktop Editors on Windows 10の音声認識機能を利用します。
４．「ONLYOFFICE Editorsを開く」と言います。その後、ONLYOFFICE Desktop Editorsのメインウィンドウが開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2655664/809b7b63-486b-2c13-737a-5c7c911f3e8a.png)

５．ドキュメント'をクリックして新しいドキュメントを作成します。
６．**Win+H** キーを押します。画面上部に音声認識ウィンドウが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2655664/513d35b8-65a1-2814-bf7e-a434d830fe5f.png)

７．マイクで口述筆記を開始します。あなたの言葉は、自動的に文書に入力されます。

書き取りの際に役立つヒントがあります。

* 「、」の場合は「コンマ」、「？」は「疑問符」、「！」は「感嘆符、ビックリマーク」
* 新しい段落を始めるには「改行」と言います。
* 一時停止したり、マウスでクリックすると、音声認識も一時停止します。左側のマイクのアイコンをクリックすると、口述筆記を続けることができます。
* 終了したら、「口述をやめる」と言うか、音声認識ウィンドウを閉じます。

音声認識コマンドの全リストは[こちら](https://support.microsoft.com/ja-jp/windows/windows-音声認識コマンド-9d25ef36-994d-f367-a81a-a326160128c7)でご覧いただけます。

音声入力が終了したら、テキストを含む文書を保存するのを忘れないようにしてください。

**注**：[ONLYOFFICE Document Editor](https://helpcenter.onlyoffice.com/userguides/docs-de.aspx?utm_source=qiita&utm_medium=article&utm_campaign=speechtotext&_ga=2.167238462.1012847778.1662971410-1704458868.1654884129)で利用可能な複数のフォーマットツールを使って、さらにテキストをフォーマットすることができます。
Modelerストリームのノード情報をmodeler scriptで取得する

Modeler ScriptをつかってModelerストリームのノード情報を取得します。

以下のようなPythonのmodeler scriptで取得できます。

```python:nodeinfo.py
import modeler.api
import pprint
stream = modeler.script.stream()

for node in stream.iterator():
    print('id: '+node.getID())
    print('label: '+node.getLabel())
    print('typeName: '+node.getTypeName())
    print('getAnnotation: '+node.getAnnotation())
    print 'getKeywords: ', ' '.join(map(str,node.getKeywords()))
    print('getToolTipText: '+node.getToolTipText())
    print''

```

以下のストリームからコメントを取得します。様々な種類のノードが使われています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/c478a941-ef40-f891-faee-e5c3af8df309.png)

特に「credit_６か月前.csv」については注釈情報を詳しく入力しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/69ea8678-f263-9250-586b-40c41dcbebdc.png)


以下のように全ノードのid、ラベル、ノードタイプ、注釈、キーワード、ツールチップの情報が取れています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/90ef7ad1-eab4-0639-0f15-5cf24e1fbe48.png)


```output:結果
id: id6I7QRGCAXGX
label: credit_６か月前.csv
typeName: variablefile
getAnnotation: 入力ファイルは適宜最新をダウンロードしてください。
getKeywords:  キーワード１
getToolTipText: 入力ファイルは最新を使ってください

id: id6Z4WQVEADMV
label: HKWD.COND4N_E104
typeName: database
getAnnotation: 
getKeywords:  
getToolTipText: 

id: id7X8RT3RE74Y
label: credit_新規結果.csv
typeName: outputfile
getAnnotation: 
getKeywords:  
getToolTipText: 

id: id5W8R6HDHYY4
label: credit_新規顧客.csv
typeName: variablefile
getAnnotation: 
getKeywords:  
getToolTipText: 

id: id5W6WKK3E9HH
label: Age > '$P-AGE'
typeName: select
getAnnotation: 
getKeywords:  
getToolTipText: 

id: id3VMXA85W5LP
label: Credit_rating
typeName: chaid
getAnnotation: 8679a6771f
getKeywords:  
getToolTipText: 

id: id492VK7JSS41
label: Credit_rating
typeName: applychaid
getAnnotation: 8679a6771f
getKeywords:  
getToolTipText: 

id: id2KGWUX5K8AH
label: Credit_rating
typeName: applychaid
getAnnotation: 8679a6771f
getKeywords:  
getToolTipText: 

id: id3QPX5A7BQWG
label: 拡張の変換
typeName: extension_process
getAnnotation: 
getKeywords:  
getToolTipText: 

id: id2GDXAWCGG6M
label: 精度分析
typeName: analysis
getAnnotation: 8679a67821
getKeywords:  
getToolTipText: 

id: id1WEX4RUL91M
label: TESTTAB
typeName: databaseexport
getAnnotation: 
getKeywords:  
getToolTipText: 
```

* テスト環境
    * Modeler 18.4
    * Windows 11 64bit

## 参考
共通のノード・プロパティー - IBM Documentation 

https://www.ibm.com/docs/ja/spss-modeler/18.4.0?topic=overview-common-node-properties
【初投稿】私のVimセットアップ公開!!



## なぜVimなんすかあまみやさん？

![スクリーンショット 2022-09-15 160203.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2081812/cc24944a-5c55-6bf0-94bd-83ea4b41ef98.png)


私がVimを採用した理由が、軽量なのもありますが憧れのエンジニアがようつべでVimを使ってアプリ開発をしていたのでその影響で使い始めました。

## んで、肝心のセットアップは？

```

set number " 行番号の追加
set ruler " 右下にカーソルの位置を表示
set showcmd " 入力中のコマンドを表示
set title " タイトルの追加
syntax enable " シンタックスハイライトを有効化
set wildmenu " vim上からファイルを選択できる機能を有効化
set ambiwidth=double " 全角文字の重なりを解消
set backspace=indent,eol,start " 挿入モードでbackspaceを使って削除を可能に
set laststatus=2 " ステータスバーを2行表示
set history=1000 " コマンドの履歴を1000件保存
set showmatch " 対応する括弧をハイライト
set smartindent " 前の行のインデントを保持
set clipboard+=unnamed " ヤンクの結果をクリップボードに保存
set noerrorbells " エラーの表示時にビープ音を鳴らさない
set mouse=a " マウスの有効化
nmap wrap <C-k>
set shiftwidth=0 " タブの設定(タブ幅4の場合)
set softtabstop=4
set tabstop=4

autocmd FileType python setlocal tabstop=4 " 言語ごとにタブ幅を設定する場合
autocmd ColorScheme * highlight Comment ctermfg=219
set hlsearch " 検索結果をハイライト
set incsearch " 最初の一文字を入力した時点から検索開始
set wrapscan " ファイル末尾に到達すると再び先頭から検索

call plug#begin()
Plug 'vim-airline/vim-airline'
Plug 'vim-airline/vim-airline-themes'
Plug 'neoclide/coc.nvim', {'branch': 'release'}
Plug 'konfekt/vim-compilers'
Plug 'guns/xterm-color-table.vim'
Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all' }
Plug 'junegunn/fzf.vim'

call plug#end()

let g:airline_theme = 'wombat'              " テーマの指定
let g:airline#extensions#tabline#enabled = 1 " タブラインを表示
let g:airline_powerline_fonts = 1            " Powerline Fonts 

nmap <C-n> <Plug>AirlineSelectPrevTab
nmap <C-p> <Plug>AirlineSelectNextTab

if !exists('g:airline_symbols')
		let g:airline_symbols = {}
	endif
	 
	"左側に使用されるセパレータ
	"let g:airline_left_sep = '⮀'
	"let g:airline_left_alt_sep = '⮁'
	""右側に使用されるセパレータ
	let g:airline_right_sep = '⮂'
	let g:airline_right_alt_sep = '⮃'
	let g:airline_symbols.crypt = '🔒'		"暗号化されたファイル
	let g:airline_symbols.linenr = '¶'			"行
	let g:airline_symbols.maxlinenr = '㏑'		"最大行
	let g:airline_symbols.branch = '⭠'		"gitブランチ
	let g:airline_symbols.paste = 'ρ'			"ペーストモード
	let g:airline_symbols.spell = 'Ꞩ'			"スペルチェック
	let g:airline_symbols.notexists = '∄'		"gitで管理されていない場合
	let g:airline_symbols.whitespace = 'Ξ'	"空白の警告(余分な空白など)

```

こんな感じです。ほかの方のコードを引っ張っている部分か大半なので、、、まぁ快適につかっています。

それでは。
pydicomを使って感動した話

# プロローグ
テストのために数多くのDICOMファイルが必要になったヤマトンボ。
ネット上で拾えるDICOMだけでは到底テストを満たすファイルをそろえることができない。
タグ情報を変更すれば、テストの条件を満たすファイルを作り出すことができるが、DICOM Viewerを使ってポチポチ変えていくのは、時間もかかるしエンジニアらしくない。
そう思いながらいい手段はないかと調べていたら、**pydicom**を使えば簡単にDICOMファイルの操作が行えるらしいことが分かった。
「これは良さそうだ」
ヤマトンボはpydicomを使って、テスト用のファイルを作り出すことを決意するのだった。

# マシンスペックとPythonのインストール
OS:Windows 10
CPU:Intel(R) Core(TM) i7-8665U CPU @ 1.90GHz   2.11 GHz
メモリ:16GB

このマシンに、Python 3.10.xをインストール
インストール方法は次のHPを参照しました。

[windows版Pythonのインストール](https://www.python.jp/install/windows/install.html)


# pydicomのインストールと使い方
pydicomのインストールと簡単な使い方は次の記事を参考にさせて頂きました。

[【DICOM】【入門】Pydicomの使い方](https://qiita.com/mizu4my/items/3fa0f085a2252249fa45)

# いざ実践

次のコードでDICOMファイルのタグを編集して、ファイルを作成することができました。

```python:example.py
import pydicom

ds = pydicom.dcmread('DICOMファイルのパス')
ds[('編集したいDICOMのタグ')].value = '変更後の値'
ds.save_as('変更後のファイル名', write_like_original=False)
```
これだけのコードでやりたいことが実現できました。

# 感想
Pythonはライブラリが豊富なのは前から知っていましたが、今回はそのおかげで大変助かりました。
久しぶりにPythonでコードを書きましたが、少ないコードでやりたいことが実現できるのは時間の節約にもなりますね。
今回はタグ情報を変更するだけでしたが、ほかにもいろいろできるようなので空き時間に試してみたいと思います。
【SwiftUI】アラートのバグの回避策

# はじめに
iOSDCで「[SwiftUIのハマりどころと回避策](https://fortee.jp/iosdc-japan-2022/proposal/41079124-aab4-40a9-b8ee-efdac7ca4e72)」を拝見して自分的にはこうすると思った事があったので記事にしておきます。

# アラートのバグ
1つのViewに対して2つのアラートを適用している場合に外側のアラートしか表示されないバグです。
```swift:iOS14
import SwiftUI

struct ContentView: View {
    @State private var isAlert1 = false
    @State private var isAlert2 = false
    var body: some View {
        VStack(alignment: .center, spacing: 30) {
            Button("アラート1") {
                isAlert1 = true
            }
            Button("アラート2") {
                isAlert2 = true
            }
        }
        .alert(isPresented: $isAlert1) {
            Alert(title: Text("アラート1"))
        }
        .alert(isPresented: $isAlert2) {
            Alert(title: Text("アラート2"))
        }
    }
}
```

上記のコードの場合、
アラート2は表示されて、アラート1は表示されません。

![Simulator Screen Recording - iPhone 12 - 2022-09-15 at 15.34.08.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/c68c25dd-67d8-1fa9-f811-79089ad9ff67.gif)

# 回避策
UIAlertControllerを使用します。
```swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack(alignment: .center, spacing: 30) {
            Button("アラート3") {
                alert(title: "アラート", message: nil, buttons: [
                    UIAlertAction(title: "OK", style: .default)
                ])
            }
        }
    }
    private func alert(title: String?, message: String?, buttons: [UIAlertAction]? = nil) {
        let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
        if let buttons = buttons {
            for button in buttons {
                alert.addAction(button)
            }
        }
        UIApplication.shared.windows.first?.rootViewController?.present(alert, animated: true, completion: nil)
    }
}
```

![Simulator Screen Recording - iPhone 12 - 2022-09-15 at 15.40.28.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/5efc4a65-f19f-7eef-5be1-c2699a664555.gif)

# 使い方
ボタンを増やすには配列の中に`UIAlertAction`を追加していきます
```swift
alert(title: "アラート", message: nil, buttons: [
    UIAlertAction(title: "キャンセル", style: .cancel),
    UIAlertAction(title: "OK", style: .default)
])
```
![スクリーンショット 2022-09-15 15.43.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/51f3fce9-7265-9f8a-78a9-3221a6cb41a8.png)

# おわり
iOS15からは[こちら](https://capibara1969.com/3757/)のやり方でアラートを実装することでこのバグを回避する事ができます。
しかし、最低OSがiOS15になるのはまだ先になると思うので、
しばらくは回避策を使うことになりそうです
Flutter 環境構築(M1 Mac)

## 環境
MacBook Air(apple M1,2020)
macOS Monterey(version 12.6)
zsh

## 手順
(1)Flutter SDK(for M1 Mac)をダウンロードする
(2)FlutterのPATHを通す
(3)Android Studio(Chipmunk for M1 Mac)をダウンロードする
(4)Xcode(version 14)をダウンロードする
(5)flutter doctorコマンドで環境構築が完成しているか確認する

## (1)Flutter SDK(for M1 Mac)をダウンロードする
 - https://docs.flutter.dev/get-started/install
 - zip解凍後にホームディレクトリへ移動させる

## (2)FlutterのPATHを通す
 - Flutter/binフォルダを右クリックして、optionキーでPATHをコピーする
 - terminalで以下のコマンドを入力する

```
echo export PATH="$PATH:{コピーしたPATH}" >> ~/.zshrc
```

※ここでflutter doctorコマンドを入力すると、環境構築に不足している箇所にエラーが表示される。(3)以降の手順でエラーを解消する。
![初期状態.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275576/ee5396c8-f9d9-9910-ff56-82c8dab2f681.png)


## (3)Android Studio(Chipmunk for M1 Mac)をダウンロードする
 - https://developer.android.com/studio
 - FlutterとDartのプラグインを追加する
 - SDK manager/SDK toolsでAndroid SDK Command-line Toolsにチェックをつけてapplyする
 - flutter doctorコマンドでAndroidの欄にエラーが出ている場合は解消する
```
# 今回表示されたエラー内容
[!] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
    ! Some Android licenses not accepted.  To resolve this, run: flutter doctor --android-licenses

# エラー文にあるコマンドをterminalで入力すると解消できる
sudo flutter doctor --android-licenses
```

## (4)Xcode(version 14)をダウンロードする
 - App StoreからXcodeをダウンロードする
 - flutter doctorコマンドでXcodeの欄にエラーが出ている場合は解消する
```
# 今回表示されたエラー内容
For more info, see https://flutter.dev/platfprm-plugins To see https://guides.cocoapods.org/using/getting-started.html#installation for instructions.

# エラー文にあるcocoapodsのサイトに載っているコマンドをterminalで入力すると解消できる
sudo gem install cocoapods
```

## (5)flutter doctorコマンドで環境構築が完成しているか確認する
 - 緑色のチェックマークがついていればOK
![インストール完了.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275576/3a35b200-b4d4-8e09-91d9-8e549524bfeb.png)
ABS Module VW

Pump ABS VW Golf 1.4
www.labsaudi.com
Informasi Produk
Kondisi : Baru
Harga : pcs
Kendaraan : VW
Bengkel Quattro melayani jasa import parts mobil-mobil Eropa, merk Audi, VW, MercedesBenz, Jaguar, Bentley, Ferrari dan merk Eropa lainnya dengan harga kompetitif dan terjangkau.
Untuk informasi selanjutnya silahkan menghubungi kami melalui WA/call : 0818777784, 081804010909, 081217777990 atau (021) 78846171
wslで.ssh/をコピペしたらUNPROTECTED PRIVATE KEY FILE!と怒られた件について

## ssh/をコピペすると怒られた
Windows PCを買い替えたので、古いPCのWSL環境から新しいPCのWSL環境に.ssh/のディレクトリをコピーしたのだけれど、その際にパーミッション周りで少し詰まったのでメモ。

結論から言えば、例えば鍵のパスが/root/.ssh/keys/id_rsaであるなら下記の様に設定すればよかった
```bash
chmod 600 /root/.ssh/keys/id_rsa
```

## 簡単な説明
まず、コピーしてそのまま

```bash
ssh hogehoge
```

とssh接続しようとすると、

```bash
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for '/root/.ssh/keys/id_rsa' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key "/root/.ssh/keys/id_rsa": bad permissions
git@github.com: Permission denied (publickey).
```
と怒られた
<br />

エラー文を軽く訳せば
```txt
/root/.ssh/keys/id_rsa' のパーミッション 0644 は開きすぎています。
秘密鍵のファイルは、他人がアクセスできないようにする必要があります。
この秘密鍵は無視されます。
……
```

つまりパーミッションを変更して他人がアクセス出来ないようにすればいいということらしい
<br />

パーミッションに関しての説明は省くが、[Linuxの権限確認と変更(chmod)（超初心者向け）](https://qiita.com/shisama/items/5f4c4fa768642aad9e06)等を読めば理解出来ると思う

なので、もし仮に鍵を /root/.ssh/keys/ に保存していたのなら、
```bash
chmod 600 /root/.ssh/keys/id_rsa
# 一斉に変更するなら chmod 600 /root/.ssh/keys/*rsa とか？
```

と入力すればいい
※chmod 600……をchmod 700……にしても問題はない
<br />

つまり、別パターンとして鍵を /root/.ssh/ に保存していたのなら
```bash
chmod 600 /root/.ssh/id_rsa
# 一斉に変更するなら chmod 600 /root/.ssh/*rsa とか？
```
ということだと思う
※chmod 600……をchmod 700……にしても問題はない

## 参考資料
- [MacでSSH接続→Permissions 0644 for ‘xxx.key’ are too open.](https://umebius.com/dev/permissions-0644-for-xxx-key-are-too-open-%E6%A8%A9%E9%99%90%E3%82%92%E3%81%A9%E3%81%86%E3%81%99%E3%82%8C%E3%81%B0%E3%81%84%E3%81%84%EF%BC%9F/)
NestJS　DIについて

## NestJSとは

効率的でスケーラブルな Node.js サーバー側アプリケーションを構築するためのフレームワークです。
プログレッシブ JavaScript を使用し、TypeScript を使用して構築され、OOP (オブジェクト指向プログラミング)、FP (関数型プログラミング)、および FRP (関数型リアクティブ プログラミング) の要素を組み合わせます。

内部では、Nest は Express (デフォルト) のような堅牢な HTTP サーバー フレームワークを利用し、オプションで Fastify を使用するように構成することもできます。

Nest は、これらの一般的な Node.js フレームワーク (Express/Fastify) より上のレベルの抽象化を提供しますが、それらの API を開発者に直接公開します。これにより、開発者は、基盤となるプラットフォームで利用可能な無数のサードパーティ モジュールを自由に使用できます。

## 基本的な考え方

モジュールと呼ばれる部品の単位で実装し、それを`app.module.ts`でインポートすることでアプリケーションを構築していきます。ビジネスロジックに関しては、 `service`、ルーティング処理に関しては`controller`が管理します。

ServiceをControllerにDIすることで、ControllerはServiceの内部構造を知る必要がなくなり、簡潔なルーティングを記述することができます。

## srcのファイル構造

```sh
# src
# ├── app.controller.spec.ts // app.controller.tsのテストファイル
# ├── app.controller.ts // ルーティング処理を記述したファイル
# ├── app.module.ts // プロジェクトで使用したいモジュールをインポートすることで、アプリケーションを構築する
# ├── app.service.ts // app.controller.tsで使用するビジネスロジック
# └── main.ts // 最初にコードが実行されるエントリーポイント
# nestjsでは各機能をモジュールという単位で管理する
```

## DI(Dependency Injection)とは

ソフトウェアを疎結合にするための設計パターンの一つです。
あるオブジェクトが必要とするオブジェクトを、そのオブジェクト自身ではなく、外部から与えることで、オブジェクトの内部構造を隠蔽し、再利用性を高めるデザインパターンのことです。
依存性の注入を行うことで、オブジェクトの生成と利用の責務を分離することができます。

NestJSでは、ServiceをControllerにDIすることで、ControllerはServiceの内部構造を知る必要がなくなります。


## 実例

```app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}
  // 既にinstance化されたものをAppControllerのconstructorで受け取る
  // これで、AppControllerのgetHello()メソッドでAppServiceのgetHello()メソッドを呼び出せる
  // nestjsは、IoCコンテナを使って、instance化したものをAppControllerに渡している
  // instanceは、cacheされているので、同じものが何度もinstance化されることはない(=singleton)

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
}
```

```app.service.ts
import { Injectable } from '@nestjs/common';

@Injectable()
export class AppService {
  getHello(): string {
    return 'Hello World!';
  }
}
```

```app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [],
  controllers: [AppController], // AppControllerを使用することをここで書く
  providers: [AppService],      // controllersで使用するServiceをここで書く
})
export class AppModule {}
```

```main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule); // AppModuleをinstance化して、appに代入
  await app.listen(3005); // 3000はReactのデフォルトポートなので変更
}
bootstrap();

```

controllerはserviceの内部実装を知ることなく、getHello関数を利用することができています。


## 参考

https://docs.nestjs.com/
https://en.wikipedia.org/wiki/Dependency_injection
【Fitbit】Fitbit APIで日中データを取得しようとするとエラーが出る（insufficient_permissions）

どうも、こんにちは。
この世界のどこかで掲題の件で困っている人がいると思い、記事を書かせていただきました。
自分の経験が助けになればうれしいです。
# 事象
ご存じ、ウェアラブルデバイスのFitbitにはWeb APIが用意されており、呼び出すことでFitbitに蓄積されたデータを気軽に取得できるのです。
[Fitbit APIについて](https://dev.fitbit.com/build/reference/web-api/ "公式サイト")

※APIの叩き方については以下を参考にさせていただきました
[Fitbit Web APIを利用して心拍数の生データを取得する方法【動画版あり】](https://zenn.dev/tatsuyasusukida/articles/5ebb0e34a17241)

そんなFitbit APIを使って開発（ユーザー登録してもらった人の心拍数などを取得してグラフ表示するようなアプリ）をしている中で事件は起きました。
以下のエンドポイントに対してリクエストを送りました。（指定された日中の時間の心拍数のデータを取得する）
```
GET https://api.fitbit.com/1/user/-/activities/heart/date/2022-08-01/1d/1min/time/08:00/08:30.json
```

すると以下のエラーが。

``` json
  {
    errorType: 'insufficient_permissions',
    message: 'API client is not authorized by Fitbit to access the resource requested. Visit https://dev.fitbit.com/docs/oauth2 for more information on the Fitbit Web API authorization process.'
  }
```
むむ・・・

# 状況
- Fitbitに登録しているアプリケーションのOauth2.0 Application Typeは「Server」
![fitbit登録画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239102/9a5cbdd5-f527-2675-cfd4-7ca36f3034c5.png)
- Fitbitの認証画面にて、心拍数（HeartRate）を取得する許可は設定済み
![fitbit認証画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239102/da5af0f8-72ac-e688-b4a0-1c2b33a13cc4.png)

# 原因
### 日中のFitbitデータを取得するためにはFitbitへの申請が必要でした（Oauth2.0 Application Typeが「Personal」以外の場合）
※「Personal」の場合は、申請を行わなくても情報取得が可能です。

# 解決方法
以下の申請画面から必要な情報を入力し、Fitbitに提出します。（英語のフォームになっているので、英語で各情報を入力しました）
[申請画面](https://dev.fitbit.com/build/reference/web-api/intraday/)

提出後、大体2週間（10営業日）ちょっと経つと、Fitbitから「日中データ取得してもいいよー」という旨のメールが来ます。（自分の場合はそうでした、早くなることもある）
※審査？にかなり時間がかかるので、もし開発に期限がある場合は早めに申請を行うことをお勧めします。
そのあと、Fitbit Web APIを呼び出すと日中のデータが取得できるようになります。やったー。

# 最後に
Fitbit、いいですよね。
Fitbit Web APIの確認をするためにわざわざ運動しました。
ついでに健康になれてよかったです。
Concrete CMS のエラーログに Stack Trace も記録させる


Concrete CMS のエラーログに、Symfony の Strack Trace も残すようにできるカスタマイズです。

画面で表示されないバックグラウンドでエラーが発生した時や、本番環境などで、デバッグモードをオフにして Stack Trace を非表示にしている際のデバッグ用に使えます。

やり方は簡単。

`application/config/app.php` に以下のような記述を追加します。


```
<?php
use Psr\Log\LoggerInterface;
/** @var \Whoops\Run $run */
/** @var LoggerInterface $logger */
$logger = $app->make(LoggerInterface::class);
$run = $app->make(\Whoops\Run::class);
$run->pushHandler(function($exception, $inspector, $run) use ($logger) {
    /** @var Exception $exception */
    $logger->debug($exception->getTraceAsString());
    return \Whoops\Handler\Handler::DONE;
});
```

以上
SQLAlchemyのIntegrityErrorを一意制約違反の例外としてexceptしてはいけない

# はじめに

SQLAlchemyで一意制約違反した時に、以下のようなエラーが発生します。
```
sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) UNIQUE constraint failed: user.email_address
```
一見、 `IntegrityError`の例外をexceptで囲んで一意制約違反の例外として処理したくなります。
しかし**これはNGです。**

# なぜNGなのか

`IntegrityError`は一意制約違反のエラーではなく**DBのエラー全般をラップしたエラー**だからです。
つまり**一意制約違反**以外にも**NOT NULL制約違反**や**外部キー制約違反**も`IntegrityError`になります。

以下は悪い例です。

```python:悪い例

def create_user(session, user_name, email):
        try:
            user = User(user_name=user_name, email=email)
            session.add(user)
            session.commit()
            session.reflesh()

        except IntegrityError:
            session.rollback()
            raise HTTPException(status=400, detail="email is already exist.")

```
emailの一意制約違反と決めてつけていますが、もしかすると別のカラムがNOT NULL制約に違反しているのかもしれません。

# どうするべきか

`IntegrityError`が保持しているオリジナルのエラーをexceptしてあげると良いです。
例えば以下のような感じです。（FastAPIとpsycopg2を例に用いています。）

```crud.py
def create_user(session, user_name, email):
        try:
            user = User(user_name=user_name, email=email)
            session.add(user)
            session.commit()
            session.reflesh()

        except IntegrityError as sqlalchemy_error:
            session.rollback()
            raise sqlalchemy_error.orig # DatabaseごとのAPIのエラーをraiseする

```

```main.py

from psycopg2 import errors as psycopg2_errors

@app.post("/users/")
def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)):
    try:
        created_user = crud.create_user(
            session=db, 
            user_name=user.user_name,
            email=user.email
        )
        return created_user
    
    except psycopg2_errors.UniqueViolation:
        raise HTTPException(status=400, detail="email is already exist.")
    
    except psycopg2_errors.NotNullViolation:
        raise HTTPException(status=400, detail="invalid parameters.")

```

# 参考

- [sqlalchemy.exc.IntegrityError](https://docs.sqlalchemy.org/en/14/core/exceptions.html#sqlalchemy.exc.IntegrityError)
Sales Enablement（旧My Trailhead）のモジュール作成およびリリースの方法

Salesforceの製品にはSales Enablementがあります
今回はSales Enabementでモジュール作成およびリリースする方法を説明します


### 備考

※Sales Enablementは2022年9月現在英語のみの設定画面です。なので今回の解説も英語の文字が多いです。ご了承ください

※ReleaseしたSales Enablementは削除することはできません。あくまでユーザに非公開にすることしかできません
なので、Releaseする前は気をつけてください
もしも非公開にしたい場合は以下の記事をご覧ください

Sales Enablement（旧My Trailhead）でモジュールを非表示（archive）にする方法

https://qiita.com/Takaa/items/7946dde1ce62bd7b617b


### そもそもSales Enambementってなんだ？

Sales Enablement（旧My Trailhead）は自分でTrailheadのモジュールみたいなものが作成できてユーザに公開して楽しく簡単にTrailheadのような学習方法を提供できるツールです



![step000.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/2bd20cbb-4129-2675-ce8a-9b6ad263ac1b.png)


それでは次のステップでSales Enambement作成およびリリースの方法を説明します

## モジュール作成方法


### ステップ１
「Content」タブから「Add　Content」から「New Module」をクリックする
![コンテンツ01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/76bbcecb-c380-ef23-1d3a-83cbed2d0cda.png)

### ステップ2

ModuleのバッジやTitleを記載する、その後右下の「New Unit」をクリックする

（フィルターは必ず設定しましょう）
![コンテンツ02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/5412495f-f9f5-acec-fef6-e08a8d67b741.png)

### ステップ3

Unitを記載する。
その後「New　Assesment」をクリックする


![コンテンツ03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/f7bc2c5d-4a7f-4a9d-d37f-a85f8fc78319.png)


### ステップ4

Question に問題文を記載
Answerに選択肢を記載します

![コンテンツ04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/6edb64d1-8be4-9148-588e-38f10e655ae6.png)


以上でModule作成は完了です

## モジュールリリース方法


### ステップ5
Releaseタブをクリックし「New Release」をクリックします

![05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/716a03f8-bd59-d453-b517-6739778fb52a.png)

### ステップ6

Release NameとAPI Nameを記載し「Create」をクリックします
![06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/6e331e10-2674-439d-b32c-df67570ed302.png)


### ステップ7

作成したMocduleの「▽」ボタンから「Add to Release」をクリック

![07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/c94b9c0c-0e2e-5b9b-425c-8847b820e825.png)

### ステップ8
先ほど作成したReleaseを選択し「Next」をクリックする
![08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/6a54caa6-c903-5f91-6e05-7c2a20cb47a0.png)

### ステップ9

再度「Release」タブをクリックし先ほど作成したReleaseを選択し「Publish」をクリック

![09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/c85ecf4d-ab7f-a9b6-3c9a-ba01588cd712.png)


### ステップ10 Let's do this!をクリック
 ![step12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/c9fbd6b4-fb75-b603-3f16-c8dff61f74a5.png)


### ステップ11 All Releases をクリック

![step13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/e7003b73-ec05-3ae3-725a-20cffdfaaeb8.png)


以上でModule作成およびReleaseができました



※ReleaseしたSales Enablementは削除することはできません。あくまでユーザに非公開にすることしかできません
なので、Releaseする前は気をつけてください
もしも非公開にしたい場合は以下の記事をご覧ください

Sales Enablement（旧My Trailhead）でモジュールを非表示（archive）にする方法

https://qiita.com/Takaa/items/7946dde1ce62bd7b617b
VSCodeでファイルやフォルダの差分を比較する

## 使いどころ
サイト上や書籍での学習をしているとサンプルコードの写経を行うことがあると思います。

サンプルコードをまとめたプロジェクトを写経した時など、エラーが起きているとバージョン違い等環境の問題で実行できないのか、コードが間違えているのか原因を探すのに手間取ってしまいます。

そんな時、ささっとファイルやフォルダの差分を比較できれば退屈な作業を減らせるし、学習速度は早まるし、モチベーションも維持できるしで一石三鳥ですよね！？

今回はその方法をご紹介します。

## ファイルの比較
1. VSCode上でコマンドパレットを開く（F1で開きます）
2. compare（比較）と入力すると３つ候補が出てくるので、任意のものを選ぶ。
- Compare Active file with...（任意のファイルを開きアクティブなファイルと比較する）
- Compare Active File with Saved（最後に保存した状態のファイルを現在の状態と比較する）
- Compare Active File with Clipboard（クリップボードをアクティブなファイルと比較する）
![compare_file.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821326/c3dc0843-3995-f961-81d1-ba49d7297eea.png)

で、選択するとこんな感じの画面になります。
![compare_file1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821326/be661e8b-a357-700d-1b38-1becaab25460.png)
画面中央部の"→"をクリックすることで差分のInsertもできますし、
Undo（Ctrl＋Z)することもできます。

## フォルダの比較
フォルダの比較は標準では使えないので拡張機能を入れてやる必要があります。
1. 拡張機能の検索窓（Ctrl+Shift+X）から、"Compare Folders"をインストールする
2. compare foldersと入力するといくつか候補が出てくるので、任意のものを選ぶ。

（よく使うのは以下の２つになると思います）
- Compare a folder against workspace（任意のフォルダを開き現在のワークスペースと比較する）
- Choose 2 folders and compare（２つのフォルダを選択し比較する）
![compare_file2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821326/a64c9d00-34a9-5c35-8ea5-e3c6f6f32f99.png)

で、開くとこんな感じの画面がサイドバーに出てきて差分のあるファイル、１つ目のフォルダのみに存在するファイル、２つ目のフォルダのみに存在するファイルが一覧できます。
![compare_file3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821326/dc601a33-d447-1d43-3277-83611d108aed.png)

あとはファイルの比較と同じ。

## あとがき
これを見つけるまでコードとコードの間違い探しに時間をかけすぎてウォーリーをさがせとか上手くなったんじゃないでしょうか…もっと早く見つければよかった。

でも、便利な機能もそのありがたみが分かるくらい遅れてくる位がちょうどいい(fashionably late)ですね。
TypeScript　型がない場合エラーを強制する設定方法

## 結論

`tsconfig.json`で以下の設定

`strict: true`の追加
`noImplicitAny`を`true`に変更します。


```jsonc:tsconfig.json
{
  "compilerOptions": {
    "module": "commonjs",
    "declaration": true,
    "removeComments": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "allowSyntheticDefaultImports": true,
    "target": "es2017",
    "sourceMap": true,
    "outDir": "./dist",
    "baseUrl": "./",
    "incremental": true,
    "skipLibCheck": true,
    "strictNullChecks": false,
    "noImplicitAny": true, // defaultではfalseなのでtrueに変更
    "strictBindCallApply": false,
    "forceConsistentCasingInFileNames": false,
    "noFallthroughCasesInSwitch": false,
    "strict": true // ここ追記
  }
}
```

## Strict - strict

> strictフラグは、プログラムの正しさを強く保証するための幅広い型チェックの挙動を有効化します。 このオプションの有効化は、以降で述べるすべてのstrict モードファミリーオプションの有効化と等価です。 必要に応じて、個別の strict モードファミリーを無効化できます。

## No Implicit Any - noImplicitAny

> いくつかの型アノテーションが存在しないケースにおいて、TypeScript は変数の型が推論できないときに、any型へフォールバックします。

falseにするとany推論されるケースでエラーを吐かせることができます。

## 参考

https://www.typescriptlang.org/ja/tsconfig
CloudFront経由ALBでのIP制限の設定誤りで通過した話

# はじめに
自社製品はWEBページ（A社）のバナーをクリックすることでアクセスできます。
開発の中でWEBページ制作外社のA社と連携テストを行いました。
内容としては、A社のIPアドレスからのリクエストに対し、自社ALBのリスナールールで設定した503のメンテナンス画面を出すというものでした。
その際に、503メンテナンス画面ではなく、なぜか200で通信できてしまったので備忘録として残します。

# 構成図・前提条件
[![Image from Gyazo](https://i.gyazo.com/53ba116d3b86c72324604f8e71e9714b.png)](https://gyazo.com/53ba116d3b86c72324604f8e71e9714b)

AWSリスナールールでは以下A社のIPアドレス
- 111.111.111.111
- 222.222.222.222

に対しALBのリスナールールより503メンテナンス画面へ遷移するように設定していました。

# 課題
A社IPアドレスを送信したところ503のメンテナナンス画面が出ずに自社アプリへの通信が成功してしまった。(ステータスコード200)

# 仮説
- キャッシュが残っている
ブラウザにキャッシュが残っており、通信が通ってしまっているのではないかと考えました。しかし、いくらキャシュクリアをしても200で返ってきてしまう。

- ALBリスナールールに誤りがある
設定しているリスナールールのconditionに誤りがあるため、200番になっているのではないかと考えました。

# 解決
ALBリスナールールに誤りがありました。
![9f1f795f2ef89ee047febc48d04b4350.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1431393/4ac10b37-6ea9-3a1b-1a31-383e07c0175e.png)
今回HTTPヘッダーのX-Forwarded-Forのvalueにサブネットマスクである/32をつけていることが原因でした。正しくは次のようになります。
[![Image from Gyazo](https://i.gyazo.com/67ad5cc727fa57c1d1a64e430d7a945f.png)](https://gyazo.com/67ad5cc727fa57c1d1a64e430d7a945f)

## X-Forwarded-Forとは
>X-Forwarded-Forとは、HTTPヘッダフィールドの1つであり、ロードバランサなどの機器を経由してWebサーバに接続するクライアントの送信元IPアドレスを特定する際のデファクトスタンダードです。クライアントの送信元IPアドレスの特定は、ロードバランサなどでクライアントの送信元IPアドレスが　変換された場合でも、HTTPヘッダに元のクライアントIPアドレスの情報を付加することで実現します。

ここではALBしか書かれていませんが、CloudFrontでも同じです。
CloudFront（エッジロケーション）を経てALBにリクエストが来る場合、IPアドレスはCloudFrontのものとなってしまいます。
CloudFrontのIPアドレスではなく、送信元のIPアドレスを特定することができるHTTPヘッダーがX-Forwarded-Forということです。

# おわりに
今回はX-Forwarded-Forのバリューにサブネットマスクを含めていたのが原因でした。
最近AWSの様々なサービスに触れる機会がありますが、ALBやCloudFront、WAFなどでも様々な設定値があり、混乱してしまいます。
一つ一つしっかり整理していかなければいけないと思いました！

# 参考
https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/x-forwarded-headers.html


https://www.infraexpert.com/study/loadbalancer11.html

https://dev.classmethod.jp/articles/waf-geographic-rule-using-x-forwarded-for-via-cloudfront/
【PostgreSQL】rake db:reset で PG::ObjectInUse: ERROR

# データベースをリセットを試みたらエラーがでた
エラー内容
~~~
Caused by:
PG::ObjectInUse: ERROR:  database "my_app_name" is being accessed by other users
DETAIL:  There is 1 other session using the database.
~~~

# 私の場合の結論
TablePlusでアクセスした状態だった。
これが原因だったので、TablePlusをクローズ。
再度、データベースをリセットを試したら成功しました。
【Docker】"apparmor_parser": executable file not found in $PATH エラー @ Armbian

> Intel ベースの macOS や Ubuntu で正常にビルド & 起動する Dockerfile を、CPU が ARM64 の Debian ベースマシンでビルドすると「`error: exec: "apparmor_parser": executable file not found in $PATH`」エラーが発生する。

```shell-session:【エラーログ】リポジトリのルートにDockerfileのあるリポジトリからDockerイメージの作成
$ docker build -t sample:local https://github.com/<your name>/<your repo>.git
Sending build context to Docker daemon  5.516MB
Step 1/15 : FROM golang:1.18-alpine AS build_base
 ---> 3cb4fa46c0ae
Step 2/15 : RUN apk add --no-cache git gcc ca-certificates libc-dev
 ---> Running in 02db750926f2
AppArmor enabled on system but the docker-default profile could not be loaded: running `apparmor_parser apparmor_parser --version` failed with output: 
error: exec: "apparmor_parser": executable file not found in $PATH
```

- マシン: NanoPi Neo2
- OS: Armbian (22.05.3, Bullseye) aarch64
- Kernel: 5.15.48-sunxi64 

## TL; DR <sub><sup><sub><sup>（今北産業）</sup></sub></sup></sub>

1. [AppArmor](https://ja.wikipedia.org/wiki/AppArmor) は、[SELinux](https://ja.wikipedia.org/wiki/Security-Enhanced_Linux) に似た**プログラムの挙動を制限するための Linux のセキュリティ・モジュール**の 1 つ。
1. Intel/ARM 関係なく、[ディストロ](https://ja.wikipedia.org/wiki/Linux%E3%83%87%E3%82%A3%E3%82%B9%E3%83%88%E3%83%AA%E3%83%93%E3%83%A5%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3)によっては `apparmor` のインストールが別途必要。<br>特に `apt install docker.io` で Docker のランタイムのみインストールした場合などには必須のモジュール。
1. `apt install apparmor apparmor-utils` でインストールする。

## 参考文献

- [AppArmor](https://ja.wikipedia.org/wiki/AppArmor) @ Wikipedia
- Issue #702 : [Upgrade to v0.21.0-k3s1r0, get CreateContainerError on all pods](https://github.com/rancher/k3os/issues/702) | K3OS | Issues @ GitHub
markovifyで文章生成時にKeyErrorが発生する【Python＋markovify】

# 経緯
markovifyを用いて自分のツイートから文章を自動生成してツイートするbotを作った。
ツイートするだけじゃ物足りないのでリプライを送る機能を追加しようとした。
リプライを送る際、送り先のツイートから単語を抜き出してその単語を起点として文章を自動生成しようとした。
ここでエラーが発生した。

# 内容

発生箇所のコードは以下の通り
```test.py
model = markovify.Text(text, well_formed=False, state_size=3)
sentence = model.make_sentence_with_start(beginning='テスト')
```

エラーの内容は以下の通り

```
KeyError: ('___BEGIN__', '___BEGIN__', 'テスト')
```

これは、``テスト``という単語を起点としてマルコフ連鎖を行い文章を自動生成する処理。
``make_sentence_with_start``関数の引数``beginning``が起点となる文字を表している。

``markovify``、``KeyError``というキーワードで検索すると``well_formed=False``にするといい、という記事が多数ヒットするが、上記にある通り、それはすでにやっている。
ではなぜエラーが発生するのか。

スタックトレースを見てみるとエラーの発生している箇所は、markovifyライブラリの以下のところ。

```chain.py
choices, weights = zip(*self.model[state].items())
```

どうやら``self.model``の中に該当するKeyがないのが問題らしいです。
この中には学習したテキストが格納されるのですが、ここで疑問に思ったのが「学習したテキストに完全一致しないと文章を自動生成できないの？」ということ。
そこで``make_sentence_with_start``の中を見ていると、ありました。
引数に``strict``というものがあり、以下のようにコメントが書かれていました。
```
If strict == True, then markovify will draw its initial inspiration
only from sentences that start with the specified word/phrase.

If strict == False, then markovify will draw its initial inspiration
from any sentence containing the specified word/phrase.
```

英語なのでよくわからないですが、``strict``という名前なので厳密にみるかどうかを表しているようです。
先ほどの「キーが学習内容に完全一致しないとエラー」という話に通じる気がします。
この引数はデフォルトで``True``になっているので、ここを``False``にするとKeryErrorが発生しなくなりました！

```test.py
model = markovify.Text(text, well_formed=False, state_size=3)
sentence = model.make_sentence_with_start(beginning='テスト', strict=False)
```


# まとめ

markovifyの``make_sentence_with_start``で単語を起点に文章を自動生成する際、その単語から始まる学習データがないとエラーなる。
その際には引数に``strict=False``を指定すると解決する。

# 参考資料

https://qiita.com/ichi_zamurai/items/60d2480edcb68a76aeb6
ReactにautoKanaをいれてみた。

Reactで作成したフォームにカタカナ自動入力の機能を実装することになった。
今回はvanilla-autokanaというライブラリを使用した。

## インストール
`npm install vanilla-autokana`

## 実装方法
①`AutoKana.bind()メソッド`を使って、名前のinput要素とフリガナのinput要素のidをAutoKanaに教える。
②`AutoKana.bind()メソッド`の戻り値を`getFurigana()メソッド`で取得する。

```react:personName.tsx
import React, { ChangeEvent, useEffect, useRef } from "react";
import * as AutoKana from 'vanilla-autokana';

const PersonName = (() => {
    const personNameRef = useRef<HTMLInputElement>(null);
    const personNameKanaRef = useRef<HTMLInputElement>(null);
    let autokana: any;

    // []を渡し、最初の一回しかレンダリング走らせない
    useEffect(() => {
        autokana = 
            AutoKana.bind('#personName', '#personNameKana', { katakana: true });　-①
    }, []);

    const onChangeEvent = (e: ChangeEvent<HTMLInputElement>) => {
        let name = personNameRef.current;
        let kana = personNameKanaRef.current;

        if (!name) return;
        name.value = e.target.value;

        if (!kana) return;
        kana.value = autokana.getFurigana();　-②
    }

    return (
        <>
            <input
                type='text'
                id='personName'
                placeholder='名前'
                onChange={onChangeEvent}
                ref={personNameRef}
            />
            <input
                type='text'
                id='personNameKana'
                placeholder='カナ'
                ref={personNameKanaRef}
            />
        </>
    );
})

export default PersonName;
```

## 仕組み
vanilla-autokanaは、jQuery.autokanaと同様、IME変換中のinput要素のvalueを読み取って、ふりがなを取得しています。
かな漢字変換の機能を持っているわけではないので注意です。

またライブラリの設計上、コピペに対応できない等の制約あり。
より本格的なかな漢字変換が必要な場合、サーバサイドにかな漢字変換APIを用意する方式になりそうです。

## 参考文献
https://qiita.com/ryo511/items/d83e1d80830e36d183e0
WindowsでVSCode Neovimを使うには（winget）

# はじめに

この記事では、Windows11でVSCode Neovimを使うまでの環境構築の記事です。Vimユーザーの方なら、この環境構築をすることでVSCode上で爆速Vimキーバインドを快適に使うことができるようになります。
動作環境：Windows11 Home
パッケージマネージャー：winget（Windows11では標準搭載）

# 0. VSCode Neovimとは

VSCode上でVimのキーバインドを利用できる、VSCodeの拡張機能です。Vim（vscodevim）という公式の拡張機能と比較して、動作が軽く、日本語を入力してもぶれず、.vimrc（init.vim）を利用できるのでおススメです。

# 1. VSCodeのインストール

※ インストール済みの場合は飛ばしてください。
筆者の場合はフォルダやファイル右クリック時に「Codeで開く」を利用したいので、以下のコマンドでインストールします。

```powershell:PowerShell
winget install vscode --override "/silent /mergetasks=""addcontextmenufiles,addcontextmenufolders"""
```

# 2. Neovimのインストール

こちらもwingetでインストールします。

```powershell:PowerShell
winget install -e --id=Neovim.Neovim
```

インストールすると、Cドライブの下のProgram Filesの下にNeovimというフォルダができていると思います。

※ インストール後は、PowerShell上でnvimのコマンドが使用できるようになると思います。

```powershell:PowerShell
nvim
```
以下のような画面が出てくればOK。
![s2_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2359398/eff732ae-995d-fd4c-e306-6f3b6e025ca3.png)
今は必要ないので、`:q!`で終了しておきましょう。

# 3. init.vimの作成

Neovimはインストールしても、init.vimを自動では作成してくれないので、自分で作成しましょう。
`%userprofile%\AppData\Local\nvim\init.vim`に作成します。

エクスプローラーで作成してもいいですし、以下のコマンドで作成してもOKです。

```powershell:PowerShell
# nvimフォルダの作成
mkdir ~\AppData\Local\nvim

# init.vimの作成（PowerShellなので、touchは使えない）
New-Item -Type File ~\AppData\Local\nvim\init.vim
```

init.vimの中身までは指定しませんが、VSCode NeovimはVimのプラグインまで読み込んでくれます。ここでプラグインなども一緒にインストールするといいでしょう。

# 4. VSCode Neovimの拡張機能のインストールと設定

左の拡張機能タブからVSCode Neovimをインストールしましょう。
※ （2022/9/15時点）VSCode Neovimの最新v0.0.89だと日本語入力時にぶれてしまうので、アンインストール右の部分からv0.0.88をインストールしています。
![s2_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2359398/849c7e16-198a-e7c5-b4c5-7f2f26edf23b.png)

そして、このままアンインストール右の設定ボタンから「拡張機能の設定」を開きましょう。

変更する箇所は以下の2箇所です。
- Neovim Executable Paths: Win32に`C:\Program Files\Neovim\bin\nvim.exe`を入力します（wingetで入手した場合この場所になると思います。違う場合は、インストールしたNeovimのbinフォルダ下のnvim.exeのパスを指定しましょう）。
- Neovim Init Vim Paths: Win32に`~\AppData\Local\nvim\init.vim`（先ほどのinit.vimのパス）を入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2359398/8a3e8671-457f-bcce-09b9-f754b40b88e4.png)

# まとめ

以上で、VSCode上で快適なVimキーバインドを使うことができます。Let's enjoy vim at VSCode!
![s2_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2359398/7e9cd0ec-ac7f-263e-3df7-d089ddd4d48b.png)

### 参考文献

- Installing Neovim
  <https://github.com/neovim/neovim/wiki/Installing-Neovim>
- WindowsにNeoVimをインストールして設定ファイルinit.vimを読み込ませるまで
  <https://qiita.com/karakuri-t910/items/81f005ab6992ff54d5a5>
- vscode-neovimでVSCodeのvim操作を高速化しつつ.vimrcも使えるようにした話
  <https://tech-blog.cloud-config.jp/2020-12-02-vscode-neovim/>
- winget で vscode をインストールする - proudust.github.io
  <https://proudust.github.io/20200726-winget-install-vscode/>
ソリューションアーキテクト対策_EC2篇

## はじめに
試験勉強した際のメモを自分用に記事化。
内容は公式やBlack Beltの写経ですので目新しいことはありません:pray:

## セキュリティグループ
EC2のセキュリティグループを編集したり設定したりしたら、全てのEC2インスタンスに即時反映。
稼働中とか新規ローンチとかは関係ない。


## EC2のインスタンスタイプについて(暗記)
ストレージやメモリ、CPUに最適化したインスタンスタイプがあるので、要件に適したものを選ぶ。
例えば、ローカルストレージの大きなデータセットに頻繁にアクセスするような要件の時はストレージ最適化のインスタンスを選ぶ。
H1、D2、I3、I3enとか。

種類は気合いで覚える。
![スクリーンショット 2022-04-08 14.56.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278897/541c7176-6694-67f5-0bac-2e7a25e4e413.png)


## スポットインスタンス
お安い。バッチ処理ジョブなどの一時的な処理に用いられる


## EC2のログについて
CloudWatch AgentをインストールしてCloudWatchLogsに転送する。
(AL系だと最初からインストールされている)

EC2のフローログも存在する。これはサーバーではなくNWのログになる。
有効化することでCloudWatchで取得可能。


## EC2の起動時に渡せるスクリプト
・ユーザーデータ
Bashスクリプトを設定して起動時に渡す

・ブートストラップ
インスタンスにユーザーデータを渡すことで起動時に実行される処理のこと


## EC2のタグについて
タグを追加すると、IAMポリシーで制御する時に指定できる。
なのでポリシーにタグを組み込んで開発/本番とかで権限を分割することが可能。


## IPフローティング
障害発生時にダウンタイムを無くすためEIPを自動で付け替える機能。
EIPを使うことで、稼働系から待機系にEIPをデタッチ→アタッチし瞬時にトラフィックの向き先を変更できる。

ちなみにELBやRoute53でも同様のことができる。
ただしこちらは切り替えると少なからずダウンタイムが発生する。IPフローティングの方が復旧までの時間が短い。
(ホスト名を待機系のIPアドレスに向け直すことで、DNS情報が伝搬するのに時間がかかるため)


## ヘルスチェック
AutoScalling配下のEC2のヘルスチェックには以下のどちらかを使用する。
・EC2ステータス
インスタンスのステータスがRunning以外の状態を異常と判断する

・ELB
ELBのヘルスチェック機能を利用する


## EC2インスタンスのRun, Start, Stopの違い
Runはローンチ。それ以外はそのままの意味


## EC2インスタンスの暗号化について
EC2インスタンス側を暗号化したい場合は、インスタンスにアタッチされているEBSの暗号化を行う。
インスタンスの暗号化ではない。
EBSの暗号化は、暗号化を有効化することで設定が可能。


## Resource IDとARN
・Resource IDとは？と改めて聞かれたら
EC2インスタンスを作った時のあれ。i-xxxxxxxxxxxxとかのやつ。

・ARNとは？を正確にいうと
まず、ARNはいつものあれ。arn:xxxxx以下略みたいなの。
このARNでAWSリソースを一意に識別する。
IAMポリシー、RDSタグ、APIコールなどのAWS全体でリソースを明確に指定する場合はARNが必要となる。

ちなみにタグは認識通り。ただしこれはリソースを一意に指定するものではない。


## ハードウェア占有インスタンス、Dedicated Host、Bare Metalの違い(暗記)
・ハードウェア占有インスタンス
専用HWのVPCで実行されるインスタンス。ただしハードウェアの固定はできない。
また、同じAWSアカウントのインスタンスとはHWを共有する可能性がある。
コンプライアンス要件などで他人と異なるサーバーで起動する必要がある場合に選択する。

・Dedicated Host
どのハードウェアで起動できるかを固定することができる、EC2インスタンス容量を完全にユーザー専用として利用できる物理サーバー。
権限が異なるIAMユーザーやグループからのアクセスも不可(アカウントが同じであっても)。
ソフトウェアライセンスがハードウェアに依存する場合や、BYOLで利用する。

・Bare Metal
通常のクラウドサーバーでは不可能な、ホストコンピューターのOSやプロセッサー、メモリに直接アクセスが可能なインスタンス。
AWSの各種サービスとの連携が可能。


## マウントターゲット
EC2からEFSにアクセスする際の接続ポイントのこと。
EBSはターゲットを設定する必要はない。

## EIP
### EIPの料金
利用されていないEIPは課金の対象となる。

以下の条件が満たされている場合は、料金は発生しない。
・EIPがEC2インスタンスに紐付けられている
・EIPに関連づけされているインスタンスが実行中である
・インスタンスに1つのEIPしかアタッチされていない

## 効率よくEC2インスタンスを多数起動する
EC2 ImageBuilderを利用してゴールデンイメージを作成し、インスタンス設定の展開を行うことで一定の設定プロセスを自動化できる。

### ImageBuilder
AMIを作るためのツール。
ソフトウェアで事前にインストールおよび設定、カスタマイズされた安全で最新のゴールデンイメージの作成・管理・デプロイメントを自動化し、特定のIT基準を満たすためのマネージドサービス。
ImageBuilerを使えば、イメージをアップデートするためのステップを手動で実施したり、独自の自動化パイプラインを構築したりする必要はなくなる。

### ゴールデンイメージとは？
EC2インスタンス、RDSインスタンス、EBSボリュームなどの特定のAWSリソースタイプにおいて最適な状態を保持することをゴールデンイメージと呼ぶ。
ブートストラップイメージと比較すると、ゴールデンイメージは起動時間を短縮し、構成サービスまたはサードパーティのリポジトリへの依存関係を削除する。
これは、需要の変化への応答として追加のリソースを迅速かつ確実に起動できるようにする自動スケーリング環境で重要である。


## おわりに
単純に知らなかったり、GUIで見ているはずなのに見逃してたりすることが結構多いですね。
引き続き追記します！

以上です。