OmniAICreator/Qiita-1.07M huggingface dataset:
Pythonデザインパターン - Template Method

# Pythonデザインパターン - Template Method

## 概要
スーパークラスで処理の枠組みを決めて、サブクラスで枠組みを決める。
スーパークラスのテンプレートメソッドでアルゴリズムが記述されていますので、
サブクラス側では アルゴリズムをいちいち記述する必要がなくなる。
そして、Template Methodパターンでプログラミングしていれば、
テンプレートメソッドに誤りが発見された場合でも、テンプレートメソッドさえ修正すればよいというその後の修正の手間を抑えることができる。
Pythonでは抽象クラスを書く場合はABCモジュールを利用して実装することができる。


具体例：

プログラム例：
_LIST・TABLE表示_

**abstract_display.py**

```Python
from abc import ABCMeta, abstractmethod

class AbstractDisplay(metaclass=ABCMeta):

    _data = list()
	
    def __init__(self, data):
        self._data = data

    @abstractmethod 
    def display_header(self):
        pass

    @abstractmethod     
    def display_body(self):
        pass

    @abstractmethod 
    def display_footer(self):
        pass

    def get_data(self):
        return self.data

    def display(self):
        self.display_header()
        self.display_body()
        self.display_footer()
```

**list_display.py**

```Python
from abstract_display import AbstractDisplay

class ListDisplay(AbstractDisply):

    def display_header(self):
		print('<dl>')

	def display_body(self):
		for k, v in self.get_data.items(): 
			print( '<dt>' + $key + '</dt>')
            print( '<dd>' + $value + '</dd>')
		
    def display_footer(self):
		print('</dl>')
```

**table_display.py**

```Python
from abstract_display import AbstractDisplay

class TableDisplay(AbstractDisply):

    def display_header(self):
		print('<table border="1">')

	def display_body(self):
		for k, v in self.get_data.items(): 
			print('<tr>')
			print('<th>' + $key + '</th>')
            print('<td>' . $value . '</td>')
            print('</tr>')
		
    def display_footer(self):
		print('</table>')
```

**main.py**

```Python
from list_display import ListDisplay
from table_display import TableDisplay

if __name__ == '__main__':
	data = [
		'Morita', 'Yamada', 'Satou',
	]
	
	display1 = ListDisplay()
	display1.display()
	
	display2 = TableDisplay()
	display2.display()
```

出力

```HTML
<dl>
<dt>0</dt>
<dd>Morita</dd>
<dt>1</dt>
<dd>Yamada</dd>
<dt>2</dt>
<dd>Satou</dd>
</dl>
<table border="1">
<tr>
<th>0</th>
<td>Morita</td>
</tr>
<tr>
<th>1</th>
<td>Yamada</td>
</tr>
<tr>
<th>2</th>
<td>Satou</td>
</tr>
</table>
```

---

他デザインパターンも更新予定:writing_hand:
いいね！と思ったら LGTM お願いします :clap::clap::clap:

【PR】プログラミング新聞リリースしました！ → https://pronichi.com
【PR】週末ハッカソンというイベントやってます！ → https://weekend-hackathon.toyscreation.jp/about/


<!--
参考URL:
http://d.hatena.ne.jp/shimooka/20141212/1418363698
https://qiita.com/nirperm/items/9651c1e0b29cdc31f064
https://qiita.com/kaneshin/items/269bc5f156d86f8a91c4
-->
SwiftUIのTabBarButtonにAccessibilityIdentifierを設定する

SwiftUIのIntegrationTestを行いたい場合、新しいフレームワークである都合から実機を用いたテストを行うのが良いです。
（Preview・シミュレーターだと実機で発生するような不具合に気がつくことが出来ない、そして、そういったケースがやたらと多い…）

このテストを自動化したい場合、利用出来るテストツールには[Appium](https://appium.io/)が挙げられるかと思います。

SwiftUIでTabViewを利用する場合、各TabBarItem（TabBarButton）にAccessibilityIdentifierを設定する方法が提供されおらず、Appium側からTabの切り替え操作を行うことができません。
（Appiumではユニークな要素取得のためにAccessibilityIdentifierを参照します）

## UITabBarControllerにアクセスする

SwiftUIではUIKitの要素に触ることは出来ませんので、[SwiftUI-Introspect](https://github.com/siteline/SwiftUI-Introspect)というライブラリを利用します。
これを利用することで、以下のようにUITabBarControllerへの参照を取得出来るようになります。

```swift
import SwiftUI
import Introspect

struct ContentView: View {
    var body: some View {
        TabView {
            Text("Tab1").tabItem {
                Label("tab1", systemImage: "circle")
            }
            Text("Tab2").tabItem {
                Label("tab2", systemImage: "square")
            }
        }
        .introspectTabBarController { tabBarController in
            print(tabBarController)
        }
    }
}
```

## UITabBarButtonにAccessibilityIdentifierを設定する

TabViewにあるボタンはUITabBarButtonというViewです。
（TabBarItemではありません！）
UITabBarButtonはUIKitでは公開されていないViewなのでこの型名を指定してUITabBarButtonを取得することは出来ないのですが、
幸いにもUIControlを継承しているViewなのでキャストを通して参照を取得することが出来ます。

```swift
let tabButtons = tabBarController.tabBar.subviews.compactMap { $0 as? UIControl }
```

取得したUIControlの参照は左から並ぶTabBarButtonとなるので、配列のIndexを見ながら各ボタンに適当なIdentifierを設定していけばOKです。

```swift
tabButtons.enumerated().forEach { (index, tabButton) in
    switch index {
    case 0:
        tabButton.accessibilityIdentifier = "tab1"
    case 1:
        tabButton.accessibilityIdentifier = "tab2"
    default:
        break
    }
}
```

---

将来的に言語・フレームワークのアップデートで動作しなくなる可能性がある方法です。
将来的にはこのような方法を採用しなくても、AccessibilityIdentifierを設定するより良い方法が提供されるようになることを期待したいですね。
[KNIME] Column Filterの使い方

Column Filterにおいて、ある特定のカラムだけをIncludeして通したいときは下部にあるEnforce inclusionにチェックを入れます。

例えば、Purposeカラムだけを通したいときは以下のようにします。
![1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1284134/cd902a88-5e6c-0ef4-8a42-93ebf9384b3f.png)
もし、Enforce inclusionにチェックを入れない場合は、入力データのカラム名が変更になったときに、ワークフローの作成に使用したテーブルには存在しなかった名前のカラムがInclude内に入ってきてしまいます。

例）Enforce inclusionにチェックを入れていないので、Purpose以外のデータまでIncludeに入ってきてしまう。
![2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1284134/115f356d-473e-7372-28cb-0ecdebf94cb5.png)
safari OMG

※ iphone,safariでインスペクタがみたい
https://www.tam-tam.co.jp/tipsnote/html_css/post12114.html

iphoneからpcのlocalhostへアクセスするためのip先に調べる
macでコマンド叩く（docker側ではなく）

```
$ ifconfig | grep -w "inet"
	inet 127.0.0.1
	inet 192.xxx.xxx *例。つかう。
```

自分は、
http://192.xxx.xxx.xxx でアクセス出来た

※ pc,safariのレスポンシブデザインツールでみたい
https://engineershareinfo.com/2018/05/02/safari-responsive-design-mode/

※ safari横はみ出し、scrollbarなくしたいときとか
https://chakoiro.net/2620
https://stackoverflow.com/questions/15879710/disabling-horizontal-scroll-on-an-iphone-website
https://yuntu-tek.com/overflow-x/
https://45395.org/codes/how-to-hide-scroll-bars/
ValueError: Input contains NaN, infinity or a value too large for dtype('float32').の対処

上記のエラーが出た。
以前も遭遇したが対処を忘れて調べ直した。
また困りそうなのでメモメモ。
#発生場面
kaggleコンペ参加中に、submission用のtestファイルを
RandomForestClassifierでpredict時に発生した。
#エラー内容
ValueError: Input contains NaN, infinity or a value too large for dtype('float32').
訳)指定されたファイルにNaN、無限値、データタイプ(今回はfloat32)にしては大きすぎる値が含まれます。
#やったこと
とりあえず

```python
df.info()
```
データにおかしな点がないかチェックした。
今回は全て必要なデータ数があることが確認できた。

ということは
NaNではなさそう？

次は無限大があればNaNに変更する処理を試した。

```python
#マイナスの無限大もあるので、それも指定
df = df.replace([np.inf, -np.inf], nan)
#再度確認
df.info()
```
さっきは存在したデータが一つのコラムで減っていた。
つまり、無限大が存在してて、nanに変更されたということ。
ここまでくればもうあと少し！
nanをfillna()を使って平均値で置換した！

```python
df = df[column].fillna(df[column.mean())
```

解決！！！
#まとめ
僕みたいな初心者が少しでも救われることを信じて。。。
rails s エラー(Migrations are pending. To resolve this issue, run: bin/rails db:migrate RAILS_ENV=development)

#rails s 【ActiveRecord::PendingMigrationError】
既存アプリを違う環境に移した際に発生。
db:migrateしたつもりが、migrationができていない模様…
よく見直すと、```rails db:migtration```とコマンド間違い…
```rails db:migrate```でmigrationに成功し、エラー解決！  
調べた中で、
```bundle exec rake db:migrate ```
で解決！というものがあり、【bundle exec】とは？となり、調べたところ、
```Gemfile.lock```にあるバージョンのgemが動くとの事でした！
Rectの中心からのベクトルと辺の交差点を求める


矩形の外周を回るオブジェクトを表現したいときに使います。
ベクトルは中心からです。四角い時計を想像してもらえればわかりやすいと思います。

```C#
    public static Vector2 GetRectEdgeCrossPointFromCenter(Vector2 direction, Rect rect)
    {
        float dot_vertical = Vector2.Dot(Vector2.up, direction);
        float dot_horizon = Vector3.Dot(Vector2.right, direction);

        Vector2 v_vertical = Mathf.Sign(dot_vertical) * Vector2.up;
        Vector2 v_horizon = Mathf.Sign(dot_horizon) * Vector2.right;

        float rad_vertical = Vector2.Angle(direction, v_vertical) / 180 * Mathf.PI;
        float rad_horizon = Vector2.Angle(direction, v_horizon) / 180 * Mathf.PI;

        float tan_horizon = float.NaN;
        float tan_vertical = float.NaN;

        if (dot_vertical != 0)
        {
            tan_horizon = Mathf.Tan(rad_vertical);
            if (Mathf.Abs(tan_horizon) > 1.0f) { tan_horizon = float.NaN; }
        }
        if (dot_horizon != 0)
        {
            tan_vertical = Mathf.Tan(rad_horizon);
            if (Mathf.Abs(tan_vertical) > 1.0f) { tan_vertical = float.NaN; }
        }

        Vector2 edge_cross_point = rect.center;
        if (!float.IsNaN(tan_horizon))
        {
            edge_cross_point += v_vertical * rect.height * 0.5f;
            edge_cross_point += v_horizon * rect.height * 0.5f * tan_horizon;
        }
        else if (!float.IsNaN(tan_vertical))
        {
            edge_cross_point += v_horizon * rect.width * 0.5f;
            edge_cross_point += v_vertical * rect.height * 0.5f * tan_vertical;
        }

        return edge_cross_point;
    }



```
useStateの使い方[React]

#useStateの使い方
今回はカウントアップするアプリの作成です。
初期値を`useState(0);`としてます。
`<button onClick={onCountUp}>Increment</button>`クリックされたら
`onCountUp`関数が呼ばれて`setCount(count + 1);`カウントを1足します。

```react:components/Conter.jsx
import React, { useState } from 'react'

const Counter = () => {
  const [count, setCount] = useState(0); //初期値
  const onCountUp = () => {
    setCount(count + 1);
  };
  const onCountDown = () => {
    setCount(count - 1);
  };
  return (
    <>
      <p>count: {count}</p>
      <button onClick={onCountUp}>Increment</button>
      <button onClick={onCountDown}>Decrement</button>
    </>
  )
}

export default Counter

```

`App.jsx`は`<Counter />`を表示しているだけです。

```react:App.jsx
import React from 'react';
import Counter from './components/Counter';

const App = () => {
  return (
    <div>
      <Counter />
    </div>
  );
};

export default App;

```

#参考

[[公式]ステートフックの利用法](https://ja.reactjs.org/docs/hooks-state.html)
[[公式]フックの導入](https://ja.reactjs.org/docs/hooks-intro.html)
パスワード攪拌関数プラグインの実装方法

---
### StreamRelay.NET.exe の一覧機能を呼び出しているプラグインの実装方法について説明する

StreamRelay.NET.exe/StreamRelay.NET.x86.exeには、いくつかの機能をプラグインとして実装できるようにインターフェイスを公開している。

今回は、暗号ストリームの共通鍵などを拡販するためのインターフェイスを使って、プラグインを作成する方法を記述する。

---
### 既存のプラグイン

プラグイン的には、このあたりかな

- ***

---
### 実装したプラグインの呼び出され方

プラグインで指定された引数が渡されると、一覧を取得して表示する。

という感じ。

---
### 実装するインターフェイス

以下のインターフェイスを継承したクラスを実装すればよい

- IPlugin.dll 中の jp.dip.rocketeer.Plugins.IPluginPasswordStirringEntity インターフェイス
- IPlugin.dll 中の jp.dip.rocketeer.Plugins.IPluginPasswordStirring インターフェイス

このクラス2つだけ実装すればよい。

---
### jp.dip.rocketeer.Plugins.IPluginPasswordStirring インターフェイス

StreamRelay.NET.exe/他のプラグインから、IPluginPasswordStirring のCreatePasswordStirringEntityメソッドが呼ばれて、IPluginPasswordStirringEntityオブジェクトを生成して返す。
そしてIPluginPasswordStirringEntityが入力値(パスワード)を攪拌する。

という感じ。

具体的には、IPluginPasswordStirringEntity CreatePasswordStirringEntity(String iArgorithmName, ref String errMsg)が、StreamRelay.NET.exe/他のプラグインから呼び出されるので、IPluginPasswordStirringEntityのインスタンスを返す。
そして、IPluginPasswordStirringEntity#GetHash(byte[]) によって、入力値(パスワード)が攪拌される。

という感じ。

---
#### jp.dip.rocketeer.Plugins.IPluginPasswordStirring インターフェイスで定義しているメソッド/プロパティ

実装する必要があるのは以下

jp.dip.rocketeer.Plugins.IPluginPasswordStirringインターフェイスで定義されているのは、以下のとおり

<dl>
 <dt><b>Dictionary<String, String> ListDescription(Boolean IsHash)</b>
  <dd>引数文字列などを返す。(引数「Boolean IsHash」は無視{別述のHash/MACオブジェクトとの関係で引数が付いているだけ})
 <dt><b>IPluginPasswordStirringEntity CreatePasswordStirringEntity(String iArgorithmName, ref String errMsg)</b>
  <dd>名称から Hash オブジェクトの実体を作成する。「iArgorithmName」はListDescription()のキー名の方が与えられる。
</dl>

jp.dip.rocketeer.Plugins.IPluginBaseインターフェイスで定義されている分については、[インターフェイス IPluginBase について](https://qiita.com/tomoki0sanaki/items/60613c29f0d627353e67)を参照

---
#### jp.dip.rocketeer.Plugins.IPluginPasswordStirringEntity インターフェイスで定義しているメソッド/プロパティ

実装する必要があるのは以下

jp.dip.rocketeer.Plugins.IPluginPasswordStirringEntityインターフェイスで定義されているのは、以下のとおり

<dl>
 <dt><b>byte[] GetHash(byte[] buf)</b>
  <dd>入力値の Hash/Mac/PasswordStirring を返す
 <dt><b>String ArgorithmName()</b>
  <dd>Hash/Mac/PasswordStirring アルゴリズム名を返す
 <dt><b>IPluginPasswordStirringEntity Copy()</b>
  <dd>マルチスレッドを考慮して自分自身のディープコピーを返す。生成された複数の値の順番から内部や次の値や元の値を推察されないようにスレッド(ストリーム)ごとにコイツを呼び出しているので、初期化された自分自身のオブジェクトを返すようにしてほしい。
</dl>

---
### 目次へ戻る

[目次というか最初の一歩](http://qiita.com/tomoki0sanaki/items/85f20cbe18378e33cd6f)
【Vue.js】動的な表現をしたいときに使うcomputedプロパティ

データは動的なものを扱うことができないらしい。
動的な表現をしたい時は、computedプロパティを使う。

```html
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.7/dist/vue.js"></script>

<div id="app">
  <p>{{counter}}</p>
  <button @click="counter += 1">+1</button>
  <p>{{lessThanThree}}</p>
</div>
```

```js
new Vue ({
	el: '#app',
  data: {
  	counter: 0
  },
  computed: {
  	lessThanThree: function() { 
    	return this.counter > 3 ? '3以上' : '3以下'
    }
  }
})
```

computedプロパティの中に関数を書く。
ここでは、lessThanThreeいう関数を書いて、returnで値を返す。
Databricksノートブックがダークモードに対応しました

[Introducing the Databricks Notebook Dark Theme \- The Databricks Blog](https://databricks.com/blog/2021/03/31/databricks-notebook-dark-theme.html)の翻訳です。

これはDatabricks始まって以来、最もリクエストが多買った機能となりました。Databricksノートブックダークモードのサポートです！ 是非試してみてください。ダークモードにするには、ノートブックを開き、**View**メニューから**Notebook Theme > Dark Theme**を選択するだけです。
![](https://databricks.com/wp-content/uploads/2021/03/dark-mode-blog-post.gif)

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)
【MotionBoard】グラフ下側スクロールバーの初期表示が右寄り→左寄りにしたい


#目標
グラフ下側のスクロールバーの初期表示が右に寄る、左に寄って出て欲しい。

↓画像内、黒いみのむし的なものは気にせず、その下のスクロールバーを見て下さい。
横向きのスクロールバーの初期表示が右に寄ってます。
チャート作った直後、こうなることがあります。初期表示はバーを左に寄せたいときに。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278265/b54fd7c3-46f7-483f-9aaf-86c2ac584cfc.png)

#手順
(1)チャートを右クリックし、メニューから「チャート編集」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278265/ea890b62-06a3-2011-65f3-575761de202c.png)
(2)チャートエディタ左上の検索窓に「スクロール」といれ、三角ボタンを押す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278265/8515426c-ee2a-fa02-46a3-f3f19a9c42f9.png)
(3)スクロールに関する該当場所、いくつか赤くなってますが、「全般」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278265/baa13871-9d6b-6ec6-3234-4bb7590d5086.png)
(4)チャートの設定の「スクロールバーの初期表示位置を右端（上端）にする」のチェックを外す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278265/7b36df76-bcf7-25b0-674f-3f62be097497.png)
2022/09/20追記
MotionBoard 6.3ではこうなってます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278265/3b14e3ca-bb54-4bf4-0f6b-a862722fc31e.png)



#つぶやき
これもよく設定するけど、よく忘れます。


#ウイングアークのユーザコミュニティ「nest」
私も参加しています。多くの有益な情報があり、交流があります。
世の中が変わり、社外活動の重要性がより増していると考えております。
社外で自分の価値を計れるものさしを持とう。

https://www.wingarc.com/wug-nest/

以上
Python3: Excelファイル(*.xlsx) を JSON に変換 （コラムを削除）

こちらのプログラムを改造して、コラムを削除してから JSON に変換するようにしました。
[Python3: Excelファイル(*.xlsx) を JSON に変換](https://qiita.com/ekzemplaro/items/84d114e0367a9da260ff)

この例では、0,1,3,5　のコラムを削除しています。

```py:xlsx_to_json_omit.py
#! /usr/bin/python
# -*- coding: utf-8 -*-
#
#	xlsx_to_json_omit.py
#
#				   Apr/07/2021
# ------------------------------------------------------------------
import sys
import pandas as pd
#
# ------------------------------------------------------------------
sys.stderr.write("*** 開始 ***\n")
#
file_xlsx = sys.argv[1]
file_json = sys.argv[2]
sys.stderr.write(file_xlsx + "\n")
sys.stderr.write(file_json + "\n")
#
df=pd.read_excel(file_xlsx,header=None)
#
df2=df.drop(columns=df.columns[[0,1,3,5]])
#
df2.to_json(file_json,orient='records')
sys.stderr.write("*** 終了 ***\n")
# ------------------------------------------------------------------
```

実行方法

```bash
./xlsx_to_json_omit.py example01.xlsx example01.json
```
Amplify Flutter の API.get（REST）で日本語が文字化け

Amplify Flutterの一般提供がはじまったので、CognitoやREST APIなど使って、アプリを作成しています。

https://aws.amazon.com/jp/blogs/news/amplify-flutter-is-now-generally-available-build-beautiful-cross-platform-apps/

公式のサンプル通り記載すると、日本語が文字化けるので、対応をメモしておきます。

https://docs.amplify.aws/lib/restapi/fetch/q/platform/flutter#accessing-query-parameters--body-in-lambda-proxy-function

* 変更前

公式のサンプル通りに、`String.fromCharCodes(response.data)`で文字列に変換すると、日本語が文字化けしてしまいます。

```dart
try {
    RestOptions options = RestOptions(
        path: '/todo',
        queryParameters: {
            'q' : 'test'
        }
    );
    RestOperation restOperation = Amplify.API.get(
        restOptions: options
    );
    RestResponse response = await restOperation.response;
    print('GET call succeeded'); 
    print(new String.fromCharCodes(response.data)); // <------- 変更箇所 fromCharCodesで文字列変換すると、日本語が文字化けします。
} on ApiException catch (e) {
    print('GET call failed: $e');
} 
```

* 変更後

レスポンスに日本語が含まれている場合は、`utf8.decode(response.data)`で文字列に変換しましょう。

```dart
import 'dart:convert';

...(中略)...

try {
    RestOptions options = RestOptions(
        path: '/todo',
        queryParameters: {
            'q' : 'test'
        }
    );
    RestOperation restOperation = Amplify.API.get(
        restOptions: options
    );
    RestResponse response = await restOperation.response;
    print('GET call succeeded'); 
    print(utf8.decode(response.data)); // <------- RestResponse.dataには、byte配列 （Uint8List） が入っているので、utf8でデコードしましょう。
} on ApiException catch (e) {
    print('GET call failed: $e');
} 
```

# 参考

https://qiita.com/takyam/items/98d6336f1b2fe912fd56
ネットワーク～冗長化技術～

#はじめに
システム障害は怖いです、サービスを止めてはいけない。
エンジニアにとって『障害』は耳をふさぎたい言葉です。
そして何か起きたらネットワークが最初に疑われます。
ということで、、
今回は障害が起きてもサービスを継続させるための『冗長化技術』を紹介したいと思います。

#Stack（スタック）
L2スイッチやL3スイッチで使う筐体冗長化の技術です。
複数台のスイッチを専用ケーブル等で接続し、仮想的に１台のスイッチとして機能させます。
基本的には、同機種・同OSのスイッチを使います。
１台として機能させるので、コンフィグは１台分になります。
インターフェースだけ構成台数と合わせて拡張されていくイメージです。
ポート割り当てを複数台に分散した設計を組めば、スイッチが１台壊れたとしても
サービスへの影響を抑えることができます。
大体2～3台の機器でstack構成を組むことが多いですが、サーバ周りのスイッチでは
ポート収容数を拡張する為、8台とか多段で組んだりします。
(当然ながら幅取ります、、stack構成が可能な台数はメーカによるので事前に確認を。)
Ciscoスイッチでは、電源もstack構成内で共有する技術があったりします。

**＜stack構成＞**
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537417/e43f379e-1e13-9381-a092-da530b3ae829.png)

#Link Aggregation（リンクアグリゲーション）
帯域拡張やリンクの冗長化技術です。LAG（ラグ）と略されることが多いです。
物理的なケーブルを複数束ねて１本のリンクとして機能させます。
ケーブルやポート障害で一部のリンクが切れたとしても、残っているリンクで通信を継続することができます。束ねることができる数は機器によりけりですが、大体８本くらい可能です。
基本的には、同一筐体でしかLAGを構成することはできませんが、各メーカーが独自の技術を提供しており、別筐体でもLAGを構成することが可能な機器もあります。
以下はメーカの独自技術の参考です。

参考：Cisco（virtual PortChannel）
https://www.infraexpert.com/study/nexus6.html

参考：APRESIA（Multi-Chassis Link-Aggregation）
https://www.apresia.jp/products/ent/configuration/mlag/

リンクの冗長化に加え、通信量が多いポイントでは複数束ねることで利用帯域を拡張することができます。

**＜LAG構成＞**
stack構成の図にもあったLANケーブルを覆う輪っか部分がLAGを表してます。
![LAG.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537417/116849b0-06aa-9b55-ad5b-310ba2abfec4.png)


#VRRP（ブィ・アール・アール・ピー）
正式名称は「Virtual Router Redundancy Protocol」で、デフォルトゲートウェイの冗長化技術です。これも略称で呼ぶことが多いです。総称「FHRP（First Hop Redundancy Protocol）」もあるようですが、あまり使ってないです。
Cisco独自の技術では、「HSRP（Hot Standby Redundancy Protocol）」というのもあります。

L3機器（ルータ、L3スイッチ等）は、各セグメントのゲートウェイとしてやインターネット網の出入口に配置されますが、通信の要となるのでハードウェア面でも大体冗長化されてます。
VRRPは、複数台のL3機器を仮想的に１台に見せることができます。
構成する機器同士で常時監視し、通常時は１台が優先的に通信を処理、障害時には自動的に切り替わって、もう片方の機器が通信を処理するようになります。
構成する機器で共通の仮想IPアドレスを持ち、これを周辺機器等のゲートウェイに設定します。
万が一、L3機器の障害が起きても通信は止まることはありません。（切り替わりで瞬断程度）
注意点としては、VRRPを設定するインターフェースでフィルタリングする際、VRRPの監視パケットを破棄しないようにすることです。監視パケットを機器間でやり取りできないと、VRRPの構成が崩れてしまいます。

**＜VRRP構成＞**
![VRRP.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537417/3de6f348-4871-f949-57a6-afb093723442.png)




以上、普段よく使っている冗長化技術の紹介でした。
ではまた次の機会に。
【働き方】テレワーク普及におけるエンジニアのハラスメントとの向き合い方

# はじめに
2020年から日本でもテレワークを導入している企業が増えています。
私自身基本的にテレワークになっているのですが、テレワークは人と人との繋がりが薄れる印象があったのでハラスメント問題とは無縁だと思ってしまっていました。
[この記事](https://jp.techcrunch.com/2021/04/04/2021-03-31-report-finds-going-remote-made-workplaces-more-hostile-for-already-marginalized-groups/)を見たことがきっかけで考えを改めました。

# テレワークとハラスメント
海外の調査ですが、**調査対象者の4分の1以上が、テレワークによって嫌がらせと職場での敵意が増加したと答えている**そうです。

![include-harassment.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1203022/550b8d26-d9b3-a70a-972c-4618c3a815be.png)
>画像のクレジット[Project Include](https://projectinclude.org/assets/pdf/Project_Include_Harassment_Report_0321_R8.pdf)
>画像は[techcrunch.com](https://techcrunch.com/2021/03/31/report-finds-going-remote-made-workplaces-more-hostile-for-already-marginalized-groups/)より

この結果には驚きました。
理由として一番考えられるのは**「1対1の閉鎖的なコミュニケーションへの依存度が高くなっている」**からだと思われます。

例えば後輩が先輩に質問する場合、テレワークでは音声通話またはビデオ通話が基本になります。
（簡単な質問であればチャットで終わると思いますが）

その際に、職場では**第三者の目**がありましたがテレワークでは当然**第三者の目**がありません。そう考えるとかなり閉鎖的な状況であるとわかります。

# テレワークでハラスメントを防ぐために（上司編）
ハラスメントは様々なパターンがあり、必ずしも上司から部下に対してではないですがもっとも起きやすいと個人的に感じるためこのケースを想定します。
知らず知らずのうちに**加害者になっていた**、**誰かを苦しめていた**なんて嫌ですもんね。

## １．チャットはオープンで行う
1対1の個人チャットは確かに便利ですが基本的にはチームのチャットを使いましょう。
やはり第三者の目は必要です。

## ２．ビデオ通話の頻度を考える
テレワークではビデオ通話による「顔を合わせること」が必要だと言われています。
ですがあくまでも自宅はプライベートな空間です。人に部屋を見られたくない人もいるでしょうし、同居する家族も実は嫌がっているかもしれません。
ビデオ通話のために化粧をしたり身なりを整えたりする必要も出てくるでしょう。
決まった曜日の決まった時間に行うくらいなら良いかもしれませんが最低限突発的な実施はやめましょう。

## ３．公私混同して話さない
上司も部下も自宅にいるため、どうしても公私混同してしまいます。
アイスブレイクとして多少のプライベートの話をすることは推奨されているかもしれませんが会社にいる時と同じ（第三者に聞かれても問題ない）かどうかを意識しましょう。

## ４．生活音についてはダメ出ししない
生活音はどの家庭にもあります。テレワーク中に子供が騒いでいる家庭もあるでしょう。
音声通話に深刻な支障をきたす場合を除いて**我慢する**ことが必要です。
深刻な支障をきたす場合は「注意」ではなく「お願い」に留めるべきです。
生活音についてのダメ出しをされると常に気をはっていないといけなくなり、過度なストレスを与えてしまいます。

## ５．オンライン飲み会に誘わない
これはかなり難しい問題です。
「オンライン飲み会は断りづらい」と言われています。
自粛が推奨されているコロナ禍に「ちょっとこの後予定が・・・」とは言いにくいものです。
開催するにしても断りやすい空気を作ってから開催するべきです。

## ６．技術的な説明は事前に図にしてから行う
口頭だけの説明は理解に限界があります。
オフィスにいた頃は紙にざっと図を書きながら説明できましたがテレワークではそれが難しいです。
口頭での説明のみなのに「なんでこんなに理解力がないんだ」なんて思わないためにも多少手間でも図に書いてから説明すべきです。その図は使いまわせます。ナレッジを共有すればみんなが幸せになれます。

## ７．言葉遣いに注意する
チャットでは文字だけで会話することになります。文字だけの場合冷たい印象を受ける人が多いです。
オフィスにいる時は乱暴な言葉遣いでも声のトーンなどで冗談ぽく伝わることもあるかもしれませんが文字だけだとそうはいきません。
絵文字を使った方が良い・・・とまでは言いませんが配慮すべきです。

## ８．サボりを疑わない
サボりを疑っても良いことはないです。
タスクを定量的に計ってその成果の積み上げで判断しましょう。
成果物さえ出せば途中15分寝てたって問題ないはずです。
成果が出ていない場合は上司のマネジメントスキルの見せ所です。

# テレワークでハラスメントを防ぐために（部下編）
部下の立場からでもハラスメントを防ぐ方法があります。

## １．不快に感じたらすぐに相談する
これはテレワークに限らずですね。
本格的なハラスメントになる前に不快に感じたらすぐに相談しましょう。
ハラスメントは被害者も加害者も不幸になります。
会社にコンプライアンス部門がなければ誰でも良いのでまずは相談してみましょう。

## ２．チャットはオープンで行う
何かを失敗したり質問する時に大人数に知られることが恥ずかしいと思うこともあるかもしれません。上司に個別チャットで報告することを繰り返していると自然と連絡が**「1対1が当たり前」**になってしまいます。
失敗の報告が恥ずかしくても、チームのオープンチャットで話すようにしましょう。

## ３．カメラに写るものに配慮する
何か言われる前に言われない状況を作りましょう。色々聞かれるの面倒臭いですし。
部屋の構造的に難しいかもしれませんが背景に何も映ってなければつっこまれることもなくなります。

# さいごに
ハラスメントは被害者も加害者も不幸になります。
ただでさえコロナ禍でストレスの多い生活です。ひとりひとりが気をつけたいですね。


参考サイト

https://jp.techcrunch.com/2021/04/04/2021-03-31-report-finds-going-remote-made-workplaces-more-hostile-for-already-marginalized-groups/
【Rails6 × React】ActiveStorageで画像のURLを取得し、フロントエンドで表示するまで

## 結論

以下のように実装

```ruby
avatar_path = Rails.application.routes.url_helpers.rails_representation_url(@user.avatar.variant({}), only_path: true) 
```

@user.avatarの部分はモデル名、ファイル名(has_one_attached以下の部分)

## これって何？

ActiveStorageを導入すると使用できるルーティング。

```
rails_blob_representation GET    /rails/active_storage/representations/:signed_blob_id/:variation_key/*filename(.:format) active_storage/representations#show
```

こんなルーティングがActiveStorageを導入すると設定される。ここにアクセスしている。

## 何が便利なの？

ReactとかRailsアプリの外部からActiveStorageにアクセスする際に必要

```ruby
avatar_path = Rails.application.routes.url_helpers.rails_representation_url(@user.avatar.variant({}), only_path: true) 
render json: {user: @user, books: @user.books, avatar: avatar_path}
```

こんな感じでRailsアプリからレスポンスを返して

```jsx
this.setState({
  user: response.data.user,
  books: response.data.books,
  avatar: response.data.avatar
})
```

このようにレスポンスを受け取ると、this.state.avatarでアバター画像が扱える。

そして

```jsx
<img src={this.state.avatar}/>
```

このようにアバター画像を表示できる。

### 参考

Railsガイド
https://railsguides.jp/active_storage_overview.html#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AB%E3%83%AA%E3%83%B3%E3%82%AF%E3%81%99%E3%82%8B
raspberry piでbluetoothが動かない

ラズベリーパイでどうしてもBluetoothが動かなかった。

結論からいうと、OSを入れなおしたら治った（SDカードも変えた）

# 事象
最初はこのコマンド結果が出てこなかったためおかしいことに気が付きました。

```
root@raspberrypi:~# hcitool scan
Device is not available: No such device
root@raspberrypi:~#
```

bluetoothctlに入ってみても、エラーが出ていました

```
root@raspberrypi:~# bluetoothctl
Agent registered
[bluetooth]# scan on
No default controller available
[bluetooth]# quit
root@raspberrypi:~#
```

bluetoothプロセスはあがっていました

```
root@raspberrypi:~# systemctl status bluetooth.service
● bluetooth.service - Bluetooth service
Loaded: loaded (/lib/systemd/system/bluetooth.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2021-03-17 16:41:07 JST; 2h 27min ago
Docs: man:bluetoothd(8)
Main PID: 870 (bluetoothd)
Status: "Running"
Tasks: 1 (limit: 4915)
CGroup: /system.slice/bluetooth.service
mq870 /usr/lib/bluetooth/bluetoothd

3月 17 16:41:06 raspberrypi systemd[1]: Starting Bluetooth service...
3月 17 16:41:07 raspberrypi bluetoothd[870]: Bluetooth daemon 5.50
3月 17 16:41:07 raspberrypi systemd[1]: Started Bluetooth service.
3月 17 16:41:07 raspberrypi bluetoothd[870]: Starting SDP server
3月 17 16:41:07 raspberrypi bluetoothd[870]: Bluetooth management interface 1.18 initialized
root@raspberrypi:~#
```

ちなみに、画面キャプチャは取っていませんが、ラズベリーパイのGUI画面を見ても右上にあるはずのBluetoothマークが見えませんでした。

# 解決
新しいSDカードにOSを入れなおしたら治りました。
同じ事象の方、お試しください。
xArmを ROS Gazeboで動かす

# はじめに
[xArm](https://www.ufactory.cc/)は中国のUFACTORYという会社が販売しているロボットアームで、6軸の可搬重量5kgのもので約$8000日本円にしておよそ80万円ほどのロボットアームです。

![Screenshot from 2021-04-07 07-19-37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589906/c08fe46f-7623-b2d9-4a31-49de64e2a4b4.png)

今回xarm_rosというパッケージを使用して、シミュレータ上からxArmを起動し操作しようと思います.

# 環境
環境は以下の通りです.
Ubuntu 18.04
ROS melodic

# インストール

https://github.com/xArm-Developer/xarm_ros.git

```
cd ~/catkin_ws/src
git clone https://github.com/xArm-Developer/xarm_ros.git
```

```
rosdep update
rosdep check --from-paths . --ignore-src --rosdistro melodic
```

```
rosdep install --from-paths . --ignore-src --rosdistro melodic -y
```

```
cd ~/catkin_ws
catkin_make
```

```
echo "source ~/catkin_ws/devel/setup.bash" >> ~/.bashrc
```

```
source ~/.bashrc
```


# 動作確認
実行

```
roslaunch xarm_gazebo xarm6_beside_table.launch
```

```
rqt
```

```Plugins > Robot Tools > Joint trajectory controller```から操作ができればOK!
これでmoveitなどからも制御ができるみたいです.

![Screenshot from 2021-04-07 07-30-21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589906/22da0ebb-4213-e572-c376-4af69e58563f.png)
rails6 devise⇨ sign_in, sign_upのコントローラの設定

## 環境

・Ruby 2.7.3
・rails 6.1.3
・docker

## 現状把握

⇨下記のよう、新規登録はのURLは出るかつ登録後も正常に指定した遷移先へ行く。
⇨コントローラで指定しているとおり。
⇨[http://localhost:5000/users/sign_up](http://localhost:5000/users/sign_up)

##ログアウト
⇨ログアウトを押してもログアウトの遷移先へ行かない。かつログイン者はログアウト出来ているかわからない。button_toでも正常に動かない。なぜか？

⇨ログアウトの遷移先はログインページへ指定している。（new_user_session_path）
　⇨試しに。元の状態へ。(super)
 　　⇨これでログアウトすると、rootで指定しているところへ。かつ以下のエラー。

```ruby
http://localhost:5000/
NoMethodError in Posts#index
undefined method `id' for nil:NilClass
```

 ⇨ならばrootを指定していなかったら、どこへ？
　⇨何も変わらずに、遷移しない。ログアウトしているかわからない。
　　⇨また、コントローラで指定はしている。（new_user_session_path）

ログアウトの遷移先を調べる。
以下の記事で解決。
[https://qiita.com/Tatty/items/a9759755e562ac4693ec](https://qiita.com/Tatty/items/a9759755e562ac4693ec)

実装はこのように。ログアウト後の遷移先はログインページに指定している。

```ruby
#def destroy
	#new_user_session_path
#end

#上記で設定してもうまくいかなかった。

def after_sign_out_path_for(resource)
  new_user_session_path
end
```

⇨遷移は出来ているが、遷移先で以下のようなエラー。
[http://localhost:5000/users/sign_in](http://localhost:5000/users/sign_in)

```ruby
ArgumentError in Users::Sessions#new
Showing /app/app/views/devise/sessions/new.html.erb where line #20 raised:

First argument in form cannot contain nil or be empty
Extracted source (around line #20):

  <%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
    <div class="form-group has-icon">
      <label class="control-label sr-only" for="inputEmail"><%= f.label :email %></label>
      <%# <input type="text" class="form-control" id="inputEmail" placeholder="メールアドレス"> %>
```

## 解決

新しいformの書き方で解決しました。
記事を参照⇨[https://qiita.com/wonder_meet/items/fac07af1edcd79ad102a](https://qiita.com/wonder_meet/items/fac07af1edcd79ad102a)

```ruby
<%#= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
⬇︎
<%= form_with model: @user, url: user_session_path, local: true do |f| %>
```

以前のよりもシンプルになりわかりやすい。

**ログイン出来るか試した。**

⇨結果止まった。遷移先のURLにも変わらず、止まった。
　⇨以下の形で指定してみる。
　　⇨**遷移出来た！！！**

app/controller/users/sessions_controller.rb

```ruby
# GET /resource/sign_in
  #  def new
  #   posts_path
  #  end

  # POST /resource/sign_in
  #  def create
  #   posts_path
  #  end

#上記で設定してもうまくいかなかった。

#ログイン後のリダイレクト先
def after_sign_in_path_for(resource)
  posts_path
end
```

コードに書いているとおり（#上記で設定してもうまくいかなかった。）
あの部分に指定しても動きませんでした。

何か役に立てばと思います。
ありがとうございました。
Windows10でRuby and Railsの開発環境を構築する(Railsチュートリアル対応)

#はじめに
みなさんこんにちは！あちえです。
今回はwindows10でRuby & Railsの環境を整えてRailsチュートリアルの環境も整えたので記事に書いていきます。
#linuxからwindowsに変えた理由
もともとLinuxのubuntuを使ってRailsチュートリアルを進めていたのですが、ある日突然cron関連のlinux特有のエラーが出てきました。
いろいろ探し、解決法を試した見たものの解決できず約3日悩んでいました。
悩むのが人生で一番無駄な時間ですが、これ以上時間を使うのはもったいないのでlinuxからwindowsにしました。

##なぜwindowsなのか
windowsにした理由は3つあります

- linuxと比べて安定している
- 環境構築が楽
- 対応しているソフトウェアが多い

特に一番最初の理由が大きいです。
モチベを保ちながら学習するのはかなり難しく、時にはさぼりたいときもあります。
そこでモチベを保つのではなく、いつでも学習できるように整え、学習のハードルを下げていました。
しかし今回のようにlinux特有のエラーが出てしまったりするのでは使い物になりません。
それに今はwindowsでもWSLやDockerなどを使って本番環境を構築することもできます。
このような理由で変えました。

あと個人的にはこの動画も少し影響されました
https://youtu.be/7pNirA0spHk


#環境
OS: Windows10
実機: Surface pro7

#環境構築
##gitのインストール
まずはエンジニアは必ず使うといっても過言ではないgitをインストールします。

https://gitforwindows.org/

まずはこのサイトからダウンロードしてきます。

インストーラーが起動したら自分に合わせて設定していってください。

次にgitの設定をしていきます。

```console
> git config --global user.name "gitのユーザー名"
> git config --global user.email "あなたの@eメール"
```

##Rubyのインストール
次にRubyをインストールします。

https://rubyinstaller.org/downloads/
ここからインストールしたいバージョンをインストールします。
自分の場合はRailsチュートリアルとバージョンを合わせるので、2.6.3です。

あとはインストーラに沿ってインストールします。

コンソールが開いたら``1,3``と入力して``Please key Enter``と表示されるまで待ちます

Enterを押すとコンソールが閉じるのでRubyのインストールは完了です。
##Railsのインストール
Rubyのインストールが終わったらRailsのインストールをしてきます。
まずはSQliteをインストールします

https://sqlite.org/download.html

ここから``for windows``の自分のbit数に対応したファイルをダウンロードします。

ダウンロードしたらダウンロードしたファイルの中にあるsqlite.dllというファイルを``C:¥Ruby26-x64¥bin``へコピーします

同じくさいとから``sqlite-tools~~~``というファイルをダウンロードし、sqlite3.exeを同じく``C:¥Ruby26-x64¥bin``へコピーします。

これでsqliteはインストールが終わったのであとはいつも通りにrailsをインストールします。
バージョンは個人的にRailsチュートリアルと同じ環境にするため``6.0.3``をインストールします。

```console
> gem install rails -v "6.0.3"
```
#Railsチュートリアルに対応させる
ここからはRailsチュートリアルを進める人向けにRailsチュートリアルで必要なものをインストールしていきます。
Railsチュートリアルをしないかたはスキップしてもいいですが、どれも開発で使うものなのでインストールしておいて損はないと思います。
##Node.jsのインストール
yarnをインストールするためにNode.jsをインストールします。

https://nodejs.org/ja/download/

このサイトからwindows向けのファイルをダウンロードしてきます。

あとはインストーラーに沿ってインストールしていきます。

##yarnのインストール
Node.jsがインストールできるとコマンド一発でyarnをインストールできます。

```console
> npm install -g yarn
```
##herokuのインストール
最後にherokuをインストールします。

https://devcenter.heroku.com/ja/articles/heroku-cli

上記サイトからwindowsのインストーラーをダウンロードしてきて実行します。
インストールが完了したら、heroku設定をしていきます。

```console
> heroku login
```

これで完了です

# さいごに
UbuntuなどのLinuxはRubyをインストールするのにもそれなりの量のコマンドを打たなければならないので、
windowsは初学者の方にはおすすめです。
現役の方でもwindowsを使ってインストールするのは個人的には「楽」と感じました。
今の時代はプラットフォームを問わずに開発ができるので、デザインや利便性などでパソコンを買うのもありだと思います。
#参考文献
https://prog-8.com/docs/git-env-win
https://prog-8.com/docs/ruby-env-win
https://prog-8.com/docs/rails-env-win
【CSS】扱いやすいレスポンシブでの横並びの方法


レスポンシブサイトの作成の際にメンテナンスのしやすい**flexbox**を使用した横並びの方法を紹介します。

#HTML
```html:html
<div class="works-inner-items flex">
            <div class="works-inner-item">
                <a href="img/難波.jpg" data-lightbox="group" data-title="No.1" >
                <img src="img/難波.jpg" alt="難波">
                </a>
                <h2 class="font-title">NAMBA</h2>
            </div>
            <div class="works-inner-item">
                 (省略)
            </div>
            <div class="works-inner-item">
                 (省略)
            </div>
             <div class="works-inner-item">
                 (省略)
             </div>
             <div class="works-inner-item">
                 (省略)
             </div>
             <div class="works-inner-item">
                 (省略)
             </div>
```
#css
```css:css
.works-inner .works-inner-items {
  width: 90%;
  margin-top: 8rem;
  display: flex;
  flex-wrap: wrap;
}

.works-inner .works-inner-items .works-inner-item {
  padding: 1rem;
  width: 30%; //親要素 width: 90% に対して、3分割
}

@media (max-width: 1024px) {
  .works-inner .works-inner-items .works-inner-item {
    width: 50%;
  }
}

@media (max-width: 600px) {
  .works-inner .works-inner-items .works-inner-item {
    width: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
  }
}
```

# コードの説明

必要なプロパティはたった3つです。

###・box-sizing: border-box

paddingとborderの幅を要素の幅と高さに含めるというコードです。
要はボックスの内側にborder、paddingが入ります。

###・display: flex
  
並べたい要素の親要素に対して指定すると直下の要素を横並び(並列)します。
念のためにIEのベンダープレフィックスを入れましょう。

###・ flex-wrap: wrap

display: flexで横並びさせた要素を回り込みさせます。

例えば、横並びの列数を2列、子要素のボックスを50%とした場合に子要素が4つあると
200%( 50% × 4つの要素 )になるためWidthを無視して横方向に4つ並んでしまいます。
これを解除して子要素が100%を超えた場合は回り込むようになります。
念のためにIEのベンダープレフィックスを入れましょう。

media screeでブレイクポイント、widthで並び数、paddingで各要素のクリアランスなどを調整して使ってください。
composerインストール時のエラー「undefined index: name 」解決法

![スクリーンショット 2021-04-07 5.44.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/712534/619b62a6-3435-b23a-c633-4bb48af3be88.png)

今回``composer install``をした時画像のようなエラーが出たので、その解決方法と原因について書きます。

## 原因
composerのバージョンのエラーでした。
[参考](https://stackoverflow.com/questions/64620849/laravel-packagemanifest-php-line-131-undefined-index-name)

## 解決方法
```
composer self-update
```

```
composer update
```

順にコマンドを打って、composerのバージョンを上げるとエラー解決しました。
SageMaker Notebook Instanceの自動停止

# 概要

SageMaker Notebook Instance を1時間使わないと自動停止するようなスクリプトが github で公開されていたので試します。以下の `auto-stop-idle` というところです。

https://github.com/aws-samples/amazon-sagemaker-notebook-instance-lifecycle-config-samples

# Lifecycle config 設定

左のライフサイクル設定のところから設定を作成します。

![スクリーンショット 2021-04-07 4.26.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/279199/d68c41f2-de8e-a897-a061-6f834deaae06.png)


ノートブックを開始するときはいつでも実行しておきたいので、ノートブックの開始用にスクリプトを設定します。作成画面になったら、エディタのところに `on-start.sh` の[中身](https://github.com/aws-samples/amazon-sagemaker-notebook-instance-lifecycle-config-samples/blob/master/scripts/auto-stop-idle/on-start.sh)を貼りましょう。同じフォルダにある`autostop.py`が、SageMaker の API を使ってノートブックインスタンスを停止するわけですが、これは実行時にダウンロードしてくれます。

IDLE_TIME を変えると、停止までの時間を変えられます。

![Amazon_SageMaker.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/279199/f4d2f968-1c7e-489b-afef-7bb60b912244.jpeg)

# ノートブックインスタンス作成

作成した LifeCycle Config を指定してノートブックインスタンスを作成しましょう。

![notebook.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/279199/4e5c7306-1287-aec5-062e-a4ea5b824a97.jpeg)

![create.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/279199/f6217b41-6d39-38bd-70a4-ddf852e1d426.jpeg)

# 作成して待ちます

![waiting.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/279199/13303696-bd1e-a953-0a3e-5c25604f3e5b.jpeg)

# インスタンスの停止が始まりました

インスタンス起動時間もあるので、1時間4分後にStopping の状態になりました。

![スクリーンショット_2021-04-07_5_40_46.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/279199/d7154362-ae04-4faa-4d93-caf60c291e47.jpeg)
【GitHub】リポジトリをクローンする方法とクローン後について

##はじめに
Laravelプロジェクトを初めてクローンした時に手順に困ったので
Laravelのプロジェクトをgit cloneする手順とクローン後のコマンドを紹介します。


##環境

Windows10 
PHP 7.3.18
Laravel 7.12.0
MySQL 
XAMPP


##クローン手順
①git clone

クローン先のディレクトリでgit cloneします。
今回は　C:\Users\ユーザー名　にクローンしました。

```c#:ターミナル
$ git clone [LaravelプロジェクトのURL]
```

これでLaravelプロジェクトをローカルに作成しました。

②vendorをインストールする。
Laravelプロジェクトを開いてみると「vendor」ディレクトリが存在しないはずです。
なのでvendorディレクトリをcomposerを使ってインストールします。


```c#:ターミナル
$ composer install
```

メモ：vendorとはフレームワーク本体のプログラムがまとめられているディレクトリのことです。

③.envファイルを作成する。
今の段階では.envファイルが存在しないはずです。
代わりに.env.exampleが入っているので、.envに名前を変更します。

④.envファイルを編集する。

.envファイルを開くとデフォルトでは以下のようになっているはずです。

```c#:.env
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret
```

データベース名（DB_DATABASE）はデータベース作成の際に設定する名前と同じ名前にしてください。
データベース名（DB_DATABASE）、ユーザー名（DB_USERNAME）、パスワード（DB_PASSWORD）を必要に応じて変更します。
今回作成した自分の環境ではパスワードとデータベース名を変更しました。
パスワードは変更してなければそのままでOKです。

⑤アプリケーションキーを作成します。

envファイルのAPP_KEY（アプリケーションキー）がデフォルトのままになっているので下記のコマンドで作成します。

```c#:ターミナル
$ php artisan key:generate
```
メモ：composerを使ってLaravelをインストールすると、APP_KEYの生成は自動で行われるようです。

⑤DB新規作成する。

XAMPP の phpMyAdmin にアクセスして DB を作成します。
③で設定したデータベース名と同じ名前で作成します。

⑥マイグレーションする。
下記のコマンドでマイグレーション（DBの構築）をします。

```c#:ターミナル
$ php artisan migrate
```

ここまでで問題なければLaravelのプロジェクトをブラウザで確認します。
表示されたら終了です。

### 参考サイト

http://vdeep.net/laravel-git-clone

https://laraweb.net/environment/1742/
Microsoft Graph を使って OneNote の文書の内容を取得する

## Microsoft Graph を使うと OneNote にアクセスできる。

[Microsoft Graph Exploer](https://developer.microsoft.com/ja-jp/graph/graph-explorer)

を使うと Microsoft 365 の いろいろな情報にアクセスできるようです。
Outlook の メールや OneNote の ドキュメントの中にまでアクセスできるようです。


```
https://graph.microsoft.com/v1.0/me/onenote/notebooks
```

のように URL を使って目的の情報にアクセスしたり、プログラムによって情報取得もできるようです。

```cs
GraphServiceClient graphClient = new GraphServiceClient( authProvider );

var notebooks = await graphClient.Me.Onenote.Notebooks
	.Request()
	.GetAsync();
```

早速 ためしてみましょう。


### サンプルプログラムの実行環境

マイクロソフトの [クイックスタート](https://developer.microsoft.com/ja-jp/graph/quick-start) のページを参考に 
アプリを作成して データ取得してみましたが、
Windows Form 版が無かったので 作成して github に公開しました。
[Microsoft Graph API サンプル (Windows Form)](https://github.com/kkato233/ms-graph-api-win-form)

![Windows Form版](https://user-images.githubusercontent.com/5441449/113758277-9f40cf00-974e-11eb-85ea-b42c1ec91742.png)

OneNote の 直近の1週間の修正した ドキュメントを取得するコードは 以下のようになります。

```cs
           GraphServiceClient graphClient = new GraphServiceClient(authProvider);

            // Note の セクション一覧を取得
            var notebooks = await graphClient.Me.Onenote.Sections
                .Request()
                .GetAsync();

            var sectionIdList = notebooks.Select(r => r.Id);

            List<Entity> getDocList = new List<Entity>();

            foreach (string secId in sectionIdList)
            {
                // 指定の セクションのページ一覧を取得
                var pageList = await graphClient.Me.Onenote.Sections[secId].Pages.Request()
                    .GetAsync();
                foreach (var page in pageList)
                {
                    // 指定のページの最終更新年月日を比較 新しい物を取得対象とする。
                    Debug.WriteLine(page.Title + " " + page.LastModifiedDateTime);
                    Debug.WriteLine(page.Links.OneNoteWebUrl.Href);
                    Debug.WriteLine(page.ParentSection.Id);
                    Debug.WriteLine(page.ParentSection.DisplayName);
                    if (page.LastModifiedDateTime > DateTime.Now.AddDays(-7))
                    {
                        getDocList.Add(page);
                    }
                }
            }

            // 指定の ページを取得する。
            foreach (var doc in getDocList)
            {
                // ページ取得のループ
                var contentSt = await graphClient.Me.Onenote.Pages[doc.Id].Content.Request().GetAsync();
                var sr = new StreamReader(contentSt);
                string s = await sr.ReadToEndAsync();
                Debug.WriteLine(s);
            }

```

他にもメール送信したり いろいろ Microsoft 365 を便利に活用できそうです。
vuforia 3Dテキストの実装

1, ３Dテキストを設置し、場所とFontサイズなど調整する
![27B236F4-5616-45E0-AA00-62BCFC48D9FE.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/7437afa9-7aff-10c2-c4b3-aae1e2426a64.jpeg)

2, 位置調整する
![44C6673B-DFE1-4881-8DA8-EDA37E99BA2A_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/0bd99673-0241-d577-87bb-69f3238055a3.jpeg)

3, fontを変えたい時はgoogleFontから持ってくる
![AA6E105C-EBDE-4BB3-AC04-BDBEEE93B47F.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/e2592f2a-f9b9-440f-42d7-79fff3dec08d.jpeg)

4, fontをフォルダに入れる
![3414B935-A61E-4373-97D7-C95378596D71_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/7b2eacc0-fc28-e383-495d-e54f86966e6b.jpeg)

5, fontにドラッグし、設定する
![AC7066C4-EC4F-4FAF-B62D-5774EB0E64C3.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/df934ca4-8315-28a0-ef4a-835984e59026.jpeg)
angular をローカルに

angular cliを、グローバルではなくローカルにインストールしたいときのメモです。

（グローバルだとプロジェクトごとに違うバージョンを使用できなかったり、古いバージョンを使ってしまったりとか、いろいろ不都合があるので）

```cmd
mkdir sample
cd sample
```

sampleフォルダの中で

```cmd
npm i @angular/cli

(または npm --instal @angular/cli)
```

でインストール  -g  を付けるとグローバルインストールになってしまうので付けない。

動作確認

```cmd
npx ng version
```

グローバルでないコマンドは、npx経由で実行する必要がある。
というよりnpxを使えばローカルにダウンロードしたnpmのライブラリをコマンドで使えるようになる。（./node_modules/.bin/パッケージ名などと指定しなくてよい）

```
npx ng new プロジェクト名(この例だとsample) --directory=./ --routing=true --style=scss
```

これで今いる階層にngプロジェクトを作成できる。

【メモ】
ng new は時間がかかるが、その途中で
node_module/.stagingというフォルダができて中に大量のフォルダが作成されていたが、

```
√ Packages installed successfully.
    Successfully initialized git.
```
と処理の完了後、再び覗いてみたらそのフォルダは消えていた。
（おそらくインストール時のワークディレクトリ）

【環境】
windwos10
git bash

【参考サイト】
https://php-java.com/posts/angular-cli-not-global/
MySQL で列名付き CSV ファイルを出力する

ありそうでなかったので記事にしてみました。
もしかすると「車輪の再発明」をしている可能性も大ですが、自分に対する備忘録も兼ねて記録を残します。
お気づきの点などがございましたら、コメントいただけるとありがたいです。

#MySQL では INTO OUTFILE で列名付きのCSVファイルが出力できない
MySQL では SELECT 文に INTO OUTFILE 句をつけることで CSV ファイルを出力することができます。（作成されるCSVファイルは新規作成のみで追記や上書きは不可なので、定期的に実行するような処理では出力先ファイルがある場合にはクエリ実行前にファイルを削除する処理を別途作成する必要があります）

```SQL:CSVファイル出力記述例
SELECT COLUMN1,COLUMN2
INTO OUTFILE '/tmp/outputfile.csv' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
FROM TABLE_NAME;
```

しかし INTO OUTFILE で出力される内容は SELECT 文で抽出されたデータ部分のみであり、CSVファイルの先頭行に列名は出力されていません。Excel などに取り込む場合には列名があると便利なので列名を出力するオプションがありそうなのですが、どうも無いようです。

#列名付きのCSVファイルを出力する一般的？な方法
ネットを検索してみると列名付きの CSV を出力したい時には、列名の羅列を作成しておき、それと UNION して列名付きCSVファイルを作成する、といった事例がヒットします。

```SQL:一般的な列名付きCSVファイルの出力方法
SELECT *
INTO OUTFILE '/tmp/outputfile.csv' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
FROM (
SELECT 'COLUMN1','COLUMN2'
UNION
SELECT COLUMN1,COLUMN2
FROM TABLE_NAME
) AAA;
```

列名が少ない場合は上記のようなクエリを記述しても大した手間ではないのですが、列名が多くなると面倒そうですし、列名と値がずれてしまうようなミスを発生させてしまうかもしれません。

#列名を自動的に取得して設定する方法を考えてみた

そこで、なるべく手作業なしに列名付きの CSV を出力する方法を考えてみました。

```SQL:クエリ内容
SET SESSION group_concat_max_len=100000;

SET @TARGET_SCHEMA:='dbname';
SET @TARGET_TABLE:='tablename';
SET @OUT_FILE:='/tmp/hogehoge.csv';

SELECT CONCAT("'",GROUP_CONCAT(COLUMN_NAME SEPARATOR "','"),"'") INTO @HEADER FROM (
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA=@TARGET_SCHEMA AND TABLE_NAME=@TARGET_TABLE
ORDER BY ORDINAL_POSITION
) AAA;
SET @SQL:=CONCAT("SELECT * INTO OUTFILE '",@OUT_FILE,"' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' FROM (SELECT ",@HEADER," UNION SELECT * FROM ",@TARGET_SCHEMA,".",@TARGET_TABLE,") AAA");
PREPARE stmt FROM @SQL;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
```

@TARGET_SCHEMA にデータベース名、@TARGET_TABLE にテーブル名、@OUT_FILE に出力ファイル名を指定してクエリを実行すると、列名付きCSVファイルを出力することができます。（上記クエリ内容をファイル化しておき、source コマンドなどで呼び出して実行するのが良いかと思います）

（処理のかんたんな説明）

- 対象のテーブルの列名は INFORMATION_SCHEMA.COLUMNS テーブルより取得しています。
- 列名の羅列の作成には GROUP_CONCAT() を使用しています。GROUP_CONCAT() で生成される文字列長には制限があるため、実行前に group_concat_max_len の値を変更して制限を緩和しています。（制限を緩和しておかないと GROUP_CONCAT() で作成される列名の羅列の文字列が長くなった時に「Warnings:Row XX was cut by GROUP_CONCAT()」が発生して一部の列が出力されない悲しい結果になります）
- GROUP_CONCAT() の区切り文字のデフォルトはカンマ(,)のみになっていて、そのままでは列見出しとしては使えないので、カンマ(,)の前後にシングルクォートがついたもの(',')に置換してさらに文字列の前後にシングルクォート(')を加えることで、列見出しとして利用可能なシングルクォートで囲まれた列名の羅列を生成しています。
- INTO OUTFILE で指定する出力先ファイル名に変数を指定できない等の理由のため、動的 SQL を使ってクエリを実行しています。

#テーブルの一部の列・一部の行だけを出力するには

クエリをカスタマイズして対応するよりは、CREATE VIEW で条件に合うビューを作成しておいて、上記クエリの @TARGET_TABLE にビュー名を指定するのがメンテナンスの観点からも良いような気がします。
Python：複数の dict の リストからキーを抽出

## はじめに

複数の `dict` から**keys**をできるだけ簡単に取り出したい．

## 条件

+ 複数の`dict`がある
+ `list` になっている
+ `keys` の `list`が欲しい

## `python` code

### `dict` の `list`

リスト **`x`** から **`['A', 'B', 'C']`** を得たい． 

```
x = [{'A':'abc','B':'bcd'}, {'C':'cdf'}]
```

### `for` で書く

とてもシンプル目的は達成できる．

```
a = []
for i in x:
    for j in i:
        a.append(j)
print(a)
# ['A', 'B', 'C']
```

### 内包表記にする

#### 単純に書く

`for`では`dict`の`key`だけが返される．
内包表記では`key`と`values`を含めた`dict`が返される．
結果，何も変わらない．（失敗）

```
[j for j in [i for i in x]]
# [{'A': 'abc', 'B': 'bcd'}, {'C': 'cdf'}]
```
####`keys()`を使う
内包表記だと`dict_keys()`になる．
これは，正しい動作．しかし，目的には合わない．

```
[j for j in [i.keys() for i in x]]
# [dict_keys(['A', 'B']), dict_keys(['C'])]
```

#### `list()` を使う

+ `list(x)` で dict **x** から **key** を取り出せる

`for`と同じ解釈なのかと思われる．

```
[list(i) for i in x]
# [['A', 'B'], ['C']]
```

#### `sum()`を使って flatten

```
sum([j for j in [list(i) for i in x]],[])
# ['A', 'B', 'C']
```

#### 内包表記の `for` を削除

+ `map` を使う
+ `lambda` を使う

```
sum(map(lambda i: list(i), x),[])
# ['A', 'B', 'C']
```

## まとめ

「`for`」で構成する方法と「内包表記，`map`と`lambda`」を使う例を示した．

---
## 参考

+ [Python3 初心者　辞書](https://qiita.com/jp_keisuke/items/29586efde37680cdc7ce)
+  [Python 3 で flatten する方法いろいろ](https://qiita.com/hoto17296/items/e1f80fef8536a0e5e7db)
CentOSでDockerのインストール・基本操作

#はじめに
備忘録です!!!

#目次
1.環境
2.インストール
3.起動
4.基本操作


#1.環境
|OS・ソフト|バージョン|
|:--:|:--:|
|Windows10||
|VirtualBox|6.1.18|
|CentOS|7.9|
|Docker|1.13.1|

#2インストール
CentOSの中にDockerをインストールします。

```
$sudo yum -y install docker
```

#3.起動
```
$sudo systemctl start docker
$sudo systemctl enable docker
```

#4.基本操作
いくつかパターンがあるので、複数の表にします。
__docker [コマンド] [オプション]__

|コマンド|内容|使えそうなオプション|
|:--:|:--:|:--:|
|start|コンテナの開始|-i|
|stop|コンテナの停止|-|
|create|Dockerイメージからコンテナの作成|--name,-e,-p,-v|
|rm|停止したコンテナの削除|-f,-v|
|exec|コンテナ内でプログラムの実行(コンテナが実行中のみ)|-i,-t|
|ps|コンテナを一覧表示させる|-a|
|cp|Dockerコンテナとホスト間でファイルのコピーをする|-|
|commit|コンテナをイメージに変換|-|

__docker network [コマンド] [オプション]__

|コマンド|内容|使えそうなオプション|
|:--:|:--:|:--:|
|connect|ネットワークに接続させる|-|
|disconnect|ネットワークから切断させる|-|
|create|ネットワークの作成|-|
|inspect|ネットワークの詳細を表示させる|-|
|ls|ネットワークの一覧を表示|-|
|prune|今現在、コンテナに繋がっていないすべてのネットワークの削除|-|
|rm|特定のネットワークの削除|-|

__docker volume [コマンド] [オプション]__

|コマンド|内容|使えそうなオプション|
|:--:|:--:|:--:|
|create|ストレージを作成|--name|
|inspect|ストレージの詳細を表示させる|-|
|ls|ストレージの一覧を表示|-a|
|prune|現在マウントされていないストレージ全てを削除|-|
|rm|特定のストレージを削除|-|

オプションの意味は下の表に示す。

|オプション|意味|
|:--:|:--:|
|--name|コンテナ名の指定|
|-p|ポート番号の指定|
|-v|ストレージをマウント|
|--net=ネットワーク名|コンテナをネットワークに接続|
|-d|バックグラウンドで実行|
|-i|コンテナにキーボードをつなぐ|
|-t|特殊キーの使用を可能にする|
|-e|環境変数を指定|




今回はコマンドをまとめただけでしたが、時間があったら実際にこのコマンドを使う記事を書きたいです。
Rで論文っぽい図を描く⑤　ggplot2のグラフ上に2way ANOVAのp値を半自動的に表示する

今回はTwo-way ANOVAの結果を図に直接示すようなことをしたいと思います。
全ての値をannotateしていると大変なのと、Rにやってもらうことで打ち間違いも防げます。

##データ読み込み

```{r}
data(iris)
head(iris) #確認
```

Two-way ANOVAをしたいので、今回も、例によって架空のTemperature列を入れていきます。
元から2要因あるデータを持っている場合はこれは必要ありません。

```{r}
iris$Temperature <- rep(c(rep("High", 25), rep("Low", 25)), 3)
```

##Two-way ANOVA

```{r}
#Two-way ANOVAをやる
anovasummary <- summary(aov(Sepal.Length ~ Species * Temperature, data = iris)) 
anovasummary <- anovasummary[[1]]
#p値を抜き出す
anovap <- as.data.frame(anovasummary[1:3,5])
#要因の名前の列を作る
anovap$factor <- as.character(row.names(anovasummary)[1:3])
#謎に要因の後ろにスペースができる場合があるので消しておく
anovap$factor <- sub(" .*", "", anovap$factor) 
#交互作用のところを良い感じにしてみた。
anovap$factor <- sub(":", " × ", anovap$factor) 
colnames(anovap) <- c("p-value", "factor")

#確認
head(anovap)
```

追記。以下の方法でもスペースを消せるようです。@dfghdfdjftyfghvgjhk様より教えていただきました。また、本題とは関係ないですがTemperature列を作った際のrep()にも、もっと簡潔に書くやり方があるようです。詳細はコメント欄を参照してください。

```{r}
anovap$factor <- trimws(anova$factor)
```

##p値の大きさを判別し、全要因の結果を返す関数を作る

```{r}
changep <- function(a) {
    #p値の大きさによって、返す文字列を決める
    p <- function(a) {
        if (a < 0.001) {
            return("p < 0.001")
        } else if (a < 0.01){
            return("p < 0.01")
        } else if (a < 0.05) {
            return("p < 0.05")
        } else {
            return("n.s.")
        }
    }

    #全要因に対して上の関数を当てはめ、結果を返す
    c <- NULL
    for (i in 1:nrow(a)){
        c <- paste0(c, "\n", a[i, 2], " : ", p(a[i, 1]))
    }
    return(c)
}
```

@dfghdfdjftyfghvgjhk様にコメントを頂き修正しました。

##ggplot2で図示

```{r}
#結果入れる用の場所の確保のために、y軸の最大値より少し大きい値を格納しておく
yRoof <- max(iris$Sepal.Length)*1.2

#plot
library(ggplot2)
g <- ggplot(iris, aes(x=Species, y=Sepal.Length, fill=Temperature)) + 
  geom_boxplot(lwd=1.5) + 
  theme(panel.grid = element_blank()) +
   scale_fill_manual(values = c("grey", "white")) + 
  labs(y="Sepal Length (cm)", x=NULL) + 
  theme(axis.text=element_text(size=20, face = "bold", colour = "black"), 
        axis.title=element_text(size=25,face="bold", colour = "black"),
        axis.line = element_line(size = 1.2, colour = "black"), 
        panel.grid.major = element_blank(), 
        panel.grid.minor = element_blank(),
        panel.background = element_blank(),
        legend.position = "none")
g <- g +
  annotate("text", x=Inf, y=yRoof,
           label=changep(anovap),
           hjust="right",
           size = 4)
```

```{r}
#保存
ggsave("xxx.png", plot = g, width = 8, height = 8)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/682014/00e67b1b-0b65-071d-a55a-fb812885cf3f.png)

大きさとかは適宜調整が必要かもしれないです。
快適なggplotライフを送りたいですね。