OmniAICreator/Qiita-1.07M huggingface dataset:
あるブックの任意の範囲を別のブックの指定した箇所にコピペする　振り返り

##はじめに
今回は
『あるブックの任意の範囲を別のブックの指定した箇所にコピペする』
のマクロの作成についての振り返りをします。
このマクロが私が初めて最初から最後まで一人で作成したマクロです。
なので反省も含め「その1」~「その4」までの計4回を下記4項目について記述します。
##項目
1.　目的
2.　解決方法
3.　躓いた箇所
4.　その他
##振り返り
**その１**
1.　とにかく動くマクロを作ること
2.　マクロの記録を実行でコードを記録し編集
　　「ブックを指定し開く」→「シートを指定しアクティブ」→「セルA1を選択」→「コピー・貼り付け」
　　　をひたすら記述
3.　すべて。何をやってもエラーが続いた。Activeを多用し強引に作成した
4.　特になし

**その2**
1.　コピペの作業で繰り返し構文を使う
2.　配列を使用。
3.　配列を実際使ってみると、意外とすんなりできた。配列の苦手意識が薄れた。
4.　下記のコードを()内を(i)にして繰り返し構文を適用した

```vb

'シート名を配列に入れる　※ブック名は「シート名YYMMDD」とする
    Dim sheetName(1) As String
    sheetName(0) = "商品マスタ"
    sheetName(1) = "顧客マスタ"
```

**その3**
1.　セルを参照して繰り返し構文を使う
2.　変数を使用
3.　どのタイミングで変数を宣言・定義すればいいのか試行錯誤した
4.　下記のコードは応用が利くと思った
　　あと、初めて記事にコメントをいただき、そこには私のやりたかったことが
　　「オブジェクト指向なコード」が記述されていて大変勉強になった

```vb
'変数の宣言
    Dim i As Long
    Dim maxSheetCount As Long
    Dim sheetName As String

'参照するセルの一番右の位置を確認する
    maxSheetCount = Cells(1, Columns.Count).End(xlToLeft).Column

'転記用シートからシート名の入っているセルを指定する
    For i = 2 To maxSheetCount
        Worksheets("転記用").Activate
        sheetName = Cells(1, i)
```

その4
1.　転記をするための条件を満たさないときメッセージを出してマクロを止める
2.　Boolean型でtrue・flaseで場合分け
　　Dir関数でファイルを検索→Len関数で見つからないときは0を返すので、0か否かで場合分け
3.　繰り返し構文で1回目にtrueがかえって来ないとflase扱いになってしまい、繰り返しされなかった。
　　trueが出るまで繰り返し、最後までtrueが出なかったらflase判定になるように調整するのが難しかった　
　　if構文で「trueだったらif構文から抜ける方法」がわからなかった（まさか空白でよかったとは・・・）　
4.　ひたすらgoogleで調べてコードにはめ込みした。
　　検索結果はたくさんあり、単体では同じ結果になるコードでも、
　　実際にこのマクロにはめて思った通りの挙動をしないものが多かった（私の応用力が足りないだけですが）

```vb
'判定2
'対象シートの有無を判定→一致するシートがあれば次へ進む。なければマクロ終了
            Dim ws As Worksheet
            Dim flag As Boolean

            For Each ws In Worksheets
                If ws.Name = sheetName Then flag = True
            Next ws
            If flag = True Then

            Else
                MsgBox sheetName & "シートがありません"
                Exit Sub
            End If

'判定3
'対象ファイルの有無を判定→一致するファイルがあれば次へ進む。なければマクロ終了
            Dim filepath As String
            Dim fileName As String

'検索対象のファイル名
            fileName = sheetName & "YYMMDD.xlsx"

'ファイルのパスを取得
            filepath = Dir(ThisWorkbook.Path & "\" & fileName)

'ファイルの存在有無を判定→一致するファイルがあれば次へ進む。なければマクロ終了
            If Len(filepath) <> 0 Then

            Else
                MsgBox fileName & "は存在しません"
                Exit Sub
            End If
```
##最後に
実際の業務でマクロが使われるのは「同じ動作を繰り返す」「コピペ」が多いと思います。
今回作成したマクロはどちらも使われているので、今後はこのマクロ作成の経験を活かし、
仕事で使えるマクロを作成していきたいです。（主に自分の業務用ですが（笑））
まだまだ基本的な部分が不安定なので数をこなしつつ、勉強していきたいと思います。
そして、きれいなコードが書けるようになったらこのマクロの「その5」で改修したいですね。

##リンク
あるブックの任意の範囲を別のブックの指定した箇所にコピペする
その1
https://qiita.com/megane55/items/2f972241921ceac716fa
その2
https://qiita.com/megane55/items/a56e89d90e1a09d0bd62
その3
https://qiita.com/megane55/items/65d57a9a010645549ab6
その4
https://qiita.com/megane55/items/a0811de26355d26fdb3e
【jQuery UI Datepicker】日付プルダウンとカレンダーアイコンを連動させる

#経緯
[jQueryのDatepicker](http://jqueryui.com/datepicker/#inline "jQueryのDatepicker")をいじって、ふと思った。
「テキストボックス+アイコン」はあるけど「プルダウン+アイコン」がない。
ググってもなかったんだ。
あったら教えてください。ごめんなさいします。

#コード
yyyy/mm/ddフォーマットで当日から3か月分の表示を想定

```index.html
<select id="ymd_pulldown" size="1"></select>
<input type="hidden" id="datepicker">

<!-- JSさんたち -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1/i18n/jquery.ui.datepicker-ja.min.js"></script>
<script src="/script.js" defer></script>
```

```script.js
$(document).ready(function(){
  setDayPulldown();
  
  function setDayPulldown(){
    let current = new Date();
    let date
    let year_val = current.getFullYear();
    let month_val = current.getMonth() + 1;
    let day_val = current.getDate();
    current.setDate(current.getDate() + 1);

    for (let i = 0; i < 90; i++) {
      date = new Date(year_val, month_val - 1, day_val + i);
      $('#ymd_pulldown').append('<option value="' + getDayStr(date) + '">' + getDayStr(date) + '</option>');
    }
    $('#ymd_pulldown').append('</select>');
  }

  function getDayStr(date){
    let yy = date.getFullYear();
    let mm = ("0" + (date.getMonth() + 1)).slice(-2);
    let dd = ("0" + date.getDate()).slice(-2);
    return yy + '/' + mm + '/' + dd;
  }
  
  $( "#datepicker" ).datepicker({
    showOn: "button",
    buttonImage: "[画像のパス]",
    buttonImageOnly: true,
    buttonText: "Select date",
    minDate: "d",
    maxDate: "+3m",
    altField:"#ymd_pulldown",
    dateFormat: "yy/mm/dd"
  });

  // プルダウンで選択時、カレンダーにも値を連動
  $('#ymd_pulldown').change(function() {
    $('#datepicker').val($('#ymd_pulldown').val());
  });
});
```

#結果
[こんな感じ](https://great-sword.glitch.me)
MATLABでのヘルプや単体テストの書き方

# はじめに

C++でコードを書くとき、私はdoxygenを使うことを前提に常にヘッダーファイルにコメントを記入する習慣がついています。ところが、MATLABスクリプトを書くときは、ほとんど授業の宿題やプロットの作成が主の（ほぼ）使い捨てのスクリプトなので、コメントやテストを書く必要性が乏しく、MATLABのヘルプや単体テスト機能についてほとんど知りませんでした。

しかし、C++で書いていたライブラリの機能の一部をMATLABのパッケージとして移植する過程で、MATLABの`ヘルプや単体テスト機能を調べたので、備忘録として簡単にまとめておきます。

# 参考リンク

- MathWorks Documentation:
    - [Create help for classes](https://www.mathworks.com/help/matlab/matlab_prog/create-help-for-classes.html)
    - [Add help for your program](https://www.mathworks.com/help/matlab/matlab_prog/add-help-for-your-program.html)
    - [Create help summary files - Contents.m](https://www.mathworks.com/help/matlab/matlab_prog/create-a-help-summary-contents-m.html)
    - [MATLAB unit test framework](https://jp.mathworks.com/help/matlab/matlab-unit-test-framework.html)
   

# クラスや関数にヘルプ用コメントを加える

関数やクラスの宣言の直下にコメントを加えると、`help`や`doc`コマンドを使ったときにそのコメントが表示されます。
例えば次のような関数を`rotateTensor.m`ファイルに作成し、

```matlab
function B = rotateTensor(A,R)
% B = ROTATETENSOR(A,R) - Rotate tensor A using a given rotation matrix R
B = R*A*R';
end
```

この関数を`help`コマンドを通して呼び出すと、コメント部分が表示されます。

```matlab
>> help rotateTensor
  B = rotateTensor(A,R) - Rotate tensor A using a given rotation matrix R
```

クラスの場合も同様に、クラス定義の直下に書かれているコメントがヘルプコマンドで表示されます。
クラスの各プロパティやメソッド直下に書かれたコメントは、各プロパティやメソッドを指定して`help`コマンドに渡すと表示されます。

```matlab
>> help [ClassName].[PropertyName]
>> help [ClassName].[MethodName]
```

# ヘルプ概要ファイルを作成する

ヘルプ概要ファイルとは、フォルダに置かれた`Contents.m`という名前のファイルで、そのフォルダのプログラムの概要を提供します。ヘルプ概要ファイルが作成されていると、`help`コマンドを使ってそのフォルダの概要を表示させることができます。

```matlab
>> help [FolderName]
```

ヘルプ概要ファイルには、フォルダに含まれる関数・クラスの機能についてコメントを書いておきます。詳しくはMathWorksのドキュメンテーションを参考にしてください。

# 単体テストの作成

MATLABは単体テストのフレームワークを提供しています。

- [スクリプトベース](https://jp.mathworks.com/help/matlab/matlab_prog/write-script-based-unit-tests.html)
- [関数ベース](https://jp.mathworks.com/help/matlab/function-based-unit-tests.html)
- [クラスベース](https://jp.mathworks.com/help/matlab/class-based-unit-tests.html)

の3つの書き方がありますので、好きなものを選んで単体テストを書きましょう。
それぞれの書き方の詳細についてはMathWorksのドキュメンテーションを参照してください。
ここではスクリプトベースの書き方について簡単に解説します。

単体テストのスクリプトには

- スクリプトファイル名の先頭または末尾は`test`でなければならない（大文字小文字は区別されない）。
- 各単体テストはスクリプトファイルの個別のセクション（`%%`で始まる行）に配置する。
- テストスクリプトでは、最初のセクション (`%%`で始まる最初の行) の前に定義された変数が共有変数となる。共有変数は各テスト内で変更可能だが、テストごとに最初の値にリセットされる。

という決まりがあります。
スクリプトを作成したら`runtests`コマンドを使ってテストを実行することができます。例えば次のような`myUnitTest.m`という単体テストスクリプトがあったとして


```matlab:myUnitTest.m
% test vector operations
v1 = [1 2 3];
v2 = [3 4 5];

%% Test 1: sum of vectors
v = v1 + v2;
assert(all(v == [4 6 8]))

%% Test 2: dot product of vectors
v = dot(v1, v2);
assert(v == 26)
 
%% Test 3: cross product of vectors
v = cross(v1, v2);
assert(dot(v,v1) == 0 && dot(v,v2) == 0)

%% Test 4: outer product of vectors
v = kron(v1',v2);
assert(all(all(v == [3 4 5; 6 8 10; 9 12 15])))
```

このスクリプトを実行するには下記コマンドを入力します。

```matlab
>> result = runtests('myUnitTest')
myUnitTest を実行しています
....
myUnitTest が完了しました
__________

result = 

  1×4 TestResult 配列のプロパティ:

    Name
    Passed
    Failed
    Incomplete
    Duration
    Details

合計:
   4 Passed, 0 Failed, 0 Incomplete.
   0.018604 秒間のテスト時間。
```
Linuxサーバの一般ユーザから、多数のWindowsマシンの共有フォルダを参照する方法

# はじめに

LinuxサーバからWindowsマシンの共有フォルダを参照したいとき、
接続先が少数であれば、fstabに設定する方法でよいですが、
接続先が多数[^1]あるときには、それらをすべてfstabに設定する作業なんてしたくないですよね。

そんなときは、sudoersに設定を入れて、一般ユーザからmount、umountを可能にすると便利です。[^2]

この記事では、/mnt 配下にマウントしたかったので、mkdirもsudoを許可してあります。

cifsはセットアップ済の想定です。
（なお、WSLは現時点ではcifsに対応していないようですね。[^3]）


# 設定手順
ここでは、一般ユーザのユーザ名は foo としてあります。

```telnet:console
$ su
# visudo -f /etc/sudoers.d/foo
```

```telnet:sudoers.d
foo ALL=(ALL) NOPASSWD:/bin/mount,/bin/umount,/bin/mkdir
```

```telnet:console
# exit
```

# マウント手順
lsコマンドは、状況確認のために実行しているだけですので、実施しなくても構いません。
下記の例は、接続先WindowsマシンのIPアドレスが 192.168.111.222 、ユーザIDが hoge 、パスワードが Hogefuga123 です。
サーバ側のマウントポイントは /mnt/shares/machine001/ です。

```telnet:console
$ sudo mkdir -p /mnt/shares/machine001/
$ ls /mnt/shares/
machine001
$ ls /mnt/shares/machine001/
$ sudo mount -t cifs -o ro,user=hoge,password=Hogefuga123 //192.168.111.222/share /mnt/shares/machine001
$ ls /mnt/shares/machine001/
(//192.168.111.222/share内の各フォルダが表示されます)
```
- 参照のみの例なので、マウント時の -o オプションで ro を指定しています。書き込みもする場合は ro, が不要になります。
- 一度マウントしたら、マウントポイント（/mnt/shares/machine001/）は残す運用をしています。

# アンマウント手順
```telnet:console
$ sudo umount /mnt/shares/machine001
$ ls /mnt/shares/machine001/
(なにも表示されなくなります)
```

[^1]: 100端末以上あって、それが頻繁に追加・変更されるような状況です。
[^2]: 最初から全コマンドがsudoできる設定になっている環境でしたら、追加設定は不要です。
[^3]: WSL上のubuntuで試したら「mount error: cifs filesystem not supported by the system」とのエラーが発生しました。
写真のExif情報を取得する時の変数名

写真に付与されているExif情報の変数名は以下の通り。

この名前をもとにして、Python Djangoにて
各種のExif情報を抜き取ることが出来る。


GPSInfo
ResolutionUnit
ExifOffset
ImageDescription
Make
Model
Orientation
DateTime
YCbCrPositioning
XResolution
YResolution
ExifVersion
ComponentsConfiguration
ApertureValue
DateTimeOriginal
DateTimeDigitized
BrightnessValue
MaxApertureValue
SubjectDistance
MeteringMode
LightSource
Flash
FocalLength
ColorSpace
ExifImageWidth
ExifInteroperabilityOffset
SceneCaptureType
ExifImageHeight
Contrast
Saturation
Sharpness
SubjectDistanceRange
FNumber
SceneType
CustomRendered
ExposureMode
FlashPixVersion
WhiteBalance
DigitalZoomRatio
FocalLengthIn35mmFilm
CloudTrailでAWS Free Tier limit alert が届いた話

# AWS Free Tier limit alert が届いた

届いたメールは以下の通り
>AWS Free Tier usage limit alerting via AWS Budgets	03/03/2019
>
>Dear AWS Customer,
>
>Your AWS account XXXXXXXXX has exceeded 85% of the usage limit for one or more AWS Free Tier-eligible services for the month of March.
>
>AWS Free Tier Usage as of 03/03/2019	AWS Free Tier Usage Limit
2,000 Requests	2,000 Put Requests of Amazon S3

簡単に訳すと、

- 無料枠の上限が近づいてきてるぜ
- S3は月に2000PUTリクエストまで無料だけど、もう85%使ってるぜ

とのこと。

# 原因
ええー、まだ月の3日目なのに？（今日は3月3日）
と思ってググってみると、どうやら **Cloud Trail** が原因のようです。

AWSを始めたらまずやることの1つに
**CloudTrailを有効にしてログをS3に保存する** というのがありますよね。

これに従って、S3にログを保存する設定をしていると、
CloudTrailがバンバンS3にログファイルを保存していって、
たった2日間で80%（1700 Requests）になるようです笑

# このまま続けるといくらになっちゃうの？

2日が終わった時点で1700リクエストなので、単純計算31日で **52700** リクエスト。

僕のS3は東京リージョンに作っているので、
[AWSの月額料金計算シミュレータ](https://calculator.s3.amazonaws.com/index.html) で調べてみると、0.28USD（≒31円）とのことでした。
　※ 12ヶ月の無料期間中
　※ 1USD=111.92（2019/3/3時点）

まあそんなに高くないけど、無料で使いたい！という人には辛いかも。

# そもそもなんでこんなにcloud trailにログが保存されるの？
そう思ってS3の中身を覗いてみた。
すると、、、

![スクリーンショット 2019-03-03 10.30.42.png](https://qiita-image-store.s3.amazonaws.com/0/369820/c802287a-fdad-9ad3-7869-88f442fe6117.png)

どうやら全然使っていないリージョンのフォルダも作成されている。
なんでだ・・・？　eu-west-とか絶対に使ってないんだけど…

試しに絶対使っていないeu-west-1の中身を覗いてみると、2月フォルダと3月フォルダができている…。
しかも、3月3日のフォルダを覗いてみると、結構たくさんファイルがいるw

![スクリーンショット 2019-03-03 10.34.02.png](https://qiita-image-store.s3.amazonaws.com/0/369820/3a2a9345-2ff2-6850-9848-344830984c62.png)

最終更新日時を見る限り、おそらくログインをした時間。
試しにログファイルの中身を開いてみると、

>{"Records":[{"eventVersion":"1.06","userIdentity":{"type":"IAMUser","principalId":"XXXXXX","arn":"arn:aws:iam::XXXXXX:user/XXXX","accountId":"XXXXXX","accessKeyId":"XXXXX","userName":"XXXXX","sessionContext":{"attributes":{"creationDate":"2019-03-03T00:32:17Z","mfaAuthenticated":"true"}},"invokedBy":"signin.amazonaws.com"},"eventTime":"2019-03-03T00:33:03Z","eventSource":"**cloudtrail.amazonaws.com**","eventName":"**GetTrailStatus**","awsRegion":"eu-west-1","sourceIPAddress":"XXXXX","userAgent":"signin.amazonaws.com","requestParameters":{"name":"arn:aws:cloudtrail:ap-northeast-1:XXXXXX:trail/XXXX"},"responseElements":null,"requestID":"xxxxxx","eventID":"xxxx","readOnly":true,"eventType":"AwsApiCall","managementEvent":true,"recipientAccountId":"XXXXXXXX"},{"eventVersion":"1.06","userIdentity":（以下略）

うーん、CloudTrailが他のリージョンに対してなにかを見に行って、
「見に行ったよ」というログを勝手に吐いているようにしか見えない・・・。
いらねえよそんなログ！

# 課金されないための対応
そんなこんなで確認しているうちに、ログファイルが2000putリクエストを突破。

31円くらいだったら止めなくてもいいかなぁ？ と思いましたが、
まだ何もサービスをローンチしていないのに金がかかるのもイマイチなので、
とりあえずCloudTrailのログ記録をOFFにしておきました。
ひとまずPUTリクエストは収まったので課金はされずに済みそうです。
踏み台サーバを経由してログインするTeratermのマクロ

# 踏み台サーバを経由して、その先にあるサーバへSSHでログインするマクロを作成してみた。

##ファイルの構成は、コンフィグ用のTTL(config.ttl)、ログイン先サーバのホスト一覧のTTL(hosts.ttl)、接続用コマンドのTTL(connect.ttl)、ホストを指定するためのTTL(xxxx.ttl)です。

1.config.ttlのxxxxxの部分を環境に合わせて編集します。
2.hosts.ttlを編集します。ELEMENT_NOは登録するホストの個数で、配列の要素数です。

- HOSTENは、英語のホスト名を指定します。このホスト名を使って後で、ホスト名.ttlを作成します。
- HOSTIPは踏み台の先の接続先サーバのIPアドレスを指定します。
- HOSTJPは、日本語のホスト名を指定します。タイトル表示用に使われます。

**※HOTEN,HOSTIP,HOSTJPのインデックスは合わせてください**

3.HOSTENで指定したサーバ名のttlファイルを作成します。例だとhost-a.ttlなど。host-x.ttlの中身は全て同じ3行です。ファイルをコピーして、リネームしましょう。

```config.ttl
;ウインドウタイトル
PLACE='XXX環境'

FUMIDAI       = 'xxx.xxx.xxx.xxx'		; 踏み台サーバのIPアドレス

;ユーザ、パスワード
LOGIN_USER='xxxxxx'					; 踏み台へのログインID
PASS_FILE = 'password.dat'

COMMON_ID='xxxxxxx'					; ログイン先の共通ログインID
COMMON_PASS='xxxxxx'				; ログイン先の共通ロスインIDのパスワード

;INIファイルの読み込み有無  無:0 有:1
READ_INI=1

getdir CURDIR						; マクロの場所
sprintf2 LOGDIR '%s\LOG' CURDIR		; マクロの場所のLOGディレクトリ

;マクロファイルのベース名を作る
strsplit param1 '.'
SERVER_NAME = groupmatchstr1		; マクロファイル名から接続先サーバ名を作る

SERVER_IP='*'

for i 0 ELEMENT_NO-1								; サーバ名からIPと日本語サーバ名を得る
	strcompare SERVER_NAME HOSTEN[i]
	if  result=0  then
		SERVER_IP = HOSTIP[i]
		SERVER_JP = HOSTJP[i]
		break
	endif
next


strcompare SERVER_IP '*'
if result=0 then
	messagebox 'ホストが見つかりません' "エラーメッセージ"
	end
endif

;ログファイルパス
getdate LOGNAME '_%Y%m%d_%H%M%S.log'
sprintf2 LOGPATH '%s\%s(%s)%s' LOGDIR groupmatchstr1 SERVER_IP LOGNAME

foldercreate LOGDIR		; あってもなくてもディレクトリ作る

;読み込みINIファイルディレクトリ

;読み込みINIファイル名		; カレントディレクトリのINIファイル
sprintf2 INI_NAME '%s_%s.ini' 'TERATERM' 'common'
makepath INI_PATH CURDIR INI_NAME
```

```hosts.ttl
;	ホスト名、ホスト名(日本語)、IPアドレスの3つの配列を定義する。
;	strdimで宣言する要素数は3つとも同じにする。
;	各配列の順番は、関連している。
;	増減した時は、ELEMENT_NOの変更と、各配列の要素を調整する。

ELEMENT_NO=3

;接続先ホスト名選択
strdim HOSTEN ELEMENT_NO

HOSTEN[0] = 'host-a'
HOSTEN[1] = 'host-b'
HOSTEN[2] = 'host-c'

strdim HOSTIP ELEMENT_NO
HOSTIP[0] = '192.168.1.10'
HOSTIP[1] = '192.168.1.11'
HOSTIP[2] = '192.168.1.12'

strdim HOSTJP ELEMENT_NO
HOSTJP[0] = 'ホストA'
HOSTJP[1] = 'ホストB'
HOSTJP[2] = 'ホストC'
```

```host-a.ttl,host-b.ttl,xxxxx-x.ttl
include 'hosts.ttl'
include 'config.ttl'
include 'connect.ttl'
```

```connect.ttl
;============================================== 
;; 接続先ホスト／ユーザ名／パスワード設定 
;LOGIN_USER = 'ユーザ名' 
;; パスワードファイル指定
;LOGIN_PASS = 'パスワード' 
;; iniファイル指定
;INI_PATH = '設定ファイルパス' 
;============================================== 
;; パスワード取得
getpassword PASS_FILE LOGIN_USER LOGIN_PASS

;; コマンド組立て 

COMMAND = FUMIDAI 
strconcat COMMAND ':22 /ssh /2 /auth=password /user=' 
strconcat COMMAND LOGIN_USER 
strconcat COMMAND ' /passwd=' 
strconcat COMMAND LOGIN_PASS
strconcat COMMAND ' /F=' 
strconcat COMMAND INI_PATH

;; 接続 
connect COMMAND

logopen LOGPATH 0 1

sprintf2 TITLE '%s(%s:%s:%s)' PLACE SERVER_JP SERVER_NAME SERVER_IP

settitle TITLE

sprintf2 SSH_LOGIN 'ssh -o StrictHostKeyChecking=no %s@%s' COMMON_ID SERVER_IP

wait '$'
sendln SSH_LOGIN

wait 'password:'
sendln COMMON_PASS
```

4.作成した接続先サーバ用TTL(例だとhost-a.ttl)をダブルクリックしてTeratermのマクロを実行します。(関連付けできてなければttlファイルをttpmacro.exeに関連付けて下さい。
[osmdroid を使って Android の OpenStreetMap 地図に 吹き出し付きのマーカーを表示する

[osmdroid を使って OpenStreetMap を Android に表示する](https://qiita.com/ohwada/items/c3741fb14a5142035314)
の続きです

## osmdroid のマーカー　

osmdroid のマーカーは2つある。

- ItemizedIconOverlay クラス

古いやり方

- Marker クラス

Google Maps  API に合わせてある新しいやり方

ItemizedIconOverlay の使い方は、下記を参考に。

[osmdroid を使って Android の OpenStreetMap 地図に マーカーを表示する](https://qiita.com/ohwada/items/a85fadbd186abac9dff7)

### Marker クラス

ソースコードのコメントが一番詳しい説明だったので、
要約を載せておく。

GoogleMaps Android API v2 にできる限り似せている。
 主な違い

 -  Z-Indexには対応していない。出現順に描画される。
 - アイコンは、Android Drawable が指定できる。
 - 吹き出しは、Android Viewを使用できる。
 - 吹き出しの説明の下に、小さいテキストフォントで表示される追加の説明(sub-description)を表示できる。
 - 吹き出し(InfoWindow)に画像を表示できる。
 - 表示する／しないが設定できる。
 - マーカーにタッチしたときは、地図の中央に配置する。
 - 吹き出しを開くと、他の吹き出しを自動的に閉じる。
 - マーカーごとにイベントリスナーを設定できる。
 
https://github.com/osmdroid/osmdroid/blob/master/osmdroid-android/src/main/java/org/osmdroid/views/overlay/Marker.java

### 使い方

```
//　基本
        Marker marker = new Marker( mMapView );
        marker.setPosition( new GeoPoint(緯度, 経度 ) );
        marker.setTitle ( タイトル );
        marker.setSnippet( 説明 );
        mMapView.getOverlays().add(marker);

    // アイコンを変更する
    Drawable icon = getResources().getDrawable(R.drawable.marker);
    marker.setIcon(icon);

    // 吹き出しに画像を表示する
    Drawable image = getResources().getDrawable(R.drawable.image );
    marker_1.setImage ( image );

    // クリックリスナーを設定する
    marker.setOnMarkerClickListener( new Marker.OnMarkerClickListener() {
        public boolean onMarkerClick(Marker marker, MapView mapView) {
           //　クリックした時の処理
            return true;
        }
    });
```
### スクリーンショット

吹き出しを表示する
![8_info.png](https://qiita-image-store.s3.amazonaws.com/0/64075/62248948-ff2b-cf12-0354-d252272432f2.png)

吹き出しに画像を表示する
![8_image.png](https://qiita-image-store.s3.amazonaws.com/0/64075/dcebbb98-9d34-fa9b-8dd3-17a98effae1a.png)

github にサンプロコードを公開した

https://github.com/ohwada/Android_Samples/tree/master/Osmdroid8
Mt. React に ２週間で８合目まで登ってみた

Reactは学習コストが高いと言われてますが、お仕事をいただくために初めて取り組んでみました。
 
先日の #nds59 で その結果 react習得に２週間で８合目まで、deployまで１月でいけたといったら、どうやって？と質問をいただいたので書き留めておきます。というかnodeもreactも初めてで必死だったのでよく覚えてないですが、とにかく知識習得・開発・デプロイ環境整備に時間がかかりがちなので、そこを短縮するのに様々な取り組みをしました。　そこさえ短くすればreactの学習コストはそんなに(flux/redux使えばもっと）高くないように思いました。

`（２週間と書いていますが、8時間 x 5日 x ２週間 = 80時間ではなく、 およそ 15時間 x 14日 = 210時間ぐらいです。 ４時間仮眠してすぐ仕事とか相当あったけど、自分でとった仕事なので全くOK。）`

# 前提
* フリーランスです。働き方・お金の使い方は自分で決められます。
* ベタのJS(ES4?), jquery, jquery-moble(古！） と CSS1/2/3(ちょっと） を使ってwebサイトを(BE/FE)構築・デバッグすることができる。 nodejs/ES5/6・sassやトランスパイラなど利用・使用した開発経験はない。 
* オブジェクト指向言語は多く経験あり。 reactのコンポーネント構成にはすぐ馴染めた。


# コードを書く外の部分での仕事への取り組み方
* 体力のマネジメント：プロジェクトに備え、普段は体力をつけておきます。（だいたいプロジェクトこなすと痩せる・筋力おちるから）
* どこに投資をするか：報酬のある仕事で、かつ顧客が一月後（早！）に欲しがっているので、時間に投資をしました。　つまりお金を出して時間を節約できるところは、本を買ったり、有償IDEを買ったりして学習・準備時間を短縮。（結果的にreactの本は古すぎて基本知識を得るぐらいにしかならなかったけどそれでも画面でみるより時短・包括的に理解できる効果あり。寝ててもどこでも読めるんだから。）
* どこから始めればいいのか、reactのエキスパートに聞きます。 IDEについては、 普段からオフィスをシェアしている [HADAL](https://www.prototype-cafe.space/hadal/) さんにお勧めをいただきました。 困った時に普段から相談できる人を作っておくのも大切ですね。

# コード開発環境を作る
* お勧めされたVisual Studio for Code（無償）をインストールし、次のチュートリアルに **忠実にそって** （ここすごく大事） プロジェクトを作って走らせるとあっけなく開発環境・プロジェクト雛形・デバッグ環境ができます。
  * https://code.visualstudio.com/docs/nodejs/reactjs-tutorial
* 他に２、３困ったこともあったような気がしますが、
  * 英語での検索を厭わずとにかくわからないことは世界中ググる。　一年以上前の情報は基本的に参考にしない。半年以内の情報に従って問題解決を進める。
  * react や ES6 を全くわかってなかったので インストールしたらカスタマイズ０で即使えて、悪いところを指摘してくれるIDEに最大限助けてもらう。 
  * 流れがわかったとこから バックエンド開発でも使用しているPyCharm とほぼ同じ使い勝手の、JetBrains社の WebStormにIDEを変更し、ファイルの操作、VCSの操作などの学習をしなくてすむようにしました。(VCS GUI は主として SourceTreeを使用）

# その他react関連で開発期間短縮に役立ったと思われること
* （単に知らなかった、ので）fluxもreduxも使っていません。大変だったけど学習は少なくてすんだ。（fluxを使わなかったため、render()のタイミング制御にはかなり苦労した。 fluxは使った方が良い。多分reduxも。）
* CSSには、styled-componentを使用。cssファイル開かなくて・管理しなくてよかったので楽でした。
* IDEからブレークポイントつけても止まってくれないときがあったり、使いづらかったので、止めてやるデバッグは全てchrome上で実施。止める場所がわかりづらいときは console.logを吐かせて、その行を示すリンクからソースを開いて確認しました。

# reactと関係ないがdeployまでの期間短縮に役立ったと思われること
* 頼まれてもいないのにプロジェクト憲章文書をまとめ、顧客・自分の疑問は解決しておく。
* サーバやドメインについて手間取らないよう、サーバ・ドメインをすぐ提案できるようにしておく。（定額・低額を希望する顧客は多い） 私はさっと提案するときにはさくらVPSと自分のドメインのサブドメインで提案しています。動的拡張性とかGPU必要とかだったりすると困りますが。
* ローカル開発はVirtualBox内でやるが、顧客を不安にさせずにフィードバックをもらえるよう、リモートはステージングサーバ・デプロイサーバの３段立てにしておき、変更をすぐ顧客も確認できるようにしておく。
* バックエンド(phthon3/django/django-rest)とフロントエンドの双方開発フルスタックでやったのでコミュニケーションによる時間ロスや分担の明確化などのためのプロジェクトマネジメントロスはなかった。
* 画面のワイヤデザインと素材は顧客から提供があったのでダウンロードのみ。
* わからないことをばばっとtrelloに書いていってとにかく優先する上位のものから作業をこなしていったので作業に迷わなくてすんだ。シングルスレッドでタスクこなしていったほうが自分を動かすには早いみたい。
* chromeのreactプラグインの使い方がよくわからない。なくても困ってない。
* vagrant/ansibleを使ってdeployプロセスを自動化。 使った雛形は https://github.com/jcalazan/ansible-django-stack/
* 各種ブラウザ上での検証を求められていたので、 [LambdaTest](https://www.lambdatest.com/) サービスを有償利用。 LamdaTest社はサポートが素晴らしいスタートアップ。　サービスの不具合や要望は適時伝え、対応していただきました。全部英語ですが、画面シェア・通話までしてリアルタイムで解決してくれます。　すごい。
* たまたま予定していた [IoTLT新潟](https://iotlt.connpass.com/event/107331/) で フロントエンド技術動向などプロジェクトに重要なアドバイスをGETしたので渡り掛けていた危ない橋を引き返せた。コミュニティでの情報シェアほんと大事です。感謝。
macにbrewでnginxとPHP7.2をインストールした


##インストール
nginxのインストール
brew install nginx

※以下のメッセージを探す。ドキュメントルート（ファイルを置く場所）と設定ファイルの場所。
Docroot is: /usr/local/var/www
The default port has been set in /usr/local/etc/nginx/nginx.conf to 8080 

phpのインストール
brew install php72

##設定変更
設定変更
/usr/local/etc/nginx/nginx.conf

変更前

```bash:nginx.conf
        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}
```

変更後

```bash:nginx.conf
        location ~ \.php$ {
            root           /usr/local/var/www;
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  /usr/local/var/www$fastcgi_script_name;
            include        fastcgi_params;
        }
```

##起動
起動
nginxの起動
brew services start nginx

phpの起動
brew services start php@7.2


##動作確認
以下のURLにアクセスする
http://127.0.0.1:8080/


##停止
nginxの停止
nginx -s stop

phpの停止
brew services stop php@7.2

##参考
新しいmacにbrewを使ってnginxをインストールする
https://qiita.com/amemolee/items/56332100f182088687cf
CentOS + nginx + PHP環境でのnginxの設定めも
https://qiita.com/alegriaghost/items/57f99539a3554b4fbd80
踏み台サーバをトンネルしてその先のサーバへ接続するTeratermのマクロ

# 踏み台サーバの先にあるサーバへ、踏み台サーバをトンネルして接続するマクロを作成した。主にHTTPサーバを想定して作ったが、いろいろ工夫すれば他にも使えると思う。

## 以下のリストをファイルに保存して、設定を変更しTeratermのマクロとして実行します。ファイル中のxxxxxxの部分、SPORT、DPORTを環境に合わせて変更します。


SPORTは例として自PC(localhost)の1080を設定していますが、適宜変更して下さい。
DPORTは例として踏み台から先のWebサーバを想定して80としていますが、適宜変更して下さい。

```Teratermトンネル設定.ttl
;==========================================================================================
;; 踏み台経由でポートフォーワードするスクリプト
;; このセッション実行中は、ポートフォーワードで踏み台の先のサーバへアクセスできる
;; 例えば以下の設定で、ローカルPCのブラウザから「http://localhost:1080」でアクセスすると
;; DIPサーバのDPORTポートへhttpでアクセスできる
;==========================================================================================

HUMIDAI = 'xxx.xxx.xxx.xxx'		; 踏み台サーバのIPアドレス
LOGIN_USER='xxxx'				; 踏み台へのログインアカウント
LOGIN_PASS='xxxxxxx'			; アカウントのパスワード
SPORT='1080'					; ローカルPCでの接続先ポート
DPORT='80'						; 踏み台から先のサーバの接続先ポート
DIP='xxx.xxx.xxx.xxx'			; 踏み台から先のサーバのIPアドレス

sprintf2 FWDSTR ' /ssh-L%s:%s:%s' SPORT DIP DPORT

;; コマンド組立て 

COMMAND = HUMIDAI 
strconcat COMMAND ':22 /ssh /2 /auth=password /user=' 
strconcat COMMAND LOGIN_USER 
strconcat COMMAND ' /passwd=' 
strconcat COMMAND LOGIN_PASS
strconcat COMMAND FWDSTR

sprintf2 TITLE '踏み台からポート転送(%s:%s:%s)' SPORT DIP DPORT

;; ②接続 
connect COMMAND
settitle TITLE
```

teratermのマクロを実行してウィンドウが開いたら、ブラウザを起動して「http://localhost:1080/」へアクセスすると、踏み台を経由してその先のWebサーバへ接続できます。
VSCodeでESLint+typescript-eslint+Prettierを導入する（2020/11/14修正）

追記: `eslint-plugin-prettier`は非推奨なので内容を修正しました。prettierはeslintを通して実行するよりも、VSCode側から実行するほうが良いです。

##前置き
[TypeScriptチームがESLintのTypeScript対応を強化するとの発表がありました。](https://qiita.com/mysticatea/items/aaf677928e965abe093d) 
これまでTypeScriptといえばTSLintでしたが、これからはESLintがメインになっていくと思われます。
そもそもESLintってなに？ という方は[こちら](https://qiita.com/mysticatea/items/f523dab04a25f617c87d)

##インストール
###eslint
```
yarn add -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin
```
###prettier

```
yarn add -D prettier eslint-config-prettier
```

##基本設定
```..eslintrc.json
{
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "prettier",
    "prettier/@typescript-eslint"
  ],
  "plugins": ["@typescript-eslint"],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "sourceType": "module"
  },
  "env": { "browser": true, "node": true, "es6": true },
  "rules": {
    // 適当なルール
  }
}
```
####型情報が必要なルールを使用する場合（パフォーマンス注意）
```..eslintrc.json
{
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:@typescript-eslint/recommended-requiring-type-checking",
    "prettier",
    "prettier/@typescript-eslint"
  ],
  "plugins": ["@typescript-eslint"],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "sourceType": "module",
    "project": "./tsconfig.json"
  },
  "env": { "browser": true, "node": true, "es6": true },
  "rules": {
    // 適当なルール
  }
}
```

- `"plugin:@typescript-eslint/recommended"`
    - 型を必要としない基本ルールを詰め込んだもの
- `"plugin:@typescript-eslint/recommended-requiring-type-checking"`
    - 型情報が必要な基本ルールを詰め込んだもの
    - TypeScriptのビルド時間分が増えるので、パフォーマンスが気になる場合外す
- `"plugin:@typescript-eslint/eslint-recommended"`
    - TypeScriptでチェックされる項目を除外する設定
    - recommendedとrecommended-requiring-type-checkingに含まれているので、どちらかを使うなら記述する必要は無いです



##個別設定例
```..eslintrc.json
{
  "rules": {
    "@typescript-eslint/explicit-module-boundary-types": "off",
    "@typescript-eslint/array-type": [
      "error",
      {
        "default": "array-simple"
      }
    ]
  }
}
```
必要であれば、[TSLintとの対照表](https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/ROADMAP.md)を確認しながら設定しましょう。
[@typescript-eslint/eslint-plugin-tslint](https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin-tslint)を追加することでtslintの設定も使用できます。

ルールの詳細は[こちら](https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin/docs/rules)を確認しましょう。

##VSCode
[ESLint拡張機能](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)、[Prettier拡張機能](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)をインストールしてください。

```settings.json
{
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
}
```
VS Code ESLint extension2.0.4から`eslint.validate`は不要になりました。

##参考
https://teppeis.hatenablog.com/entry/2019/02/typescript-eslint
https://github.com/typescript-eslint/typescript-eslint/releases
失敗から学んだ開発時の注意点（GitHub）

#はじめに
今回初めてGitHubを使用し、オリジナルアプリの開発を進めるにあたって自分が起こしてしまった失敗についてまとめてみました。
#何を失敗したか？
オリジナルアプリを開発するにあたってGitHubを利用して進めることになり、Gitの基本的なadd,commit,push,pullといった操作を学んだ上で、GitHubの使い方などを教えていただきました。そしてローカルにで自分が作成したものをプルリクエストして確認してもらい開発を進めていくはずでした。しかし作業に入ってまず僕がしたのは開発順序を明確に考えずに出来るところから、ガツガツとコードを書いてプルリクエストを送りまくるということ。これをしてしまったことによって、GitHub上での管理が把握できなくなってしまった。。。
#起こしてしまった失敗の詳細
- 他のブランチを切るときに、Masterから作成されていない。例えば、Masterから`user_function`と`home_function`の2つのブランチがあった時に`home_function`を`user_function`から作成していたり。
- 別のブランチを作成し、開発を進める時に、移る前にチェンジファイルを空にできていないまま。そのため移行先にもそのファイルがついてしまっていた。
- 自然な現象なのにブランチを切り替えた際にローカルでファイルが消えたりしていると感じ勝手に焦っていた。
- コミットする際には、そのブランチに関係のないファイルやコードが含まれている。（確認する側が混乱してしまう。）
- 各ファイルの修正、追加、削除などをローカルだけでなくGitHub上でも操作していた。
- GitHub上でファイルを削除したりしていた

#対策
- 各ファイルの修正、追加、削除などは全てローカルで行うこと。（例：pull request後修正したい場合、ローカルで修正し再度commitメッセージを書き、pushする）
- GitHub上でファイルを削除したりしては絶対いけない。
- コミットする際には、そのブランチに関係のあるものだけにすること。（メンター側が確認するときに困る）
- 不要なファイルはそもそもコミットしないこと。（例：DS.storeファイルなど）
- 今回は原則として1つの機能に対して、1ブランチ1プルリクエストとする
- ブランチを作成するときはMasterから作ること。（悪い例：Master→homeブランチとある場合、homeからブランチを切るのではなく、Masterに戻ってから別のブランチを切る。）
- 別のブランチを作成し、開発を進める際は、移る前にチェンジファイルを空にしてからにすること。でないと移行先にもそのファイルがついてきてしまう。（移行前のブランチでcommitするかそのファイル自体を削除するかで対応する）もう一つのやり方としては1度`commit to ブランチ名` を押して仮に保存しておくやり方。こちらは忘れがないように注意！
- ブランチはできるだけ細かく切ることを意識する（少ないと、1つの量が膨大になるから。）
- ローカルで開発している際にファイルが消えたりしていると感じるのは自然な現象である（例：Masterから「ユーザー、ポスト」という2つのブランチがあったとしてMasterには3ファイル、ユーザーには10ファイルあったとした場合、ユーザーブランチからポストブランチに切り替えるとMasterにある3ファイルだけなのでローカルに表示させるのはそのファイルだけであるので焦らないこと。）

#今回の学び、反省
開発が始まり、開発の順序を明確に考えずに作業に取り掛かった結果、GitHub上での管理が把握できなくなってしまった。そのため同時に開発を進めていくはずだったメンターさんには多大な迷惑をかけてしまいアプリ自体最初から作り直しとなった。完全な個人プレーだった。見る側の人のことを全く考えずただただ自分ができることからまとめて開発するといった状態だった。（例：コントローラーを3つまとめて作成したり、機能ごとに開発できていない。）また把握できなくなり、エラー文が発生した際にも、全文コピペといったことをしていた。これは完全に思考停止で伸びないし、コピーしてググるなら、関係のありそうな1文だけに絞ってみたりなど工夫が一切ない。読むクセが全くついていないこの行動で改めて感じた。また相談不足で勝手に進めていっていた部分も多かったため、当たり前だが、わからないときは（実行する前に）相談すること。ただわかりきった質問はよくない。この失敗を糧にして、また開発を進め、努力していきたいと思った。
PXEbootの設定

---

DHCPサーバーが既にルーターなどで設定、稼働している場合に、新たにPXEブート用サーバーを設置する方法をまとめる。

---

###前提
ネットワークセグメント:192.168.1.0
PXEブート用サーバー:192.168.1.100
PXEブート用サーバーOS:CentOS7

###1. ProxyDHCPの設定
PXEブート用サーバーをproxyDHCPとtftpで兼用する。
proxyDHCPとして、dnsMasqを使う。

```
# yum install dnsmasq dnsmasq-utils
```

/etc/dnsmasq.d/tftpを作成し、以下を追記。
（/etc/dnsmasq.confの内容とかぶらないように注意。今回はdnsmasq.confが全てコメントアウトされたので問題なし

```
port=0
log-dhcp
dhcp-range=192.168.1.0,proxy
dhcp-boot=pxelinux.0,192.168.1.100
pxe-service=x86PC,"Network Boot",pxelinux,192.168.1.100
```

サービス起動

```
# systemctl start dnsmasq
```

###2. TFTPサーバーの設定

```
# yum install tftp-server
# systemctl status tftp
```

設定は特にないが、tftpのルートを変える場合は、以下の設定ファイルを変える。
今回は、デフォルトの/var/lib/tftpbootを使う。
/etc/xinetd.d/tftp 

###3. SYSLINUXの設定

```
# yum install syslinux syslinux-tftpboot
```

CentOS用ブートローダーを取得

```
CentOS7
# mkdir /var/lib/tftpboot/centos7
# cd /var/lib/tftpboot/centos7
# wget http://mirror.centos.org/centos/7/os/x86_64/images/pxeboot/initrd.img
# http://mirror.centos.org/centos/7/os/x86_64/images/pxeboot/vmlinuz

CentOS6
# mkdir /var/lib/tftpboot/centos6
# cd /var/lib/tftpboot/centos6
# wget http://mirror.centos.org/centos/6/os/x86_64/images/pxeboot/initrd.img
# http://mirror.centos.org/centos/6/os/x86_64/images/pxeboot/vmlinuz
```

###4. PXEブート用メニューを作成

```
# cd /var/lib/tftpboot/
# mkdir pxelinux.cfg
# vi pxelinux.cfg/default
```

上記で取得したCentOSブートローダーを入れる場合は、以下のようになる。

```
DEFAULT menu.c32
PROMPT 0
TIMEOUT 300
ONTIMEOUT Local

MENU TITLE PXE Boot Menu

LABEL Local
        MENU LABEL 1. Local HardDisk Drive
        LOCALBOOT 0

LABEL CentOS7 x86_64
        MENU LABEL 2. CentOS7 x86_64
        kernel centos7/vmlinuz
        append load initrd=centos7/initrd.img

LABEL CentOS6 x86_64
        MENU LABEL 3. CentOS6 x86_64
        kernel centos6/vmlinuz
        append load initrd=centos6/initrd.img

LABEL Reboot
        MENU LABEL 4. Reboot
        COM32 reboot.c32

LABEL Poweroff
        MENU LABEL 5. Poweroff
        COMBOOT poweroff.com
```

#### debian系の設定追加
まとめ中


参考
http://zappy.hatenablog.jp/entry/2018/05/31/190434
http://www.maruko2.com/mw/PXE%E3%83%96%E3%83%BC%E3%83%88%E7%94%A8%E3%82%B5%E3%83%BC%E3%83%90%E3%82%92%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B
https://www.unix-power.net/networking/post-672
http://www.mikitechnica.com/14-centos72-pxe.html
https://www.hiroom2.com/2016/05/05/ubuntu-16-04-debian-8%E3%81%ABpxe%E3%83%96%E3%83%BC%E3%83%88%E3%82%B5%E3%83%BC%E3%83%90%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%97%E3%81%A6%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E7%92%B0%E5%A2%83%E3%82%92%E6%95%B4%E3%81%88%E3%82%8B/#sec-5
https://ameblo.jp/shinnaka54/entry-12409911643.html
http://arborvitae.oops.jp/dokugaku/%E5%82%99%E5%BF%98%E9%8C%B2/pxe-boot/
Ubuntu 18.04 LTS > setup > USキーボードで漢字入力をできるまで > [トラブル]再起動で設定がクリアされる

```txt:動作環境
Ubuntu 18.04.2 LTS 
東プレRealForce(87UW55)
```
## セットアップ内容

- 漢字入力をできること
    - mozc使用
- USキーボード設定

## 漢字入力

### 漢字入力にならない

mozcは最初から入っていたが、漢字入力にならなかった。
mozcを一度削除し、設定したが漢字入力にならなかった。

ふと気づいたのが「入力メソッド」。
「直接入力」だったのを「ひらなが」にして漢字入力になった。

16.04 LTS使用時にはそういう変更はほとんどしなくなったため、忘れていたのだろう。

### UIが変わっている（使いにくい）

16.04 LTSのときはShift+Spaceにてmozcへ変更。
18.04 LTSの場合はWin+Spaceになった？

UIが変わると慣れるまで失敗を繰り返す。

***UIは安易に変えないでほしい。***

一方で、新しいUIがそうなったのであれば、古いUIの設定にはしない。
「標準からはずれた設定を使い続けるのは間違い」という考え。

「一度はずれた設定を今後ずーーーっと使い続ける」という考えもなくはない。

## USキーボード設定

- 下記は成功せず
    - `/etc/default/keyboard`の書き換え
    - fcitx使用
        - [UbuntuのmozcでUSキーボード入力/JISキーボード入力を簡単に切り替える方法](https://qiita.com/AnchorBlues/items/beeb40593fd4c579dbe5)
        - 下記の項目を追加しようとしたが、リストが表示されない
            - Mozc
            - キーボード: 英語（US)
            - キーボード：日本語

別途、以下の方法で成功いたしました。

- [Ubuntu 16.04で英語キーボードを使えるようにする方法](https://qiita.com/SUZUKI_Masaya/items/2f2ef9fdb63fe017c6d2)

情報感謝です。

### [トラブル]再起動でクリアされる
(追記　2019-03-03)

再起動でUSキー設定はクリアされるようです。

再起動の度に同じコマンドを実行。
面倒ですね。


### 解決法
(追記 2019-07-01)

@momosetkn さんによる解決方法が下記に紹介されています。
こちらでも試したところ、再起動後にも設定が保持されていました。

Ubuntu 19.04で英語キーボードを使えるようにする方法
https://qiita.com/momosetkn/items/5d0b940dd8a9b5fe1fc9
Rails テーブルのデータ型について

# はじめに
Railsで使用するテーブルの型の種類について、興味があったので簡単にまとめてみました。

# 基本コマンド

```bash:command
# マイグレーションファイル作成コマンド
$ rails generate migration クラス名

# モデル作成
$ rails generate model モデル名
```

クラス名は何でもOKだけど「アクション+テーブル名」とかが慣例っぽい。

モデルの新規作成は`model モデル名`。命名規則は[モデル名とテーブル名の規約](http://railsdoc.com/model)を参照。

「generateは g 」「destroyは d 」と略すことができるので、略して使う。

# テーブルを作る、消す

```bash:作る例
$ rails g model User name:string
```
$ rails g model モデル名 カラム名:型
※モデル名は必ず最初を大文字にして、単数形にすること。

```bash:消す例
$ rails d model User
```
$ rails g model モデル名

## 指定できる型

- string : 文字列
- text : 長い文字列
- integer : 整数
- float : 浮動小数
- decimal : 精度の高い小数
- datetime : 日時
- timestamp : タイムスタンプ
- time : 時間
- date : 日付
- binary : バイナリデータ
- boolean : Boolean

## マイグレーション実行

このままだと、実際のDBには反映されないので、db:migrateコマンドを実行する。

```bash:command
# 実行
$ rails db:migrate
```
rails g scaffoldとは？

#はじめに。
学びをアウトプットしたかったので、scaffoldについて簡単にまとめてみました。

##scaffoldってなに？
railsでは、`rails g`コマンドでコントローラーやモデルを作成し、ルーティングでページを繋げる操作が必要。
Webアプリケーションに必要なこれらの操作を一度に自動で組み立ててくれるのがscaffold。
scaffoldの本来の意味は足場です。足場を作ってその上に自分の作りたいものを組み上げていくイメージ。

##scaffoldの使い方
例としてhoge_appを作るとすると
`$ rails new hoge_app`
hoge_app内に入る。
`$ cd /hoge_app`
アプリ内で、scaffoldを使う。
`$ rails g scaffold hoge title:string content:text`
このコマンドだけでhogesコントローラーやhogeモデルができる。

マイグレーション後にサーバを立ち上げましょう。
`$ rake db:migrate`
`$ rails s`

ブラウザより`localhost:3000/hoges`にアクセスするとtitleとcontentに入力ができ、保存が可能になる。上記の手順を踏むだけで、簡単なアプリが完成してしまうのがRailsだと感じた。しかし、個人的に、はじめのうちはMVCやルーティングについての理解がまだ浅いと思うからscaffoldではなく、model,controllerなど細かく作成していくほうが理解を深めるのにはいいのかなと思った。
iOSアプリにFirebaseの設定を追加してみた

以前、Firebaseの設定までを記事にしたので、今回は実際にiOSアプリ開発でFirebaseを使えるように設定を行います。

前回の記事はこちらです！
[Firebaseの設定をしてみた](https://qiita.com/kumas/items/fc10569bbd4130ab2eff)

###Firebaseの設定を追加
Firebaseのプロジェクト作成後、今回はiOSアプリにFirebaseを追加を選択します

![無題.png](https://qiita-image-store.s3.amazonaws.com/0/239560/cb008da6-974f-3a50-5cf3-44c74ac53392.png)

まずはアプリの登録を行います。
iOSバンドルIDを入力します。iOSバンドルIDはFirebaseを適用させたいXcodeプロジェクトで設定した情報です
![スクリーンショット 2019-02-21 11.36.00.png](https://qiita-image-store.s3.amazonaws.com/0/239560/b95ad7de-bc85-251b-c8d3-b666afd08a92.png)

#####Xcode#####
Bundler identiferに記載されているものを登録します

![無題.png](https://qiita-image-store.s3.amazonaws.com/0/239560/cd4c94f7-3d40-2174-ebeb-5dc3272cf997.png)


次にGoogleService-info.plistをダウンロードして、プロジェクトの指定の場所に配置します。
公式サイトに詳しく載っているので、親切ですね!
![スクリーンショット 2019-02-21 11.36.21.png](https://qiita-image-store.s3.amazonaws.com/0/239560/7ad6cf98-1974-748d-9568-d84017661680.png)

そして、GoogleService-info.plistを開き、REVERSED_CLIENT_IDの値をコピーします

![スクリーンショット 2019-02-21 11.39.17.png](https://qiita-image-store.s3.amazonaws.com/0/239560/a452d58f-8a5c-1b3e-44e6-fb9f9772ecb7.png)

Xcodeを開いたらプロジェクト名を押下して、info→URL Types→URL schemesにコピーした値を貼りましょう

<img width="684" alt="スクリーンショット 2019-02-21 11.39.38.png" src="https://qiita-image-store.s3.amazonaws.com/0/239560/d1042115-5243-8422-5a36-a06d0b274dd2.png">

CocoaPodsを使えるように、下記設定を行います。
ターミナルで、プロジェクトのディレクトリまで移動して、下記設定を行ないます
pod initを行うと、プロジェクトの中にPodFileが生成されるます
![スクリーンショット 2019-02-21 11.47.45.png](https://qiita-image-store.s3.amazonaws.com/0/239560/76aeeb9c-cd2f-54ba-3fb3-e889df94dee6.png)

今回はPodFileには下記設定を追加しました。
手順通りだと、必須のライブラリとアナリティクスと公式ドキュメントには書かれてましたが、Databaseが入っていないかもと思い、下記設定を追記しました。

```
pod 'Firebase'
pod 'Firebase/Database’
pod 'Firebase/Storage'
pod 'Firebase/Auth’
```

Pod installまで完了すれば、アプリ起動時に接続出来るように設定を行いましょう。
ただし、次からはxcodeを起動する際には◯◯◯◯.xcworkspaceというファイルが作成されているはずなので、そちらから起動しましょう。

起動したら下記設定を行いましょう
![スクリーンショット 2019-02-21 11.48.00.png](https://qiita-image-store.s3.amazonaws.com/0/239560/1ebebdf5-16c9-901a-e342-4945138a8765.png)

これで、実装は出来るようになるのですが、下記接続確認を行うことも出来ます

<img width="692" alt="スクリーンショット 2019-03-03 9.02.30.png" src="https://qiita-image-store.s3.amazonaws.com/0/239560/dd765a9f-1a80-3bde-b712-447419581ddd.png">

こちらは強制ではありません。
実機とつないで、Xcodeで作っているプロジェクトに接続して問題無ければ、コンソール画面に戻ります。
実装していて、Firebaseを導入できていたら、importしてエラーにならないので、とりあえずはそれで判断しても良いかもしれません。

最後に、コンソール画面に手順が記載されているので、導入はしやすいと思います
他の機能を使いたい場合でも、まず始めに公式ドキュメントを見るのがオススメです！

###参照###
公式サイト --- https://firebase.google.com
AWS SDK for C++でS3にファイル作成する

AWSにあるS3利用のサンプルは、ローカルファイルをアップロードするものでしたが、プログラム上で直接ファイルの内容を生成してPUTするにはどうしたらよいのか調べてみました。

通常のファイルアップロードは公式のサンプルが参考になります。

put_object.cpp - AWS Code Sample
https://docs.aws.amazon.com/ja_jp/code-samples/latest/catalog/cpp-s3-put_object.cpp.html


## サンプルがありました

あれこれ調べてたらGitHubのAWS公式？アカウントでリポジトリが公開されていました。

aws-doc-sdk-examples/cpp at master · awsdocs/aws-doc-sdk-examples
https://github.com/awsdocs/aws-doc-sdk-examples/tree/master/cpp


こちらのC++のS3利用サンプルに`put_object_buffer.cpp` がありました。ありがたや

aws-doc-sdk-examples/put_object_buffer.cpp at master · awsdocs/aws-doc-sdk-examples https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/cpp/example_code/s3/put_object_buffer.cpp

```cpp:put_object_buffer.cpp_一部抜粋
  const std::shared_ptr<Aws::IOStream> input_data =
        Aws::MakeShared<Aws::StringStream>("");
    *input_data << object_contents.c_str();
    object_request.SetBody(input_data);
```

`*input_data << "hoge";` でファイル内容を追加できるみたいです。改行は`\n` で。

ここで利用されている`Aws::StringStream` ですが、あまり情報がなくAWS公式サイトでソースコードが確認できるくらいでした。~~やっぱりC++はソースコード読めって感じなのかなぁ。怖い~~

AWS SDK for C++: aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSStringStream.h Source File
https://sdk.amazonaws.com/cpp/api/LATEST/_a_w_s_string_stream_8h_source.html


## 参考

put_object.cpp - AWS Code Sample
https://docs.aws.amazon.com/ja_jp/code-samples/latest/catalog/cpp-s3-put_object.cpp.html

aws-doc-sdk-examples/cpp at master · awsdocs/aws-doc-sdk-examples
https://github.com/awsdocs/aws-doc-sdk-examples/tree/master/cpp

AWS SDK for C++: aws-cpp-sdk-core/include/aws/core/utils/memory/stl/AWSStringStream.h Source File
https://sdk.amazonaws.com/cpp/api/LATEST/_a_w_s_string_stream_8h_source.html
メソッドのインライン化(Inline Method)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/257568/fdaf5b9d-a029-52fa-35b6-44022684defa.png)


1つずつリファクタリング技法まとめ
個人的に簡単かつ取り入れ易いと思うものから

## 目的
すぐ引き出せるようにする

## 基本作業サイクル
- システムを動かして仕様を精査
- テストメソッドを作成
- テストの失敗を確認
- テストの成功を確認
- 小さい変更、随時テスト実行(パターン追加失敗確認->成功確認)
- 最後テスト実行
- 最後動作確認

## メソッドのインライン化(Inline Method)
呼び出し先のメソッドを呼び出し元に組み込み、呼び出し先のメソッドを削除すること
メソッドの抽出の逆
 
## ポイント
- 実際の処理と、抽出されているメソッド名が同じくらい分かりやすい
- **メソッドオブジェクトに持たせたいふるまいを実装しているメソッド内の呼び出し**をインライン化することが多い
- メソッドがポリモーフィックな場合はできない(オーバーライドメソッドを消す事になるため)

## 例
```
def evaluation
  output ? 'Success' : 'Failed'
end

def output
  @wrote >= 3
end
```
　　　↓

```
def evaluation
  @wrote >= 3 ? 'Success' : 'Failed'
end
```

## 書籍情報
Jay Fields (著), Shane Harvie (著), Martin Fowler (著), Kent Beck (著),
長尾 高弘(訳), リファクタリング:Rubyエディション
https://amzn.to/2VlyWML

## 雑感
分かり易さの基準によって切り出すべきかインライン化すべきの判断は違いそう
コンテキストとなる表現に近いか次第な感じがする
基本的には抽出のステップあってのインライン化の検討なはず
stm32f4-discoveryの作法

#概要

stm32f4-discoveryの作法、調べてみた。

#写真

![stm32f4_discovery.jpg](https://qiita-image-store.s3.amazonaws.com/0/18104/e1c2c2bc-1e2e-9c57-bc1f-e9feee2e2d8b.jpeg)


#ピン配置

![pin.jpg](https://qiita-image-store.s3.amazonaws.com/0/18104/0dc25c9e-ab06-a444-cfc7-e7c1b5d591e0.jpeg)


#比較

| |Arduino Uno|Spresense|stm32f4-discovery|
|:--|:--|:--|:--|
|Processor type|AVR|ARM M4F|ARM M4F|
|Bits|8|32|32|
|Number of cores|1|6|1|
|Clock speed|16 MHz|156 MHz|168 MHz|
|Operating system|None|Nuttx|None|
|Boot time|0|<1 second|0 Seconds|
|RAM|0.002MB|1.5 MB|0.1MB|
|FLASH|0.032MB|8 MB|None|
|SD Card|Shield|On-Board, optional|Shield|
|eMMC|None|Shield|None|
|EEPROM|0.001MB|Use Flash|Use Flash|
|Voltage|5v or 6-20V|5V or LiPo(3.7V)|5V|
|Typical Operating Power|50 mW|100mW + low power modes|00mW|
|audio Quality|Shield|High|Low|
|Microphones|Shield|up to 8 microphone|Stereo|
|Speakers|Shield|Stereo|Stereo|
|GNSS|Shield|GPS & GLONASS|Shield|
|Time|Shield|RTC|Shield|
|IO Pins|14|29 + 4 LED|32|
|IO voltage|5V|5V/3.3V/1.8V|3.6V|
|UART|1|2|2|
|SPI|1|1 (3.3/5v) +1 (1.8V)|1|
|I2C|1|1 (3.3/5V) +1 (1.8V/camera)|2|
|PWM|6|4|1|
|adc Channels|6|6|None|
|Bits|10|10|None|
|Fastest rate|~10 kHz|500 kSPS|None|
|USB|1 device|2 device|1 otg|
|Camera|Shield|5M Pixel|shield|
|Video display|None|SPI up to 360x240 Pixel|None|
|WiFi|Shield|Shield|Shield|
|Bluetooth|Shield|Shield|Shield|
|Ethernet|Shield|Shield|Shield|
|Cellular|Shield|Shield|Shield|
|価格|約3000円|約6000円|約2000円|


以上。
npm install -g に失敗した時の解決

npm install -gコマンドでエラーが出たため、その解決を行う

# 発生したエラー

```
$ npm install -g firebase-tools
npm WARN checkPermissions Missing write access to /usr/lib/node_modules
npm ERR! path /usr/lib/node_modules
npm ERR! code EACCES
npm ERR! errno -13
npm ERR! syscall access
npm ERR! Error: EACCES: permission denied, access '/usr/lib/node_modules'
npm ERR!  { Error: EACCES: permission denied, access '/usr/lib/node_modules'
npm ERR!   stack: 'Error: EACCES: permission denied, access \'/usr/lib/node_modules\'',
npm ERR!   errno: -13,
npm ERR!   code: 'EACCES',
npm ERR!   syscall: 'access',
npm ERR!   path: '/usr/lib/node_modules' }
npm ERR! 
npm ERR! The operation was rejected by your operating system.
npm ERR! It is likely you do not have the permissions to access this file as the current user
npm ERR! 
npm ERR! If you believe this might be a permissions issue, please double-check the
npm ERR! permissions of the file and its containing directories, or try running
npm ERR! the command again as root/Administrator (though this is not recommended).

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/ec2-user/.npm/_logs/2019-03-02T21_35_10_898Z-debug.log
```

# 解決方法
使用するユーザーに設定用ディレクトリを作成する

```
$ mkdir ~/.npm-global
$ npm config set prefix '~/.npm-global'
$ echo ' export PATH=~/.npm-global/bin:$PATH' >> ~/.bash_profile
$ source ~/.bash_profile
```

# 結果
解決

```
$ npm install -g firebase-tools
/home/ec2-user/.npm-global/bin/firebase -> /home/ec2-user/.npm-global/lib/node_modules/firebase-tools/lib/bin/firebase.js

> @google-cloud/functions-emulator@1.0.0-beta.5 postinstall /home/ec2-user/.npm-global/lib/node_modules/firebase-tools/node_modules/@google-cloud/functions-emulator
> node scripts/upgrade-warning


If you're using the Emulator via the Firebase CLI, you can
disregard this message.

If you're upgrading @google-cloud/functions-emulator, these
are the recommended upgrade steps:

1.  Stop the currently running emulator, if any:

        functions stop

2.  Uninstall the current emulator, if any:

        npm uninstall -g @google-cloud/functions-emulator

3.  Install the new version of the emulator:

        npm install -g @google-cloud/functions-emulator

If you have trouble after upgrading, try deleting the config
directory found in:

    ~/.config/configstore/@google-cloud/functions-emulator

Then restart the emulator. You can also check for any renegade
Node.js emulator processes that may need to be killed:

    ps aux | grep node

+ firebase-tools@6.4.0
added 554 packages from 274 contributors in 11.874s
```
分散トランザクションってトランザクションと何が違うの？？

業務中に分散トランザクションにハマって色々調べたので学んだ事を纏めます。

#1.分散トランザクションとは

###1.1.トランザクションとは
まず初めにトランザクションの定義について記述します。
トランザクションとはアプリケーションがデータベースに対してinsert、update、deleteなどの処理を実行した際の処理のグループで、コミット、もしくはロールバックが実行されるまで続きます。
<img width="304" alt="1.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/162114/0cff1d1f-a3b6-d6e5-3ef8-5a2428b8d445.png">

1つのトランザクションに含まれる処理は1つでもいいし複数あっても大丈夫です。
しかし、トランザクション内の処理が1つでも失敗した場合はデータが不完全な状態なので処理を開始する前に戻したいということは多いと思います。
例えば、商品が売れた際に売り上げ管理テーブルに数値を足してと在庫管理テーブルから在庫を減らす処理をするアプリケーションの場合、
売り上げ管理テーブルへの更新は成功したが、在庫管理テーブルへの更新は失敗した場合、商品は売れているのに在庫は減っていないという状態になります。
これはおかしいので一旦売り上げ管理テーブルも更新する前に戻す必要があります。
この時に処理のグループ(=トランザクション)を売り上げ管理テーブルと在庫管理テーブルの更新に設定しておけば二つが成功してようやくコミット。片方でも失敗すればロールバックする。
という動作ができるようになります。
<img width="424" alt="2.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/162114/d4a7e51b-6c54-2d09-eafd-cda53831cb14.png">

1言で纏めると(文中でも書きましたが)トランザクションとは処理のグループの事です。
グループにいくつの処理を入れるかはアプリケーションで設定できます。

###1.2.分散トランザクションとは
ではいよいよ分散トランザクションとはどういうものなのかという話になります。
分散トランザクションとは、先ほどの売り上げ管理テーブルと在庫管理テーブルの例で言うと下図のようなDB構成の場合に発生するものです。

<img width="670" alt="3.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/162114/205724a2-8279-fa65-b7a7-53d1b81b297a.png">

図を見れば違いがわかると思いますが、売り上げ管理テーブルと在庫管理テーブルが別のDBに属しています。
つまり、トランザクションが成功するにはデータベース1の売り上げ管理テーブルの更新に成功し、かつデータベース2の在庫管理テーブルの更新にも成功する必要があります。
どちらか1つでも失敗してしまえば売り上げと在庫の計算が合わなくなるので両方をロールバックする必要があります。
データベースが2つになっただけで実際の動きとしてはもとのトランザクションと同じと考えていいでしょう。
SSH 接続が極端に遅いときの対処法

## 問題

個人で heteml というレンタルサーバーを契約している。
このレンタルサーバーは ssh 接続が可能なのだが、 ものすごく接続に時間を要する。(普通に1分とかかかる)

普通にストレスだし、一瞬で接続できて欲しい。

## 原因

ssh コマンドで接続を試みる際に -v オプションを付けてデバッグログを出してみると、

```
debug1: Next authentication method: gssapi-with-mic
```

という箇所で詰まっているのが分かる。

調べてみると、GSSAPIAuthentication という方式で認証を試みているのが原因らしい。 
つまり、GSSAPIAuthentication で認証を試みないようにすれば解決するっぽい。

## 解決方法

`~/.ssh/config` で `GSSAPIAuthentication no` してあげれば、解決する。

```~/.ssh/config
Host *
  GSSAPIAuthentication no
```
全問リアル就活Qの問題


### ねむい

- 寝ようと思ったらTwitterで流れてきた問題文を読んで考えてしまった。
- 人は考えると寝れなくなるそうですね。知らんけど



### 問題文

大文字の英字のみからなる文字列が与えられる。文字列のうち3箇所を選び、左から順に取り出した時に`ABC`となるのは何通りか。ただし、計算量は$O(N)$とする



### 入力例1

```
AABBCC
```

### 出力例1

```
8
```



### 入力例2

```
ABCABCABCABCABCABCABCABCABCABCABC
```

### 出力例2

```
286
```



---



### 想定解

- $S_i$を頭から見ていく。そのとき、$S_i$まで見たときの`A`の個数、`AB`の個数、`ABC`の個数を持つ変数を用意しておく
- $S_i$が`A`のとき、Aの個数をプラス1する。
- $S_i$が`B`のとき、`AB`の個数に`A`の個数を足し合わせる。
- $S_i$が`C`のとき、`ABC`の個数に`AB`の個数を足し合わせる。

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

int main() {
  string s;
  cin >> s;

  int a = 0, ab = 0, abc = 0;
  for (int i = 0; i < s.size(); i++) {
    if (s[i] == 'A') {
      a++;
    }
    if (s[i] == 'B') {
      ab += a;
    }
    if (s[i] == 'C') {
      abc += ab;
    }
  }

  cout << abc << endl;

  return 0;
}
```



### 他の解法

- `B`を固定して考える
- 各`B`の左側の`A`の個数と`C`の個数の積が、その`B`を使った時にできる`ABC`の場合の数になる
- $S_i$まで見たときの`A`の個数と`B`はあらかじめ求めておけば良い
- なんかコード汚い気がする。ごめんなさい

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

int main() {
  string s;
  cin >> s;

  int n = s.size();
  vector<int> ruiA(n+1), ruiC(n+1);

  // この辺で累積和取ってる
  for (int i = 0; i < n; i++) {
    ruiA[i] = s[i] == 'A';
    ruiC[i] = s[i] == 'C';
    if (i >= 1) ruiA[i] += ruiA[i-1];
  }
  for (int i = n-1; i > 0; i--) {
    ruiC[i-1] += ruiC[i];
  }

  // 答えを求める
  int ans = 0;
  for (int i = 1; i < n-1; i++) {
    if (s[i] == 'B') {
      ans += ruiA[i-1] * ruiC[i+1];
    }
  }

  cout << ans << endl;


  return 0;
}
```



### 他の解法

- 想定解のやつをDPでやる
- 文字数が増えるとDPの方が良いって強い人が言ってた
- `dp[0]`が`A`、`dp[1]`が`AB`、`dp[2]`が`ABC`の状態になってる.

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

int main() {
  string s;
  cin >> s;

  vector<int> dp(s.size());

  for (int i = 0; i < s.size(); i++) {
    if (s[i] == 'A') {
      dp[0]++;
    }
    if (s[i] == 'B') {
      dp[1] += dp[0];
    }
    if (s[i] == 'C') {
      dp[2] += dp[1];
    }
  }

  cout << dp[2] << endl;

  return 0;
}

```





### 感想

- 普通に思いつかなかった。
- 走査したとき、`B`を見つけたらそのときの`AB`の個数は`A`の個数。`C`を見つけたらそのときの`ABC`の個数は`AB`の個数。普通に考えればそうか。なんで思いつかなかったんだろ。えーんえーん。
- 僕がやったことないDPの使い方が知れてよかった。今までインデックスを持つタイプのDPしかやったことなかったから。
(積分)  「2019東北大学 前期日程 数学（理系）［5］」 をWolframAlpha とsympyで.やってみたい

オリジナルリンク

https://www.densu.jp/tohoku/19tohokuspass.pdf#page=5

お探しのページが見つかりません＜読売新聞

https://www.yomiuri.co.jp/nyushi/sokuho/k_mondaitokaitou/tohoku/mondai/img/tohoku_zenki_sugaku_ri_mon.pdf#page=3

https://www.yomiuri.co.jp/nyushi/sokuho/k_mondaitokaitou/tohoku/kaitou/img/tohoku_zenki_sugaku_ri_kai.pdf#page=5

#wolframalphaで
(1)

https://www.wolframalpha.com/input/?i=Integrate%5Bsin(pi*x)**2%2F(1%2Bexp(x)),%7Bx,-1,1%7D%5D

integral_(-1)^1 (sin^2(π x))/(1 + e^x) dx = 0.5

https://www.wolframalpha.com/input/?i=Integrate%5Bsin(pi*x)**2,%7Bx,0,1%7D%5D

integral_0^1 sin^2(π x) dx = 1/2 = 0.5
(2) わかりませんでした。
(sin(x)**2+Integrate[sin(pi*x)**2),{x,-1,1}])/(1+exp(x))


#sympyで


```python
from sympy import *
x = Symbol('x')
f=sin(pi*x)**2/(1+exp(x))
print("#(1)",f)
print("#(1)",integrate(f,(x, -1, 1)))
f=sin(pi*x)**2
print("#(1)",f)
print("#(1)",integrate(f,(x, 0, 1)))
print("#(2) わかりませんでした。")
#(1) sin(pi*x)**2/(exp(x) + 1)
#(1) Integral(sin(pi*x)**2/(exp(x) + 1), (x, -1, 1))
#(1) sin(pi*x)**2
#(1) 1/2
#(2) わかりませんでした。
```