OmniAICreator/Qiita-1.07M huggingface dataset:
LonghornでReadWriteManyを使用する方法

# TL;DL
LonghornがインストールされているK8sクラスタ内のノードに入って
```
sudo apt install nfs-common
```
を実行

# Longhornのinstall
```
kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/v1.3.0/deploy/longhorn.yaml
```
# LonghornUIにアクセスできるようにingressの設定
```
USER=<USERNAME_HERE>; PASSWORD=<PASSWORD_HERE>; echo "${USER}:$(openssl passwd -stdin -apr1 <<< ${PASSWORD})" >> auth
```
```
kubectl -n longhorn-system create secret generic basic-auth --from-file=auth
```
longhorn-ingress.ymlを作成
```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: longhorn-ingress
  namespace: longhorn-system
  annotations:
    # type of authentication
    nginx.ingress.kubernetes.io/auth-type: basic
    # prevent the controller from redirecting (308) to HTTPS
    nginx.ingress.kubernetes.io/ssl-redirect: 'false'
    # name of the secret that contains the user/password definitions
    nginx.ingress.kubernetes.io/auth-secret: basic-auth
    # message to display with an appropriate context why the authentication is required
    nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required '
    # custom max body size for file uploading like backing image uploading
    nginx.ingress.kubernetes.io/proxy-body-size: 10000m
spec:
  rules:
  - http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: longhorn-frontend
            port:
              number: 80
```
```
kubectl -n longhorn-system apply -f longhorn-ingress.yml
```

# K8sクラスタ内のノードにアクセスしてnfs-commonをinstall
```
sudo apt install nfs-common
```

# PVC作成例
#### Longhornがinstallされている場合はPVCを作成すればPVCで要求したPVを自動作成してくれるのでPVCのみを記述すればOK
```yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pv-test
  labels:
    <PVと接続したいPodのラベル>
spec:
  storageClassName: longhorn
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 5Gi
```


# 参考文献
- [Install with Kubectl](https://longhorn.io/docs/1.3.0/deploy/install/install-with-kubectl/)
- [Create an Ingress with Basic Authentication (nginx)](https://longhorn.io/docs/1.3.0/deploy/accessing-the-ui/longhorn-ingress/)
- [Support for ReadWriteMany (RWX) workloads (Experimental Feature)](https://longhorn.io/docs/1.1.0/advanced-resources/rwx-workloads/)
c++ std::map,std::vectorの実装サンプル(同じキーで登録する)

c++
std::map,std::vectorの実装サンプル
同一のキーをmapのデータ部のvectorに設定するサンプルプログラム

データを検索する
検索してヒットしなかった場合はmapにデータを新規で登録する
検索してヒットした場合はmapのvector配列に追加登録する

```sample.cpp
#include <iostream>
#include <map>
#include <vector>

using namespace std;

std::map<int, std::vector<std::string>> mpData;

void Push_back(int key, std::vector<std::string> vcStr)
{
	auto itr = mpData.find(key);
	if (itr != std::end(mpData))
	{
		// ②すでに同じキーで登録されている場合はsecondにvector配列として追加登録する
		for (auto itr2 = vcStr.begin(), end = vcStr.end(); itr2 != end; ++itr2)
		{
			(*itr).second.push_back(*itr2);
		}
	}
	else
	{	// ①キーが登録されていないので新規で登録する
		mpData[key] = vcStr;
	}
}

int main(void)
{
	// ①キーが登録されていないので新規で登録する
	int key1 = 1;
	std::vector<std::string> vcStr1;
	vcStr1.push_back("aaa");
	vcStr1.push_back("bbb");

	Push_back(key1, vcStr1);

	// ②すでに同じキーで登録されている場合はsecondにvector配列として追加登録する
	int key2 = 1;
	std::vector<std::string> vcStr2;
	vcStr2.push_back("ccc");
	vcStr2.push_back("ddd");

	Push_back(key2, vcStr2);

	// ③キーが登録されていないので新規で登録する
	int key3 = 2;
	std::vector<std::string> vcStr3;
	vcStr3.push_back("eee");
	vcStr3.push_back("fff");

	Push_back(key3, vcStr3);

	return 0;
}
```
製造業　大企業デジタル推進所感　ペーパーレスについて

# 前提

ある製造業職場のデジタル化推進を初めて1年（以上）経ったので所感をまとめていきたい。

わざわざ大企業と書いたのは、日本の大企業の風土文化が面白かったからです。
今までの工場勤務だけでは得られない知見・視点がありました。

# 目的

まとめ。

## 前提の昔話

去年の3月「デジタル関係、得意でしょ」と言われて工場勤務から全く畑違いのデジタル化推進関係の部署に異動となった。
「得意でしょ」とは言われたが、休日にパソコンをいじったり、皆さんのちょっとしたお困りごと（モニターが映らない、設定がわからない）などを助ける程度の、趣味で畑をイジっているレベルだった。

## 経過

その後も謎の高熱を出したり（知恵熱と言われた）、元の職場に戻っても一人別部署でデジタル化を継続して推進したり、今も楽しく元気にやっている。

### ペーパーレス

1年経って実感できたことだが、工場現場では解決（ソリューション）第一である。工場には生産数であったり可動率であったり、良くなるのが正解である数字が沢山ある。問題は当然それらの数字を阻害しており、ステップに基づいて解決すれば、その数字も良くなって解決！　というのを繰り返している。ただ、デジタル化を進めるうえでそういった「風土」があると以下のようなことが問題になる。

現場で良く推進されるのが「ペーパーレス」。紙を電子化すれば、はい、デジタル化達成。最もわかりやすいんじゃないだろうか。
だけど、一度考えてみてほしい。紙を電子化した時、確かに1枚数円もしない紙の使用量は多少低減されるだろう。
ただ、それ以外にどんな効果があるのだろうか？　下手をしたら紙に直接書く時間より、パソコンで電子帳票を開いて記入する時間の方が長い…なんてことにならないだろうか。
生産現場では時間は製品原価に直結する「コスト」である。こういったコストが増える可能性のあるペーパーレス化に現場が乗り気ではないのは納得するところがある。（そして何より、現場は今のやり方に慣れているし、新しいやり方は面倒である）

なので、これには単純に時間も短縮できるペーパーレス化を提供することを大事にする。例えば手順を省略したり、やりやすくしたり、見える化したりと、紙低減だけじゃないメリットを提供することが重要だと思う。

# 予定

・ペーパーレス
・チャットとメール
・デジタル化への意識（学ぼうとすること）
・何故デジタル化は職場風土の話になるのか（DX）

# 結果

エンニジアになれているとは言えません（
Flutterアプリで、CrashlyticsにdSYMが送信されてなくて困った話

https://firebase.google.com/docs/crashlytics/get-started?platform=flutter
の通りに手順を実行したはずが、Firebase consoleよりCrashlyticsの画面を見ると、dSYMが送信されてなかった。

## 前提

- cocoapodsは、brew経由でインストールしていた
- rubyはasdfでインストールしていた

## どうなっていたか

ビルドは普通に成功し、
https://firebase.google.com/docs/crashlytics/get-started?platform=flutter#force-test-crash
に記載されている test crash を実行すると、Crashlytics上でクラッシュ自体は確認できる。
ただし、「dSYMがありません」的なエラーが表示されていた。

## 結論

asdf経由でインストールしていたrubyが、うまく動作していなかった。
（おそらく、asdfのバージョンアップ時に何かが起こっており、shimがきれいに切り替わっていなかった）

`ruby --version` などを実行すると、以下のような感じになっていた。

```
/Users/.../.asdf/shims/ruby: line 3: /opt/homebrew/Cellar/asdf/0.9.0/libexec/bin/asdf: No such file or directory
/Users/.../.asdf/shims/ruby: line 3: exec: /opt/homebrew/Cellar/asdf/0.9.0/libexec/bin/asdf: cannot execute: No such file or directory
```

一度 `~/.asdf/shims/ruby` を削除して、 `asdf reshim ruby 3.1.1` を実行すると、正常になった。

```
> rm /Users/.../.asdf/shims/ruby
> asdf reshim ruby 3.1.1
> ruby --version        
ruby 3.1.1p18 (2022-02-18 revision 53f5fc4236) [arm64-darwin21]
```

その後、対象のFlutter projectの `ios` ディレクトリにて、 `pod install` を再実行。
するとBuild Phasesに "[firebase_crashlytics] Crashlytics Upload Symbols" が作成された。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8708/5f661de6-c3de-22aa-8d7e-de9c9101f19a.png)

改めて、Flutterアプリをビルド、test crashを再度起こしてみたりしていると、Crashlyticsで詳細が確認できるようになった。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8708/cc84f0e8-763b-8462-d966-1e3b9d8175c6.png)

## 中身を見てみた

もともと、`flutterfire configure` で配置される `firebase_app_id_file.json` の意味を調べていた。

https://github.com/firebase/flutterfire で `.` を押してVSCodeを起動、 `firebase_app_id_file.json` を検索すると、 `crashlytics_add_upload_symbols` というスクリプトで使っていた。
`crashlytics_add_upload_symbols` で再度検索すると、 `firebase_crashlytics.podspec` でrubyを利用して実行されており、おそらく `pod install` 時に実行されるんだろうと予想できた。
https://github.com/firebase/flutterfire/blob/f3a6bdc5fd2441ed3c77a9d0ece0d6460afd2ec4/packages/firebase_crashlytics/firebase_crashlytics/ios/firebase_crashlytics.podspec#L10

改めて、自分のプロジェクトで `pod install` を実行してみると、先のrubyのエラーが発生していたため、原因が特定できた。
（VSCode上でFlutterアプリとして実行していると、このあたりのエラー？警告？が表示されてない気がする。このせいで、なかなか気づけなかった。）

## 感想

おそらく、多くの開発者は `cocoapods` をrubyのgemとしてインストールするため、 `pod` コマンドが動いていれば、 `ruby` コマンドも成功するんだと思われる。
自分の環境では、M1 (Apple Silicon) でcocoapodsを `gem install` することに挫けてしまったので、Homebrew経由でインストールしていたため、こんな自体が発生したのだと思う。

FlutterアプリをiOSにビルドするために、cocoapodsが必要だと認識していたけど、単体のrubyも利用されていることまで気が回っていなかった。。。
Octave で分布の同一性の検定

# Octave で分布の同一性の検定

2 つの観察データが同一の分布からの標本であるといえるかどうか（同じ分布に従うといえるかどうか）の検定である。

    usage:
    [pval, chisq, df] = chisquare_test_homogeneity (x, y, c)
    
    x, y はデータベクトル，c は データの分割点ベクトル
    戻り値を指定しない場合は p 値のみを表示する
    戻り値を指定した場合は，後で変数を使用すること（表示するなど）ができる



```matlab
pkg load statistics   % statistics が必要
format long           % 表示精度を高くする（任意）
```


```matlab
x = [49.6; 52.5; 48.3; 50.6; 56.7; 32.8; 51.6; 46.1; 54.6; 52.0; 39.3; 49.5; 45.1; 37.1; 63.9;
     48.3; 37.4; 33.4; 37.8; 51.2; 63.0; 74.3; 54.4; 60.1; 55.6; 49.3; 57.4; 40.4; 57.8; 60.9];
y = [48.7; 36.8; 51.9; 65.5; 62.6; 57.3; 43.3; 57.7; 61.4; 69.8; 48.0; 37.1; 29.8; 53.6; 49.3;
     50.2; 46.1; 50.6; 51.4; 61.0; 50.8; 51.7; 52.4; 57.3; 55.4];
c = [40; 45; 50; 55; 60; 65];
```

データは，$c$ の長さを $k$ とすると，階級 $(-\infty, c_1), [c_1, c_2), \dots, [c_k, \infty)$ により集計されるので，特に整数データのような場合には注意が必要である。

戻り値を変数に代入しない場合には $p$ 値のみが表示される。


```matlab
chisquare_test_homogeneity(x, y, c);
```

      pval: 0.940698


戻り値を変数に代入すれば結果を自由に表示できる。


```matlab
[pval, chisq, df] = chisquare_test_homogeneity(x, y, c);
printf("chisq = %.5g,  df = %d,  p value = %.5g\n", chisq, df, pval)
```

    chisq = 1.7562,  df = 6,  p value = 0.9407


`c` を適切に指定しなければならない例

以下の `x`, `y` は，ポアソン乱数である。


```matlab
randp("state", 123)
x = poissrnd(2, [1, 100]); #generate 100 poisson 
y = poissrnd(3, [1, 100]); #another 100 poisson
```

ポアソン乱数は 0, 1, ... の値をとるが， c = 0:10 のようにしてしまうと，0 未満の階級には該当するデータがないことになり，計算過程で 0 による割り算が行われるため結果が `Nan` になってしまう。


```matlab
c = 0:10;
[pval, chisq, df] = chisquare_test_homogeneity(x, y, c);
printf("chisq = %.5g,  df = %d,  p value = %.5g\n", chisq, df, pval)
```

    chisq = NaN,  df = 11,  p value = NaN


このエラーを避けるためには例えば c = 0.5:10 のようにすればよい。


```matlab
c = 0.5:10;
[pval, chisq, df] = chisquare_test_homogeneity(x, y, c);
printf("chisq = %.5g,  df = %d,  p value = %.5g\n", chisq, df, pval)

```

    chisq = 49.161,  df = 10,  p value = 3.8059e-07


しかし，これでもまだ不適切である。`x`，`y` の最大値は今の場合 8 である。


```matlab
max([x  y])
```

    ans = 8


最後の階級は $[8, \infty)$ なので c = 0.5:7.5 が適正である。

`chisq = 49.161` は `c = 0.5:10` のときと同じであるが，`df` の値が違う。`df = 8` が正しい。


```matlab
c = 0.5:7.5;
[pval, chisq, df] = chisquare_test_homogeneity(x, y, c);
printf("chisq = %.5g,  df = %d,  p value = %.5g\n", chisq, df, pval)

```

    chisq = 49.161,  df = 8,  p value = 5.9221e-08
Laravel breezeでviteからmixに戻す方法

# Laravel breezeでviteからmixに戻す方法
Laravelのbreezeに新しく導入されたビルドツール、viteがなぜかcloud9だとうまく動作しない。  
そのためビルドツールを、viteからmixに戻す方法をまとめました。
（Laravel SailやMAMPを使っている場合は、こんなことしなくても問題なく動作します）

## ファイル名の変更
resources/app.jsxになっていた場合は、resources/app.jsに直す

## Laravel Mixのインストール
```実行コマンド
npm install --save-dev laravel-mix
```
## app.jsの編集
```コード
import './bootstrap';

import React from 'react';
import { render } from 'react-dom';
import { createInertiaApp } from '@inertiajs/inertia-react';
import { InertiaProgress } from '@inertiajs/progress';

const appName = window.document.getElementsByTagName('title')[0]?.innerText || 'Laravel';

createInertiaApp({
    title: (title) => `${title} - ${appName}`,
    resolve: (name) => require(`./Pages/${name}.jsx`),
    setup({ el, App, props }) {
        return render(<App {...props} />, el);
    },
});

InertiaProgress.init({ color: '#4B5563' });
```

## package.jsonの修正
package.jsonのscriptsというところを書き換える。

```コード
  "scripts": {
     "dev": "npm run development",
     "development": "mix",
     "watch": "mix watch",
     "watch-poll": "mix watch -- --watch-options-poll=1000",
     "hot": "mix watch --hot",
     "prod": "npm run production",
     "production": "mix --production"
  }
```

## webpack.mix.jsの作成
.envなどと同階層にwebpack.mix.jsファイルを作成する。  
ファイルに下記のコードを記述する。
```コード
let mix = require("laravel-mix");


mix.js("resources/js/app.js", "public/js")
    .react()
    .postCss("resources/css/app.css", "public/css", [
        require("postcss-import"),
        require("tailwindcss"),
        require("autoprefixer"),
    ])
    .alias({
        "@": "resources/js",
    });

if (mix.inProduction()) {
    mix.version();
}
```

## .envの内容を修正する
.envファイル内でVITEになっている箇所を全て書き換えてください。
```
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_HOST="${PUSHER_HOST}"
MIX_PUSHER_PORT="${PUSHER_PORT}"
MIX_PUSHER_SCHEME="${PUSHER_SCHEME}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
```

## app.blade.phpの内容を修正する
```コード
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title inertia>{{ config('app.name', 'Laravel') }}</title>

        <!-- Fonts -->
        <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700&display=swap">

        <!-- Scripts -->
        @routes
        <link rel="stylesheet" href="{{ mix('css/app.css') }}">
        <script src="{{ mix('js/app.js') }}" defer></script>
        @inertiaHead
    </head>
    <body class="font-sans antialiased">
        @inertia
    </body>
</html>
       
```

## 使わなくなったViteを削除する
```実行コマンド
npm remove vite laravel-vite-plugin

rm vite.config.js
```

## 必要なパッケージをインストール
```実行コマンド
npm install @babel/preset-react --save-dev --legacy-peer-deps
```
## https化
AppServiceProviderのboot()に下記のコードを追加
こちらに関しては必要に応じて追加してください。
```コード
 public function boot()
    {
        \URL::forceScheme("https"); //追加
    }
```

###
こちら参考にした記事です。
https://github.com/laravel/vite-plugin/blob/main/UPGRADE.md#migrating-from-vite-to-laravel-mix
ONNX 概要

# はじめに

Edge AIパイプラインツールのWeDXをGitHubに公開したら、ONNXモデルについて整理する必要があったので、この機会で整理しておきます。

https://github.com/motojinc25/WeDX

# ONNXとは

- Open Neural Network eXchangeの略です。
- ディープラーニングや機械学習モデルのような人工知能モデル(以下、AIモデル)を表現するためのフォーマットです。
- Microsoftさんとパートナー コミュニティによって作成されました。[(GitHub - onnx)](https://github.com/onnx/onnx)
- ONNXは日本語で「オニキス」と発音することが多いです。
- ONNXフォーマットで作られたモデルのことをONNXモデルで呼ばれたりします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287622/656482de-56c7-0c24-2275-d7e378b6713e.png)

# ONNXが必要な理由

一つのAIモデルだけで業務利用に達するレベルにはいかないので複数のAIモデルを組み合わせることで精度高く表現できます。ここで複数のAIモデルはPyTorch, TensorFlow, scikit-learnなどの各種フレームワークで学習したモデルのことです。

様々なフレームワークのAIモデルは該当するプラットフォームで推論するのが一般的であり、フレームワークとハードウェア(クラウドまたはエッジ)と組み合わせを最適化するのはハドル高くなりがちです。

ONNXを使うと異なるフレームワーク間で学習したモデルを運用できますし、ハードウェアのサポートによって最適化されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287622/35c761d8-db37-0a61-a49d-52ae02fa038d.png)

# ONNXモデルの取得方法

## ONNX Model Zoo

GitHubの[ONNX Model Zoo](https://github.com/onnx/models)で学習済みモデルのONNXモデルをApacheライセンス(無料?)でダウンロードできます。

とりあえず、ここで自分がほしいAIモデルをダウンロードして手軽くスタートしても良いと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287622/f6c3acd9-9aa1-cc60-41d5-8cb0e99a04d9.png)

## ONNXモデル変換

別の形式で作成された既存のAIモデルをONNXモデルに変換します。

変換するにはフレームワークでネイティブサポートされていると変換コマンドで変換できます。サポートしてないフレームワークについては関連変換ツールがほぼ用意されているのでそのツール経由で変換できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287622/851d3a6e-7fe8-b3bd-7b91-b15bde5081a6.png)

## SaaSサービスによるONNXモデル作成

[Azure Custom Vision](https://www.customvision.ai/)のようなクラウドでAIモデルを作成できるSaaS(Software as a Service)サービスからONNXモデルを作成できます。自分のドメインに合わせてONNXモデルを作成できますし、無料でプランも用意されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287622/f4acc90b-6865-b88e-8150-d87d20ee30bb.png)

## PaaSサービスによるONNXモデル作成

本格的にAIモデルを作成することになると[Azure Machine Learning](https://azure.microsoft.com/en-us/services/machine-learning)のようなPaaS(Platform as a service)サービスを使うことになります。好きなフレームワークを使ってONNXモデルを作成できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287622/fc9cf7d1-3c92-7e38-d169-aed381ad7870.png)

# おまけ

## ONNX Runtime

ONNXモデルの推論エンジンで公開されてどんどん機能とサポート領域が広がっています。

推論環境をONNX Runtimeで構築したら、異なるフレームワークで作成されたAIモデルをONNXモデルに変換しておけば、そのままONNX Runtimeで推論できます。

ONNX RuntimeはNvidia CUDAのようなハードウェアアクセラレーションの種類によってインストール方法が異なります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287622/cec4ce17-8d3d-a79a-d030-c7d64a160ff2.png)

## ONNXモデルの視覚化ツール

[Netron](https://github.com/lutzroeder/Netron)というツールを使用するとONNXモデルをグラフで表示することができますので必須ツールでも言えるでしょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287622/71fb1515-8df2-b66d-518e-dc835cf1234c.png)
TensorflowでGPUを使う方法

# はじめに

自分はtensorflowで機械学習しようと思い、CPUだと遅すぎるのでGPUを用いようとしましたが、なかなか環境構築がうまくいかずに3，4時間かかりました。同じような境遇の方の助けになりたいよ思い、この記事を書こうと思いました。

パソコンのスペックや環境によって多少異なるので参考程度に閲覧してください。

# 環境
・Windows10
・Python3.9.13
・GPU : RTX3060 ti

# 構築の手順
## NVIDIA　Driver
まずはじめにNVIDIAドライバーのインストールをおこないます。

https://www.nvidia.co.jp/Download/index.aspx?lang=jp

自分のGPUのスペックを調べて入力し、検索してください。

自分の場合は、GPU：RTX 3060 tiなので以下の画像のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729175/581208ad-f7d5-56ae-9f0e-e4a73ae543d6.png)

検索すると以下のようになります。
__※バージョンの数字を覚えておいてください。例：「516.59」__
これをダウンロードしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729175/1317b513-9960-407c-9f4c-a04e081d71b1.png)

## CUDA
次にCUDAのダウンロードですが、NVIDIAドライバーとCUDAの対応表を見てダウンロードするCUDAを選びます。
バージョンを間違えると動きませんので気を付けてください
対応表→https://docs.nvidia.com/cuda/cuda-toolkit-release-notes/index.html

対応表を見て、先ほどのバージョンの数字を確認して図に書いてある数字以下のものを選んでください。
私の場合は「516.59」なので、最新のCUDA11.7まで使うことができます。
この記事ではCUDA11.7をダウンロードします。
バージョンごとによって異なるかもしれませんが、ダウンロード後には自動でPATHが指定されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729175/fdbafc0b-725b-bae5-49b2-ee1d3cda9a47.png)

## cuDNN

CUDA11.7をダウンロードする方はこちらのサイトを参考にしてください

https://www.kkaneko.jp/tools/win/tensorflow2.html

CUDA11.2以前のバージョンをダウンロードする方はTensorflow公式のサイトを参考にしてください

https://www.tensorflow.org/install/source_windows#gpu

自分の場合は、CUDA11.7は最新のcuDNN8.4.1を使えるそうなので[このページ](https://developer.nvidia.com/cudnn)からダウンロード
※ダウンロードには会員登録が必要です（無料）。

## tensorflow-gpu
GPU版のtensorflowをインストールします。

Pythonのバージョンや上記でいれたもののバージョンを対応させながらtensorflow-gpuをインストールしてください。
人によって異なると思うので、対応表をみつけて丁寧に確認してください。
自分と同じバージョンを入れている方はtensorflow-gpu=2.9.1で大丈夫です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729175/b38b950c-9b61-3cee-0244-084a0f489aba.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729175/a3f3c463-123c-55c5-a2b6-b6558309edd8.png)

# 確認
### NVIDIAドライバーとCUDAのバージョン確認
cmdで「nvidia-smi」と入力すると各バージョンが出てくると思います。
 
### cuDNNのバージョン確認
入れたフォルダーによりますが、大体の人が以下のpathに「cudnn_version.h」があると思います。
PATH：「C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.7\include」

自分の場合は
CUDNN_MAJOR 8
CUDNN_MINOR 4
CUDNN_PATCHLEVEL 1
となっているのでバージョン8.4.1であることが確認できました。
```
#ifndef CUDNN_VERSION_H_
#define CUDNN_VERSION_H_

#define CUDNN_MAJOR 8
#define CUDNN_MINOR 4
#define CUDNN_PATCHLEVEL 1
```
### tensorflow-gpuの動作確認
ここまで確認できた方はcmdで以下のコードを入力してください。
```python
from tensorflow.python.client import device_lib
device_lib.list_local_devices()
```
このような表示がされれば成功です。
逆に、CPUのみであったり、「skipping ～」のようなものが出ていれば、どこかバージョンが違っていると思われます。
```xla_global_id: -1
, name: "/device:GPU:0"
device_type: "GPU"
memory_limit: 5762973696
locality {
  bus_id: 1
  links {
  }
}
incarnation: 9287072046004413228
```

# さいごに

もし上手くいかなかったり、いい対応表などがあればコメントで書いてくれると嬉しいです。
ツリー状の依存関係をシェルスクリプトで表現

# 実現したいこと
入力: 依存関係
```
a->b
a->c
a->d
c->e
c->f
```

出力: ディレクトリツリー
```
a
|-- b
|-- c
|   |-- e
|   `-- f
`-- d
```

# 実装

```
$ f(){ mkdir -p $1/$2; [ -d $2 ] && (mv $2/* $1/$2/; rmdir $2); ln -s $1/$2 $2;}; export -f f

$ g(){ xargs -n2 bash -c 'f $1 $2' --; rm *;}

$ echo a b a c a d c e c f | g; tree a # 単一の木
a
|-- b
|-- c
|   |-- e
|   `-- f
`-- d

$ echo a b a c a d c e c f g h g i | g; tree # 複数の木でも動く
.
|-- a
|   |-- b
|   |-- c
|   |   |-- e
|   |   `-- f
|   `-- d
`-- g
    |-- h
    `-- i
```

- 制約
    - ノードにはユニークな名前が付いていると仮定。
    - 表現できるのは木のみ。 (親が2個のノードとかは不可)
    - ルートノード1個だけからなる木 (宙ぶらりんの単一ノード) は表現不可。
        - 入力に依存関係を与える使用のため。

# 解説
- `f()`: 1つのノードを追加する処理。
- `g()`: ノードの数だけ `f()` をループで回す。

## `f()` の解説
1つのノードを追加する。

```bash:f( ) の定義
$ f(){
    mkdir -p $1/$2
    [ -d $2 ] && (mv $2/* $1/$2/; rmdir $2) # $2 がディレクトリの場合の例外処理。
    ln -s $1/$2 $2
}
$ export -f f # xargs で使うため。
```

`f()` の `mkdir` と `ln` が肝である。
`mkdir` で木にノードを追加し、`ln` でそのノードへの参照を保存する。
`f a c` は基本的に `mkdir -p a/c; ln -s a/c c;` と等価である。

```bash:f( ) の実行例
$ f a c         # mkdir -p a/c; ln -s a/c c と等価。

$ tree
.
|-- a           # ノード (ルート)
|   `-- c       # ノード
`-- c -> a/c    # ノードへの参照

$ f c e         # mkdir -p c/e; ln -s c/e e と等価 。

$ tree
.
|-- a           # ノード (ルート)
|   `-- c       # ノード
|       `-- e   # ノード
|-- c -> a/c    # ノードへの参照
`-- e -> c/e    # ノードへの参照
```
ディレクトリ (ノード) とシンボリックリンク (ノードへの参照) ができることがわかる。
シンボリックリンクは中間ファイルであり、木の中には存在しない。

では `f()` の例外処理では何をしているのか?

```bash:f( ) の例外処理
    [ -d $2 ] && (mv $2/* $1/$2/; rmdir $2) # $2 がディレクトリの場合の例外処理。
```

先程の例を逆順に実行するとどうなるかを考える。

```bash
$ f a c; f c e # これではなく
$ f c e; f a c # これを実行した場合を考える
```

```bash:f( ) の逆順の実行例
$ f c e

$ tree # 問題なし
.
|-- c
|   `-- e
`-- e -> c/e

### 以下、f a c == mkdir -p a/c; ln -s a/c c を分解して実行

$ mkdir -p a/c

$ tree # ここまでは問題ない
.
|-- a
|   `-- c
|-- c
|   `-- e
`-- e -> c/e

$ ln -s a/c c

$ tree # 変な状態になった
.
|-- a
|   `-- c
|-- c
|   |-- c -> a/c # ディレクトリ (木) の中にシンボリックリンクを作ってしまった。
|   `-- e
`-- e -> c/e
```

上記の問題は、`ln -s a/c c` をする時点で c/ が既に存在するため起こる。
そのため、c/ が既に存在し、かつディレクトリの場合に、例外処理が必要となる。

```
if [ -d c ]; then # c が存在しディレクトリの場合 (= この時点で c/ が独立した木である場合)
    mv c/* a/c    # c の子ノードを木 a の中に移動 (a/c は前段の処理で既に作成されている)
    rmdir c       # c (独立していた木) を削除
fi
```

`ln` の実行前に上記の例外処理を行えば、c/ が存在しなくなるので、`ln` で普通にノードへの参照が作成できる。

`ln` 実行時に c が存在してかつシンボリックであることはありえない。
なぜなら `ln` を行うのは新しいノードを作成するときであり、ノードの名前はユニークという制約があるからである。(同じ名前のノードが2度作られない)

## `g()` の解説
ノードの数だけ `f()` をループで回す。
`f()` を呼び出すインターフェース的なものである。
本質的な話題ではないのでサラッと流す。

```
g(){
    xargs -n2 bash -c 'f $1 $2' --
    rm * # シンボリックリンクは中間ファイルなので最後に削除
}
```

xargs の部分でパイプからの入力を2個ずつに分解して `f()` を呼び出している

```
$ echo 0 1 2 3 | xargs -n2 echo # ちなみに echo は省略可能
0 1
2 3

$ echo 0 1 2 3 | xargs -n2 bash -c 'echo $1,$2' -- # f() が関数なのでこんな形で呼び出す必要がある
0,1
2,3

$ echo 0 1 2 3 | xargs -n2 bash -c 'f $1 $2' -- # 最終形
```
【Git】VimをGitのエディタのdefaultに設定する方法

## はじめに
VimをGitのエディタのdefaultに設定する方法を書いておきます。

## 本記事を書こうと思った背景
自宅のPCでTerraformのコードを触っている中で`git rebase`を実施しようとした際に、「atomのコマンドは存在しない」というエラーが表示されたため。

```zsh
% git rebase -i --autosquash 9fd7947
hint: Waiting for your editor to close the file... atom --wait: atom: command not found
error: There was a problem with the editor 'atom --wait'.
%
```

既にatomはアンインストール済みですが、Git側の設定を変更することを忘れておりました。

## 対応
`Vim`をgitのエディタのdefaultに設定する。

```zsh:コマンド
git config --global core.editor vim
```

設定確認は以下になります。

```zsh:設定確認
% git config --global --list | grep editor
core.editor=vim
%
``` 

こちらの設定をすることで、`git rebase`や`git commit`を使用するとデフォルトで`Vim`が起動されるようになります。

## 参考記事
https://qiita.com/Syunto07ka/items/f87c9a82dfacf1472ee5

https://git-scm.com/docs/git-config#Documentation/git-config.txt-coreeditor

https://git-scm.com/docs/git-var
Vueのデータのやり取り:props

Vueにはデータをやり取りする方法がいくつかあります。
それを順番に勉強していこうと思いました。

今日は「props」。コンポーネント間のデータのやりとりをするときに使います。3つの子コンポーネントを使ったサンプルを作りました。ソースはこちら。

```php:App.vue
<template>
  <div class="top">
    <one-child :hoge="title"></one-child>
    <two-child @input-text="addText"></two-child>
    <three-child :fuga="textList"></three-child>
  </div>
</template>
<script>
import OneChild from './components/OneChild.vue';
import TwoChild from './components/TwoChild.vue';
import ThreeChild from './components/ThreeChild.vue';
import moment from "moment"

export default{
  components:{
    OneChild,TwoChild,ThreeChild
  },
  data(){
    return{
      title:'ToDoリスト',
      textList:[],
    }
  },
  methods:{
    addText(value){ 
      var m = moment();
      var today = m.format("YYYY年MM月DD日");    
      this.textList.unshift(today + " " + value);
    }
  }
}
</script>
<style>
</style>
```
```php:component/OneChild.vue
<template>
  <p>{{hoge}}</p>
</template>
<script>
export default{
    props:['hoge'],
};
</script>
```
```php:component/TwoChild.vue
<template>
  <form @submit.prevent="addText">
    <div>
      <label for="test">テキストを入力</label>
      <input type="text" name="test" id="test" v-model="inputText"/>
      <button @click="addInputText">表示</button>
    </div>
  </form>
</template>
<script>
export default{
    data(){
        return{
            inputText:null,
        }
    },
    methods:{
        addInputText(){
            this.$emit('input-text',this.inputText);
            this.inputText = '';
        }
    }
}
</script>
```
```php:ThreeChild.vue
<template>
    <li v-for="item in list" :key="item">{{item}}</li>
</template>
<script>
export default{
    props:['fuga'],
    data(){
        return{
            list:this.fuga,
        }
    }
};
</script>
```
実行結果はこちら。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2725725/71fee8cd-73ce-251e-160b-3a3586f4243d.png)


入力したテキストがリストとして表示されます。
momentを使って、今日の日付が自動的に表示されるようにしました。
【UIKit】iOS15でNavigationBarの色を変更する

# やり方
「Cocoa Touuch Class」を選択して「Next」を選択します。
![スクリーンショット 2022-07-09 16.39.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/5d6c5625-a427-45b1-4d15-1e77cd0c1820.png)

**Class**: 任意のクラス名を設定
**Subclass of**: `UINavigationController`を選択
![スクリーンショット 2022-07-09 16.40.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/33efb98b-0138-9e89-d048-44a1752bed97.png)

作成したクラスをStoryboardと紐付けます。
![スクリーンショット 2022-07-09 16.45.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/17e42906-0033-2bc3-877a-3c7460ac7056.png)


作成したファイルに以下の記述をします
```NavigationViewController.swift
import UIKit

class NavigationViewController: UINavigationController {

    override func viewDidLoad() {
        super.viewDidLoad()
        navigationBar.barTintColor = UIColor(red: 85/255, green: 197/255, blue: 3/255, alpha: 255/255)
        if #available(iOS 15.0, *) {
            let appearance = UINavigationBarAppearance()
            appearance.backgroundColor = .red
            UINavigationBar.appearance().standardAppearance = appearance
            UINavigationBar.appearance().compactAppearance = appearance
            UINavigationBar.appearance().scrollEdgeAppearance = appearance
        } else {
            navigationBar.barTintColor = .red
        }
    }

}
```


## デフォルトカラーにする
![Simulator Screen Shot - iPhone 12 - 2022-07-09 at 15.51.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/52d1583c-e9ad-ef5a-882f-65a268092b09.png)
```swift
appearance.configureWithDefaultBackground()
```

## 色を選択する
![Simulator Screen Shot - iPhone 12 - 2022-07-09 at 15.48.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/356d88c3-58ca-d0e5-b42c-470029eb381a.png)
```swift
appearance.backgroundColor = .red
```
pythonanywhereでbottleとlmdbを用いたウェブアプリのデプロイ方法

以下に方法を書き留めます。

python3.9のコンソールを1つ立ち上げて、
```sh
pip install --user lmdb
```

でlmdbのインストールが可能。
コンソールはそのまま立ち上げておく


pythonanywhereのwebappsから新しいサイトを作成。
python3.9のbottleを選択


pythonanywhereでアプリを動かす際は、
```sh
bottle.run()
```
の代わりに
```sh
application = bottle.default_app()
```
が必要。
(wsgiを用いて.pyを動かしているため。)
ない場合は書き込む（置換）。

また、ユーザ名_pythonanywhere_com_wsgi.pyの、
```sh
project_home =
```
と
```sh
templates_dir = 
```

も書き換えが必要
STM32G031と温度センサーS-8120Cで温度をシリアル出力(整数)


x PA2をGPIOにがわかる人むけ

目的
安価に温度を測る。

v = -8.2 * t + 1705

式の変形

t = (v - 1705.0) / -8.2;

t = DIV082( (1705 - v) );


![o_con569.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/a6dd5602-944f-e8b5-8e92-783bed220c4c.jpeg)


![o_con570.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/1cfcf38d-16b5-22b0-1857-1b16e40d2730.jpeg)



```c++



//SER_S-8120C_DEC_031_1

//0.82で割る 0から400までは、正しい
#define DIV082(n) ((n*4996)>>12)

#include <Arduino.h>

//初期化処理
void setup()
{

  delay(3000); //not delete

  //シリアルの初期化
  Serial.setTx(PA2_ALT1);
  Serial.setHalfDuplex();
  Serial.begin(9600);

} //setup

//メインループ
void loop()
{

  //センサーの値を読み込む
  analogReadResolution(12); // ADC 12bit mode
  int s = analogRead(A9);   // PB7  PIN1 031 センサーの読み取り値

  //センサーのADC値を電圧に変換
  int v = (s * 3300) >> 12;

  //センサーの電圧を温度に変換
  // v = -8.2 * t + 1705  =>  t = (v - 1705.0) / -8.2;
  // => t = (1705 - v) / 0.82
  int t = DIV082( (1705 - v) );

  //温度の表示
  Serial.print(t / 10);
  Serial.print('.');
  Serial.print(t % 10);
  Serial.println();

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

} //loop




```

https://paiza.io/ja/projects/new?language=c


テストプログラム


```c++



//0.82で割る 0から400までは、正しい
#define DIV082(n) ((n*4996)>>12)

#include <stdio.h>
int main(void){
    
    int s;
    float v;
    float t;

    int i_v;
    int i_t;
    
    for(int ii=1900;ii<=1915;ii++){
        printf("[%d]= ",ii);
        
        s = ii;
        
        v = s * (3300.0 / 4096);
        
        printf("V[%f]= ",v);
        
        t = (v - 1705.0) / -8.2;
        
        printf("T[%f]= ", t );

        i_v = (s * 3300) >> 12;

        printf("T[%d]= ", i_v );
        
        i_t = DIV082( (1705 - i_v) );
        
        printf("T[%d]= ", i_t );
        
        //printf("[%d]= ",DIV082(ii) );
        
        //printf("[%d]= ",(ii*4996) >>12 );

        
        printf("\r\n");
    }
    
}



```
クラスとインスタンスとオブジェクト

## 概要

概念的で抽象的な物が苦手なので、これを機にまとめようと思います
説明するのはRubyですけど、どの言語において共通して使える考え方だと思います

### オブジェクトとは
そもそもオブジェクトとはなんだろう
Rubyの世界は全てのものがオブジェクトになります
配列ハッシュ以外にもnilもオブジェクトに当たります
つまり全部オブジェクトです
ただ抽象的すぎて分からないですよね
なのでたこ焼きで考えましょう
たこ焼きは紅生姜や青さ、鰹節、マヨネーズ、油、たこ、たこ焼き粉などの材料から作られています
つまりこれら全部がオブジェクトになります

### クラスとは
次にクラスとはどのようなものでしょうか？
こちらはオブジェクトを作るための設計書になります
簡単に示すと型です
こちらもたこ焼きで表すと分かりやすいです
1個ずつたこ焼きを作っていたらお客さんが怒ってしまいますので、一気にたくさん作りたいと思ったたこ焼き屋さんの店長さんはたこ焼き器を作りました
こうすることで一気に焼けてお客様を待たせることなく提供できます
またたこ焼き器を作ったことで、具材にチョコを入れたデザートたこ焼きなども作ることができて様々な要望に対応することもできて一石二鳥です
このたこ焼き器がプログラミングのクラスになります
クラスを作ることで、型がある為簡単にものを作れるようになり、応用もできるというわけです
### インスタンスとは
インスタンスはクラスによって生成されたオブジェクトです
つまりたこ焼き器からできたたこ焼き本体になります


では早速これらを生かしてRubyのコードで見ていきましょう

```
class Takoyaki
  def delicious
　　　　　　　puts　"たこ焼きは美味しいよ！！"
  end

  def　oomoji
    takoyaki = "Takoyaki"
    takoyaki.upcase
  end
end

Takoyaki.new.delicious　# => たこ焼き美味しいよ！！
Takoyaki.new.oomoji#=> "TAKOYAKI"

```
Takoyakiクラスを作りました
Takoyaki.newでインスタンスを作れます
deliciousとoomojiメソッドはどちらもインスタンスメソッドですのでインスタンスを作ってその上にメソッドをつけます
## 最後に
この記事で少しでも概念的なものを理解できたらいいなって思います
DataBinding-ktx導入時の注意点

# はじめに
皆さんご存知、wada811さんが作成されている、[DataBinding-ktx](https://github.com/wada811/DataBinding-ktx)ですが、非常に便利ですよね。
私もDataBindingでの実装の際はできる限り使用しているのですが、導入時にいつも通りimplementationを追加するだけだとビルドエラーとなってしまいます。
こちらちょっとした調整が必要なのですが、忘れてしまいそうなので、簡単にまとめておこうと思います。

# 調整内容

まず、以下を変わらず追加します。

```
implementation 'com.github.wada811:DataBinding-ktx:6.1.0'
```
バージョンは最新を使用いただいていいと思います。

次に同じくapplicationレベルのgradleに以下を追加します。
```
android {
    buildFeatures {
        dataBinding = true
    }
}
```

最後に、setting.gradleに以下コメント部分を追加します。
```
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        // 追加
        maven { url "https://jitpack.io" }
    }
}
```

以上になります。

# さいごに
こういう設定をうっかり忘れていると、意外とハマったりしますよね。
ちなみにallprojectsをprojectレベルのgradleに追加して対応しても解決できるかと思います。
こういった忘れる事で発生するコストをなるべく少なくしていく為に、どんどん記事にしておこうと思います。
Rubyのハッシュのキーについて

私はJavaScript歴4年のところから、最近になってRubyを書き始めたのですが、[こちらの記事](https://qiita.com/beeytnh/items/b2bef53b680cb3741a80)に関連して、JavaScriptでは `{}` の定義において以下のサンプルの両者の違いをあまり意識しなくてもそこまで問題にはならないと分かったのですが、Rubyだとまた違った記法があり、各々の違いを全然理解できていなかったので改めて調べてみました。

```jsx
const sample1 = {
  id: 1,
  name: "name"
};
const sample2 = {
  "id": 2,
  "name": "name"
};
```

まず、上記サンプルをRubyで定義すると以下のようになります。

```ruby
sample1 = {
  id: 1,
  name: 'name'
}
sample2 = {
  'id': 1,
  'name': 'name'
}
```

この場合、sample1とsample2に違いはなくキーはSymbolと呼ばれるオブジェクトになり、`sample1[:id]` や `sample2[:name]` のようにプロパティを取り出します。

また、Rubyだと以下のように書くこともできます。

```ruby
sample1 = {
  :id => 1,
  :name => 'name'
}
sample2 = {
  'id' => 1,
  'name' => 'name'
}
```

この場合、sample1とsample2では意味が違ってきます。
違いとしてまずわかりやすいところだとプロパティの取り出し方が異なります。
sample1の場合は `sample1[:id]` となりますが、sample2の場合は `sample2['id']` となります。
この違いが生まれる理由としては、sample1はSymbol、sample2はStringだからです。
※知らないで使っていると取り出すことすらできなくてハマることになります。。


Symbolが何かというところだと、公式ドキュメントでは以下のように記載があります。

> Rubyの内部実装では、メソッド名や変数名、定数名、クラス名などの'名前'を整数で管理しています。これは名前を直接文字列として処理するよりも速度面で有利だからです。そしてその整数をRubyのコード上で表現したものがシンボルです。
> シンボルは、ソース上では文字列のように見え、内部では整数として扱われる、両者を仲立ちするような存在です。
> 名前を管理するという役割上、シンボルと文字列は一対一に対応します。また、文字列と違い、immutable (変更不可)であり、同値ならば必ず同一です。


Ref: [https://docs.ruby-lang.org/ja/latest/class/Symbol.html](https://docs.ruby-lang.org/ja/latest/class/Symbol.html#:~:text=Ruby%E3%81%AE%E5%86%85%E9%83%A8%E5%AE%9F%E8%A3%85%E3%81%A7%E3%81%AF,%E3%81%97%E3%81%9F%E3%82%82%E3%81%AE%E3%81%8C%E3%82%B7%E3%83%B3%E3%83%9C%E3%83%AB%E3%81%A7%E3%81%99%E3%80%82)

つまりSymbolで定義した場合immutableとなり、Stringで定義するより高速に処理することができるということのようです。
言語ごとに違いをきちんと意識しないと思わぬところで嵌ってしまうという教訓でした。
pythonの文字列操作

python3を久しぶりに使ったらかなり忘れていたので、よく使うコードをメモとして残します。

# 文字コード変換

|目的|コード|結果|
|:--|:--|:--|
|1文字を、10進数に変換|ord('a')<br>ord('あ')|97<br>12354|
|10進数を、1文字に変換|chr(97)<br>ord(12354)|'a'<br>'あ'|

# 文字列-数値変換、数値判定

|目的|コード|結果|備考|
|:--|:--|:--|:--|
|数値を、10進数で書かれた文字に変換|str(97)|'97'||
|数値を、16進数で書かれた文字に変換|hex(97)|'0x61'|0xが追加される|
|数値を、2進数で書かれた文字に変換|bin(97)|'0b1100001'|0bが追加される|
|10進数で書かれた文字を、数値に変換|int('97')|97||
|16進数で書かれた文字を、数値に変換|int('61',16)<br>eval('0x61')|97<br>97|<br>evalで式を評価する|
|16進数で書かれた文字を、数値に変換|int('1100001',2)<br>eval('0b1100001')|97<br>97|<br>evalで式を評価する|
|文字列が10進数で書かれているか判定|'123'.isdigit()<br>'４５６'.isdigit()<br>'78.9'.isdigit()<br>'-123'.isdigit()|True<br>True<br>False<br>False|<br>全角でも判定可能<br>少数は判定不能<br>マイナスは判定不能|

文字列をint型に代入できるか判定するだけなら、try ～ except を使ったほうが楽だと思います。

```python:
try:
    data = int(input())
except:
    data = 0
```

# 文字列の長さ

|目的|コード|結果|備考|
|:--|:--|:--|:--|
|文字列の長さを調べる|len('abcdefg')<br>len('あいうえお')|7<br>5|半角も全角も1文字としてカウントする|

# 文字列の切り出し

|切り出す部分|コード|結果|
|:--|:--|:--|
|前n文字分|'abcdefg'[:3]|'abc'|
|後ろn文字分|'abcdefg'[-3:]|'efg'|
|前n文字目より後ろ|'abcdefg'[3:]|'defg'|
|後ろn文字目より前|'abcdefg'[:-3]|'abcd'|
|前n文字目からm文字目まで|'abcdefg'[3:5]|'de'|

# 大文字-小文字変換、文字判定

|目的|コード|結果|
|:--|:--|:--|
|小文字を大文字にする|'abcdefg'.upper()|'ABCDEFG'|
|大文字を小文字にする|'ABCDEFG'.lower()|'abcdefg'|
|全て小文字か判定する|'abcdefg'.islower()|True|
|全て大文字か判定する|'abcdefg'.isupper()|False|

# 半角-全角変換

英数字は半角に、日本語は全角に変換にする

```python:
import unicodedata
unicodedata.normalize('NFKC','１２ＡＢ34cdあいｳｴ')

'12AB34cdあいウエ'
```

# 文字列検索、置換、分割

|目的|コード|結果|備考|
|:--|:--|:--|:--|
|対象とする文字列が存在するか判定|'cd' in 'abcdefg'|True||
|対象とする文字列の位置を求める|'abcdefg'.find('cd')<br>'abcdefg'.find('hi')|2<br>-1|一番左の文字位置を返す<br>ない場合は-1を返す|
|対象とする文字を置き換える|'abc def ghi'.replace(' ','_')|'abcd_def_ghi'||
|文字列を区切り文字で分割する|'ab,cd,ef'.split(',')<br>'abcdef'.split('cd')|['ab','cd','ef']<br>['ab','ef']|<br>区切り文字は2文字でも可能|
|文字列を複数の区切り文字で分割する|re.split('[,:]','ab,cd:ef')|['ab','cd','ef']|正規表現モジュール(re)を使う|

# 空白処理

|目的|コード|結果|備考|
|:--|:--|:--|:--|
|前後の空白を削除する|'  abcd  efg  '.strip()|'abcd  efg'|文字列の中にある空白は消えない|
まだgit add -A使ってるの?　GUI使いなよ。

# はじめに
先日、先輩エンジニアとペアプログラミングをしている時のことでした。
普段と変わりなく、軽快にターミナルに入力するgit add -A。

ここで先輩エンジニアから一言。
**「まだgit add -A使ってるの？」**

これを機にGUIを使うようにしたのですが、色々と便利だったので紹介します。
特に、僕のようにプログラミングスクールでGitを学んできた方には参考になるかと思います。


|  目次  |
| ---- |
|  [1.GUIってなんなんだ](#1-guiってなんなんだ)  |
|  [2.実際にGitをGUIで操作してみた](#2-実際にgitをguiで操作してみた)  |
|  [3.GitでGUIを使うメリット](#3-gitでguiを使うメリット)  |
|  [4.おわりに](#4-おわりに)  |




# 1. GUIってなんなんだ
僕の場合、まず、GUIってなんなんだ、ってところからのスタートでした。
[ITトレンド](https://it-trend.jp/words/gui#:~:text=GUI%E3%81%A8%E3%81%AF%E3%80%81%E3%82%B0%E3%83%A9%E3%83%95%E3%82%A3%E3%82%AB%E3%83%AB%E3%83%A6%E3%83%BC%E3%82%B6,%E6%93%8D%E4%BD%9C%E3%81%A7%E3%81%8D%E3%82%8B%E3%81%AE%E3%81%8C%E7%89%B9%E9%95%B7%E3%80%82)では、以下のように説明されています。

>GUIとは、グラフィカルユーザインターフェース(Graphical User Interface)の略語。
コンピュータへ出す命令や指示等を、ユーザが画面上で視覚的に捉えて行動を指定できるもので、それまで主流であった命令文を入力して実行する方式(CUI)に比べ、直感的に操作できるのが特長。

これを咀嚼すると、コマンド入力ではなく、ボタンやアイコンの操作で直感的にコンピューターへ指示や命令を出すインターフェイスであるという意味合いになります。

# 2. 実際にGitをGUIで操作してみた
早速、GitをGUIで操作してみました。
僕はGitの公式インストーラーに含まれている[Git GUI](https://git-scm.com/book/ja/v2/%E4%BB%98%E9%8C%B2-A%3A-%E3%81%9D%E3%81%AE%E4%BB%96%E3%81%AE%E7%92%B0%E5%A2%83%E3%81%A7%E3%81%AEGit-%E3%82%B0%E3%83%A9%E3%83%95%E3%82%A3%E3%82%AB%E3%83%AB%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%95%E3%82%A7%E3%83%BC%E3%82%B9)を使っています。
他にも様々なGUIクライアントがあるようなので、興味のある方は[こちら](https://git-scm.com/downloads/guis/)。

## Git Guiを使う準備
Git GUIを使用するには、下記のどちらかを行います。
* [公式ページ](https://git-scm.com/downloads)からインストーラーをダウンロード
* ターミナルで下記のコマンドを実行する
```
brew install git git-gui
```
これでGit GUIを使う準備は整いました。

## Git GUIでコミットしてみる
では、Git GUIを起動してコミットしてみましょう。
これまで入力していたgit add -Aを次のコマンドに置き換えます。
```
git gui
```
すると、以下のような画面に遷移します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729568/61351d0d-f072-331b-f79e-c93dfef968d7.png)


変更をコミットするための手順は、
①「コミット予定に入っていない変更」の差分を確認し、コミット予定に入れていく。
②「コミットメッセージ」を入力し、「コミット」を押す。
③「プッシュ」を押して別タブを開き、プッシュ先のブランチを確認する。
④問題なければ「プッシュ」。コミット成功！

コマンドを入力せずとも、これだけでコミットができてしまうんですね。。
# 3. GitでGUIを使うメリット
それでは、GUIを使うメリットを挙げていきましょう。
## 1. 差分がわかりやすい
削除した要素は赤で、追加した要素は緑で表示されます。
これはVSCodeでも表示されますけどね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729568/8f8797b4-1f7f-9462-b7e5-9f006298c517.png)

## 2. 必要な差分だけを簡単にコミット
コードを変更したけれども、全部はコミットしたくない、
そんな要望に応えてくれます。
git add -Aだと不要なファイルまでコミットに入れてしまいますから。。

## 3. 各種ミスが起こりにくい
* ブランチの選択ミス
* コマンド入力のタイポ

あたりがなくなるので、より正確にスピーディーにコミットできると思います。

# 4. おわりに
先輩エンジニア曰く、
**「初心者はgitをコマンドで扱うべきでない！」**
とのことでした。

その理由は、**余計な差分をコミットすることを防ぐため**だったり、
**誤操作によるファイル等の削除を防ぐため**なのかなと思いました。

しかし、コマンド入力にはできて、GUIではできないといったこともあるので、
用途に応じて切り替えることが必要であると感じました。
JavaScriptのオブジェクトのキーのクォート有無

JavaScriptでオブジェクトは以下のように定義すると思います。

```jsx
// 例1
const sample = {
  id: 1,
  name: "name"
};
```

しかしながら、以下のような定義も見るかと思います。

```jsx
// 例2
const sample = {
  "id": 1,
  "name": "name"
};
```

例2の定義ではキーをクォート（” or ‘）で囲っているのですが、例1では囲っていません。
恥ずかしながら、これまで何となくで使っていて違いをきちんと意識できていなかったので改めて調べてみました。

結論、例1と例2の違いはオブジェクトかJSONかの違いでした。
オブジェクトの定義においてクォートで囲んでも囲まなくても問題はないのですが、囲まないことが基本ルール(※)となっています。一方でJSONを定義する際はダブルクォートでキーを囲むのがルールになっています。
Ref: [https://prettier.io/docs/en/options.html#quote-props](https://prettier.io/docs/en/options.html#quote-props)

※基本ルールと書いたのは例外があるからで、例えば以下のような場合はクォートで囲むそうです。

```jsx
const sample = {
  "strange key": "value"
}
```
Ref: [https://google.github.io/styleguide/javascriptguide.xml#Array_and_Object_literals](https://google.github.io/styleguide/javascriptguide.xml#Array_and_Object_literals)

JSON.stringify()とJSON.parse()を使ってみると違いが如実にわかるかと思います。
※JSON.stringify()はJavaScriptのオブジェクトをJSONに変換する関数で、JSON.parse()はJSONをJavaScriptのオブジェクトに変換する関数です。

```jsx
const sample = {
  id: 1,
  name: "name"
};

console.log(JSON.stringify(sample));  // {"id": 1, "name": "name"}
console.log(JSON.parse(sample)); // {id: 1, name: "name"}
```
Octave で独立性の検定

# Octave で独立性の検定

分割表（二重クロス集計表）を与えて，2 変数の独立性の検定を行う。元データからカイ二乗検定を行う場合には `crosstab()` を使うことができる。

    usage:
    [pval, chisq, df] = chisquare_test_independence (x)
    
    x は分割表（二重クロス集計表）
    戻り値を指定しない場合は p 値のみを表示する
    戻り値を指定した場合は，後で変数を使用すること（表示するなど）ができる



```matlab
pkg load statistics   % statistics が必要
format long           % 表示精度を高くする（任意）
```


```matlab
x = [2 4 9
     8 1 1];
```

戻り値を変数に代入しない場合には $p$ 値のみが表示される。


```matlab
chisquare_test_independence(x);
```

      pval: 0.00360656


戻り値を変数に代入すれば結果を自由に表示できる。


```matlab
[pval, chisq, df] = chisquare_test_independence(x);
printf("chisq = %.5g,  df = %d,  p value = %.5g\n", chisq, df, pval)
```

    chisq = 11.25,  df = 2,  p value = 0.0036066


$2 \times 2$ 分割表の場合には，連続性の補正（イェーツの補正）をしない結果が表示される（連続性の補正をするオプションはない）。


```matlab
t = [1 2; 3 4];
[pval, chisq, df] = chisquare_test_independence(t);
printf("chisq = %.5g,  df = %d,  p value = %.5g\n", chisq, df, pval)
```

    chisq = 0.079365,  df = 1,  p value = 0.77816
twitterAPIで自動ツイートをしたい

### APIキーを取得
[やり方](https://di-acc2.com/system/rpa/9688/)
callback url は　`http://127.0.0.1:3000/oauth/callback`
### gem
公式の[developer platform](https://developer.twitter.com/en/docs/twitter-api/tools-and-libraries/v2)に[sample code](https://github.com/twitterdev/Twitter-API-v2-sample-code)があったのでそれに則っていく
```
gem install typhoeus
```
httpクライアントとして使用
```
gem install oauth
```
APIキーの認証に使う
```
gem install dotenv
```
今回自分はDockerを使用したので、環境変数を渡すのに便利な'dotenv'も使用しました

### コーディング
ファイルの作成
```
touch tweet.rb
```
ほぼコピペでいいのですが、sample codeのままだと毎回実行するたびにアクセストークンの発行をしてしまうので、ruby標準ライブラリの`pstore`を使って保存していきます
```
# require 'dotenv'
require 'pstore'
require 'oauth'
require 'json'
require 'typhoeus'
require 'oauth/request_proxy/typhoeus_request'
 
# キーは環境変数から
consumer_key = ENV['CONSUMER_KEY']
consumer_secret = ENV['CONSUMER_SECRET']

create_tweet_url = "https://api.twitter.com/2/tweets"

db = PStore.new("/tmp/access_token")

# これがツイートの内容
@json_payload = {"text": "Hello world!"}
 
consumer = OAuth::Consumer.new(consumer_key, consumer_secret,
 :site => 'https://api.twitter.com',
 :authorize_path => '/oauth/authenticate',
 :debug_output => false)
 
def get_request_token(consumer)
 
 request_token = consumer.get_request_token()
 
 return request_token
end
 
def get_user_authorization(request_token)
 puts "Follow this URL to have a user authorize your app: #{request_token.authorize_url()}"
 puts "Enter PIN: "
 pin = gets.strip
 
 return pin
end
 
def obtain_access_token(consumer, request_token, pin)
 token = request_token.token
 token_secret = request_token.secret
 hash = { :oauth_token => token, :oauth_token_secret => token_secret }
 request_token = OAuth::RequestToken.from_hash(consumer, hash)
 # Get access token
 access_token = request_token.get_access_token({:oauth_verifier => pin})
 return access_token
end
 
 
def create_tweet(url, oauth_params)
 options = {
 :method => :post,
 headers: {
 "User-Agent": "v2CreateTweetRuby",
 "content-type": "application/json"
 },
 body: JSON.dump(@json_payload)
 }
 request = Typhoeus::Request.new(url, options)
 oauth_helper = OAuth::Client::Helper.new(request, oauth_params.merge(:request_uri => url))
 request.options[:headers].merge!({"Authorization" => oauth_helper.header}) # Signs the request
 response = request.run
 
 return response
end
 
 
 
def run_oauth(consumer)
 request_token = get_request_token(consumer)
 pin = get_user_authorization(request_token)
 access_token = obtain_access_token(consumer, request_token, pin)
end


db.transaction do 
  unless access_token = db["token"]
    access_token = run_oauth(consumer)
    db["token"] = access_token
  end
  oauth_params = {:consumer => consumer, :token => access_token}
  response = create_tweet(create_tweet_url, oauth_params)
  puts response.code, JSON.pretty_generate(JSON.parse(response.body))
end
```
ツイートのパラメータについては
[Post, retrieve, and engage with Tweets](https://developer.twitter.com/en/docs/twitter-api/tweets/manage-tweets/api-reference/post-tweets)

## 実行
ターミナルから
```
ruby tweet.rb
```
初実行時のみ、URLの表示とPINを入力しろと出る。
URLにアクセスし、認証すると出てくる７けたの数字を入力してEnter
二回目以降は、pin入力なしで実行できる。
ただし、同じ内容のツイートは連投できないので、ツイート内容は変更しなければならない
VSCodeのCodeHelperのCPU使用率が異様に高いときの対処法

ここ最近MacBookProでVSCodeを開くだけで`Code Helper`がCPUをかなり使い、コードを書くのもカクカクで仕事にならない状態になりました。
ネットで情報を探ったところ、Macで`Code Helper`がCPUを使いすぎる問題はよくあるようです。
そこで今回はVSCodeが重いときの原因特定方法、解決手段を共有します。

# 原因の種別を特定する
まずはターミナルで以下のコマンドを入力します。
`code --status`

すると以下のようにVSCodeがどこでCPUやメモリを使っているか表示されます。
```
（一部省略）
CPU %	Mem MB	   PID	Process
    0	   164	  8402	code main
    0	    66	  8405	   gpu-process
    0	    33	  8411	   utility-network-service
    0	   360	  8412	   window (xxx)
   72	   197	  8420	   extensionHost
```

`extensionHost`のCPU使用率がぶっちぎりなので、どうやら今回は拡張機能が原因のようです。

# 具体的な原因箇所を特定する
それでは拡張機能に原因があるとわかったところで、どの拡張機能が原因なのか特定していきます。

VSCodeには不具合の原因の拡張機能を特定する`Extension Bisect`という機能があります。
拡張機能の画面から`Start Extension Bisect`をクリックしましょう。
![スクリーンショット 2022-07-07 17.19.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316688/d0b689cb-f93b-dd46-657b-dcec83fd5b80.png)
するとこのように、VSCodeがインストールされている拡張機能のオンオフを切り替えながら、PCの状態が良好であるか聞いてくれます。
CPU使用率が低くなれば`Good now`を、高いままなら`This is bad`をクリックしましょう。
これを続けることで、2分探索の要領で原因の拡張機能を特定してくれます。
手動でオンオフを繰り返して検証するのは手間なので素晴らしい機能ですね。
![スクリーンショット 2022-07-07 17.23.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316688/72b732b5-b051-36b9-694d-e646318a078c.png)
私の場合は`Settings Sync`という拡張機能が原因で、これをオフにするとCPU使用率が落ち着きました。

# おまけ
ちなみに、`CodeHelper CPU`等でググると、
>VSCodeの監視対象ファイルが多すぎるのが原因

といった記事も出てきます。
その場合はおそらくですが、`window`のような`code main`に属するプロセスのCPU使用率が高くなっているかと思います。
しかしながら、[VSCodeのパフォーマンス問題解決に関するwiki](https://github.com/microsoft/vscode/wiki/Performance-Issues)では
>High CPU consumption is often caused by an issue in an extension.

と書かれています。
VSCode本体じゃなくて、拡張機能が原因だと初めから疑ってかかるべきだそうです。
さすがは天下のMS。すごい自信ですね。
ですが実際に拡張機能が原因であり、しかもその原因を特定するための機能まで用意されているあたり、VSCodeの品質と便利さ、そしてMSの強い自信を再認識できました。
HTTPのリダイレクト関係のステータスコードについて整理する

HTTPでリダイレクトさせるための応答ステータスコードにはたくさん種類がある。適切な使い分けができるように整理する。

結論から言うとリダイレクト関係のステータスコードは以下のように2つの軸のマトリクスとして整理できる。

||元のメソッドを維持する|GETメソッドに変更する|メソッドの変更をするかどうか曖昧|
|-|-|-|-|
|恒久的|308 Permanent Redirect||301 Moved Permanently|
|一時的|307 Temporary Redirect|303 See Other|302 Found|

以下では縦と横それぞれの軸について解説する。

# 恒久的か一時的か
恒久的なリダイレクトは将来の同じURLに対するリクエストを、そのURLへのリクエストをスキップしてリダイレクト先URLに直接リクエストを送る可能性がある。一方で一時的なリダイレクトはそのようなことはせず、毎回元のURLにアクセスしてからその応答をみて挙動を決める。よって恒久的リダイレクトはサイトの改修などでページのURLが変わった場合に、一時的リダイレクトはフォーム等のPOST後に投稿完了画面へ移動させる場合等に使う。

# メソッドの変更をするかしないか
リダイレクト先のURLにリクエストを送るときに元のリクエストのメソッドを維持するものと、元のリクエストのメソッドを無視してGETでリクエストするもの、そしてどちらになるか曖昧なものがある。元のリクエストのメソッドを無視するものは、例えばフォームの投稿をPOSTメソッドでしたときに投稿完了画面へのリダイレクトをGETで行って欲しいと言う場合に使う。曖昧なものはHTTP規格上は変更しないことになっているがこれに準拠せずGETでリダイレクト先にアクセスするエージェントが存在するというもの。よって曖昧なものは元がGETリクエストである場合以外使うべきではない。

# あとがき
メソッドの変更をするかどうか曖昧な`301 Moved Permanently`と`302 Found`はもう使わないとしてしまって良い気がする。個人的にはこれからは挙動が明確な`303 See Other`、`307 Temporary Redirect`、`308 Permanent Redirect`のみを使うようにしたい。恒久的でGETメソッドに変更する場合がないが、そもそもそのような挙動が求められる状況が思いつかないので存在しないってことかな。
Bind9で自前DNSサーバを建ててみる

Bind9を使ってDNSサーバを建ててみました。その時のメモを残します。
（実際サーバを立ててみると、うまくいかない時もあったので、参考程度と思って読んでください）

# Bind9のインストール

Bind9をインストールするには、下のコマンドを使います。

```
$ sudo apt install bind9
```

インストールが正常に終わったことの確認も含め、バージョン確認を行います。

```
$ named -v
BIND 9.18.1-1ubuntu1.1-Ubuntu (Stable Release) <id:>
```

# ゾーンの登録

自分が管理しているゾーン`test.com`を登録するために、下記の設定を`/etc/bin/named.conf.default-zones`に追記します。これはゾーン`test.com`の問い合わせが来た時に`/etc/bind.test.com`を見に行くという設定を追加するためのです。

```:"/etc/bin/named.conf.default-zones"の最後に追加する設定
zone "test.com" {
        type master;
        file "/etc/bind/test.com";
};
```

# サーバの登録

ゾーンファイル`test.com`の中にDNSサーバ`test.com`とWEBサーバ`www.test.com`を登録します。`/etc/bind/test.conf`を新規に作成し下記の設定を入れます。

```:"/etc/bind/test.com"を作成する
$TTL    604800
@       IN      SOA     test.com. root.test.com. (
                              2         ; Serial
                         604800         ; Refresh
                          86400         ; Retry
                        2419200         ; Expire
                         604800 )       ; Negative Cache TTL
;
@       IN      NS      test.com.
@       IN      A       192.168.100.100
www     IN      A       192.168.100.200
```

設定が正しいか下のコマンドで確認します。なお、正しい場合は何も出力されません。

```
$ named-checkconf
```

# 名前解決の確認を行う

下のコマンドでBind9を起動します。（設定ファイルを書き換えただけでは、起動中のサービスに反映されません）

```
$ sudo service named satrt
```

`nslookup`で名前解決を行います。

```
$ nslookup test.com
............
Name:   test.com
Address: 192.168.100.100
```

```
$ nslookup www.test.com
............
Name:   www.test.com
Address: 192.168.100.200
```

最後に自動起動する設定をします。

```
$ sudo systemctl enable named
```

# セキュリティ設定を行う

必要に応じて`/etc/bind/named.conf.options`の`options`内に下の設定を追加します。

### 問い合わせを受け付けるIPアドレスを指定する。

IPアドレス`192.168.100.0/24`からのクエリのみ許可します。

```
        allow-query { 192.168.100.0/24; };
```

### 再帰的問い合わせを受け付けるIPアドレスを指定する。

IPアドレス`192.168.100.0/24`からのクエリのみ許可します。今回は再帰問い合わせ先を`192.168.200.100`に指定しています。

```
        allow-recursion { 192.168.100.0/24; };
        forwarders {
                192.168.200.100;
        };
        dnssec-validation no;
        listen-on-v6 { any; };
```

`dnssec-validation`を`no`に、`listen-on-v6`も使えるようにしないと、forwarderが機能しませんでした。

### ゾーン転送先を指定する。

IPアドレス`192.168.200.100`へのみゾーン転送を可能にします。

```
        allow-transfer { 192.168.200.100; };
```

# おわりに

自分ではここに書いたことは間違いはないとは思っていますが、ミスを発見したら修正します。
【Django】アプリ別にurls.pyを分ける方法

Djangoで開発している時にアプリが多くなると、1つのurls.pyに各ルーティングを記載していくとコードが多くなってしまいます。

この改善策として、各アプリのディレクトリにurls.pyを配置し、アプリ内のルーティングは、対象ディレクトリ内のurls.pyを使用することでルーティングを整備することができます。

そのやり方を以下に記載します

## プロジェクトのurls.py

django-admin startprojectにて、作成された最初のurls.pyは、以下のように記載します

```python
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('myapp/', include('myapp.urls')),
]
```

from django.urls import pathにincludeを記載します

urlpatterns内には、startappコマンドで作成したアプリ名をincludeを使用して記載します。

この場合は、myapp以降のパスがmyapp/urls.pyに記載できるようになります。

## アプリ側のurls.py

django-admin startappにて作成されたディレクトリにurls.pyを作成します

そのurls.pyには、以下のように記載します

```python
from django.urls import path
from . import views

urlpatterns = [
  path('', views.index, name='index')
]
```

from . import viewsは、アプリ自体のviews.pyを指します。

urlpatternsの記載は、上記の場合は、http://localhost:8080/myapp/
にアクセスすると
myappのviews.pyのindex関数が実行されるようになります

以上、アプリ別のurls.pyの記載方法でした
VMware ゲストOS 時刻の同期無効化

デフォルトではサスペンドやvMotion、スナップショット作成などで自動的にゲストOSの時刻同期がされてしまうので、そのような操作をして意図しない時刻変更をされる前に、
ゲストOSとESXiの時刻同期を無効にしておいたほうが良いそうです。

【参考】
https://kb.vmware.com/s/article/1189?lang=ja

【仮想マシンの「設定の編集」から以下のパラメーターを追加】

tools.syncTime = "0"
time.synchronize.continue = "0"
time.synchronize.restore = "0"
time.synchronize.resume.disk = "0"
time.synchronize.shrink = "0"
time.synchronize.tools.startup = "0"
time.synchronize.tools.enable = "0"
time.synchronize.resume.host = "0"