OmniAICreator/Qiita-1.07M huggingface dataset:
PHP×SpreadSheetAPIで特定のSpreadSheetにシートを名前をつけて追加する

## やりたいこと
タイトルの通り

## 前提
Google_Clientを使用できるようにしておく。

## ソースコード

```php:sheet.php
<?php

/**
 * Class GoogleSheetsAPI
 */
class GoogleSheetsAPI {

    /**
     * @var Google_Service_Sheets
     */
    protected $service;

    /**
     * @var array|false|string
     */
    protected $spreadsheetId;

    /**
     * GoogleSheetsAPISample constructor.
     */
    public function __construct()
    {
        $dotenv = new Dotenv(__dir__);
        $dotenv->load();
        $credentialsPath = getenv('SERVICE_KEY_JSON');
        putenv('GOOGLE_APPLICATION_CREDENTIALS=' . dirname(__FILE__) . '/' . $credentialsPath);
        $this->spreadsheetId = getenv('SPREADSHEET_ID');
        $client = new Google_Client();
        $client->useApplicationDefaultCredentials();
        $client->addScope(Google_Service_Sheets::SPREADSHEETS);
        $client->setApplicationName('test');
        $this->service = new Google_Service_Sheets($client);
    }

    public function createNewSheet()
    {
        $title = "追加シートのタイトル";
        $req = new Google_Service_Sheets_BatchUpdateSpreadsheetRequest(array(
        'requests' => array('addSheet' => array('properties' => array('title' => $title )))));
        $response = $this->service->spreadsheets->batchUpdate($this->spreadsheetId, $req);
    }
}
$a = new GoogleSheetsAPI;
$a->createNewSheet();
```
DVDとBlu-Rayの違いって何？DVDとBlu-Rayの違いを分かりやすく解説

DVDとBlu-Rayの違いについて▼
![dvd-vs-bluray-02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432052/bff03b8c-577a-54c1-3d9c-56cb97a75e9e.jpeg)


①、容量
DVDの容量なら、片面1層4.7GB、片面2層8.5GB。ブルーレイなら、DVDの5倍以上の容量を実現しています。片面1層25GB、片面2層50GB。

②、画質
DVDの画素数は約35万画素程度。それに対して、ブルーレイの画素数は約207万画素程度。
![dvd-vs-bluray-01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432052/e5cf7a17-77b9-87bf-091c-d15b4d463336.jpeg)

③、寿命
ブルーレイディスクとDVDディスクに金属窒化物を使っていて、経年劣化の差はそれほどなく、10年～20年程度保存できると言われています。
![dvd-vs-bluray-04.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432052/2e9e4301-3510-7f88-a046-0a15089717b8.jpeg)


④、対応レコーダー
ブルーレイレコーダーはDVDにも互換性があるので、ブルーレイDVD 再生、録画なら、どっちも実現可能。そのレコーダーの価格はDVDレコーダーより高い。

⑤、コピーガード
ブルーレイのコピーガード（著作権保護技術）主に四つ種類： AACS (Advanced Access Content System)、ROM Mark、BD+、Cinavia

DVDのコピーガード（著作権保護技術）主に六つ種類：CSS（Content Scramble System）、ARccOS、Disney X-project DRM、容量偽装（ファイルサイズ偽装）、UOPs、APSマクロビジョン

![dvd-vs-bluray-03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432052/d8743623-439f-dc4a-89da-336afbda68a7.jpeg)


詳細は、　　https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q11185269476　　　
までにご参照ください。
CentOS7のシェルスクリプトでFizzBuzzやってみた

入門のシェルプログラミング系の本を一冊読み終えたので試しにFizzBuzz問題をシェルスクリプトで解いてみました。
とりあえず1~100までの数字に関して実行したらうまくできました。seqの横の数字をいじれば数字も変更できます。
readコマンドを使って入力された数字に関してもおそらくできると思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/409727/83a2afe6-b356-cb3c-5bb6-ba6edd5a982d.png)

とりあえずこんな感じです。間違ってたら悲しい.....
AtCoder Educational DP Contest A - Frog 1

## はじめに
AtCoder初心者が勉強していく記事です。
初学者の時にわからなかったことって、慣れてくると忘れてしまうかとおもいます。
後の初学者の方のためにもくどいくらいにコメントを書いていきます。

## 問題を解く
動的計画法(DP: Dynamic Programming)関連の問題が沢山集まったEducational DP Contestの問題を解いていきます。
今回はこちら。
[A - Frog 1](https://atcoder.jp/contests/dp/tasks/dp_a)

```cpp
//A - Frog 1
#include <iostream>
using namespace std;

int main(){
  int n;
  //int nを入力
  cin >> n;

  //足場iにおける高さを入力
  int h[n];
  for (int i = 0; i < n; i++) {
    cin >> h[i];
  }

  //足場iにおけるコストの最小値
  int dp[n];
  //スタート時点ではジャンプしていないのでコストゼロ
  dp[0] = 0;
  //足場1に行く方法は足場0から+1でジャンプする1通りのみ
  dp[1] = abs(h[1] - h[0]);

  /*足場2以降に関して計算。
  足場iに到達する方法は
  ①足場i-2から+2のジャンプ or ②足場i-1から+1のジャンプ
  */

  for(int i = 2; i < n; i++){
    //①の場合に関して計算しdp[i]に代入
    dp[i] = dp[i - 1] + abs(h[i] - h[i-1]);
    //さらに②の場合も計算。①と②を比較した際の最小値(min)が足場iに到達するための最小コスト
    dp[i] = min(dp[i], dp[i - 2] + abs(h[i] - h[i-2]));
  }

  //最後の足場におけるコストを出力。
  cout << dp[n-1] << endl;
  return 0;
}
```
OneDriveというかSharePoint Onlineのタイムゾーン

OneDriveというか、たぶんSharePointの話ではないかと思いますが、ファイルの更新時刻が太平洋標準時で表示されてしまう、という現象があるようです。

これは、Office365などで、タイムゾーンをJSTと設定していても、OneDriveをブラウザから使った場合に太平洋標準時(UTC-8)で表示される、という現象です。JSTからだとJST-17ということですね。

[SharePoint Online の個人用サイトのタイムゾーンが既定で太平洋標準時に設定される](https://support.microsoft.com/ja-jp/help/2901182)


上記に、この現象の説明と解決方法があります。要点は，上記に書かれている以下の補足：

「個人用サイトのタイムゾーンを一括で設定する方法はありません。各ユーザーが手動で設定する必要があります。」

に尽きます

なお，近頃のOneDriveの場合、従来のOneDriveに戻す、を選択すれば上記の方法で時刻表示をJSTにすることができます。
App is not indexable by Google Search;...のワーニングを消す

## 課題
`AndroidManifest.xml` を開くと、`<application/>` タグ全体に黄色のワーニングが出る。このままでも問題はないが消したい。

## 解決方法

<intent-filter>タグ内に以下行を追加すると、ワーニング自体は消える。

```xml
<action android:name="android.intent.action.VIEW"/>
```

修正例

```xml
<activity android:name=".view.splash.SplashActivity"
            android:screenOrientation="portrait"
            >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <action android:name="android.intent.action.VIEW"/>

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
</activity>
```


## 所感

このワーニングは下記のURLが参照先となっているが、これは、「Android App Links」についての説明が主になっており、これを使う予定がない人にとっては、あまり役に立たない。

https://developer.android.com/studio/write/app-link-indexing

## 参考

https://stackoverflow.com/a/52934566/6891441
【合格体験記】AZ-900:Microsoft Azure Fundamentals

#Azure-900に受かりました
ので、その際に利用した勉強方法等を記載します。
##どんな試験！？
[Azure](https://www.microsoft.com/ja-jp/learning/exam-az-900.aspx)の基本的な概要やクラウドの初歩的な用語を聞かれる試験です。

###試験概要
問題数 　: 44 問 
時間 　　: 60 分 
合格点 　: 700 / 1000 点
※注意事項※
問題文の日本語と英語の切り替えは可能（Lpicと一緒）

##勉強方法
[こちら](https://docs.microsoft.com/ja-jp/learn/paths/azure-fundamentals/)をひたすらやりました。勉強時間は1日2-3時間を1週間程度ですかね。
##試験の感想
難易度は~~ITILファンデーション~~程度かな？ってのが本音です。そのため難しくはないけど勉強しないと受からないですね。特にMS特有の用語とか覚えないと厳しい・・・（´Д`q゜
ただ業務でクラウドは一切利用していない私でも受かりましたので、大丈夫です！
資格勉強で得た知識としては業務に直結しないことが多く、もやもやすることも多いですがお互いにがんばっていきましょー！！
Djangoを使ってみた感想

#はじめに

「DjangoかLaravelの勉強会をやるから資料作ってくれない？」

ある昼下がり、こう上司に言われました。
Laravelは以前、同僚がやったこと、だいたいみんな使えるということ、
Djangoを使った案件が近々動き出すこと、社内に使える人が少ないことからDjangoの勉強会を開くこととなりました。


# Djangoって何？
DjangoはPythonのFrameworkの１つである。
あのFa●●bookやYo●●ubeなどもこのDjangoを使って作られている。

そういえば、Yo●●ubeではオススメの動画が表示されるが、これはPythonを使った機械学習によるものなのかな。
![スクリーンショット 2019-06-24 10.54.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/343721/355922df-ec83-d6a4-5152-1c08068fa15c.png)


## Djangoを使ってみて
DjangoとLaravel（会社に入社して一番はじめに触ったFramework）の厄介なところは関連付けて考えられなかったことです。

具体的にいうと、LaravelはM(Model),V(view),C(Controller) なのに対して
DjangoはM(Model),T(Template),V(View)であるということ。

このMVCという考え方に慣れていればいるほどMTVの考え方を受け入れるのは相当困難なのではないかと思う。

ただ、デメリットだけではなく、メリットもあります。

コードがとても簡単に書けるということもあります。
この記事では詳しくは書きませんが、驚くほど簡単にコードを書けます。✌️

# 最後に

今回、全くズブの素人状態からなんとか、Djangoを使ったサンプルアプリを一つ作ることができました。
皆さんも挑戦してみてください。
それでは
foreachを使って配列の最後を取るお話。

PHPの基本構文、foreachのお話。

foreach内で文字列操作等をする場合に、最終行判定をして処理を行いますよね。
こんな感じで！

サンプルコード1：

```php

$count = 0;
$array = [1, 2, 3, 4, 5];
foreach($array as $value)
{
    $count++;
    if ($value === end($array)) {
        echo  '配列の最後は'.$count.'個目!'. PHP_EOL;
    }
}
```

結果：

```
配列の最後は5個目!
```

OK！ 最終行判定はend()でできた！


では次のパターンでの場合、どうなるだろうか

サンプルコード2：

```php

$count = 0;
$array = [1, 2, 5, 4, 5];
foreach($array as $value)
{
    $count++;
    if ($value === end($array)) {
        echo  '配列の最後は'.$count.'個目!'. PHP_EOL;
    }
}
```

結果：

```
配列の最終は3個目!
配列の最終は5個目!
```

oh.. 最終行目ではない３つ目も文字出力されているではないか

配列の３つ目と５つ目が同じ値のため、出力されていました。


foreachを使って配列の最後を取る場合、値によっては適切な処理ができないため
ループカウンターを使って取得しましょう！

サンプルコード3：

```php

$loop_count = 0;
$array = [1, 2, 5, 4, 5];
foreach($array as $value)
{
    $loop_count++;
    if ($loop_count == count($array)) {
        echo  '配列の最終は'.$loop_count.'個目!'. PHP_EOL;
    }
}
```

結果：

```
配列の最終は5個目!
```


初心者ではなくても結構やってしまう
PHPあるあるでした:point_up:
Oracleマスター Silver 12ｃ データベースのメンテナンスの実行

※用語はなるべく、Oracle® Databaseリファレンス　12c リリース1 (12.1) より抜粋しております。

###■公式チェックリストより出題範囲
データベースのメンテナンスの実行
・サーバーが生成したアラートを使用する

■試験内容　チェックリストから除外されたトピック
　－自動ワークロード・リポジトリ（AWR）を管理する
　－自動データベース診断モニタ（ADDM)を使用する
　－アドバイザ・フレームワークについて説明し使用する
　－アラートしきい値を設定する
　－自動化タスクを使用する

－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－

###要点

全体的に削除されたトピックが多い。
覚えることは非常に少ないのでさらっと流してもいい。

－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－

###サーバー生成アラート
　Oracleは、さまざまな問題をアラートとして出力します。
　さまざまな統計情報をメトリックとして分析した結果を表示しますが、メトリックにはしきい値を設定できます。このしきい値を超えたときに生成されるアラートを**サーバーアラート生成**と呼ばれます。

※注意※サーバー生成アラートには、しきい値をベースにしたものだけでなく、イベント駆動型（ORA-01555：スナップショットが古すぎます　など）のものもあります。

■メトリックのしきい値設定
　警告：注意をうながす段階。基本的に解決しなくても操作は継続可能　
　クリティカル：これ以上は問題あり。即時に問題を解決したほうがよい

■アラートへの対応
　アラートはEnterprise Managerに表示されるだけでなく、Eメールによる通知も可能です。

　　●しきい値アラート
　　　－**ステートフルアラート**とも呼ばれ、データベースメトリックに警告およびクリティカルのしきい値を設定し、その値に達するとアラートを通知するものです。

生成されると**DBA_OUTSTANDING_ALERTSビュー**に記録され、必要な処置をおこなったあとその**アラートを消去することで、問題は解決したとみなされ、**DBA_ALET_HISTROYビューに記録されます。

　　●非しきい値アラート
　　　－**ステートレスアラート**とも呼ばれ、データベースイベントに対応してアラートを通知します。
　　　　「スナップショットが古すぎます」
　　　　「リカバリ領域の空きが低下しています」
　　　　「再生可能なセッションが一時停止しています」
　　　　のようなエラーなど、特定のイベントに対応しているものです。

非しきい値のアラートはDBA_OUTSUTANGING_ALERTSビューには記録される、問題の原因が解消されると自動的に消去され直接DBA_ALERT_HISTORYビューに記録されます

※違いをしっかりと把握しよう。



<FONT COLOR=red></FONT>
Ubuntu MATE 19.04で突然WiFiが使えなくなった件

Ubuntu Mate 19.04をちょっと古いMacBook Airにインストールしました。
当初は内蔵WiFiを使えたのですが、apt upgradeすると使えなくなって困っていました。
いろいろ試してみたのですが、対応策は見つからず。

ふと、カーネルをkernel-ppa/mainlineの5.1.14にしてみるとあっけなく動作。

よかったよかった。
UX評価に必要なこと

# about

Webサービスにおける、ページ改修・ページリニューアルについての話

どうしてもUXの良しあしについての議論って、空中戦になってしまうので、
それをどのように実のあるものにしていくかの覚書

## 立ち位置

現業では、以下の役割がいます。その中での機能実装・品質管理の立場でどのように考えるのかを整理していきたいと

1. プロダクトオーナー（事業責任者）
2. デザイナー・コーディング
3. 機能実装・品質管理

### 簡単な説明
（後ほど埋める）

# UX開発の進め方

一般用語＋日本語！

1. ユーザーカテゴライズ：利用者分類
2. ペルソナ作成：利用者の具現化・生活基盤・社会生活・名前・日常生活について細かく設定する
3. （ペルソナプライオリタイズ：具現化した利用者の優先順位設定）
4. （デザイン：画面設計）
5. dev-design：機能詳細設計
6. UXテストデザイン：評価基準作成
7. UXテスト：利用者観点での評価

## それぞれに対応する合意文書

1. ユーザーカテゴライズ
2. ペルソナ作成
    * ペルソナシート（例：https://www.kikakulabo.com/post-6670/）
3. （ペルソナプライオリタイズ：具現化した利用者の優先順位設定）
4. （デザイン/プロトタイピング：画面設計/紙芝居作成）
5. プロトタイプテスト：紙芝居上での利用者目線でのテスト
    * プロトタイプテストのメモ：（デザインシンキング・プロトタイプ：https://www.mermirai.com/entry/designthinking）
5. dev-design：機能詳細設計
6. UXテストデザイン：評価基準作成
    * ヤコブニールセンのヒューリスティック10か条をもとにする予定：https://www.takurokamiyoshi.net/blog/111/
7. UXテスト：利用者観点での評価
[Java] serialVersionUIDの意義


# Serializableクラスのバージョン管理に使う


```java
private static final long serialVersionUID = 1L;
```

* 同じクラスは、シリアライズされたときと、デシリアライズされるときに同じバージョン（変更が加えられていない）でないといけない。
* シリアライズする予定がない場合は、消してしまっても構わない。
【初心者向け】slimの書き方

#はじめに

職場で初めてslim記法に触れて全く読めなかったので、基礎だけでも押さえようと記事にまとめてみました。
修正点等ありましたら教えていただけると助かります。

#参考

[RailsのHTMLテンプレートエンジン、Slimの基本的な記法](https://qiita.com/mom0tomo/items/999f806d083569529f81)
[【爆速で習得】Railsでslimを使う方法から基本文法まで](https://qiita.com/ngron/items/c03e68642c2ab77e7283)

#slimとは

１：Ruby製のテンプレートエンジン
２：高速、軽量
３：htmlの閉じタグ不要
４：条件分岐などの`end`不要
５：インデントによって階層構造を表現するため、 ずれるとエラーになる

#概要

大まかな概要はこちら。

`<>`不要
<%= %> → `=`
<% %> → `-`
コメント → `/`
id指定 → `#`
class指定 → `.`

#書き方一覧

`a`

```example.html
<a href="www.example.com">ホームページ</a>
```
```example.slim
a href="www.example.com" ホームページ
```

`p`

```example.html
<p>
      ほげほげ　ふがふが
      ほげほげ　ふがふが
</p>
```

```example.slim
/ （改行する場合はパイプ(|)を使う）
p
  |
    ほげほげ　ふがふが
    ほげほげ　ふがふが

/ パイプの後ろに書いても良い
p
  | ほげほげ　ふがふが
```

`erb記法`

`<%> <%> → -`

```example.slim
- if logged_in?
 li = link_to '投稿する', new_path
 li = link_to 'ログアウト', logout_path
- else
 li = link_to 'ログインする', '/auth/twitter'
```


`<%=> <%> → =`

```example.slim
= form_for @micropost, :html => { class: "foo"} do |f|
  = f.text_field :title, placeholder: "内容"
  = f.submit "投稿する", class: "btn"
```

`コメントアウト /`

```example.slim

 / li = link_to 'ログアウト', logout_path
```

`クラス .` `ID #`

```example.slim

<div class="text">
</div>

<div id="text">
</div>

/ 正 （divタグ省略）
.text
#text

/ 複数クラスの記載は.で繋ぐ
.text.text-plain
```

`render` `yield`

```new.html.slim
/ 誤
= render 'form', user: @user

/ 正 （render yield は ==）
== render 'form', user: @user
```

`if`文

```example.html
<% if current_user.nil? %>
  <li>新規登録</li>
<% else %>
  <li>ログイン</li>
<% end %>
```
```example.slim
- if current_user.nil?
  li 新規登録
- else
  li ログイン

/ end不要
```
Ubuntu16.04 でシステムログ(syslog)が容量を圧迫している場合

Ubuntu16.04 でシステムログ(syslog)が容量を圧迫している場合には削除しましょう。
問題はないようです。
ディスク使用量アナライザーで圧迫しているログのアドレスを適当に探して
```
sudo rm syslog.1; sudo rm syslog
```
これで万事解決！
TortoiseGitでアカウントを切り替える

## 1. はじめに

「1台のPCで複数のGitアカウントを使いたい！」といった場合に、アカウントを切り替える方法の備忘録。

## 2. 環境

- TortoiseGit
- Windows 10

## 3. 手順

### 3-1. TortoiseGitのアカウント設定変更

1. TortoiseGitの設定画面を開く。
2. ツリーにて「Gti」を選択し、「このユーザの設定を編集」から名前とメールを変更する。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247638/519877cf-024e-2a45-1f59-dddf56caa139.png)

### 3-2. 資格情報を削除

1. 「コントロールパネル」⇒「ユーザーアカウント」⇒「Windows資格情報の管理」開く。
2. Gitの資格情報を削除する。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247638/68672b4b-8c5b-c664-a429-fce8d1446db5.png)
SSH管理のConfig設定のメモ

# SSH管理のConfig設定のメモ
自分用にSSH管理のConfig設定のメモ

## Configの場所
基本はユーザホーム直下の ```.ssh/config``` というファイル

#### Mac

```
~/.ssh/config
```

#### Windows

```
%HOME%\.ssh\config
```

## SSHコマンド
ssh {接続先のユーザ名}@{IPまたは名前解決できるドメイン} -i {鍵ファイルのパス}

```:例
$ ssh root@dev.hogehoge.com -i ~/.ssh/hogehoge.com/dev-root.pem
```

### 文法

```
Host {自由につける名前}
    HostName {IPまたは名前解決できるドメイン}
    User {接続先のユーザ名}
    IdentityFile {鍵ファイルのパス}
    Port {22ポート以外だったらこれで指定}
```

```:例
Host dev-hogehoge
    HostName dev-hogehoge
    User root
    IdentityFile ~/.ssh/hogehoge.com/dev-root.pem
```

```:使用時
$ ssh dev-hogehoge
```
【初心者】Webサーバー、アプリケーションサーバーの違い

## はじめに
Webサーバー、アプリケーションサーバーの違いについて書いていきます。

**対象者**

- Webサーバーって何をやっているか？？
- アプリケーションサーバーって何をやっているか？？
- それら二つの違い

この辺りを知りたい方は是非、共に学習しましょう！

## Webサーバーが何をやっているか？？

<img width="627" alt="スクリーンショット 2019-06-23 16.18.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401375/dd4033fb-01ad-50d0-ca07-aa240179594a.png">

例　Webページを閲覧したい場合
1.図のようにWebブラウザ（Chromeなど)からリクエスト(HTTP)を送ります。
2.リクエストを受け取ったWebサーバーはそれを読み取り、処理を行いWebブラウザにレスポンス(HTTP)を返します。
[※HTTPの説明](https://wa3.i-3-i.info/word165.html)

**まとめるとWebサーバーとは**
上記の2のように受け取ったリクエストを読み取り、処理を行いその結果を返す役割りをしている
※ただしここで注意点があります
**静的コンテンツを処理する役割りを担っています。**
静的コンテンツとは
誰が見ても変わらないページのことですね（企業のトップページ、会社概要など）

**仮に静的コンテンツのみの場合だとアプリケーションサーバーがなくても大丈夫です**

## アプリケーションサーバーは何をやっているか？？
<img width="509" alt="スクリーンショット 2019-06-23 19.38.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401375/59e5a347-a96f-b053-c33f-aa26416fa37a.png">


## Webサーバーとの主な違い
上記、図のような感じで

- アプリケーションサーバーは動的な処理も返せる。
- アプリケーションサーバー単体で動かすケースはあまりない


## まとめ
自分もそうですがRailsなどでアプリケーションを作ろうとするとき、このような知識がなくても動いてくれますよね？
それはRailsなどをインストールするだけで標準で装備されていたりするからですね（詳しくは調べてください）
ただ、実際の現場でやっていくとなると、大量のリクエストを処理、運用していかないとダメなので、このような根本的知識が大切になってくるわけです。
今回は範囲を絞り、かなりザックリとした説明なので詳しくは**Web三層構造システム**を理解することが大切です。

## 参考文献

https://qiita.com/shuntaro_tamura/items/ae55b99deb9e2a170754

https://kitsune-programming.com/ap-server-summary#APWeb
intra-mart の設定画面がテキストのみになってしまう。

あれこれ調べたが、ネット上ではほとんど情報がなかったので。
自分の記録用もかねて記載します。

【構築環境】
　・Java：Oracle JDK11
　・Webサーバ：Apache2.4
　・Webアプリケーションサーバ：Resin Pro 4.0.61
　・DB：PostgreSQL 9.6
　・その他：IM-Juggling 1.0


【現象】
　intra-martの構築が完了し、設定画面を表示させたがなぜかテキストのみの表示（下図参照）になり、各項目を入力後に「登録」ボタンをクリックしても反応ない。
![intra-mart-Text.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434774/3d1898b8-3160-c65a-ac40-51fbbffcc1ae.png)

【原因】

~~　IM-Jugglingにて環境構築時に「server-context-config.xml」でBase urlの設定を行っていなかったことが原因。
　Apacheの設定との兼ね合いもあるが、8080を外しても同様の現象になる。~~

2019年8月22日：訂正
　Apache上に静的コンテンツを配置していないのが原因。
Jugglingで静的コンテンツの出力を行う部分があるので、静的コンテンツを作成しApache上に展開する必要ある。
![StaticFileOutput.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434774/ff40f16c-58c9-e2a2-9949-e9507213dcad.png)

詳細については下記リンクをご参照ください。
[intra-mart Accel Platform セットアップガイド 「5.5.　静的コンテンツの出力」](https://www.intra-mart.jp/document/library/iap/public/setup/iap_setup_guide/texts/create_war/create_static_file.html)

なお、httpd.confにて追記した下記部分は静的コンテンツを使用する設定部分となる。
![UseStaticFile.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434774/2b7d8931-9fc1-0f7b-d7e7-995f72a7013f.png)
AmazonLinux2にDockerとDockerComposeをインストールする。

## Dockerのインストール

- AmazonLinux2の起動などは割愛
- ec2-userでSSH接続をしている想定

```
$ sudo amazon-linux-extras install -y docker
$ sudo systemctl enable docker
$ sudo systemctl start  docker
```

## DockerComposeのインストール

```
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
```

## ec2-userをDockerユーザーグループに追加する。

- `ec2-user`でDockerコマンドを利用できるようにする。
- 接続・利用ユーザー名が別の場合は適時読み替えてください。

```
$ sudo gpasswd -a $USER docker
```

うまく反映されない場合は、一度ログアウトする
機械学習における問題設定の重要性

ビジネスの現場で機械学習を使う場合、問題設定は非常に大事です。
アルゴリズムの取捨選択も大事ですが、問題設定も同等、もしくはそれ以上に重要だと思います。

理由は、問題設定は基本的に人間にしかできないタスクであり、人間でもできる人が限られるからです。
[Kaggle](https://www.kaggle.com/)の影響もあり、アルゴリズムに詳しい、また、データクレンジングに慣れている人は最近かなり増えてきたように見えます。

一方、Kaggleで出題されるものは問題設定が既に済んでいるものが多く[^1]、どれだけKaggleに取り組んでも問題設定能力を身に付けることは難しいと思います。
例えば、

- 金融機関の融資審査
    - その人にお金を貸してよいか？貸さないほうがよいか？を審査する
- テキスト（例：ツイート、投稿）のポジネガ判定
    - テキストがポジティブな内容か？ネガティブな内容か？を判定する

など解くべき問題が既に明確な場合は必要ありませんが、

- ECサイトの売り上げが減っているので、機械学習を使って何とかしたい
- データが大量にあるので機械学習が使える気がするけど、どこから手を付けて良いのか分からない
- 機械学習を使って複雑な業務フロー（オフラインの業務含む）を改善したいけど、どこに機械学習が使えるのか分からない

という場合は適切な問題設定ができるのか？機械学習が解けるまでに問題を明確化できるのか？が最初の関門になります。

例えば、「ECサイトの売り上げが減っている」という場合においては、

- 客数が減っているのか？
- 客単価が減っているのか？
    - 購買回数が減っているのか？
    - 1回当たり購買金額が減っているのか？

のように問題を切り分けることが必要です。切り分け方は様々な軸が考えられ、絶対的な正解というものはありません。
そして、「購買回数の減少」が一番の問題であれば、

- 購買回数を増やすために配信するメールでレコメンドする商品を決める
- 購買タイミングを予測し、購買の取りこぼしが発生しないようにする

のように解くべき問題を明確化できる、つまり、適切な問題設定をすることができます。

# 適切な問題設定をするためには？
適切な問題設定をするために、意識しておいた方が良いことが幾つかあります。
これらの点を意識しておけば、適切に問題設定できる可能性は高まると思います。

### 1. 分類問題、もしくは回帰問題に帰着させられるか？
当たり前ですが、機械は数値しか扱うことはできません。
機械学習においても、入力は数値である必要があり、出力も数値である必要があります。

分類問題においては、二値分類の場合は出力を`0`か`1`、N値分類の場合も出力を`0`、`1`、…、`N`のいずれかにしているに過ぎません。
回帰問題においては、出力が離散データではなくて連続データとなりますが、数値であることに変わりはありません。

出力が数値である必要があるということは、逆に言えば、出力を数値に落とし込むことができればその問題は分類問題、もしくは回帰問題に帰着させることができ、それはつまり機械学習で解ける可能性があるということです。

### 2. 問題を解決した場合、デメリットよりもメリットの方が大きいか？
多くの場合、「掛かったコストよりも生み出される利益のほうが大きいか？」に置き換えることができます。
「掛かったコスト」には機械学習のロジック開発やシステム構築に掛かった人件費やサーバ代などが該当し、「生み出される利益」は削減された人件費や増加した売り上げなどが該当します。

### 3. 問題の解決に必要なデータセットは揃っているか？
機械学習に必要なデータセット（「教師データ」や「学習データ」とも呼ぶ）を用意できるか？ということです。
ひとまず機械学習を試してみようと思っても、

1. 直近のデータしか保存していない
2. 重要なデータが保存されていない
3. ある程度の期間の必要そうなデータが保存されているけど、ノイズがたくさん混ざっている
4. 正解ラベルを全てゼロから作る必要がある

ということは頻繁にあります。
そして、解決しようと思っても、すぐに解決できない場合が多いです。

データセットについてさらに知りたい方は、[機械学習のデータセットの重要性](https://qiita.com/nonbiri15/items/b29fe079d359d531bf85)などをご覧下さい。

# 適切な問題設定ができるようになるためには？
それでは、適切な問題設定ができるようなるためには何をすればよいのでしょうか？
人により考えは異なるかもしれませんが、私は下記の二点が大事だと考えます。

### 1. 経験を積む
経験を積めば、前記の

**1. 分類問題、もしくは回帰問題に帰着させられるか？**

に対する嗅覚が上がると思います。

機械学習絡みの分析案件を色々と経験すると、この案件は過去のあの案件に似ているので、問題設定はこうすれば良さそう、または、適切な問題設定ができないので機械学習の導入は見送ろうと判断できる事があります。
もちろん、過去に似たような案件がない場合もありますが、様々な事例を経験しておけば勘所が何となく分かるということはよくあります。

事業会社で多種多様な分析案件を手掛けることができない場合は、

- 勉強会や学会で他社の取り組み事例を聞く
- ブログやネット記事で他社の取り組み事例を読む

というのがオススメです。アルゴリズムの部分だけを取り上げた発表や記事もありますが、問題設定の部分の難しさや苦労を紹介したものも少なからずあります。

### 2. 事業ドメインに詳しくなる
事業ドメインに詳しくなれば、前記の

**2. 問題を解決した場合、デメリットよりもメリットの方が大きいか？**
**3. 問題の解決に必要なデータセットは揃っているか？**

に対する感度が上がる思います。

事業ドメインに詳しくなるということはコスト構造の把握に繋がり、メリットとデメリットの比較が容易になります。時には、数値化できないリスクの存在に気付くこともできます。
また、事業ドメインに詳しくなれば、

- このデータは機能Aの裏側で取得している
- このデータは会員登録の項目に入っていないので、きっと取得していないだろう

という当たりが付きやすくなります。

[^1]: 問題設定が済んでいるからこそ、Kaggleに出題することができる。
AWS Step FunctionsのCallback PatternsでCodeBuildをステートマシンに組み込んでみた

先日、AWS Step Functionsで[Callback Patterns](https://aws.amazon.com/jp/about-aws/whats-new/2019/05/aws-step-functions-support-callback-patterns/)がサポートされ、成功・失敗が通知されるまで指定した箇所でステートマシンの動作を停止させておくことができるようになりました。これによって、ワークフローのある地点で処理を一時停止させ、承認を取ってから処理を続行するといったことができるようになりました。

これを使い、Step Functionsに正式対応していないサービスであっても、擬似的に統合できるのではないかと考え、CodeBuildをワークフローへ組み込めるか試してみました。具体的には、コールバックパターンでLambdaを起動しそこからCodeBuildをキックします。CodeBuildでのビルド完了後に実行が完了したことをStep Functionsに通知すると、ステートマシンが再開しその後の処理が続行されるという流れです。

## ユースケース
今回私は、PHPの最新バージョンを定期的に確認しECRで保有しているイメージと突き合わせ、まだビルドしていない最新バージョンが出た場合は、CodeBuildを叩いてDockerイメージをビルドします。ビルド完了後はParallelでSlackへの通知とECSへのデプロイを行います。
<img width="432" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60714/0464ec53-058c-aa72-fc2a-8d3ddcbdcf6c.png">

## 方法

### ステートマシンの定義
必要部分のみ抜粋するとこんな感じになります。Serverless Frameworkを使用しているためyamlで記述していますが、JSONでも形式は変わりません。

```yaml
BuildImage:
  Type: Task
  Resource: arn:aws:states:::lambda:invoke.waitForTaskToken
  Parameters:
    FunctionName: [実行するLambdaのARN]
    Payload:
      input.$: $
      token.$: $$.Task.Token
  HeartbeatSeconds: 600
  Next: AfterBuildImage
```

#### パラメータの解説
- `Resource`は普段だと実行するARNを指定していますが、コールバックパターンの場合は専用のARNを設定します
    - 今回はLambdaを呼び出すためこの文字列になります
    - `.waitForTaskToken`がコールバックパターンで実行させるためのキーワードになります
- コールバックパターンの場合、呼び出すLambdaのARNは`Parameters.FunctionName`に定義します
- `Payload`にはLambdaに渡したいパラメータを指定します
    - `token`はタスクの処理完了をStep Functionsに通知する際に使うため、必ず渡して下さい
        - tokenは`$$.Task.Token`で参照可能です
    - その他前段の処理で生成されたパラメータも渡すことが可能です
- コールバックパターンの場合、ステートマシンは応答があるまで無期限で待機するため、一定期間応答がなかった時点で失敗として取り扱うために`HeartbeatSeconds`を設定します
    - 指定した秒数以上タスクからHeartBeatが送信されてこなかった場合、タスクは失敗として取り扱われステートマシンが強制的に終了します

### コールバックパターンで実行されるLambda
LambdaではSDKでCodeBuildを叩いてあげるだけです。ただ、CodeBuildからStep Functionsに対して終わったら実行完了を通知してあげないといけないため、Step Functionsから渡されたtokenは忘れずにCodeBuildに対しても渡して下さい。

### CodeBuild
`post_build`の中でStep Functionsから渡されたトークンでタスクの処理完了を通知してやります。CI環境にはAWSのCLI SDKがインストールされているため、コマンドで叩いてやるだけです。outputのJSONを渡すこともできるので、後続の処理で使用したいパラメータがある場合はそこに含めることで、それを踏まえた処理を実装することもできます。

```yaml
  post_build:
    commands:
      - 'aws stepfunctions send-task-success --task-token $TASK_TOKEN --task-output "{\"example\": \"example\"}"'
```

## 最後に
今回はCodeBuildで試してみましたが、叩く際に対象のサービスに対してトークンを外から渡せる・完了通知を送る処理を挟めるサービスであれば、他のサービスでも擬似的に統合が可能かと思います。

別にpost_buildからデプロイ・通知はやってしまってもよかったのですが、個人的にCI以外の責務をCodeBuildに持たせてしまうことは気持ち悪かったので、Step Functionsでオーケストレーションできるならと思ってやってみました。

これまではCloudWatch Eventsが叩く親Lambdaから別のLambdaを起動してオーケストレーションするようなファットな構成だったので、Step Functionsで各Lambdaを結合する形に再構成できたので、疎結合となり全体の見通しがよくなりました。

## 参考文献
- [Service Integration Patterns - AWS Step Functions](https://docs.aws.amazon.com/ja_jp/step-functions/latest/dg/connect-to-resource.html#wait-token-hearbeat)
ABC 131（PyPyは再帰してはいけない）

#ABC 131
着実にPythonに慣れてきた結果ABCD完であった。Eは問題の意味が分からないのでやめた。
そもそもAから頭が働かなくてどうしようもなく、時間が無駄にか掛かった。
寝不足は大敵なのでやめよう。

#ABC 131 F Must Be Rectangular!
3点在ったら4点目を埋めてその追加できる最大数を求める問題。
例によってできなかった問題をやる。
youtubeの[問題解説](https://www.youtube.com/watch?v=XI8exXVxZ-Q)の通りのやり方では出来なかった。
以降、解説前提のため先にyoutubeを見ることを勧める。
なお、Pythonの再帰限界はデフォルト1000なので変える場合は、以下のようにする。

```python:atcoder.py
import sys
sys.setrecursionlimit(10**5)
```
こう変えることでREがTLEになるだけで問題は解決しなかった。
単純な深さ優先でC言語なら出来てもPythonの速度ではTLEする例である。
仕方がないのでUnionFindをどこかから持ってきた。
x,y成分を分けて考え、線で結んで連結して、同じ根につながっているx側とy側の数を別々にカウントする。
カウントが終わったらx側の数*y側の数が点数の最大値である。
異なる根についても同様に計算して総和を求め、最後に総和-Nが今回求めたい追加できる最大数となる。
ソースは載せない。参考にしたサイトをPython化しただけになったためである。

##追記
結果から言うと解説通りのコードで、Python3ならACでPyPy3ではTLEであった。
まず、AtCoderのPyPy3の再帰最大数は100であり、ケース9だけREするため、再帰が一番深いのがケース9だと推定できる。
Python3やローカル環境で同じコードで何度やっても1秒かからず10万入力処理出来ていて謎だったが、PyPyについて調べると再帰が遅いというのがあった。
入力やほかの部分が遅い可能性については、ググって最適に近いといわれているものを選んだので否定的である。

**結論「AtCoderで再帰を使うときはPyPyはやめた方がいい」**

以下のコードはPython3でAC、PyPy3でTLEするものである。

```python:atcoder.py
import sys
sys.setrecursionlimit(10**5)
m = 100005
visited = [False]*(m*2)
cnt = [0,0]
def dfs(i):
    visited[i] = True
    cnt[i//m] = cnt[i//m]+1
    for j in to[i]:
        if not visited[j]:
            dfs(j)
 
input = sys.stdin.readline
n = int(input())
to = [[] for _ in range(m*2)]
for _ in range(n):
    x,y = map(int,input().split())
    y = y+m
    to[x].append(y)
    to[y].append(x)
 
ans = 0
for i in range(m):
    if not visited[i]:
        cnt = [0,0]
        dfs(i)
        ans = ans + cnt[0]*cnt[1]
 
print(ans-n)

```
先に実装が終わってしまったコードにGitを使ってテストコードを書く

バグ修正や、機能追加などをとにかく早くリリースしたあとで、「やっぱテストを追加もしておくか」となったときの方法です。


### 1. git checkout [不具合発生時のコミット]
まず不具合が発生する状況に戻します。このとき、`You are in 'detached HEAD' state.` のようなメッセージが表示されると思いますが、とくにブランチを切ったりする必要はありません。

### 2. 失敗するテストを書く
未実装に対して、テストを書いて、エラーになることを確認します。もちろんプロダクトコードの実装はしなくてよいです。これ以降は、ソースコードをいじることはありません。

### 3. git stash
書いたテストをプロダクトコードに当てるため、一旦、Stashのスタックに入れておきます。

### 4. git checkout [テストをあてるブランチ]
不具合修正済みのコミットを含むブランチであれば、なんでも構いません。

### 5. git stash pop
スタックに入れていたものを吐き出します。消えるのが嫌であれば `git stash apply` にしておきましょう。（ただし、applyばかりしていると、どんどんスタックが積まれていってしまうので、ときどき `git stash list` などで見て、整理しましょう）

### 6. テストが成功することを確認してcommitする
テストがRed→Greenになったことを確認したら、コミットしておしまいです。
プルリクとは

# プルリクとは
Pull Requestの略で、Githubの機能の一つ。誰でもどんなリポジトリに対しても、修正や機能追加を提案できる機能。

共有のリポジトリ(master branch)を操作することが出来るのは、基本的にリポジトリの管理者だけです。チーム開発をする際はBranchを切り、別のBranchから、本番環境に対してプルリクを出し、採用となれば（マージ）、本番環境に反映します。

#プルリクの流れ
流れは[こちらのQiita記事](https://qiita.com/samurairunner/items/7442521bce2d6ac9330b
)の通りですが、個人的な復習も兼ね、一通り流れを以下に記載します。

## ①共有ディレクトリのファイルをローカルに落とす。

```
$ git clone リポジトリ名 ディレクトリ名 // こちらは一回目のみ
又は
$ git pull リポジトリ名 ディレクトリ名
```

## ②branchを切る

```
$ git checkout -b branch名
```

開発をした後、次のコマンドへ

## ③変更内容をローカルリポジトリに記録する

```
$ git add . (一部のファイルのみを記録する場合は . の代わりに変更したファイルを記載します。)

$ git commit -m"(変更内容を記載)"
```

git addすることにより、ファイルをstagedという状態にし、git commitすることにより、ローカルリポジトリに変更内容コミットすることが出来ます。

## ④branchのリモートリポジトリに変更内容をPush

```
$ git push リモートリポジトリ branch名 // 基本origin
```
上記では、branchに対して、変更内容をPush（修正内容を反映）しています。

## ⑤プルリクを送る

続いてプルリクを送る作業です。こちらはGithubのGUI上で行うことが出来ます。

<img width="686" alt="スクリーンショット 2019-06-24 7.33.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392294/b48c7eb8-19b5-ddaf-cf91-96aae1e5530e.png">

<img width="683" alt="スクリーンショット 2019-06-24 7.44.43.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392294/d6e929b6-71af-0bb0-1cb1-b7c696fa767b.png">
<img width="707" alt="スクリーンショット 2019-06-24 7.45.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392294/6b13855d-808f-d49f-37dd-57ab974b74dd.png">


上記のようにPull Requestタブに移動し、New Pull Requestボタンを押してから、該当するBranchを選び、Create pull requestを押してあげると、プルリクを出せます。

## ⑥マージする
最後に行うのが、マージという作業です。これはレビュワー（おそらくプロダクトの管理者？）がプルリクされた修正内容をレビューし、Master Branch（本番環境）にマージさせます。こちらもGithubのGUI上から出来ます。

<img width="532" alt="スクリーンショット 2019-06-24 7.45.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392294/4bd1c767-996b-faac-3d2c-b8931eb9ed99.png">

プルリクを確認し、Merge pull requestを押すとマージが完了し、無事本番環境に反映出来ます！

こちらの記事なんかもおすすめですので、時間があれば読んでみてください。
[ターミナルからprコマンドで、Githubに[WIP]PullRequestを一瞬で出そう！](https://qiita.com/IZUMIRU/items/e1c86fa993287ef5bdeb)
WSL(Windows10)でDarknetのYOLOv3を動かした（→問題なし)

#目的
LinuxとかDarknetYOLOv3とかに関して、全く、知識なしです。
（語弊があるか、、、、スキル0が、本人の感覚に近い。）

以下に示す環境で、表題のとおり無事動いたので、何かの参考に:candy:と思い、記載します。
（CORE i3 7th Genです。GPUとか利用していません。）
openCVとかではまって、1日ぐらいかかりました。。。cmakeとかが1ミリもわかってないので。。。

本人は、linuxのコマンドとかを少しだけ勉強したいので、
一旦（1weekほど）、解散。

#できたこと
darknetのYOLOv3で、定番の画像に、定番の枠を出せた。
下記が、最終の実行コマンド。

```
$ ./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg
```

以下、実際の表示。

<img width="385" alt="エビデンス20190624.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342207/956fab60-7c6e-5745-ad48-c6ead2495854.png">

↓ちなみに、すごく処理時間がかかっている。

```
Loading weights from yolov3.weights...Done!
data/dog.jpg: Predicted in 31.319356 seconds.
dog: 100%
truck: 92%
bicycle: 99%
```



#環境
OS：　Windows10 バージョン1803(OSビルド 17134.829)
　※細かい条件を書かれている方がいたので念のため。
　　極端には、古くないはず。
WSL(Windows Subsystem for Linux):上記のWindows10のとおり
Linux:Ubuntu 18.04LTS
表示:VcXsrv バージョン1.20.1.4
　　※この「表示」とかが、Ubuntuの範囲内じゃないんですね。。。。
opencv:3.4.0
　　※3.4.1とかではないです。

#参考にしたサイト
https://qiita.com/nnn112358/items/746357a341ccf9ff6324
https://hatobus.hatenablog.jp/entry/2018/07/05/104114
https://www.atmarkit.co.jp/ait/articles/1812/06/news040.html

#初心者 2 初心者のアドバイス
・Linuxのユーザ名は、**短めが合理的かも**。。。あちこちで表示されるので。。
・特殊なことはしなくても、動作するようです。（ワタシの環境では、うまく動きました。）

#関連（本人）
省略

#今後
Linuxとかを少しだけ勉強する。(まず、viを15分勉強しよう。)
この類の作業、WSLで、やっていけるのでしょうか:question:
実践しているSEO対策の手法が有効かどうかの調べ方│簡単に検索上位取れたｗ

先日、SEOを使ったかなりシュールな遊びを発案してしまった。
その名は「謎ワードSEOゲーム」

簡単にルール説明をすると
・マジで関係ない2単語を用意
・その2単語を検索キーワードとした記事をブログにアップ
・使いたいSEO対策の手法を使う

これだけです。

##SEO対策の手法に効果があるのかを調べる


まず、このゲームを発案したTwitterのツイートがこちら。

<blockquote class="twitter-tweet" data-cards="hidden" data-lang="ja"><p lang="ja" dir="ltr">誰かブログやってる人でさ<br><br>「引越し」+「肛門」<br><br>みたいなマジで関係ない2ワードの組み合わせで検索1位を狙うゲームしない？w<br><br>スモールワードでコツコツ検索1位を取っていってSEO集客する練習にもなるし！ｗｗｗｗ<br><br>ちなみに「引越し」+「肛門」ならいつでも1位取れそう🤣🤣<a href="https://twitter.com/hashtag/%E8%AC%8E%E3%83%AF%E3%83%BC%E3%83%89SEO%E3%82%B2%E3%83%BC%E3%83%A0?src=hash&amp;ref_src=twsrc%5Etfw">#謎ワードSEOゲーム</a> <a href="https://t.co/TMTkkVbmHi">pic.twitter.com/TMTkkVbmHi</a></p>&mdash; インキャ2.0 (@INCANOMIKATA) <a href="https://twitter.com/INCANOMIKATA/status/1141868379193540608?ref_src=twsrc%5Etfw">2019年6月21日</a></blockquote>

発案当時はこのゲームにSEO対策の手法の確認における大きな価値があるなんて全く思いもしなかった。
本当に面白半分で、文字通りつぶやいたのだった。

それで、その翌日に仕事が入っていなかったため実際に発案のサンプルである
・引っ越し
・肛門
この２つのキーワードを意識した[「それっぽい記事」](https://cantavirtual.com/zakki/hikkoshikoumon/)
を書いてみた。
正直まったく関係のない二つの単語をまるで関係性があるかのように文章を書くのは苦痛だった。

今回実践してみたSEO対策の手法はこちら
・タイトルにキーワード
・見出しにキーワード
・画像のalt要素にキーワード
・本文にキーワード

とりあえずすぐ試せそうな手法を4つくらい織り込んで記事を作ってみた。

（本当にめっちゃそれっぽい記事でむしろ面白いから正直一度読んでほしい）

[その記事がこちら](https://cantavirtual.com/zakki/hikkoshikoumon/)

##記事の更新後
正直、内容も内容でそれっぽく書いてTwitterの仲いい人にウケたらそれでいいと思ってた、


まあ一応「引っ越し　肛門」と調べる

![1561313794950.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445586/be730dcd-b94d-d059-6a62-befa98075b8f.jpeg)


**検索二位じゃねえか**

むしろ一位何者だよ...

これはやべえ、これはありとあらゆるSEOの手法をライバルのいない自由な戦場で試せるわけだ。

ライバルはいなくとも、本番と同じ環境（アルゴリズム）の中で手法を試せる。

これは使い方によってはかなり有用である。試してみる価値はあるんじゃないだろうか？

でも急にブログから意味わからん2単語が連発された記事を読むと、読者は困惑するでしょうから

「謎ワードSEOゲーム」について例のそれっぽい記事（[https://cantavirtual.com/zakki/hikkoshikoumon/](https://cantavirtual.com/zakki/hikkoshikoumon/)）を導入文などで引用しながら言い訳してくださいね。

以上、肛門から生まれた奇跡をお送りしました。
【UE4】アウトプットログに出力される文字列を取得する

# 開発環境
UE4.21.2 
VisualStudio 2017  

#手順
1. FOutputDeviceを継承するクラスを作成する  
2. Serialize関数を作成  
3. 渡された文字列をGLogからデバイス登録をする  
4. アウトプットログに出力される処理を実行する（ログ、コンソールコマンドなど）  
5. 出力し終わったら再びGLogからデバイス登録を解除  

#実際のコード
<font color="Red">**※専用のUMGを用意するのがめんどくさいので出力方法をImGUIライブラリを使っている.実際に使う際は適当なクラスなり変数なり用意してほしい**</font>

```c++:ConsoleActor.cpp

#include "ConsoleActor.h"
#include <imgui.h>

namespace
{
	TArray<FString> strArray;
}

class CONSOLETEST_API FConsoleDevice : public FOutputDevice//手順1
{
public:
	FConsoleDevice()
	{
	}
	//手順2(consoleに吐き出されるlog情報が1行ごとに渡される)
	virtual void Serialize(const TCHAR* Data, ELogVerbosity::Type Verbosity, const class FName& Category, const double Time) override
	{
		strArray.Insert(Data, 0);
	}
    //手順2
	virtual void Serialize(const TCHAR* Data, ELogVerbosity::Type Verbosity, const class FName& Category) override
	{
		strArray.Insert(Data, 0);
	}
};

void AConsoleActor::OutputStr(const FString& str)
{
	FConsoleDevice device;
	GLog->AddOutputDevice(&device);//手順3
	UE_LOG(LogClass, Log, TEXT("output -> %s"), *str);//手順4
	GLog->RemoveOutputDevice(&device);//手順5
}
// Called when the game starts or when spawned
void AConsoleActor::BeginPlay()
{
	Super::BeginPlay();
	OutputStr("AAAAAAAAAAAAAAAAAA");
	OutputStr("BBBBBBBBBBBBBBBBBB");
	OutputStr("CCCCCCCCCCCCCCCCCC");
}

// Called every frame
void AConsoleActor::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	//取得したログのゲーム内への出力方法は各々で考えてください

	ImGui::NewFrame();
	Super::Tick(DeltaTime);
	//setting
	ImGui::SetNextWindowPos(ImVec2(50, 20), ImGuiCond_Always);
	ImGui::SetNextWindowSize(ImVec2(550, 300), ImGuiCond_Always);
	ImGui::SetNextWindowBgAlpha(0.5f);
	bool isVisiableCloseBtn = true;
	//Draw
	if (ImGui::Begin("Console"), isVisiableCloseBtn)
	{
		for (int i = 0; i < strArray.Num(); i++)
		{
			ImGui::Text("%s", TCHAR_TO_ANSI(*mBuffer[i]));
		}
	}
	ImGui::End();
}


```


#結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138731/7d047d5c-a005-74dd-05c0-9d996fe9d98a.png)
kubectl実行時に「localhost:8080 was refused」が出る時の対処

備忘録。
既知の人も多いだろうから、タイトルで読み飛ばしやすくしたつもり。


# こんなエラー出たことある？

k8sクラスタをkubeadmで作成後に、こんなエラーが出たことないだろうか？

```
niiku-y@master01:~$ kubectl get nodes
The connection to the server localhost:8080 was refused - did you specify the right host or port?
niiku-y@master01:~$
```

上記、タイミング的には、masterノードで
sudo kubeadm init --pod-network-cidr=10.244.0.0/16
を実行して、
workerノードで
sudo kubeadm join （上記コマンド実行後のメッセージで記載のオプション）
を実行して、そのあとに出ている。

# 原因はadmin.confのcopy忘れかも

kubeadmでクラスタ構築したての時であれば、作業が足りてない可能性あり。
kubectl config viewをみても中身が全然入ってないのではなかろうか？
落ち着いてkubeadm init後のメッセージをteraterm等のログが残っていれば読んでみよう。

「To start using your cluster, you need to run the following as a regular user:」
から先のところで何か忘れていないだろうか？

```
niiku-y@master01:~$ mkdir -p $HOME/.kube
niiku-y@master01:~$ cp /etc/kubernetes/admin.conf $HOME/.kube/config
niiku-y@master01:~$ chown $(id -u):$(id -g) $HOME/.kube/config
niiku-y@master01:~$ export KUBECONFIG=$HOME/.kube/config
niiku-y@master01:~$
niiku-y@master01:~$ kubectl get nodes
NAME       STATUS     ROLES    AGE     VERSION
master01   NotReady   master   5d23h   v1.14.3
worker01   NotReady   <none>   5d23h   v1.14.3
niiku-y@master01:~$
　→　kubectl実行時に上記のメッセージは出なくなった
　　　（ちなみにstatusがNotReadyなのはcanal.yaml適用前だから。）
```

抜けていたコマンドを実行するとlocalhost:8080 was refusedは出なくなりましたね。
で、.bashrcとかにKUBECONFIGは書いておきましょう。
Ubuntu16.04にTensorFlow・Kerasを入れたい！

##環境
ubuntu 16.04 LTS
GTX1070
##やること
Windowsの方でdiskpartを使っていたらubuntuが入っているディスクを掃除してしまうという事件が起きました。再度ubuntuをインストールして諸々入れ直している中で、TensorFlow・Kerasを入れるのに意外と苦労したので備忘録を兼ねて記録を残します。
##CUDAをインストールする
TensorFlowやKeras自体のインストールは簡単なのですが、GPUに対応させるためCUDAと後述のcuDNNをインストールする必要があり、これに少々手間がかかります。

CUDAとはNVIDIAが提供しているGPU向けの統合開発環境で、TensorflowやChainerといった深層学習関連のライブラリはこれを前提としています。
###①公式サイトからダウンロード
https://developer.nvidia.com/cuda-toolkit
「Download Now」をクリックすると選択肢が出てくるので Linux > x86_64 > Ubuntu > 16.04 > deb〔network〕と進め右下に表示される「Download」を押してください。
###②インストール

```
$ sudo dpkg -i cuda-repo-ubuntu1604_10.1.168-1_amd64.deb
$ sudo apt-key adv --fetch-keys http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/7fa2af80.pub
$ sudo apt update
& sudo apt install cuda
```
/usr/local/にcudaというフォルダが作成されていればオッケーです。
###③パスの設定
ホームディレクトリにある.bashrcに下の2行を追加します。

```
$ vi ~/.bashrc
```

```
export PATH="/usr/local/cuda/bin:$PATH"
export LD_LIBRARY_PATH="/usr/local/cuda/lib64:$LD_LIBRARY_PATH"
```
##cuDNNをインストールする
CUDAと同じようにcuDNNも深層学習関連ライブラリの前提となっていますが、CUDAがGPGPUを利用する処理全般に使われるのに対して、cuDNNはディープラーニングの計算に特化しています。
###①公式サイトからダウンロード
https://developer.nvidia.com/cudnn
左下の「Download cuDNN」をクリックするとログインを求められるので初めての場合は登録します。
ダウンロードページでライセンスに同意するとCUDAのバージョンごとの選択肢が現れるので、CUDAのインストール時にバージョンを指定していなければ一番上の最新のものを選びます。
すると多くのファイルが表示されますが、最初の「Library for Windows, Mac, Linux, Ubuntu and RedHat/Centos(x86_64 architecture)」にある「cuDNN Runtime Library for Ubuntu16.04 (Deb)」と「cuDNN Developer Library for Ubuntu16.04 (Deb)」の2つをクリックしてダウンロードしてください。
###②インストール

```
$ sudo dpkg -i libcudnn7_7.6.0.64-1+cuda10.1_amd64.deb
$ sudo dpkg -i libcudnn7-dev_7.6.0.64-1+cuda10.1_amd64.deb
$ sudo apt-get update
$ sudo apt-get libcudnn7 libcudnn7-dev
```
libcudnn7-devの方を先にインストールしようとするとエラーになります。/usr/include/にcudnn.hというファイルが作成されていればオッケーです。
##TensorFlow・Kerasのインストール
ここまで来れば簡単です。

```
$ pip install tensorflow-gpu
$ pip install keras
```
お疲れ様でした！
ホストOS上のEncFSで暗号化したディレクトリを、Dockerコンテナにマウント

# はじめに

まず掲題の内容を実現することで私が期待することを、以下に箇条書きで記載します。

1. ホストOS上のプロジェクト毎のディレクトリは、EncFSを使って暗号化
2. Dockerコンテナで、RailsサーバをDevelopmentモードで起動
  - データボリュームとして、1のディレクトリをマウント
  - このディレクトリ内でRailsサーバを起動
3. 1のディレクトリ内のファイルをホストOS上で編集
4. 2で起動しているRailsサーバに変更が反映される

要約すると、ホストOS上のEncFSで暗号化したディレクトリ配下のファイルをエディタで編集した内容が、
Dockerコンテナで起動しているRailsアプリに即時反映されることを、目的としています。
上記の実現は簡単だと思ったのですが、EncFS関連で若干詰まったので、再度詰まらないための備忘録として、本記事を記載します。

# 環境

```bash
# OS
$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION="Ubuntu 18.04.2 LTS"
# EncFS
$ encfs --version
encfs バージョン 1.9.2
# Docker
$ docker version
Client:
 Version:           18.09.5
 API version:       1.39
 Go version:        go1.10.4
 Git commit:        e8ff056
 Built:             Thu May  9 23:11:19 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server:
 Engine:
  Version:          18.09.5
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.4
  Git commit:       e8ff056
  Built:            Thu May  9 22:59:19 2019
  OS/Arch:          linux/amd64
  Experimental:     false
```

# 何もせず、EncFSで暗号化したディレクトリを指定した場合

まずテスト用にEncFSで暗号化したディレクトリを作成します。

```bash
$ cd ~/tmp
$ mdkir .test
$ mkdir {,.}test
$ encfs ~/tmp/.test ~/tmp/test
新しい暗号化ボリュームを作成します。
Please choose from one of the following options:
 enter "x" for expert configuration mode,
 enter "p" for pre-configured paranoia mode,
 anything else, or an empty line will select standard mode.
?>

標準の設定が選択されました。

設定が完了しました。以下のプロパティのファイルシステムが
作成されます:
ファイルシステム暗号アルゴリズム: "ssl/aes", バージョン 3:0:2
Filename encoding: "nameio/block", version 4:0:2
鍵サイズ: 192 ビット
ブロックサイズ: 1024 バイト
Each file contains 8 byte header with unique IV data.
Filenames encoded using IV chaining mode.
File holes passed through to ciphertext.

Now you will need to enter a password for your filesystem.
You will need to remember this password, as there is absolutely
no recovery mechanism.  However, the password can be changed
later using encfsctl.

新しい Encfs パスワード:
Encfs パスワードの確認:
# 確認用に、適当なファイル名でファイルを作成
$ touch test/a.txt
```

次に上記で作成したディレクトリをボリュームとして、Dockerコンテナを起動します。

```bash
$ docker run -v ${PWD}/test:/test -it --rm busybox ls /test
docker: Error response from daemon: error while creating mount source path '/home/takuya/tmp/test': mkdir /home/takuya/tmp/test: file exists.
```

上記のようなエラーが出て、コンテナの起動に失敗してしまいます。

# 解決方法

エラーメッセージからは読み取れませんが、EncFSの実行時に `allow_root` オプションを追加することで解決しました。
まず `/etc/fuse.conf` を以下の差分のように編集します。

```diff
@@ -5,4 +5,4 @@
 #mount_max = 1000

 # Allow non-root users to specify the allow_other or allow_root mount options.
-#user_allow_other
+user_allow_other
```

次に `allow_root` オプションを追加して、`encfs` コマンドを実行します。

```bash
# マウントした状態で、再度マウントしようとするとエラーになるため、アンマウント
$ fusermount -u ./test
# allow_root オプションを追加して実行
$ encfs -o allow_root ~/tmp/.test ~/tmp/test
```

先程失敗した、Dockerコンテナの起動を試してみます。

```bash
$ docker run -v ${PWD}/test:/test -it --rm busybox ls /test
a.txt
```

Dockerコンテナが無事起動し、ホストOS上に作成した `a.txt` を `ls` で確認することが出来ました。

# おわりに

指定するディレクトリを適宜変更することで、「はじめに」に書いたことが実現可能になりました。
同様の問題に悩んでいる人が居るかどうか分かりませんが、本記事の情報が問題解決の一助になれば幸いです。
データ分析未経験SEがデータサイエンティストを目指す No.3 [Scipy(仮説検定)]

#記事の概要

第3回は数値計算ライブラリであるScipyを使用した仮説検定の方法についてまとめます。

#Scipy

ScipyはNumpyと同じ計算ライブラリだが、Numpyでできる行列計算等の機能に加え、高度な統計解析が可能となっている。
本記事では仮説検定の方法についてまとめる（仮説検定の詳細な数式は省いています）。

###1 Sample T-Test

1 Sample T-Test(1標本t検定)は、ある正規分布の母集団の平均値が、特定の値に一致するかどうかを検定する。
p値は帰無仮説（ある正規分布の母集団の平均値が、特定の値に一致すること）を採択する確率を表す。
p値が有意水準（例えば0.05）を下回った場合、帰無仮説を棄却し、その母集団の平均値は特定の値と有意に差があることになる。

```python
from scipy.stats import ttest_1samp
tstat, pval = ttest_1samp(example_distribution, expected_mean)
```

###2 Sample T-Test

2 Sample T-Test（2標本t検定）は、正規分布の母集団2つについて、平均値が一致するかどうかを検定する。
p値は帰無仮説（正規分布の母集団2つについて、平均値が一致すること）を採択する確率を表す。
p値が有意水準（例えば0.05）を下回った場合、帰無仮説を棄却し、2つの母集団の平均値の間には有意に差があることになる。

```python
from scipy.stats import ttest_ind
tstat, pval = ttest_ind(example_distribution1, example_distribution2)
```

###ANOVA

T-Testは最大で2標本までの検定に使用できない。3つ以上の標本に対して行う検定がANOVA(Analysis of Variance, 分散分析)である。
ANOVAは、全ての母集団について平均値が一致するかどうかを検定する。
p値は帰無仮説（全ての母集団について平均値が一致すること）を採択する確率を表す。
p値が有意水準（例えば0.05）を下回った場合、帰無仮説を棄却し、少なくとも1組の母集団の間の平均値に有意に差があることになる。
ただし、どの母集団の間の平均値に有意に差があるかは判定できない。

```python
from scipy.stats import f_oneway
fstat, pval = f_oneway(example_distribution1, example_distribution2, example_distribution3)
```

###Tukey's Range Test

※Scipyのメソッドではない
ANOVAではどの母集団の間の平均値に有意に差があるかは判定できないが、
Tukey's Range Test(テューキーの範囲検定)によりどの母集団の間に有意に差があるかを表形式で確認できる。

```python:In
from statsmodels.stats.multicomp import pairwise_tukeyhsd
import numpy as np

v = np.concatenate([a, b, c]) #a, b, c: 母集団
labels = ['a'] * len(a) + ['b'] * len(b) + ['c'] * len(c)

tukey_results = pairwise_tukeyhsd(v, labels, 0.05)
print(tukey_results)
```

```Out
Multiple Comparison of Means - Tukey HSD,FWER=0.05
=============================================
group1 group2 meandiff  lower   upper  reject
---------------------------------------------
  a      b     7.2767   3.2266 11.3267  True 
  a      c     4.0115  -0.0385  8.0616 False 
  b      c    -3.2651  -7.3152  0.7849 False 
---------------------------------------------
```

###Binomial Test

Binomial Test(二項検定)は、二項分布の母集団が与えられたとき、その成功確率が特定の値に一致するかどうかを検定する。
p値は帰無仮説（二項分布の母集団の成功確率が、特定の値が一致すること）を採択する確率を表す。
p値が有意水準（例えば0.05）を下回った場合、帰無仮説を棄却し、二項分布の母集団の成功確率と特定の値の間に有意な差があることになる。

```python:In
from scipy.stats import binom_test
pval = binom_test(510, 10000, 0.06)
print(pval)
```

```Out
0.000115920327245
```


###Chi Square Test

Binomial Testは2種類のカテゴリへの分類に関する検定となっている。
これに対し、Chi Square Test(カイ二乗検定)は、2種類以上の任意の分類に関して検定が行える。
カイ二乗検定は、「クロス集計表」に対して、各母集団がすべて同じ度数分布に従うかどうかを検定する。
p値は帰無仮説（各母集団がすべて同じ度数分布に従うこと）を採択する確率を表す。
p値が有意水準（例えば0.05）を下回った場合、帰無仮説を棄却する。

```python:In
X = [[30, 10],
     [20, 20]]
chi2, pval, dof, expected = chi2_contingency(X)
print(pval)
```

```Out
0.0376669222286
```

---

次回はPandasについてです。Kaggleコンペでも頻繁に使用するライブラリでもあり、分量が多くなる予定です。
最適お釣り計算。

お釣りの金額に対して、
現在の日本の通貨何枚で払えばよいか、計算します。

`cc curr.c -o curr`として、コンパイルして、
`./curr <金額>`として、実行して下さい。

単純なアルゴリズムです。2千円札は、話がややこしくなるので、扱いません。

```curr.c
#include  <stdio.h>
int main(int argc,char *argv[]) {
    int a;
    int c10000,c5000,c1000,c500,c100,c50,c10,c5,c1;
    if (argc==2)
      sscanf(argv[1],"%d",&a);
    else return 1;
    
    c10000=a/10000; a%=10000;
    c5000=a/5000; a%=5000;
    c1000=a/1000; a%=1000;
    c500=a/500; a%=500;
    c100=a/100; a%=100;
    c50=a/50; a%=50;
    c10=a/10; a%=10;
    c5=a/5; a%=5;
    c1=a;

    printf("1万円札%d枚　5千円札%d枚  千円札%d枚\n",c10000,c5000,c1000);
    printf("500円玉%d枚　100円玉%d枚　50円玉%d枚\n",c500,c100,c50);
    printf("10円玉%d枚   5円玉%d枚    1円玉%d枚\n",c10,c5,c1);
}
```

実行結果

```
$ ./curr 77777
1万円札7枚　5千円札1枚  千円札2枚
500円玉1枚　100円玉2枚　50円玉1枚
10円玉2枚   5円玉1枚    1円玉2枚
```

# python版

こちらは、python版です。`chmod +x change.py`として実行権を付け、`./change.py n`として実行して下さい。

```change.py
#!/usr/bin/python
import sys

def change(n):
    currency=[
              [ 10000,"1万円札 " ],[ 5000,"五千円札" ],[1000,"千円札  "],
              [ 500,  "五百円玉" ],[100,  "百円玉  "], [50,  "五十円玉"],
              [ 10,   "十円玉  "], [5,    "五円玉  "], [1,   "一円玉  "]
             ]

    for i in currency:
        print(f"{i[1]}:{n//i[0]}枚")
        n%=i[0]

if __name__=='__main__':
    change(int(sys.argv[1]))
    exit(0)
```

#### 実行例

```
$ ./change.py 77777
1万円札 :7枚
五千円札:1枚
千円札  :2枚
五百円玉:1枚
百円玉  :2枚
五十円玉:1枚
十円玉  :2枚
五円玉  :1枚
一円玉  :2枚
```
VS CodeでNode.jsのクラスタ化されたサーバをデバッグする

# 概要

Node.jsで作成したサーバで、マシンスペックを最大限発揮させられるように、[Cluster](https://nodejs.org/api/cluster.html)を使います。
そのとき、デバッグの設定を作るのに苦労しました。
なので、備忘録的にここに残したいと思います。

# コード

## 設定ファイル

```launch.json
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Cluster Server",
      "program": "${workspaceFolder}/dist/server.js",
      "autoAttachChildProcesses": true,
      "console": "internalConsole"
    }
  ]
}

```

### autoAttachChildProcesses

デバッガの子プロセスに接続するために使用します。
`true` にすることで、簡単にクラスタ化されたWorkerプロセスを追跡できるようになります。
デフォルト値は `false` です。

### console

デバッガを開く場所を指定するために使用します。
これを指定しないと、子プロセスがターミナルで開いてしまいます。
`internalConsole` にすることで、WorkerプロセスがMasterプロセスのコンソールに紐付けられたコンソールに開くようになります。

```
Masterプロセス
 |- Workerプロセス
 |- Workerプロセス
 |- Workerプロセス
 `- Workerプロセス
```

## サーバ

```server.ts
import cluster from 'cluster';
import os from 'os';

const numCPUs = os.cpus().length;

import app from "./app";

if(cluster.isMaster) {
  console.log(`Master ${process.pid} is running`);

  for(let i=0; i<numCPUs; i++) {
    cluster.fork();
  }

  cluster.on('exit', (worker, code, signal) => {
    console.log(`worker ${worker.process.pid} died`);
  });
} else {
  app.listen(app.get("port"), () => {
    console.log('App is running at http://localhost:%d in %d pid', app.get("port"), process.pid);
  });
}
```

```app.ts
import express from "express";
import bodyParser from "body-parser";

import router from './router';

const app = express();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.set('port', process.env.PORT || 3000);

app.use(router);

export default app;
```

### Workerプロセスを開く

```.js
cluster.fork();
```
Slimの基本的な使い方

##はじめに
ずっとHamlを使っていましたが、SlimというHTMLテンプレートを使ってみたかったので備忘録として残しておきたいと思います。

##環境
- Ruby 2.5.1
- Rails 5.2.3
- slim-rails 3.2.0


##導入
Gemfileにslim-railsを記述してbundle　install。

```ruby:Gemfile
gem 'slim-rails'

```
slim-railsを入れるだけで、デフォルトでslimに置き換わるそうです。めっちゃ便利。

##基本的な構文
```
 h1 マークアップ例

.uk-position-relative
	
#content
      p このマークアップ例は Slim の典型的なファイルがどのようなものか示します。

- if logged_in?
- else

= link_to "Home",root_path 

body
  p
    |
      これはテキストブロックのテストです。
```

特徴としては、

- HTMLの閉じタグがいらない。（Slimと混合してもエラーにはならない）
- Classは.uk-position-relative、Idは#contentのように書く。divは省くことができる。
- if文やeach文は **- if logged_in?**のように書く。
- <%= %>は **= link**のように書く。
- パイプ( | )を使うと、 Slim はパイプよりも深くインデントされた全ての行をコピー。


##気になった使い方

使っていくうちに気になったことを書いていきます。

**classを途中でつける書き方の時にどうすれば良いか？**

```
<%= f.submit 'ログイン',class: 'ttt' %>

```
Slimでは、

```
= f.submit class: "ttt"
```
---
**複数のclassの付け方、式展開は使えるのか？**

```
<div class="alert alert-danger">#{@user.errors.count}</div>
```
Slimでは、

```
.alert.alert-danger #{@user.errors.count} error
```
---
**複数の属性を持っているコードはどう書くか？**

Slimでは、

```
	= image_tag　"balloons-2347123_1280.jpg", alt: "",width: "100%",height: "40%"

```

##まとめ
自分なりにSlimを紹介しました。
感覚的にHamlと書き方が似てるので、すっと馴染めました。
日本語のリファレンスがあるのでわかりやすいです。
[https://github.com/slim-template/slim/blob/master/README.jp.md](https://github.com/slim-template/slim/blob/master/README.jp.md)
外部サーバーを経由してポート開放していない自宅Raspberry Piにssh接続

# 使用環境
外部サーバー：Ubuntu16.04
自宅サーバー：Raspbian Stretch Lite (on Raspberry Pi 3 Model B)

# 対象PCから外部サーバーへリモートポートフォワード
リモートポートフォワーディングとは、外部サーバのポートに送られたパケットをローカルサーバのポートに転送する機能のことです。Raspberry Pi側から次のコマンドを実行するとsshトンネルを作成できます。

```
$ ssh -R [外部サーバー側の空いているポート]:localhost:[Raspberry Piのsshポート] -i [秘密鍵の場所] -p [外部サーバーのsshポート] [ユーザー名]@[外部サーバーIPアドレス]
(例)$ ssh -R 10001:localhost:22 -i /home/user/.ssh/id_rsa -p 10000 user@serverip
```
(例)で説明すると、serverip:10001からlocalhost:22へのトンネルが出来上がりました。sshでserverip:10001に接続すればRaspbery Piにつながります。コマンドについては「ssh リモートポートフォワード」などで検索すると良いページがたくさん出てくると思います。

# autosshを使えば接続が切れても自動再接続
上で使ったsshコマンドは接続が切れた場合手動で再接続する必要があります。これを自動化してくれるautosshを使えば便利です。aptでインストール出来ます。

```
$ sudo apt install autossh
```

コマンドをsshからautosshに変えるだけで使えます。

```
$ autossh -R 10001:localhost:22 -i /home/user/.ssh/id_rsa -p 10000 user@serverip
```

# crontabで起動時にsshトンネル作成
最後にcrontabを使って起動時に自動でトンネルを作成するようにします。次のコマンドで編集モードで起動します。

```
$ crontab -e
```

最後の行に次を追加すれば設定完了です。

```
@reboot /usr/bin/autossh -fN -R 10001:localhost:22 -i /home/user/.ssh/id_rsa -p 10000 user@serverip
```

追加した-fNはシェルを使用せずにバックグラウンドで実行するコマンドです。Rapsberry Piを再起動して外部サーバー経由でssh接続できれば成功です。
carthageの導入部分での参考記事リスト

# carthage導入部分で困りがちな事
最近RxSwiftを使用する場面があったのですが、`carthage`のみインストール可なのでつまづいた時に役立った記事をメモしときます
・インストールしたはずなのにビルドした時`No Such module --`って出る
・`update`がうまくいかない
# 参考記事
#### 導入全般
・[Carthage について](https://qiita.com/s-harada/items/47295d653ef0cf34d540)
・[Carthageで外部ライブラリを導入する](http://progra.blog.jp/archives/5518662.html)

#### no such module関係
・[【iOS Carthage】Carthage Buildしたら怒られた時の話し。](https://qiita.com/residenti/items/c550a234f81dbe84123c)
・[ Carthageのライブラリを更新する際の注意点](https://tech.librastudio.co.jp/index.php/2017/05/10/post-1494/)
・[【Swift】no such module ...（Carthage を利用したフレームワークの追加）](https://teratail.com/questions/62759)
#### update関係
・[carthageでupdateの方法を指定する](https://qiita.com/fuwamaki/items/8d3c8ed62b9ccf306626)
・[swift初心者:[carthage導入時のfailed with exit code 72 --- , not a developer tool or in PATH]の対処方法](https://qiita.com/Atsushi_/items/40b204d6ff576eef86b9)
・[Command Line Toolsを切り替える方法](https://sutepulu.com/how-to-switch-command-line-tools/)
エクセルシートの差分を確認する方法

エクセルで２枚のシートで違いがあるかを確認する方その中で法はいくつもありますが、
その中で私が気に入って使ってる方法を紹介しておきます。

～こんなときに使える！～
・表等の形式が同じシートで、値に差があるかを確かめたい
・元のシートには手を加えたくない

具体的にはこんな感じの表を見比べる時に使えます！

〇比較データ１
![キャプチャ01.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429234/4b1b11a8-c63e-09b4-3b8f-f21f98703aed.png)

〇比較データ２
![キャプチャ02.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429234/980542d3-0d93-211b-fa0b-e75b65106621.png)

このようにたくさんの数値が並んだシートに違いがあるかを調べていきます。
いくつか方法はあるかと思いますが、今回はもう一枚のシートを利用する方法でやってみます。

①新規シートを作成し、A1セルに以下の計算式を記入する
=IF(比較シート１!A1=比較シート２!A1,"o","x")
※シート名は実際のものにしてください

②ドラッグで必要な範囲まで広げる
![キャプチャ03.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429234/f4eee428-9729-ae8e-7be4-1997220788f2.png)

③見やすいように、[x]となっているシートに色をつける
シートを全選択し、ホーム→条件付き書式→セルの強調表示ルール→指定の値に等しい
これで[x]となっているセルが赤色に表示されます!
![キャプチャ04.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429234/f2f30ee0-2059-c2f4-a533-a9c275442976.png)



今回は[F5]セルなど、４か所が異なっていることがわかりました。
比較対象のシートを修正し、一致させてやると比較用のシートからも赤色が消えて
一致したことがわかります。

必要な調査や修正が済めばこの比較用のシートを消すだけで元通りなので、
元データのシートに計算式や書式を残したくないときに便利です！