OmniAICreator/Qiita-1.07M huggingface dataset:
かんたんSmoothScroll

## はじめに

久しぶりにHTMLを触った際に、
ボタンなどをクリックしたときのスーとスクロールする動きって、
Javascriptで作らないと（jQueryのライブラリとか使わないと）駄目だっけ・・・と思って検索したのが始まり。

## CSSで指定

CSSで指定できるようになっている。

```css:example.css
html {
  scroll-behavior: smooth;
}
```

これだけで同一ページ内リンクを踏めば、スーとスクロールしてくれる。便利。
ただ、一部、[サポートしていないブラウザ](https://developer.mozilla.org/ja/docs/Web/CSS/scroll-behavior#Browser_compatibility)で動作しない。

## そこにぴったりの便利パッケージ

https://github.com/wessberg/scroll-behavior-polyfill


Readmeにある通りですが、インストールして以下のコードを加えれば動きます。
（typescriptだからどうかなと思いましたがとりあえず動きました）

```ts
if (!("scrollBehavior" in document.documentElement.style)) {
    import("scroll-behavior-polyfill");
}
```

ただ、一つ欠点があり、このパッケージはスタイルシートに対応していないので、HTMLに直接書くなりが必要です。

Reactで作ってたので、tsxに書こうかと思ったところ、もちろん定義にないものなので怒られて、土台になってるHTMLの方に直接書きました。

```html
<html lang="ja" style="scroll-behavior: smooth">
```
ちょっとかっこ悪い

## 余談

作者の方が対応していない理由として貼られているリンク先で、
どういう仕組に対して拡張しないといけなくなり大変だよみたいなことが書かれており、全くしらない部分だったので勉強になりました。

で、興味が惹かれたのがHoudini。
実はこちらが本題でメモとして残そうと思った次第。

最初、3Dソフトのほうしか頭に浮かびませんでした。。

4年前のデモのサンプル。
https://github.com/GoogleChromeLabs/houdini-samples

Houdini Task Force?
https://github.com/w3c/css-houdini-drafts/wiki

仕様自体はドラフトみたいですが、ものになったらちょっとおもしろそうですね。
一部はChromeに実装されてるようなので、今度触ってみたいと思います。

### 追記

ちゃんとした内容解説。サンプルもあって、内容後で読みたい。
https://www.kabuku.co.jp/developers/a-small-taste-of-css-houdini
Windowにやさしいバッチで大量の連番フォルダ作るよ！（連番100～999）

```
@echo off
 
set /p filename="フォルダ名を入力してください："
set /p number="フォルダ数を入力してください："
 
setlocal enabledelayedexpansion
 
for /l %%n in (1,1,%number%) do (
  set num=%%n

  mkdir %filename%_!num!
)
 
endlocal
```

あとはお好みで
保存してbatファイルにしてcmdから実行ドーン✌
SwiftUIでキーボードを下げる（非表示にする）方法

まず、下記の拡張を実装しておきます。
新しいファイル作って保存しておくと良いと思います。

```UIApplication+ext.swift
extension UIApplication {
    func endEditing() {
        sendAction(
            #selector(UIResponder.resignFirstResponder),
            to: nil,
            from: nil,
            for: nil
        )
    }
}
```

あとは、キーボードを下げたいところで呼び出して使うだけです。

```ContentView.swift
struct ContentView : View {
    var body: some View {
        Button(action: {
            // ここでキーボードを下げる
            UIApplication.shared.endEditing()
        }) {
            Image(systemName: "keyboard.chevron.compact.down")
        }
    }
}
```
SFアイコンを使ってキーボードを下げるボタンを実装してみた例になります。

## 参考
https://stackoverflow.com/questions/56491386/how-to-hide-keyboard-when-using-swiftui
色々なfizz_buzz(逐次追記)


##if文
```ruby:fizz_buzz.rb
def fizz_buzz(n)
  if n % 15 == 0
    "fizz_buzz"
  elsif n % 3 == 0
    "fizz"
  elsif n % 5 == 0
    "buzz"
  else
    n.to_s
  end
end

int = [*1..100]
int.each do |n|
  puts fizz_buzz(n)
end
#もしくは下記でもOK
#(1..100).each do |n|
#  puts fizz_buzz(n)
#end
```
```ruby:fizz_buzz.rb
def fizz_buzz
  int = [*1..100]
  int.each do |n|
    if n % 15 == 0
      puts "fizz_buzz"
    elsif n % 3 == 0
      puts "fizz"
    elsif n % 5 == 0
      puts "buzz"
    else
      puts n.to_s
    end
  end
end

fizz_buzz
```

##case文
```ruby:fizz_buzz.rb
def fizz_buzz(n)
  case 0
  when n % 15
    "fizz_buzz"
  when n % 3
    "fizz"
  when n % 5
    "buzz"
  else
    n.to_s
  end
end

int = [*1..100]
int.each do |n|
  puts fizz_buzz(n)
end
```
Envoyで試すL7での経路制御

# Envoyとは

Lyft社が開発しているHTTP/2に対応しているモダンなL7プロキシです。CNCF Graduatedなプロジェクトで、既に多くの企業での採用事例もあります。マイクロサービス基盤におけるService MeshでSideCarとして使われる事が多く、SDやCircuit Breakerといった機能も備わっています。あくまでプロキシなので、静的ファイルの配信といった目的には使われません。

https://www.envoyproxy.io/docs/envoy/latest/intro/intro


# HTTP Filters

Envoyに備わっている機能の一つで、HTTPなIngress/Egressに付加されている情報を動的に書き換えたりする機能があります。この機能を用いることで、Headerに記述されているメタな情報を動的に書き換えて色々なことが出来ます。例えばJWTの検証とか、Fault Injectionとか。また、Luaを用いてプログラマブルな制御も可能です。Worker Thread単位でLuaJITを起動しています。

https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/http_filters#config-http-filters

# やりたいこと

HTTP Filterを使って動的にヘッダを書き換え、Kubernetes上の同一Pod内での経路制御を行うことです。HTTP/2では、コロンから始まるヘッダフィールドが実装されていて、このヘッダフィールドの中に`:path`ヘッダが含まれるようになっています。このフィールドの値をLuaで動的に書き換えたいという話ですね。

https://greenbytes.de/tech/webdav/draft-ietf-httpbis-http2-09.html#HttpRequest

この`:path`ヘッダの値を、Header内に定義されているユーザーに対して一意に割り振られている情報を参照しつつ書き換えます。これは、ユーザーの値に応じて疎通先を変えたいA/Bテストやカナリアリリースのような事にも応用可能です。この方法が正しいかどうかはよくわかりませんが。

# 実装
<img width="526" alt="Screen Shot 2019-10-03 at 23.36.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163803/93e6a8b1-4584-282f-1f55-b6148362ad97.png">

構成図は上のような感じで、Goで書かれたGreen, Blueのアプリケーションに対して、Envoyでヘッダに書かれたユーザーIDを参照しつつ、Luaを用いて経路制御を行うといったものになります。Redisはセッションストアとしてしか用いていません。

全体の実装はここに置いてます。

https://github.com/Shikugawa/envoy-http-filter-ab-testing

```
http_filters:
  - name: envoy.lua
    typed_config:
      "@type": type.googleapis.com/envoy.config.filter.http.lua.v2.Lua
      inline_code: |
        function envoy_on_request(request_handle)
          local mod = request_handle:headers():get("x-user-id-mod")
          local current_post = request_handle:headers():get(":path")
          if mod == 0 then
            local replaced_post = "/green" .. current_post
            request_handle:headers():replace(":path", replaced_post)
          else
            local replaced_post = "/blue" .. current_post
            request_handle:headers():replace(":path", replaced_post) 
          end
        end
```

実装は上みたいな感じで、`x-user-id-mod`というカスタムヘッダに、ユーザーIDの剰余が設定されていて、その値に応じてアクセスを振り分けるといったものになっています。剰余の取り方や、経路制御の条件をより細かく設定すれば、より細かい制御も可能だと思います。

# 総括
工夫すればこのような事もEnvoyでできますし、アプリケーション側から煩わしいネットワーク周りの処理も削減することができそうな機能です。ただ、この実装はあまりエレガントではない気がするので、もっとキレイに書けたら良さそうです。[^1]

[^1]: 一応Issueだけ立てた https://github.com/envoyproxy/envoy/issues/8316
【Tips】WSLのgcloud initはGUIが使える

# 概要
表題の通り。
Google Cloud Platform 用のCLIアプリ`gcloud`はWSL上のLinuxにインストールできるが、（少なくともUbuntuでは）Windows上のブラウザでアクセスできるURLが表示され、ブラウザから認証ができた。

# 環境
- Windows 10 Home 1903
- Windows Subsytem for Linux
    * Ubuntu 18.04 LTS

# 実行
## 入力
```sh
export CLOUD_SDK_REPO="cloud-sdk-$(lsb_release -c -s)"
echo "deb http://packages.cloud.google.com/apt $CLOUD_SDK_REPO main" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
sudo apt update
sudo apt install google-cloud-sdk
sudo apt install kubectl google-cloud-sdk-app-engine-python google-cloud-sdk-app-engine-python-extras
gcloud init
```

## 出力
`gcloud init`後、画像の通りCLIでURLが表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147741/ee2b5bbd-59fb-f898-3a31-c9c7617da68c.png)
白抜きになっている部分にURLが表示されており、そこにアクセスすることで認証ができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147741/c68abfdd-ae52-3905-9c0c-fb4e5fa1e338.png)
アクセス先でGCPを使いたいGoogleアカウントにログインするとこのような画面が表示されるため、画像では黒塗りになっている部分に表示されているコードをコピーしてCLIの「Enter verification code: 」の後に貼り付ける。
あとはプロジェクトやゾーンの選択をCLI上で行えば設定が完了する。

# 補足
「入力」にある各種コマンドの意味については[公式ドキュメント](https://cloud.google.com/sdk/docs/quickstart-debian-ubuntu?hl=ja)か[こちらの記事](https://qiita.com/yoshidna/items/8a12fb3a540531bcacaf)を参照。

# 参考文献
- [Debian と Ubuntu 用のクイックスタート](https://cloud.google.com/sdk/docs/quickstart-debian-ubuntu?hl=ja)
- [[GCP]01.（今更ながら）WSLとCentOSでGCP（Cloud SDK）を使えるようにする](https://qiita.com/yoshidna/items/8a12fb3a540531bcacaf)
- [GCPのgcloudコマンドをインストールする](https://qiita.com/kentarosasaki/items/2232113b44b016a56adc)
Gitについて勉強する。第五弾 (ブランチとマージについて 編)

# ブランチを作成する
* git branch "ブランチ名"

作成するだけで、切り替えは行いません。

# ブランチの一覧を表示する
* git branch -a

現在のブランチの一覧を表示します。
自分がいるブランチはアスタリスクが付いて、緑色になります。


# ブランチを切り替える
* git checkout "ブランチ名"

存在するブランチに切り替える

Gitバージョン2.23.0 から「git switch」コマンドが追加されたようです。
これは、「git checkout」にできることが多すぎるから、分割されたということらしいです。(以前の記事参照)

# ブランチを新規作成して切り替える
* git checkout -b "ブランチ名"

# ブランチの名前を変更する

* git branch -m "新ブランチ名"

# ブランチを削除する

* git branch -d "ブランチ名"

masterにマージされてない変更に関しては、削除されません。
強制的に削除する場合は、下記のコマンド。

* git branch -D "ブランチ名"（強制削除）

# マージには3つの種類がある

1. Fast Forword 
ブランチが枝分かれしていないときに、使用されます。
ブランチのポインタ(コミット)を一つ前に進めます。

2. Auto Merge
一般的なマージ
ブランチのポインタ(コミット)を一つ前に進めます。

3. Concreft
変更が競合したときに、使用するマージ。
マージした際に、メッセージが出ます。

# マージする
* git merge "ブランチ名"
* git merge "リモート名/ブランチ名"

# コンクリフトの解決
「CONFLICT (content): Merge conflict in "ファイル名"
Automatic merge failed; fix conflicts and then commit the result.」
とメッセージが出るので、対象のファイルを見てみると競合している内容が記載されています。
ファイル内容をきれいにして、コミットしなおせばOKです。
(スクショ忘れた...)

# コンクリフトが起きないようにするには
## 複数人で同じファイルを変更しない。
当たり前ですね。

## pullやmergeをする前に、stash、commitをしておいて変更中のファイルをなくす。
最近はIDEが警告を出してくれることが多い気がします。

[次・第六弾](https://qiita.com/hajime_manul/items/44b9ef4f7ddd682ab424)
Gitについて勉強する。第四弾 (リモートリポジトリとやり取りするコマンド 編)

# git remote
リモートリポジトリの設定内容が表示されます。
そのままだと、リモートリポジトリ名しか表示されないので、
URLなどの情報を見る場合、以下のオプションを付けます。

* git remote -v

# git remote add "リモート名" "リモートのURL"
リモートリポジトリを作成できます。
複数のリモートリポジトリを作成することもできます。


# git fetch "リモート名"/
リモートリポジトリからローカルリポジトリに情報を取得します。

その後 「git merge "リモート名"/"ブランチ名"」でワーキングディレクトリに反映する事ができます。

# git pull "リモート名" "ブランチ名"
リモートリポジトリから、ローカルリポジトリに情報を反映し、ワーキングディレクトリに反映させることをセットで行うことができます。

フェッチだとこうですが
* git fetch origin
* git merge origin/master

下記コマンドで上記2つと同じことをしています。
* git pull origin master
ちなみにorigin masterの場合、省略して「git pull」でも良いです。

# pullの注意点
git pullのほうが簡単だし、fetchの存在理由ある？
となりますが、pullには一つ落とし穴があります。

「git pull origin hoge」と仮に実行した場合、 git pullの挙動は
1. リモートのorigin/hogeの情報をローカルのorigin/hogeに取得する。
2. 「今現在いるブランチ」にhogeを統合する。
となります。

つまり、自分がorigin/masterにいる場合、hogeの内容がmasterに統合されてしまうことになります。

# git remote show "リポジトリ名"

リモートの状態の詳細を表示する事ができます。
例：git remote show origin


# git remote rename "旧リモート名" "新リモート名"
リモート名の変更ができます。

# git remote rm "リモート名"
リモート名の変更ができます。

[次・第五弾](https://qiita.com/hajime_manul/items/1f93818044b0384bf14e)
Gitについて勉強する。第三弾 (gitの変更を取り消そう 編)

# gitの変更を取り消してみる
## git checkout -- "ファイル名"
ワーキングディレクトリ内にある変更を取り消します。
* git checkout -- "ファイル名"
* git checkout -- "ディレクトリ名"

すべての変更を取り消す
* git checkout -- .

## git restore "ファイル名"
Gitバージョン2.23.0 から「git restore」コマンドが追加されたようです。
これは、「git checkout」にできることが多すぎるから、分割されたということらしいです。

下記コマンドで、先程のチェックアウトコマンドと同じことができます。
* git restore "ファイル名"
* git restore"ディレクトリ名"

すべての変更を取り消す
* git restore .

## git reset HEAD "ファイル名"
ステージングエリア内にある変更を取り消します。
ステージから消すだけなので、作業中のフォルダには反映されません。
* git reset HEAD "ファイル名"
* git reset HEAD "ディレクトリ名"

すべての変更を取り消す
* git reset HEAD .

# 直前のコミットを取り消したいとき
## git commit --amend
コミット内容を取り消すことができます。
あくまでローカルリポジトリを取り消すためpushしたものには実行しないようにしましょう。
gitの動作としては、ステージの内容で直前のコミットを上書きするイメージのほうが正しいです。

# バージョン管理する必要のないファイルを設定する
.gitignoreファイルでバージョン管理しないファイルを指定できます。
.gitignoreファイルを作成し、対象のファイル名を書き込めばOKです。

[次・第四弾](https://qiita.com/hajime_manul/items/c95c5526a7c15f6bb16a)
【pandas】データフレームの各列の型が揃っているかどうかに寄って行アクセス時の挙動が変わる話

pandas.DataFrameに値を代入するとしばしばこういう警告が出てくる→

```
C:\anaconda\lib\site-packages\ipykernel_launcher.py:3: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame
```
「(参照ではなく)コピーしたものに値を代入してるよ。元のDataFrameは変更されないけど大丈夫？」ということ。
例えば以下のように.locで1行とって代入すると、.locの時点でコピーが返るのでrowは変更されるが元のDataFrameは変更されない: 

```python

df = pd.DataFrame({
    "string": ["aaa", "bbb", "ccc"], 
    "integer": [1, 2, 3]})
row = df.loc[0]
row["string"] = "hoge"

# コピーは変更される
print(row) 
# string     hoge
# string2     ddd
# Name: 0, dtype: object

# コピー元は変更されない
print(df)
# string	string2
# 0	aaa	    ddd
# 1	bbb	    eee
# 2	ccc	    fff
```

よく使うテクニックとして、これを避けたければ次のよう1行で書けば良い: 

```python

df.loc[0, "string"] = "hoge"
print(df)
#   string  integer1
# 0   hoge         1
# 1    bbb         2
# 2    ccc         3
```

しかしながら、次のように全ての列が同じデータ型を持つ場合挙動が異なる。すなわち、.locは参照を返すので、rowの変更がDataFrameに反映される: 

```python
import pandas as pd
df = pd.DataFrame({"string": ["aaa", "bbb", "ccc"], "string2": ["ddd", "eee", "fff"]})
row = df.loc[0]
row["string"] = "hoge"

# 参照先が変更される
print(row)
# string     hoge
# string2     ddd
# Name: 0, dtype: object

# 参照元も変更される！
print(df)
#   string string2
# 0   hoge     ddd
# 1    bbb     eee
# 2    ccc     fff
```

理由は分からないが、効率性を求めた結果苦肉の策でこういう仕様にしたような感じがしておもしろい。

.locだけでなく、.iterrows()や.valuesなども以下のように同様の挙動を示す。

* 型がそろっていないとコピーが返り、DataFrameは変更されない: 

```py
df = pd.DataFrame({
    "string": ["aaa", "bbb", "ccc"], 
    "integer": [1, 2, 3]})

# iterrows: 2行目のbbbをhogeに変更
for i, row in df.iterrows():
    if i==1:
        row[0] = "hoge"

# 1行目のaaaをbarに変更
val = df.values
val[0,0] = "bar"

# -> コピー元は変更されない
print(df)
#  string  integer1
# 0    aaa         1
# 1    bbb         2
# 2    ccc         3
```


* 型がそろっていれば参照が返り、DataFrameは変更される: 

```py
df = pd.DataFrame({
    "string": ["aaa", "bbb", "ccc"], 
    "string2": ["ddd", "eee", "fff"]})

# iterrows: 2行目のbbbをhogeに変更
for i, row in df.iterrows():
    if i==1:
        row[0] = "hoge"

# values: 1行目のaaaをbarに変更
val = df.values
val[0,0] = "bar"

# -> 参照元は変更される
print(df)
#  string  string2
# 0    bar     ddd
# 1   hoge     eee
# 2    ccc     fff
```

これくらいの小さい例だとあまり怖さはないが、データフレームにあとから列を足して型の統一が崩れたりすると、それまで参照が返ると思い込んでいたところにコピーが返ってくるようになって見つけにくいバグになる。

「基本はコピー、型が揃っているときだけ参照が返る」という話でした。

参考: 
https://stackoverflow.com/questions/47972633/in-pandas-does-iloc-method-give-a-copy-or-view
redux-sagaの解説は最初に読んではいけない

こんにちは、react 一年生、 redux/redux-saga 入学生のyukilabです。

redux-sagaの解説記事をいろいろ読んだ結果、 redux-sagaを知りたかったらredux-sagaの記事は（少なくとも最初に）読んではいけない。　という事実が判明したのでシェアします。

結論から言うと、 redux-sagaを理解したかったら、まず saga を理解せよ、ということ。 （筆者はコンピューターサイエンスを知らないなんちゃってソフトウェアエンジニアなので saga が常識の皆様には不要の記事です。これ） react / fluxとなんの関係もありませんが、　https://microservices.io/patterns/data/saga.html や https://qiita.com/nk2/items/d9e9a220190549107282 を最初に読むことが大事です。saga とはなんぞや、 「新しくsagaを作る」 ・・・(・・?) とはなんぞや、とか redux-saga解説記事を読むと最初に出てくる、なにそれてきなことがまずわかるので、すんなり redux-saga記事をそのあとに読むことができるようになります。（いや、筆者はなりました）
【今日から書ける！伝わるレジュメ】第3回 転職透明化らぼ-レジュメチェック編　に参加してきました #転職透明化らぼ

求職者の立場として参加してきました！さっそく、ふりかえりを書いていきます。

今回のイベントは、**レジュメの内容を採用担当者はどう見ているのか？**といった内容です。

このイベントの主旨は、求職者と採用担当者の２つの立場の方が集まって、互いの情報格差を無くしていこうというものです。

網羅的でなくてすみませんが、個人的に刺さったポイントを書きます。

公式はこちら↓
https://rtlabo.connpass.com/event/147673/


## 良かったこと

技術的なこと以外で、採用担当者がレジュメの何を見ているか聞けたことです。

例えば、「**第三者から見た自身への評価が書かれていると嬉しい**」という意見がありました。これはなかなか、自分で書くことの多いレジュメでは思いつきませんでした。具体的に誰に言って貰えた評価なのかをセットで書くと、よりその人がどんな人か分かるそうです。

また、「**どんな考え方で仕事をしているかを書くと嬉しい**」という意見もありました。自社のカルチャーにフィットするかどうかを見るために必要なのだそうです。

さらに、「レジュメといえば経歴書のことを指すので、過去の経歴を書き下すことが多いが、**実際に入社してからやる仕事は過去の仕事そのままではない**。よって、未来に解像度を向けてアピールする内容が良い」というのもありました。なかなか難易度は高そうですが、出来たら採用側にも「おっ！」っと言って貰える材料になりそうです。

## 次回のイベントでやったら面白そうだと思ったこと。
実際に求職者のレジュメを見て、採用担当者がチェックしてみるワークショップを行うことです。かなりセンシティブなことだと思うので大変だとは思いますが、やれたら面白そうな気がします。**同じ人のレジュメを複数の採用担当者がチェックしてみると、採用側にも新しい発見があるかもしれません**。

## 自分がやってみた行動
レジュメの自己PR欄に、これまで担当した現場でお客様からいただいた評価内容を書いてみました。
自分がアピールポイントと思っていなかった点を、アピール欄に入れました（顧客と継続関係を結べている点）。

※レジュメ(技術経歴書)は、[Qiitaのプロフィール欄](https://qiita.com/omokawa_yasu)にURLで公開しています。

## まとめ
今回に限らず、自分と違った立場の方の話を聞ける機会は少ないです。そういった意味で、希少で価値のあるイベントだと思いました。

次のイベントでは、ワークショップ形式で互いにフィードバックをし合うのも、面白そうだなと思いました。

主催の皆さま、ありがとうございました。
［Android］MediaPlayerとExoPlayerの違いをまとめる

# 更新(2022/01/26)

ExoPlayer でも RTSP がサポートされてるようになったり状況は変化しているようです。
こちらの記事の情報は古くなってきているので、参考までにご覧ください。

https://exoplayer.dev/rtsp.html

# はじめに

Androidでメディアを再生するにはMediaPlayerとExoPlayerを使った2種類の方法がある。
この２種類の特徴についてまとめて、どのような違いあるのか比較します。

# MediaPlayerとは？
Android 1.0(API Level 1)の頃からあるライブラリです。
Androidに保存されている動画・音声、またはRAWリソースファイルの再生ができる。

# ExoPlayerとは？
Googleが提供しているメディア再生用のOSSライブラリです。
Androidに保存されている動画・音声、またはRAWリソースファイルの再生できるだけでなく、
メディア配信([DASH](https://en.wikipedia.org/wiki/Dynamic_Adaptive_Streaming_over_HTTP)・[HLS](https://developer.apple.com/streaming/)・[SmoothStreaming](https://docs.microsoft.com/en-us/iis/media/smooth-streaming/smooth-streaming-transport-protocol))・プレイリスト再生・字幕表示などもサポートしている。

# 何が違うのか？
MediaPlayerとExoPlayerでは機能的なところや技術的なところにも違いがある。
今回はそのなかでも機能的な面についてまとめます。

## サポートするデバイス
MediaPlayerとExoPlayerではサポートするデバイスが異なる。
特にExoPlayerでは利用する機能ごとにサポートデバイスが変わるようなので注意が必要。

| 名称 | Android Minium Version | API Minimum Level | 参考資料 |
| :----------- | :---------: | :----------------: | :------ |
| MediaPlayer | 1.0 | 1 | - |
| ExoPlayer | 4.1 | 16 | 詳細は[こちら](https://exoplayer.dev/supported-devices.html)に書いてる |

## サポートする機能
メディア再生にはあまり違いがありませんが、ストリーミング配信に関しては大きく違いがある。
またプレイリスト機能などExoPlayerにしかないものがある。

| 名称 | 機能 | 参考資料 |
| :----------- | :--------- | :------ |
| MediaPlayer | ・音声・映像再生(AAC・MP3・FLAC・MP4・WebM)<br/>・ストリーミング再生(RTSP・HTTP Progressive Streaming)<br/>・画像表示(BMP・GIF・JPEG・PNG)<br/>・DRMコンテンツ再生 |・[MediaPlayer overview](https://developer.android.com/guide/topics/media/mediaplayer)<br/>・[Supported media formats](https://developer.android.com/guide/topics/media/media-formats.html) |
| ExoPlayer | ・音声・映像再生(AAC・MP3・FLAC・MP4・WebM)<br/>・ストリーミング再生(DASH・HLS・SmoothStreaming)<br/>・DRMコンテンツ再生<br/>・プレイリスト再生<br/>・UIコンポーネント<br/> |・[Pros and cons - ExoPlayer](https://exoplayer.dev/pros-and-cons.html)<br/>・[Supported media formats - ExoPlayer](https://developer.android.com/guide/topics/media/media-formats.html) |

### ストリーミング配信
MediaPlayerはレガシーな配信プロトコルであるRTSPを再生でき、
ExoPlayerはモダンな配信プロトコルであるDASH・HLSを再生できるようになっている。
RTSPでしか通信できないものに対してはMediaPlayerが使うしかなさそう。

### プレイリスト再生
ExoPlayerはプレイリスト再生に対応している。
このプレイリスト再生は次の映像をプリバッファリングしてくれるので、
映像を途切れさせることなく再生できるみたい。

#### MediaPlayerで再生すると
例えばMediaPlayerで映像を切り替えると
切り替え時にバッファリングが発生してしまうので映像が途切れる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79387/43ade857-1646-f99d-39f4-1de4c24bdc77.png)

#### ExoPlayerで再生すると
しかしExoPlayerで再生すると次の動画を切り替える前に
バッファリングしてくれるので映像を途切れさせないで再生できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79387/f99efd76-cbb0-8073-8128-b01b3e84a258.png)

# まとめ
* メディア再生の機能については特に違いはないので、  
 MediaPlayer、ExoPlayerのどちらを使っても問題ない
* ストリーム配信については使える配信プロトコルが大きく違うので、  
 配信プロトコルにあわせてMediaPlayerかExoPlayerを使うか決める必要がある。
* ExoPlayerにはプレイリストを使った再生ができるので、  
 複数のメディアを操作したり切り替える場合はExoPlayerを使ったほうが便利そう。

# 参考
- [MediaPlayer - Overview](https://developer.android.com/guide/topics/media/mediaplayer)
- [ExoPlayer | Android Developers](https://developer.android.com/guide/topics/media/exoplayer)
- [ExoPlayer: Flexible Media Playback for Android(Google I/O '17)](https://www.youtube.com/watch?v=jAZn-J1I8Eg)
Q&A サイトを Zendesk に移行した際の反省点

お仕事にて、Q&A サイトをオンプレミスの Web システムから [Zendesk](https://www.zendesk.co.jp/) に移行しました。

しばらく運用していて、気づいた反省点などを残しておこうと思います。検討している方などの参考になれば幸いです。

正直、本来はできていて当然なものもあるかとは思いますが、そこはご容赦いただければと…

## パッケージ導入／移行でも良く聞く話

### なるべく標準的なフローにあわせる

トリガやマクロといった機能を駆使すれば結構複雑なワークフローも実現できます…が、当たり前ですがやりすぎると煩雑になりスパゲッティ化します。変更影響把握とかもややこしくなりますので、ほどほどにしましょう。

### 現行踏襲に固執しない

業務フローだけでなく分析項目なども、現行踏襲に固執しない方がよいと思います。なるべくシンプルに、めったに使わない機能／項目は一度見送る。チケット情報は JSON なので、項目の追加もオンプレで RDB でやっていたときに比べれば楽 (※) です。そのためにも、意思決定者も上手く巻き込んでいきたいですね。

(※) 追加は容易なのですが、チケットが凍結した後は編集ができず、遡ってデータを入れることができないのは注意です。まぁそういうところは割り切りをするのが良いかなと。

なお、現行踏襲に固執されて複雑になるようなら、それは Zendesk を選択するべきではないのかもしれないです。

## イマドキのスタイルに変える話

### クラウドを受け入れる

SaaS なので、こちらが想定していないタイミングで微細な変更があったりします。実際、意識していない間に UI が変わってたりもしました。こちらもユーザーも、そういうもんだと受け入れる心が必要です。

### 改修時の意思決定やリリース作業を軽くする

できれば、こちらの改修速度も軽く速くしておきたいです。API が結構しっかり用意されているので、試験環境で確認⇒本番環境へデプロイ　といったリリース手順を取る場合は、設定確認～設定変更～反映は頑張って API を活用するのも良いかと。

総合テストは、おそらくブラウザ中心になるため自動化がしんどいですが、「何かあっても復旧できればよい」マインドにして、なるべく軽くしておくと良いと思います。

### 自動化はしやすい、完璧を求めない

API やチャット連携も豊富なため、自動化できる部分は多いと思います。

機械による自動化については、完璧を求める人もいると思いますが、ある程度「コンピュータに任せ、何か起こったら人間が謝ればよい」マインドも必要になってくるんじゃないかと思っています。

## Zendesk 特有？のポイント

### 「ライトエージェント」は意外とやりたいことができない

チケット一覧といったビューなどの設定や、分析ツールである Explorer の利用にかなりの制約があります。「回答を送る人数分だけエージェント買う」という構成は多いような気がしますが、データ分析者や意思決定者はエージェント権限を持っておいたほうが良いです。

### やりとりは長くしすぎない方がよい？

これは賛否両論あると思いますが、やり取り (社内メモなど) が多いとスクロールが大変で、双方のユーザビリティが悪くなります。情報量とのトレードオフだと思いますが、やっぱり短い方がチケットの内容を把握しやすいです。

### 回答レビューは別のツールでやったほうがよい？

これも、使い方によって賛否両論あると思いますが、Zendesk ではインタラクティブなレビューをすることを想定して作られていないと感じます。プルリク的なことや回答文案の版管理もできませんし。

また、上記の通りチケットのスレッドが長くなる原因にもなります。レビューはチャットツールなどでやったほうが良いと思います。

### 分析ツールを覗いておいた方がよい

デフォルトで分析ダッシュボードが用意されており、結構色々なデータが取れます。その取得条件とチケット対応のワークフローの想定があっているか、検証して確認しておいた方がよいです。対応時間の算出方法とか。

### ビューは四半期くらいのスコープにしか使えない

ビューを使うと色々な条件でチケットを一覧化することができますが、「凍結されてから 120日経過したチケット」は表示対象から除外されます。つまり、半年前のデータをビューで見たときに、既に表示されなくなっているチケットがチラホラある状況になります。ビューから CSV を吐いて集計していたりすると罠に掛かります。

### 検索の頭が地味に悪い

特に、記事の数が多いと顕著だと感じます。Frequently な Q&A が多いならいいかもしれませんが、そうでない場合は結局よくわからん検索結果になってしまい、ひとつもクリックすらされない可能性があります。もしかしたら、数を絞ったり、タイトルを工夫したり、記事内容としての最適化はまだまだ欠かせないのかもしれません。

-----
非IT系でもわかる検索エンジンの仕組みの説明


<H1>検索エンジンの仕組み</H1>



<h2>きっかけ</h2>
サイト制作ではなく、サイトのことについて教えてほしいことがある～とよく知る方がツイートしていたので、リプしたところ、「検索エンジンがサイトをどうやって読み込んで、どうやって検索結果に反映させているのか」という疑問にぶつかったそうなので、調べてみました。自分なりにまとめてみたので、検索エンジンの仕組みを非IT人でも理解するとこんな形かなとおもいますので、共有します。(文字ばっかですいません。)



<h2>本題</h2>
日経電子版などWEBサイトの更新を頻繁にしていたり、表示されないリンクなどがない。といったユーザーにとって問題がない順に、検索エンジン側がサイトを読み込みに行きます。
この読み込み作業をクローリングといい、クローリングには3段階に作業が分かれています。


①クローラー：Webページを巡回して、記載されている情報を取得する
②インデクサー:クローラーが取得した情報を記憶する
③サーチャー：②の情報からキーワードに関する情報だけを抽出し、重要度に応じて並べ替える


①クローラは、Webページのプログラムのワードを見ているもの(画像やデザインは人間の視覚なので、ロボットには難しいためほとんど文字をみます。 例：普通のグーグル検索)や写真のみ(グーグル画像検索)などがあります。
クローラをサイトに呼ばないと、検索エンジンでいくら検索しても新しいサイトは探しても出てきません。
このクローラはグーグルだとGooglebotと名付けられています。グーグルの場合、新しいサイトは30分で反映させれるようです。*1

②「①」で取得したサイトはなんの話をしているサイトなのか、何をテーマにしているのかと分析し、保存します。
簡単にいうと検索した時にでてくるサイトの順番とそのサイトの3行の詳細欄を保存しているところです
③「②」のデータと検索キーワードを基に関連性の高い順に並び替え、順位付けをします。SEOの結果が反映される部分になります。
SEOをあげればあげるほど次のサイトの変更の反映の時間も短くなります。つまり、ロボットがよく来て検索エンジンの更新をしてくれます。SEOについては、業界がとてつもなく広いのでよく知らないですｗ ブロガーが詳しい印象です。

この一連の作業のクローリングをしていることで、検索エンジンがサイトを読み込んで、検索結果に反映させています


参考にしたURL
クローラーの動き概要(=検索エンジンの読み込む動きについて)
https://www.crosswalk-seo.com/seo/%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%95%E3%82%8C%E3%82%8B%E4%BB%95%E7%B5%84%E3%81%BF%EF%BC%88%E3%82%AF%E3%83%AD%E3%83%BC%E3%83%A9%E3%83%BC%E3%81%AE%E5%8B%95%E3%81%8D%E6%96%B9/


Google 検索の仕組み
https://support.google.com/webmasters/answer/70897

*1グーグルにWEBサイトを検索エンジンに反映させる方法
https://uruchikara.jp/fetch_as_google/



<h5>編集後記</h5>
自分は元々JAVAエンジニアだったため、日ごろIT関係の意訳作業を実家でしています。このようにお役に立てそうなのでよかったと思います。
<a href="https://twitter.com/sanche1012">筆者のTwitter</a>
C#における文字コードの扱い(Windows10環境)

普段Shift_JISでC#ソースを書いていたが、ちょっと気になったので調べてみた。
Shift_JISのテキストファイルを読み込むときは気を付けようくらいのつもりで
「初心者」タグをつけてみたものの、色々調べてみたら自分も「初心者」であることが露見した件。

下記はWindows10環境です。
使ったコンパイラ：`C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe`

# ソースコードの文字コード

下記のコードを
1. Shift_JISで保存してコンパイル
2. UTF-8で保存してコンパイル
して実行してみる。

```csharp

using System;

class SampleTest
{
    [STAThread]
    static void Main() {
        Console.WriteLine("Hello World ようこそ");
    }
}
```


実行結果はいずれも下記が表示された。

```

Hello World ようこそ
```

<strike>C#ソースコードの文字コードはShift_JISでもUTF-8でもよさげ？</strike>
⇒[コンパイルオプション(`/codepage`)で明示しない場合はUTF-8が推奨のよう](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/codepage-compiler-option)

直接cscを使う場合は`/codepage`が指定できるが、Visual Studioではこのオプションはサポートしてないらしい。（使う必要がないからと思われる。）

## ソースコードのエンコードの指定
`/codepage:XXX` オプションでソースコードの文字コードを指定できる。
ここの`XXX`はコードページ番号を指定しないといけない。(`/codepage:UTF-8`とかだとcscがエラーを吐く。)
UTF-8の場合は、`csc /codepage:65001 YYY.cs` みたいに指定する。
[コードページ一覧はここ参考](https://www.ipentec.com/document/windows-codepage-list)

# 文字列(string)のC#プログラム内部表現

上記で作成した各exeをildasmで開いてみた。
C#の内部表現は[UTF-16(のリトルエンディアンのほう)](https://www.buildinsider.net/language/csharpunicode/02)だそう。
<strike>さっきまでUTF-8かと思っていた</strike>

```

.method private hidebysig static void  Main() cil managed
{
  .entrypoint
  .custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 ) 
  // Code size       13 (0xd)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldstr      bytearray (48 00 65 00 6C 00 6C 00 6F 00 20 00 57 00 6F 00   // H.e.l.l.o. .W.o.
                                  72 00 6C 00 64 00 20 00 88 30 46 30 53 30 5D 30 ) // r.l.d. ..0F0S0]0
  IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_000b:  nop
  IL_000c:  ret
} // end of method SampleTest::Main
```

とはいえ、処理速度やリソースがシビアでなければ内部表現を気にする必要はあまりないと思ってます。

# C#プログラムが読み込むテキストファイルの文字コード

基本的には（エンコードを指定しない場合は）`UTF-8`のよう。([`File.ReadAllLines(string)メソッド`](https://docs.microsoft.com/ja-jp/dotnet/api/system.io.file.readalllines?view=netframework-4.8#System_IO_File_ReadAllLines_System_String_)など)
標準外のライブラリとかはしらんですが。

`Encoding`クラスで明示的に指定するのが無難かと。
Shift_JISのテキストファイルを扱うプログラムを書くときは気を付けよう。

# 識別子に日本語が使えてしまう

下記のソースコードはコンパイルが通り、正しく動作する。ちなみに全角空白は空白として処理されるよう。
個人的には、英語が苦手でも識別子を日本語にするのはお勧めしない。日本語は表現がゆらぐので。。

```csharp

using System;

class SampleTest
{
    [STAThread]
    static void Main() {
        int あ = 5;
        Console.WriteLine(あ+6);
    }
}
```


# 正規表現

初心者向けから逸れてきた感があるが・・・
`\s`は全角スペースも含む。
`[あ-お]`みたいなこともできるっぽい。
`[あぁいぃうぅえぇお]`と多分おなじ。※ちゃんと確認してない。



# コマンドプロンプトにおける文字コード

自分の環境はデフォルトはShift_JISになっている。
参考サイト: [Windowsコマンドプロンプト　文字コード設定](https://qiita.com/user0/items/a9116acc7bd7b70ecfb0)
2019年のJavaScript minifier "terser"

# 背景

## UglifyJS と uglify-es
[UglifyJS](https://github.com/mishoo/UglifyJS2)という大変有名な minifier がありました。しかしES6に対応していないため、class構文などのES2015以降に追加された文法をつかったJavaScriptをminifyできません。

[uglify-es](https://github.com/mishoo/UglifyJS2/tree/harmony)というUglifyJSをES2015の文法に対応させる開発ブランチもありました。開発終了しています。

## terser

[terser](https://github.com/terser/terser)という minifier があります。生きてます。
2019年の2月ぐらいからuglify-esより使われるようになりました。
現在も増加傾向にあります。

<img width="1092" alt="スクリーンショット 2019-09-11 22.47.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15964/ee4cbf86-51dd-339d-d314-a5a9278bf7b3.png">
https://www.npmtrends.com/terser-vs-uglify-js-vs-uglify-es より

# モジュールバンドラー
この流れはモジュールバンドラーにも来ています。

## browserify

[uglifyify](https://github.com/hughsk/uglifyify)というbrowserify向けのminify用トランスフォームモジュールがあります。
以前は名前の通りUglifyJSをつかっていました。

### 2017年1月から uglify-es
[use uglify-es as the main uglify module by lrlna · Pull Request #65 · hughsk/uglifyify](https://github.com/hughsk/uglifyify/pull/65)

### 2018年6月から terser
[Switch to uglify-es fork by toddself · Pull Request #86 · hughsk/uglifyify](https://github.com/hughsk/uglifyify/pull/86)


## Webpack

Webpackは2018年2月からは、デフォルトでES2015をminifyできます。

### 2018年2月から uglify-es

- https://github.com/webpack/webpack/releases/tag/v4.0.0
- https://github.com/webpack-contrib/uglifyjs-webpack-plugin/releases/tag/v1.0.0

### 2018年11月から terser

- [Release v4.26.0 · webpack/webpack](https://github.com/webpack/webpack/releases/tag/v4.26.0)

uglifyjs-webpack-plugin は名前の通りの uglify 用プラグインに戻り、ES2015向けには terser-webpack-plugin が生まれました。

- https://github.com/webpack-contrib/uglifyjs-webpack-plugin/releases/tag/v2.0.0
- https://github.com/webpack-contrib/terser-webpack-plugin

## WebpackのES2015対応の変遷リンク

- [【webpack】(2018年2月25日現時点で)ES2015 (ES6)のままminifyする方法 - Qiita](https://qiita.com/ota-meshi/items/8d30743fd72f8389628c)
- [【webpack】(2018年1月現時点で)ES2015 (ES6)のままminifyする方法 - Qiita](https://qiita.com/ota-meshi/items/9e9bfcbfab00e109494f)
- [【webpack】(現時点で)ES2015 (ES6)のままminifyする方法 - Qiita](https://qiita.com/ota-meshi/items/e60fa3778c0e53ac6a56)

# その他参考リンク

- [個人的にTerser & Babelの好きなところ](https://gist.github.com/antidotech/d101cae50dd83ab7d3487cdb10b80f4d)
- [UglifyJSの代わりに、terserを使ってwebpackする - Qiita](https://qiita.com/ArcCosine@github/items/e45119347fd0f01f0b66)
- [uglifyify - 橋本商会](https://scrapbox.io/shokai/uglifyify)
- [10 Javascript Compression Tools and Libraries for 2019](https://blog.bitsrc.io/10-javascript-compression-tools-and-libraries-for-2019-f141a0b15414)
- [Uglify vs. Babel-minify vs. Terser: A mini battle royale - LogRocket Blog](https://blog.logrocket.com/uglify-vs-babel-minify-vs-terser-a-mini-battle-royale/)
CSS 5


#ふぉんとふぁみりー

きた！
ふぉんとシリーズ多すぎて違いあるのか謎です。。。
これふぁみりー以外選択したらどうなるのでしょうか？？

フォント考えた人もすごいし指示出す人もすごい

コード書くってすごい世界です。

また今日も勉強になりました。
A状態：中華カメラをHack!? / P2P 通信を手動設定 miSafes D304

## はじめに．．．
準備編で次の状態であったものが対象になります。
miSafes D304 カメラを**[TUTK P2P Server（ThroughTek Co.）](https://www.throughtek.com/privacy_policy.html)**に再び接続し、リアルタイムの映像、録画させる事が目的です。
　**[準備編：中華カメラをHack!? / P2P 通信と miSafes D304](https://qiita.com/PIGYO/items/12632147f73ddf12965c)**
　**A状態：『Misafecam』サービス終了までカメラの映像は見られた。カメラの RESET ボタンは押していない。**

この記事を見て分からない方は、**[こちら](https://qiita.com/PIGYO/items/12632147f73ddf12965c)**を参照してください。
ここから先は、自己責任でオペレーションです。

## 概要．．．
準備編で取得した microSD のファイル『misfaes_D304_config_sportdv_sysenv.out』を**『[サクラエディタ](https://sakura-editor.github.io/)』**などで開くと、ルーターのSSID、TUTK P2P 認証情報が表示されています。
　例
　　　PEN367A9D3803MX2381A 　・・・TUTK P2P 認証ID
　　　87931362 　　　　　　　 　・・・TUTK P2P 認証パスワード

```ruby:準備編_参照：misfaes_D304_config_sportdv_sysenv.out

75F39C45A7CF
Buffalo-G-E320                 ※ ルーターのSSID名
admin
r0ot@dmin                      ※ ルーターのSSID接続パスワード（WPA PreSharedKey）
PEN367A9D3803MX2381A           ※ TUTK P2P 認証ID / 20桁のコード
87931362                       ※ TUTK P2P 認証パスワード / 8桁のパスワード
SY_MCP_IPC
INFOTM
Japan 
```
qiwocloud 認証IDファイルもあるので、microSD へのループ録画も自動実行されます。
　ファイル名：/mnt/config/reg_info_file

```ruby:準備編_参照：config-reg_info_file
VTPITz3wN4UTLkO2Qi4iZAa3d2Hm4GfebnwOSEwMhM8MiE3MdQvMaYpKTS1RT3yDD51Y1E68CeMOEzFJ      ※ 80文字程度の文字列
```

## TUTK P2P 対応のアプリは．．．
**[TUTK P2P（ThroughTek Co.）](https://www.throughtek.com/privacy_policy.html)**に対応したアプリをインストールして、TUTK P2P 認証を行えば完了です。
![TYPEA_screen001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502610/7ec892a4-3876-bbfc-a8b8-02e47573cb9a.png)

テスト動作は確認していますが、探せば他にあると思います。
　![TYPEA_screen002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502610/23d19927-df90-01b6-bd24-fe16034a397d.png)　**[P2P CamLive](https://play.google.com/store/apps/details?id=com.tutk.P2PCamLive&hl=ja)**
　![TYPEA_screen003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502610/dbcf3780-d556-a5fa-75d7-92ad22df174b.png)　**[tinyCam Monitor FREE - IP camera viewer](https://play.google.com/store/apps/details?id=com.alexvas.dvr&hl=ja)**

**設定例**
P2P CamLive では、『LAN内を検索』を実行すると TUTK P2P 認証ID が表示されます。
『パスワード設定』に TUTK P2P 認証パスワードを入力すれば完了です。
　例
　　　PEN367A9D3803MX2381A 　・・・TUTK P2P 認証ID
　　　87931362 　　　　　　　 　・・・TUTK P2P 認証パスワード
![TYPEA_screen004.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502610/64cec52b-2f2b-2bcd-c998-78e21d35d613.jpeg)

TUTK P2P サーバを経由するので外出先(自宅WiFi圏外）からも、映像は見ることができます。
microSDに録画された映像を再生する時は、**[『再生編：中華カメラをHack!? / miSafes D304 録画を再生』](https://qiita.com/PIGYO/items/25b71b0c6966a7668847)**を参照してください。
Linux で OneDrive

# やりたいこと
LinuxでOneDriveを使いたい。
いま時点でMS社公式は無いようなので OneDrive Free Client なるものを使ってみる。
今回は Ubuntu 16.04 を対象。
以下に要点のみ手順を記す。プラットフォームごとのより詳細な手順解説は[こちら](https://github.com/abraunegg/onedrive/blob/master/docs/INSTALL.md)や[こちら](https://www.virment.com/setup-onedrive-ubuntu18-04/)。

# 手順

## 1. OneDrive Free Client のビルドに必要なものインストール （[詳細](https://github.com/abraunegg/onedrive/blob/master/docs/INSTALL.md#dependencies-ubuntu--debian---x86_64)）

```
sudo su
apt install build-essential
apt install libcurl4-openssl-dev
apt install libsqlite3-dev
apt install pkg-config
curl -fsS https://dlang.org/install.sh | bash -s dmd
source ~/dlang/dmd-2.088.0/activate
```
※'dmd-2.088.0'バージョンは適宜読み替える

## 2. OneDrive Free Client のビルド （[詳細](https://github.com/abraunegg/onedrive/blob/master/docs/INSTALL.md#compilation--installation)）
```
cd /opt
git clone https://github.com/abraunegg/onedrive.git
cd onedrive
./configure
make clean
make
make install
```

## 3. アカウント設定 （[詳細](https://github.com/abraunegg/onedrive/blob/master/docs/USAGE.md#first-run-zap)）
```
onedrive
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195839/eff53766-4cf4-1513-e94a-267a501e2dca.png)

ターミナルに記されたアドレスにブラウザからアクセス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195839/a0caf946-a90c-067c-bf68-603892633dc8.png)

OneDriveアカウントでサインインしアクセス許可を設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195839/caf4c748-213d-d356-67cd-faaad09d381c.png)

アクセス許可設定後にリダイレクトされたページのアドレスをコピー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195839/5151b7d4-b00d-33c6-8fad-d98d2610a09b.png)
ターミナルに戻り上記でコピーしたアドレスを'Enter the response uri:'につづけて貼り付け
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195839/3939f04e-1f2b-ed70-fe34-20155dfcf8ed.png)

準備完了
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195839/4fe14328-e6dd-391b-48d0-a911672ae21a.png)

## 4. 設定（[詳細](https://github.com/abraunegg/onedrive/blob/master/docs/USAGE.md#configuration)）

```
mkdir -p ~/.config/onedrive
echo 'sync_dir = "~/OneDrive"' > ~/.config/onedrive/config
cat ~/.config/onedrive/config
```

## 5. OneDrive起動（[詳細](https://github.com/abraunegg/onedrive/blob/master/docs/USAGE.md#performing-a-sync)、[オプション一覧](https://github.com/abraunegg/onedrive/blob/master/docs/USAGE.md#all-available-commands)）

例：一度限り＆ダウンロード方向のみの同期

```
onedrive --synchronize --download-only
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195839/6c43aee4-6c84-d8e5-e43d-04d8ba9adba5.png)

例：常時＆ダウンロードのみ同期

```
onedrive --monitor --download-only
```

## 6. サービス登録

```
cd /opt/onedrive
systemctl --user enable onedrive
systemctl --user start onedrive
```

## 7. ログ確認
```
journalctl --user-unit onedrive -f
```

## 7. アンインストール （[詳細](https://github.com/abraunegg/onedrive/blob/master/docs/INSTALL.md#uninstall)）

```
cd /opt/onedrive
sudo make uninstall
rm -rf ~/.config/onedrive
```
再生編：中華カメラをHack!? / miSafes D304 録画を再生

## はじめに．．．
『Misafecam』のサービス終了で、microSD に保存された録画データが再生出来ない．．．
と言う方へのアドバイスになります。
この記事を見て分からない方は、**[こちら](https://qiita.com/PIGYO/items/12632147f73ddf12965c)**を参照してください。

## 録画再生のアプリケーションは．．．
録画データの保存先は、次のようになります。

```ruby:録画データの保存先
microSDカード： /DCIM/100CVR

ファイル名(例)：
2019_09_24_190100_600_0.mp4      2019_09_25_124100_600_0.mp4      2019_09_26_062100_600_0.mp4
2019_09_26_233100_600_0.mp4.tmp  ← 録画中だったファイルは tmp が付く
```

**[『HandBreak』](https://handbrake.fr/downloads.php)**のフリー・アプリを使用すると、簡単に再生、他の映像フォーマットに変換できます。
　![play001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502610/959df9a8-2c87-d341-1b78-2095e8a27c29.png)　**[HandBreak](https://handbrake.fr/downloads.php)**
アプリケーション起動後に mp4 ファイルを選択、<font color="Blue">**「Preview」**</font>を押せば再生できるので楽チンです!!
![play002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502610/80de97aa-ffc9-d1a1-f322-c1deffb61106.png)

## 録画されない時は．．．
カメラの RESET ボタンを押すと『qiwocloud 認証ID』が削除され、録画するLinuxプロセスが停止します。
B状態、C状態で発生し、録画するための設定が再度必要になります。
 　　ループ録画・qiwocloud 認証IDファイルが削除：　/mnt/config/reg_info_file

**【状態】**　
　 <font color="Gray">**[A状態](https://qiita.com/PIGYO/items/e41ccf527fc36d0e4548)**：『Misafecam』サービス終了までカメラの映像は見られた。カメラの RESET ボタンは押していない。</font>
　 **[B状態](https://qiita.com/PIGYO/items/5caf7efbc57e85a81077)**：『Misafecam』サービス終了までカメラの映像を見られた。<font color="Red">カメラの RESET ボタンを押した。</font>
　 **[C状態](https://qiita.com/PIGYO/items/b86547f67e534db4d560)**：『Misafecam』からカメラの接続が出来なかった。カメラの映像は見えない。または新品の状態。

　　 参考 ： 　[準備編：中華カメラをHack!? / P2P 通信と miSafes D304](https://qiita.com/PIGYO/items/12632147f73ddf12965c)
　　　　　　　「認証ファイル、起動実行シェル 抜粋」
Photonに接続する(PUN2編)

#はじめに
以前にPUNを使っての接続方法を投稿しましたが、PUN2でもなんとかできるようになったので記事を書きます。前回の内容と被る部分のあるのでそちらを参照してください。PUNをインポート後AppIDを入力するところまでは、PUN2をインポートする以外は同じになります。

Photonに接続する
https://qiita.com/uroshinse/items/004b47562e202be10b72

##PUN2(Photon Unity Network 2)をインポートする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307841/51bd4afe-ebc7-b783-28fb-f95f7fbfad86.png)



##PhotonServerSettings

Settingsはインポート後AppID入力がうまくいけば、App Id Realtimeに自動的に反映されているので確認してください。入力しなかった場合は必ず入力してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307841/4c2ec828-28ee-a2fc-7914-f52426559e3d.png)


##部屋の作成から接続までのスクリプト

ヒエラキー上にPhoton(空のGameObject)を作成して、以下のスクリプトを作成後Photon(空のGameObject)にスクリプトをアタッチする。

~~~C#
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;


namespace PhotonPractice{
public class PhotonLogin : MonoBehaviourPunCallbacks {

	//ゲームバージョン指定（設定しないと警告が出る）
	string GameVersion = "Ver1.0";

	//ルームオプションのプロパティー
	static RoomOptions RoomOPS = new RoomOptions()
	{
		MaxPlayers = 2, //0だと人数制限なし
		IsOpen = true, //部屋に参加できるか
		IsVisible = true, //この部屋がロビーにリストされるか
	};

	

	// Use this for initialization
	void Start () {

		//PhotonCloudに接続
		Debug.Log("PhotonLoing");
		//ゲームバージョン設定
		PhotonNetwork.GameVersion = GameVersion; 
		//PhotonServerSettingsファイルで構成されたPhotonに接続。
		PhotonNetwork.ConnectUsingSettings();
		
	}

	//クライアントがマスターサーバーに接続されたときに呼び出される。
	public override void OnConnectedToMaster()
	{

		//ルームへの参加　or 新規作成
		PhotonNetwork.JoinOrCreateRoom("Photonroom",RoomOPS, null); //("ルームの名前",ルームオプションの変数,新規ルームを一覧したいロビー。nullで無視)
		
	}

	//ルーム作成して入室に成功したときに呼び出される。
	public override void OnJoinedRoom()
	{
		//Room型とPlayer型の指定。
		Room myroom = PhotonNetwork.CurrentRoom;　//myroom変数にPhotonnetworkの部屋の現在状況を入れる。
		Photon.Realtime.Player player = PhotonNetwork.LocalPlayer;　//playerをphotonnetworkのローカルプレイヤーとする
		Debug.Log("ルーム名:" + myroom.Name);
		Debug.Log("PlayerNo" + player.ActorNumber);
		Debug.Log("プレイヤーID" + player.UserId);
		

		//この部分はニックネームを決めるためのもので、入力は不要です。
		if(player.ActorNumber  == 1)
		{
			player.NickName = "わたしは1です";
		}
		
		Debug.Log("プレイヤー名" + player.NickName);
		Debug.Log("ルームマスター" + player.IsMasterClient); //ルームマスターならTrur。最初に部屋を作成した場合は、基本的にルームマスターなはず。
		
	}

	//入室失敗したときに呼び出される動作。
	public override void OnJoinRandomFailed(short returnCode, string message) {

		Debug.Log("入室失敗");
		//ルームを作成する。
		PhotonNetwork.CreateRoom(null, RoomOPS); //JoinOrCreateroomと同じ引数が使用可能。nullはルーム名を作成したくない場合roomNameを勝手に割り当てる。
	}

	//ルーム作成失敗したときの動作。
	public override void OnCreateRoomFailed(short returnCode, string message) {

		Debug.Log("作成失敗");

	}

}

}

~~~

再生ボタンを押して以下の画像が表示されれば接続成功です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307841/d34f01e0-5891-fa88-a72d-83878e797573.png)

#おわりに
今回は接続のみでしたが、次回はプレイヤー操作も含めた記事を書く予定です。

#参考
VR-studies：https://github.com/yumemi-inc/vr-studies/wiki
ドキュメント：https://doc-api.photonengine.com/en/pun/v2/index.html
flutterでpod setupしても何も反応しない

環境：Mac(10.14.6)

Flutterの [macOS install](https://flutter.dev/docs/get-started/install/macos) を見ながらFlutterのインストールを行なっていたが、 `pod setup` を入力しても何も起こらなかった。

原因はどうやら現在インストールされている `cocoapods 1.8.1` が原因のようだった。

下記コマンドにて不要なバージョンを削除したら正常に動いた。

```
$ sudo gem uninstall cocoapods
Password:

Select gem to uninstall:
 1. cocoapods-1.7.5
 2. cocoapods-1.8.1
 3. All versions
> 2
Successfully uninstalled cocoapods-1.8.1
```

参考：https://github.com/flutter/flutter/issues/41253
FluentTerminalというwindows terminalを使ってみた

https://github.com/felixse/FluentTerminal

```sh
# 管理者権限でpowershellを開きます
$ choco upgrade chocolatey
$ choco install fluent-terminal
```

chocoのpathは、大体が`c:/ProgramData/Chocolatey`にあります。実行ファイルは`bin`に置いてある事が多く、ライブラリが`lib`です。

`fluent-terminal`は普通にwindows10アプリに登録されますので、`設定 > アプリ > fluent-terminal`から起動できます。

ついでにpowershellのpowerlineを設定してみました。

![](https://github.com/felixse/FluentTerminal/raw/master/Screenshots/terminal.jpg)

https://github.com/Jaykul/PowerLine

```
$ pwsh

$ echo $psversiontable
6.2.0

$ Install-Module PANSIES -AllowClobber
$ Install-Module PowerLine
$ Import-Module PowerLine

$ Set-PowerLinePrompt -SetCurrentDirectory -RestoreVirtualTerminal -Newline -Timestamp -Colors "#FFDD00", "#FF6600"
```
裁判所HPの規則リンク集スクレイピングのコードを改修する。

自分自身の改修事項メモなのです。
法技研六法は，e-Govの法令データ提供システムだけではなく，裁判所HPの規則集からもリンクを収集して検索できるようにしています。裁判所規則は（行政規則とは異なり）法律と同格の法なので，実務上重要。

```:日本国憲法
第７７条①　最高裁判所は、訴訟に関する手続、弁護士、裁判所の内部規律及び司法事務処理に関する事項について、規則を定める権限を有する。
```
裁判所規則は裁判所ウェブサイトに一覧が載っているので，これをスクレイピングすればリストを作ることができます。
これまで，法令リストを作るにあたっては，e-Govの法令APIのXMLデータをBeautifulSoupで処理していた余勢を駆って，裁判所規則集もBeautifulSoupで処理していたのですが，どうも最近の裁判所Web更新の折にHTMLがinvalidになったらしく（余計な`</a>`タグが入ってる），BeautifulSoupでのスクレイピングがうまくいかなくなりました。
ということで，（最初からそうしてりゃよかったのですが）正規表現でスクレイピングするように改修したので，そのメモ。

```python:共通部分
import requests
import json
from urllib.parse import urljoin

#分野別の規則集URL
URL_COURTS = [
  "http://www.courts.go.jp/kisokusyu/minzi_kisoku/index.html",
  "http://www.courts.go.jp/kisokusyu/keizi_kisoku/index.html",
  "http://www.courts.go.jp/kisokusyu/kazi_syonen_kisoku/index.html",
  "http://www.courts.go.jp/kisokusyu/sonota_kisoku/index.html"
]

lawList = []
```
```python:旧コード
from bs4 import BeautifulSoup

for genre in URL_COURTS:
  r = requests.get(genre)
  r.encoding = "utf-8" #裁判所HPはencodingがHTTP-Headerでわからない？
  soup = BeautifulSoup(r.text, "html.parser")
  links = soup.select('div#contents ul.txt90 a')
  for alink in links:
    print(alink)
    if alink.string: #何故か裁判所のリンク集に，文字を含まないリンクがある場合が。
      aLaw = {
        "LawName": "裁判所::"+alink.string,
        "LawNameShort": alink.string,
        "URL": urljoin(r.url, alink.get('href'))
      }
lawList.append(aLaw)
```
```python:新コード
import re

reKisoku = re.compile('<li class="li01"><a href="(.+?)" target="_.+?">(.+?)</a>')
for genre in URL_COURTS:
  r = requests.get(genre)
  r.encoding = "utf-8"
  kisokus = reKisoku.findall(r.text)
  for aKisoku in kisokus:
    aLaw = {
      "LawName": "裁判所::"+aKisoku[1],
      "LawNameShort": aKisoku[1],
      "URL": urljoin(r.url,  aKisoku[0])
    }
    lawList.append(aLaw)

```
【SQL】テーブルの作成・削除(CREATE,DROP,TRUNCATE)

テーブルの作り方や、インデックスの貼り方とかを殴り書き

#テーブル作成
列情報を指定して空のテーブルを作る方法をいくつか

##CREAT
とりあえずシンプルなCREAT文
紙に罫線と項目名の名前だけを各イメージ。
学年別の学生一覧を作るならこんな感じ。


```SQL:Create
CRATE TABLE first_grader (
   student_number int(3), --3桁以下の整数
   first_name verchar(10) NOT NULL,  --nullを認めない10文字以内の文字列
   last_name verchar(10), --null(データなし)でもよい10文字以内の文字列
   birthday date --日付
)
```

#テーブルの参照作成
##CREAT SELECT
既存のテーブルを参照して作る方法
列の属性がコピーされ、SELECT文で抽出されるデータもコピーされる
1年生の一覧から2年生の一覧を作るならこんな感じ

```SQL:RefCreate
CREATE TABLE name_list AS
   SELECT * FROM first_grader
```
特定の列やデータだけをコピーすることもできる
例えば、1年生の一覧から学生番号が10以下の学生の名前だけの一覧を作るなら

```SQL:RefSelectCreate
CREATE TABLE name_list AS
   SELECT first_name FROM first_grader
      WHERE student_number < 10
```

##CREAT INTO
参照作成の場合、CREAT文を使わずにSELECT INTO文でも作れる
さっきの例文を書き換えると

```SQL:SelectInto
SELECT first_name 
   INTO name_list
   FROM first_grader
   WHERE student_number < 10 
```

#テーブルの削除
テーブルや、データを消す方法をいくつか

##DROP
データもテーブル情報(どんな列を持っていたかなど)を消す
リカバリも出来ないのでご利用は計画的に
手元にある表をシュレッダーにかけるイメージ

```SQL:Drop
DROP TABLE first_grader
```

##TRUNCATE
一度テーブルを削除してから同じ構造のテーブルを再作成する
データを消す方法はDELETE文もあるけど、こちらの方が変なごみが残らない
Truncateは既存の表をシュレッダーにかけて、新しい紙に罫線と項目名を書くけど、
Deleteは消ゴムで表を消すイメージ。消しゴムだと白紙のようなキレイさにはならないよね
あと、Truncateの方が処理が早い。
```SQL:TRUNCATE
TRUNCATE TABLE first_grader
```


##DELETE
こちらは対象の列を指定して消す
where句などを使うことで、部分的に削除することができる

```SQL:DELETE
DELETE FROM first_grader
   WHERE student_number < 10
```
MAYAのよくわからないエラーを解消したい  (hikCharacterControlsUI.mel line 323: オブジェクト 'hikCharacterList|OptionMenu')

#現状
`エラー: file: C:/Program Files/Autodesk/Maya2019/scripts/others/hikCharacterControlsUI.mel line 323: オブジェクト 'hikCharacterList|OptionMenu' が見つかりません。 //`

こんな感じにボーンがズレる現象
![Desktop Screenshot 2019.10.03 - 21.04.58.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374827/4d55a420-a7f3-5c3a-118e-51bd0a48830d.png "頭痛い")


エラーはこんな感じ
![Desktop Screenshot 2019.10.03 - 21.06.17.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374827/5beae8ad-15a6-1398-8169-455fc4451cd8.png "エラー辛い")

調べてみると一つだけ記事があった
ありがたや～&#x1F64F;

http://blog.livedoor.jp/morisoba123/archives/52179486.html

この記事いわく
右上のT字キャラアイコンのcharactor control toolを一旦開いた状態で閉じると発生するらしい

#ほんへ
今回はウィンドウ情報をモデルデータに保存しない設定をしていきます
[参考元](http://mainote.net/posts/3dcg1.html)

まず忘れないうちにcharactor control toolを閉じておきましょう
![Desktop Screenshot 2019.10.03 - 22.00.33.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374827/ceeac8dd-7085-d252-0957-453cf16ba05e.png)

1.（ウインドウ ＞設定/プリファレンス ＞プリファレンス）からプリファレンスを開きます

![Desktop Screenshot 2019.10.03 - 22.01.25.79.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374827/81e93ef3-1987-fc8b-72f8-2a0348c599a0.png)

2.左のカテゴリからUI要素を選択します
![Desktop Screenshot 2019.10.03 - 22.02.38.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374827/45b88462-890c-7d2c-c89d-3888ef69352e.png)

3.「パネルの構成」の中の「保存するとき」「開くとき」のチェックを外します
![Desktop Screenshot 2019.10.03 - 22.02.32.86.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374827/8db4beaa-0b5a-dc29-7918-9279dc5301f2.png)

4.ファイルを開き直しましょう
ここまでの操作が上手くいっていれば直っているはずです
![Desktop Screenshot 2019.10.03 - 22.03.18.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374827/e1320292-cce7-4517-177f-98ce5b0460d4.png)



#おまけ
ちなみに昔からあるバグらしい
[MAYA公式フォーラム](https://forums.autodesk.com/t5/maya-forum/ctrl-z-warning-message/m-p/6566873/highlight/true#M36131)
RxSwift  combineLatest で いずれかの更新を無視する

#追記
withLatestFromを使えば良い！って知りませんでした。たはー
ということで、下記はあんまり読まないで良い内容です。。

##前書きのようなもの
RxSwiftのcombineLatestは、複数のストリームを比較するために利用します。挙動としては、比較対象のいずれかの値の更新が行われた時にストリームが流れてきます。例えば下記のような場合において

```swift
let main = PublishSubject<Int>()
let sub = PublishSubject<Int>()

Observable
.combineLatest(main, sub)
.bind { (mainValue, subValue) in
     NSLog("main, sub > \(mainValue)-\(subValue)")
}

sub.onNext(1) // main側の値がないので何も出力されない
main.onNext(2) // 2-1
sub.onNext(2) //  2-2
sub.onNext(3) //  2-3
main.onNext(10) // 10-3
```
```
main, sub > 2-1
main, sub > 2-2
main, sub > 2-3
main, sub > 10-3
```
main側、sub側 どちらの値の更新も契機となって、イベントストリームが流れてきます

##やりたいこと
この例だと、sub側の更新ではストリームを流すことはしないで、main側が更新されたときに、一緒に最新のsubの値が欲しいのです。
つまり、期待する出力は下記のようになります

```
main, sub > 2-1
main, sub > 10-3
```

##オススメしない実装

これを上手に言語化できないのが、自分の技術力の無さなのですが、、
rxのオペレータ (map、filter、bind、etc...) にはクロージャを渡しますが、そのクロージャに渡ってくる引数以外の値を利用することはオススメしません。
マルチスレッドを考えた時に、期待した値になっているか保証がないとの、そもそもクロージャにおいて参照透明性がありません。

```swift
let main = PublishSubject<Int>()
let sub:Int = 0

main.bind { (mainValue) in
     //self.sub はこのクロージャの世界の"外"の値であって、参照透明性を考慮してない
     NSLog("main, sub > \(mainValue)-\(self.sub)")
}

sub = 1 // 値を変えてから
main.onNext(2) // イベントを起こすが
sub = 2 //マルチスレッドだと、
sub = 3 //この値の変更が onNext(2)を追い越してしまうのか保証がない
main.onNext(10)
```

##combineLatest + distinctUntilChanged
Rx の distinctUntilChanged は "新旧の値を比較して、更新を通知しない条件" を返す為に利用できます。

```swift
Observable
.combineLatest(main, sub)
.distinctUntilChanged { (old, new) -> Bool in
　　//old は (main, sub)というタプル、newにも(main, sub)のタプルが入ってくる
　　//新旧のmain側の値が同じ（=変化してない)場合には、イベントの通知を行わない
   return old.0 == new.0
}
.bind { (mainValue, subValue) in
   NSLog("main, sub > \(mainValue)-\(subValue)")
}
```

```
main, sub > 2-1
main, sub > 10-3
```

ほら、main 側の値が変わった時だけストリームが流れてきてますよね！
busybox vs toybox

# Overview

what is the difference between busybox and toybox? at this time, user perspective and aspect only, not diving into the deep detail.

ahhh, what is the busybox and toybox anyway?

# busybox

BusyBox combines tiny versions of many common UNIX utilities into a single small executable. It provides minimalist replacements for most of the utilities you usually find...okay

read [here](https://github.com/mirror/busybox) to get more intel.

**Busybox predates Android, but has never shipped with Android due to the license.**

# toybox

but, toybox is toybox is a fresh from-scratch implementation under an android-compatible license.toybox is replacing busybox in Aboriginal Linux one command at a time.

read [here](http://landley.net/toybox/about.html) or [here](https://github.com/landley/toybox)

# let's put hands on them

### busybox

let's just use docker,

```
docker search busybox
docker pull busybox
docker run -it <image id> /bin/sh
```

checking some statistics,

```
~ # ls -lt /bin/busybox 
-rwxr-xr-x  398 root     root       1132888 Sep  4 17:26 /bin/busybox
~ # busybox --list | wc
      397       397      2731
```

of course that would be depending on configuration, but so far 395 commands available, and busybox itself is just 1,132,888byte binary which is pretty much compact enough.

### toybox

no official docker is available now, so just get binary to go.

```
wget http://landley.net/toybox/bin/toybox-x86_64
chmod +x toybox-x86_64

ls -lt toybox-x86_64 
-rwxr-xr-x 1 tomoyafujita tomoyafujita 596K  5月 30 10:47 toybox-x86_64*

./toybox-x86_64 echo hello world
hello world

./toybox-x86_64 --list | tr -s ' ' '\n' | wc
    200     200    2585

```

the size of binary toybox is almost half of busybox, which is 596KB. but current supported command is also half of them, really statically reasonable.

# Appendix

https://www.elinux.org/Busybox_replacement
サクラエディタの簡単ですぐ使える正規表現

## 前置き
現在社会人４年目の筆者が業務で超超使っているサクラエディタの正規表現を正規表現初心者向けにまとめた記事。初心者向けなので難しい（否定先読みとか）ものに関しては除外している。
サクラエディタを使用している方は業務効率化にとっても役立つ。
※サクラエディタ向けなので各種プログラミング言語や別ソフトでは文法は異なることがあることに注意。

## 基本文法
- 「.」・・・任意の一文字を表す。
- 「^」・・・行頭を表す。
- 「$」・・・行末を表す。
- 「+」・・・直前の文字の１文字以上の繰り返しを表す。
- 「*」・・・直前の文字の０文字以上の繰り返しを表す。
- 「{数値}」・・・直前の文字の数値個の繰り返しを表す。
- 「{数値1,数値2}」・・・直前の文字の数値1個以上数値2個以下の繰り返しを表す。
- 「¥r」・・・改行コードCRを表す。
- 「¥n」・・・改行コードLFを表す。
- 「¥r¥n」・・・改行コードCRLFを表す。
- 「¥t」・・・タブを表す。

### 使用例
#### 検索
``` :"b"が6つ続いている箇所を検索
b{6}
```
``` :"error"という文字を含む行を検索
^.*error.*$
```
#### 置換
``` :空行を削除
置換前：「^¥r¥n」
置換後：「」
```
``` :csvをtsvに変換
置換前：「,」
置換後：「¥t」
```
``` :行末に「,」を挿入
置換前：「$」
置換後：「,」
```
#### 応用例
- 置換元の文字列を使用したいとき  
→()を用いる。置換元の文字列を()で囲むと、置換後の文字列の指定時に「\$数値」で指定が可能。\$の次の数値は1,2,・・・と置換元の文字列で用いた()の出てくる順番に依存。    
例：「2018/09」という文字列を「09/2019」にしたいとき  

``` :「2018/09」という文字列を「09/2019」にしたいとき
置換前：「(2018)/(09)」
置換後：「$2/$1」
```
``` :「2018/09」という文字列を「09/2019」にしたいとき(汎用例)
置換前：「(.+)/(.+)」
置換後：「$2/$1」
```
- 最短一致  
→「2019/10/02」を、「^.+/」で検索すると「2019/10/」がヒットする。  
もし「2019/」をヒットさせたいときは「?」を用いる。

``` :最短一致
^.+?/
```
- 最短一致・置換元文字列使用の応用例  
→「顧客:日付:従業員:予約番号」という文字列を「('顧客','日付','従業員','予約番号')」という文字列に整形する

``` :最短一致応用例
置換前：「(.+?):(.+?):(.+?):(.+)」
置換後：「('$1','$2','$3','$4')」
```

## まとめ
結構便利では？否定とかアルファベットの大文字・小文字変換もできたりするので調べて使用してみると楽しいかも。キーマクロとの組み合わせもアリ。
良いサクラエディタライフを！