OmniAICreator/Qiita-1.07M huggingface dataset:
TableViewをスクロールしてデータ更新（上・下それぞれバージョン）

SNSなどで見かける、読み込み済みコンテンツの端までいったら、続きを読み込む方法です。
![IMG_1523.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/c5e721fa-8622-230e-6335-87f5b0673730.png)


#データ更新部分を準備

データ更新処理を待つためにセマフォを設定します。

```swift

let semaphore = DispatchSemaphore(value: 1)
```

リフレッシュ時に以下の関数を呼ぶこととします。
ここで通信リクエストなど行います。

```swift
func updateData () {
    DispatchQueue.global().async {
        
        //*** ここでデータを更新する処理をする ***

        DispatchQueue.main.async {
            self.tableView.reloadData()
            self.semaphore.signal() // 処理が終わった信号を送る
        }
    }
}
```


#下向きスクロールで更新
下向きに引っ張ってリフレッシュする場合は、UIRefreshControlが使えます。

この記事：[[Swift/iOS] フリックで更新するTableView](http://blog.cafeform.com/?p=1608)の方法です。

###１、UIRefreshControlを設置します

```swift
var refreshControl:UIRefreshControl!
```

```swift
override func viewDidLoad() {
        super.viewDidLoad()
        refreshControl = UIRefreshControl()
        refreshControl.attributedTitle = NSAttributedString(string: "再読み込み中")
        refreshControl.addTarget(self, action: #selector(ViewController.refresh), for: UIControl.Event.valueChanged)
        tableView.addSubview(refreshControl)
}
```
###２、リフレッシュ時に呼ばれる関数を設定します

```swift
    @objc func refresh() {
        updateData()

        semaphore.wait()
        semaphore.signal()
        // データ更新関数が終了したら、リフレッシュの表示も終了する
        refreshControl.endRefreshing()
    }
```

#上向きスクロールで更新
TableViewの一番下までスクロールしたら続きを更新する方法。YoutubeなどのUIみたいな。
ScrollViewのデリゲートメソッドを使います。TableViewはScrollViewクラスを継承しているので。

```swift
func scrollViewDidScroll(_ scrollView: UIScrollView) {
   let height = scrollView.frame.size.height
   let contentYoffset = scrollView.contentOffset.y
   let distanceFromBottom = scrollView.contentSize.height - contentYoffset
   if distanceFromBottom < height {
       if self.reloading { // デリゲートは何回も呼ばれてしまうので、リロード中はfalseにしておく
           updateData()
           semaphore.wait()
           semaphore.signal()        
           self.reloading = false
       }
   }
}
```

🐣
****
お仕事のご相談こちらまで
rockyshikoku@gmail.com

Core MLを使ったアプリを作っています。
機械学習関連の情報を発信しています。

[Twitter](https://twitter.com/JackdeS11)
[Medium](https://medium.com/@rockyshikoku)
ARQuickLookの使い方

ARオブジェクトをブラウザやViewで手軽に表示できます。
Reality ComposerでつくったオブジェクトやUSDZファイルを表示可能です。
コーチングオーバーレイとコンテンツがアニメーション付きで表示されます。
![Oct-15-2020 14-06-12.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/9eb8389f-8036-422c-f628-15aedbad9565.gif)

#手順

##１、3Dファイルを用意する
対応フォーマットはRealityファイルとUSDZファイルです。
どちらもアニメーションを含んだ３Dオブジェクトファイルです。
どちらかで用意します。

**・Reality ComposerでRealityファイルをつくる**
Reality Composerはオブジェクトを置くだけ。
![スクリーンショット 2020-10-15 13.35.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/d1132c53-0422-96b3-d5d9-c5e64786b3a5.png)
**・USDZファイルを用意する**
USDZファイルは[アップルのギャラリー](https://developer.apple.com/jp/augmented-reality/quick-look/)からも入手できます。

##２、ARQuickLookで再生
###Case１：ローカルで再生
XCodeに.rcprojectか.usdzファイルをバンドルして、QLPreviewControllerで再生します。
.rcprojectファイルはXCodeにバンドルすると自動的にRealityファイルとして出力されます。

```swift
import UIKit
import QuickLook
import ARKit

class ViewController: UIViewController, QLPreviewControllerDataSource {
    
    override func viewDidAppear(_ animated: Bool) {
        let previewController = QLPreviewController()
        previewController.dataSource = self
        present(previewController, animated: true, completion: nil)
    }
    
    func numberOfPreviewItems(in controller: QLPreviewController) -> Int { return 1 }
    
    func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
        guard let path = Bundle.main.path(forResource: "Scene", ofType: "reality") else { fatalError("Couldn't find the supported input file.") }
        let url = URL(fileURLWithPath: path)
        return url as QLPreviewItem
    }
}
```
###Case２：ブラウザで再生
下記をHTMLに埋め込むことで、SafariやWEBビューで再生されます。

```html
<div>
    <a rel="ar" href="/assets/models/Scene.reality">
        <img src="/assets/models/my-model-thumbnail.jpg">
    </a>
</div>
```

🐣
****
お仕事のご相談こちらまで
rockyshikoku@gmail.com

Core MLを使ったアプリを作っています。
機械学習関連の情報を発信しています。

[Twitter](https://twitter.com/JackdeS11)
[Medium](https://medium.com/@rockyshikoku)
Youtube Data APIのリクエスト結果表示数（resultsPerPage）を変える

デフォルトでは「５」だけ表示されます。


```json
"pageInfo": {
    "totalResults": 40,
    "resultsPerPage": 5
}
```

次の５個を取得するには、結果に含まれる「NextPageToken」をリクエストURLにつけます。

```
https://www.googleapis.com/youtube/v3/playlists?part=snippet&channelId={CHANNEL_ID}&key={API_KEY}&pageToken={PAGE_TOKEN}
```

最初から取得する数を増やすには、「max_Results」をリクエストURLにつけます。

```
https://www.googleapis.com/youtube/v3/playlists?part=snippet&channelId={CHANNEL_ID}&key={API_KEY}&&maxResults=20
```

```json
"pageInfo": {
    "totalResults": 40,
    "resultsPerPage": 20
}
```

🐣
****
お仕事のご相談こちらまで
rockyshikoku@gmail.com

Core MLを使ったアプリを作っています。
機械学習関連の情報を発信しています。

[Twitter](https://twitter.com/JackdeS11)
[Medium](https://medium.com/@rockyshikoku)
React Hooksの強制再レンダリング方法

#React Hooksでの強制サイレンダリング方法
クラスコンポーネントでは、

```
this.forceUpdate()
```

が使えましたが、関数コンポーネントではそうは行きませんよね。
「形が不細工でもレンダーしたい！」という方にお勧めなのがこちらの方法です。

```
//boolean型のstateを作成
const [update,setUpdata]=useState<boolean>(false)
//レンダリングしたい場所でこれを差し込むだけ
setUpdata(update?false:true)
```
setUpdata(update?false:true)の役割は、updateステートがtrueだった場合"false"、falseだった場合"true"にするだけです。
ぜひ使っていきましょう。
このポリュームは認義可能なファイルシステムではありません

この記事では、「<a href="https://jp.bitwar.net/course/delete/2740.html">このポリュームは認義可能なファイルシステムではありません</a>」エラーの解決策を示します。このエラーは珍しいことではありません。私たちの多くは、毎日の作業中にこのエラーメッセージに遭遇する場合があります。


外付けハードディスク、USBフラッシュドライブ、SDカードなどのストレージデバイスをコンピューターに接続しようとすると、次のプロンプトが表示される場合があります。ドライブを使うにはフォーマットする必要があります。フォーマットしますか?


もちろん、このストレージデバイスに重要なデータが含まれている場合は、[キャンセル]をクリックしてパーティションの再フォーマットをキャンセルする必要があります。キャンセル後、コンピューターにプロンプトが表示されます。G：にアクセスできません。このポリュームは認義可能なファイルシステムではありません。必要なファイルシステムドライバーカすべて誌み込まれているか、ボリュームがれていないかが確認してください。


このエラーは通常、RAWファイルシステムが原因です。このような問題は、ファイルシステムタイプ情報が失われたり、複数のシステムテーブル間で不安定な場合に発生する可能性があります。


心配しないでください！この記事では、関連データを失うことなく、この問題の可能な解決策を提供します。


<strong>「このポリュームは認義可能なファイルシステムではありません」の原因</strong>


このエラーを引き起こすさまざまな要因はここにあります。


1.システムの再インストール

2.ウイルスまたはマルウェア攻撃

3.異常なコンピューターのシャットダウン

4.ファイルシステムの変換に失敗しました

5.誤ってファイルシステムを削除する

6.電源エラー

7.物理的な損傷


<strong>「このポリュームは認義可能なファイルシステムではありません」エラーのトラブルシューティング方法</strong>



「このポリュームは認義可能なファイルシステムではありません」問題に対処する前に、このパーティションがRAW読み取り不能ファイル構造になっていることに注意する必要があります。コンテンツを選択してマウスを右クリックすると、コンテンツを表示することもできます。0バイトとして表示されていることがわかります。


また、ディスク上に重要なデータがあり、それを失いたくない場合。次に、ディスクで表示できないデータを取り戻す必要があります。そもそもフォーマットする必要はありませんが、プロのデータリカバリソフトウェアBitwar Data Recoveryを使用して、高品質の結果を得るためにデータを取得してください。


Bitwar Data Recoveryは非常に便利なRAWデータ復元ソフトウェアです。 RAWでアクセスできないデータを回復するのに役立ちます。

   詳しくは、「<a href="https://jp.bitwar.net/course/delete/2740.html">「修復済み」このポリュームは認義可能なファイルシステムではありません</a>」をご参照ください。
【Vim】カーソルキーでの移動を禁止する設定（ドラゴン付き）。

## 事前インストール

cowsayとｓｌコマンド必要なので予めインストールが必要
`brew install cowsay sl`

## 設定方法

.vimrcに以下を設定する。

設定するとAAのドラゴンが丁寧に教えてくれる。

```vim
function TeachKey(message)
    let summon = join([“!clear; cowsay -f dragon “, a:message, “を押すのだ”])
    exec summon
endfun
nnoremap <buffer> <Left> <Esc>:call TeachKey(‘h’)<CR>
nnoremap <buffer> <Right> <Esc>:call TeachKey(‘l’)<CR>
nnoremap <buffer> <Up> <Esc>:call TeachKey(‘k’)<CR>
nnoremap <buffer> <Down> <Esc>:call TeachKey(‘j’)<CR>
nnoremap <buffer> <PageUp> <Esc>:call TeachKey(‘Ctrl+B’)<CR>
nnoremap <buffer> <PageDown> <Esc>:call TeachKey(‘Ctrl+F’)<CR>
inoremap <buffer> <Left> <Esc>:call TeachKeyBi)ding(‘h’)<CR>
inoremap <buffer> <Right> <Esc>:call TeachKey(‘l’)<CR>
inoremap <buffer> <Up> <Esc>:call TeachKey(‘k’)<CR>
inoremap <buffer> <Down> <Esc>:call TeachKey(‘j’)<CR>
inoremap <buffer> <PageUp> <Esc>:call TeachKey(‘Ctrl+B’)<CR>
inoremap <buffer> <PageDown> <Esc>:call TeachKey(‘Ctrl+F’)<CR>
vnoremap <buffer> <Left> <Esc>:call TeachKeyBi)ding(‘h’)<CR>
vnoremap <buffer> <Right> <Esc>:call TeachKey(‘l’)<CR>
vnoremap <buffer> <Up> <Esc>:call TeachKey(‘k’)<CR>
vnoremap <buffer> <Down> <Esc>:call TeachKey(‘j’)<CR>
vnoremap <buffer> <PageUp> <Esc>:call TeachKey(‘Ctrl+B’)<CR>
vnoremap <buffer> <PageDown> <Esc>:call TeachKey(‘Ctrl+F’)<CR>

nnoremap <buffer> <Del> <Esc>:<C-u>!sl<CR>
inoremap <buffer> <Del> <Esc>:<C-u>!sl<CR>
vnoremap <buffer> <Del> <Esc>:<C-u>!sl<CR>

set backspace=0
```

## 確認方法

設定されるとこんなのが出る。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89244/6472df56-61ef-4f9c-781b-8e0ccda65d9a.png)

## 参考URL
[vi(vim)で完全にカーソルキーを無効化させたい - スタック・オーバーフロー](https://ja.stackoverflow.com/questions/1611/vivim%E3%81%A7%E5%AE%8C%E5%85%A8%E3%81%AB%E3%82%AB%E3%83%BC%E3%82%BD%E3%83%AB%E3%82%AD%E3%83%BC%E3%82%92%E7%84%A1%E5%8A%B9%E5%8C%96%E3%81%95%E3%81%9B%E3%81%9F%E3%81%84)

#development/vim
超簡単に始めるGitHub CLI

## 利用手順
### 1.GitHub CLIをインストール
ターミナルで`brew install gh`を実行する

```
$ brew install gh

Updating Homebrew...
==> Auto-updated Homebrew!
Updated 1 tap (homebrew/core).
==> New Formulae
box2d                    fleet-cli                libpciaccess             protoc-gen-go-grpc
envoy                    git-hound                matplotplusplus          tfsec
==> Updated Formulae
Updated 508 formulae.

==> Downloading https://homebrew.bintray.com/bottles/gh-1.1.0.catalina.bottle.tar.gz
==> Downloading from https://d29vzk4ow07wi7.cloudfront.net/6045fefd30216e3ddde0f473669334727234a0a337
######################################################################## 100.0%
==> Pouring gh-1.1.0.catalina.bottle.tar.gz
==> Caveats
Bash completion has been installed to:
  /usr/local/etc/bash_completion.d

zsh completions have been installed to:
  /usr/local/share/zsh/site-functions
==> Summary
🍺  /usr/local/Cellar/gh/1.1.0: 60 files, 16.4MB
```

### 2. githubにログインする

ターミナルで`gh auth login`を実行する

```
$ gh auth login
```

####GithubかEnterpriseか聞かれる(環境による)ので選択する

```
? What account do you want to log into?  [Use arrows to move, type to filter]
> GitHub.com
  GitHub Enterprise Server

```

####認証方法を聞かれる
`Webブラウザ` or `トークン`のどちらかを選択する
矢印で選択してEnterをタップする => Webブラウザが起動します。
ここではWebブラウザを利用(簡単)

```
? How would you like to authenticate?  [Use arrows to move, type to filter]
> Login with a web browser
  Paste an authentication token

```

####ワンタイムコードが発行される
ここでは`7536-EAC9`がワンタイムコードにあたります。

```
? How would you like to authenticate? Login with a web browser

! First copy your one-time code: 7536-EAC9
- Press Enter to open github.com in your browser...

```

####起動したWebブラウザ画面
`Enter your one-time code`に先ほどターミナル上に表示されたワンタイムコードを入力し`Continue`をタップする => 認証画面へ遷移する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59015/57bb37bf-a38d-1422-276a-06d55c6290c7.png)


####認証する
`Authorize github`ボタンをタップする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59015/68e52ccf-00af-f1e3-9743-e6ecb781d015.png)



####パスワードを入力する
パスワードを入力して`Confirm password`ボタンをタップする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59015/77fd7053-88cc-4c01-1b1e-e6471f718517.png)

認証完了画面が表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59015/c06ac213-6eea-277f-1cdb-b4a631d81b27.png)

####ターミナルに戻る
以下のメッセージが表示されているのでEnterをタップする
`✓ Authentication complete. Press Enter to continue...`


####git protocolを選ぶ
HTTPSかSSHかを矢印で選択します。(ここではHTTPSを利用)


```
? Choose default git protocol  [Use arrows to move, type to filter]
> HTTPS
  SSH

? Choose default git protocol HTTPS
- gh config set -h github.com git_protocol https
✓ Configured git protocol
✓ Logged in as tkhrname
```

こちらでgithubへのログインが完了です。

###3. プルリクエストを作成する

```
git checkout -b feature/ブランチ名
git commit --allow-empty -m "Pull request start."
gh pr create --base develop --title "Title of Pull request" --body "This is the first pull request."
```
fatal error: boost/ detail/endian.hpp: No such file or directory #include <boost/detail/endian.hpp>

boost 1.73にしたら、プログラムが表題のエラーを吐いてコンパイルできなくなったので、治し方の備忘録（ただの情報元のコピーですが、毎回その情報元を探すのに苦労するので）。


以下の２つは、boost 1.73で削除されたとのこと。(1.72までは存在する）

```
https://www.boost.org/doc/libs/1_73_0/boost/predef/detail/endian_compat.h
https://www.boost.org/doc/libs/1_73_0/boost/detail/endian.hpp
```

1.73以降は、`<boost/detail/endian.hpp>`の代わりに以下を使う。

```cpp
//#include <boost/detail/endian.hpp>
#include <boost/predef/other/endian.h>
```

さらに、`BOOST_XXX_ENDIAN`を`BOOST_ENDIAN_XXX_BYTE`に書き換える。

```cpp
//#if defined(BOOST_BIG_ENDIAN)
#if defined(BOOST_ENDIAN_BIG_BYTE)
...
//#elif defined(BOOST_LITTLE_ENDIAN)
#elif defined(BOOST_ENDIAN_LITTLE_BYTE)
```

これでコンパイル通るようになりました。

情報元：
https://github.com/boostorg/endian/issues/45
コードを販売できるサービス「Code-sell」をリリースした！(個人開発)

追追追追追追記
手数料０％キャンペーンやってます！今がチャンス！

###初めに
今回、約２か月ぶりにwebアプリを公開しました。
プログラミングコードを販売できるサービス Code-sellです。

https://www.code-sell.net/

なるべく気軽に販売・購入できるように工夫しました。
100円から価格設定できます。
ちなみに僕が今まで作ってきた4つのwebアプリのコードをすべて無料で公開しています！
ほしい人いるかわからないけど何かの参考にでも...。

![code-sell.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480294/6fa5f9e1-080e-8e43-0e92-605dfac28863.png)

↑topページ

###なぜ作ったか
今まで作ったwebアプリを販売（譲渡）しようと思ったのですが権利の問題や面会などめんどくさそうなものがたくさん出てきました。そんな時に思いつきました。Code-sellは譲渡はせずコードをダウンロードするだけなので権利の問題も考えなくていいですし、面会ももちろんありません。

###できること
google認証
stripeを使った、購入、送金
いいね
通知
言語タグ・説明タグ

とかです。基本的な機能しかいまはありません...。


###使った技術
rails6
ruby2.7
stripe
postgresql
slim
ridgepole
JavaScript
heroku

くらいですかね。
このなかでもstripeには本当に苦労しました。
情報はあるんですがどれもこれもコードの説明？で実践的な情報が本当に少ないです。
なので組み立てるのにかなり時間をかけました。
絶対にstripeに関する記事を出すと約束します。

###終わりに
読んでくれてありがとうございました。ぜひcode-sell使ってみてください！
https://www.code-sell.net/

※まだ公開したばかりなので不具合を見つけたらお問い合わせフォームやらQiitaのコメントなどで教えてください。お願いします。

追記
https://note.com/utog/n/nb7a29b3d4f76
noteも書きました。

追追記
https://twitter.com/Codesell2
ツイッターアカウントつくりました！

追追追記
https://www.service-safari.com/posts/38647
ServiceSafariで紹介されました！
申請から数日たったのでもうだめかと思ってました汗

追追追追記
~~ダウンロードするとエラーになるという致命的な現象を発見しました。
開発環境では正常に動いているので気が付きませんでした。
至急、修正していますがなかなか治りません。
何かわかる方はコメントでお願いします。~~

解決しました。cloudinaryではなくAWSにしました。

追追追追追記
ほしい機能などがあったらqiitaのコメントなどで教えてください。
内容次第では即採用します！
windows設定　備忘録

windowsを支給され場合に必ず入れるアプリ、設定についての備忘録


普段はMACを使っているがpjによっては支給されたpcを使って開発することも多い。

毎度毎度ぐぐりながらあのアプリやこのアプリを入れてうんやかんやと時間の無駄なので

このシートだけで完結させたい。


- clibor
- executor
- サクラエディター
- Mysql workbench
- A5
- chrome
- source tree
- VSCode


chromeの中の拡張機能
- vimium
- ダークモード設定



##これからやりたいこと

dotfilesを利用して設定ファイルを一元管理する
API（非同期通信を実装する場合）

# 前提
- 非同期通信を実装する際のAPIについての内容である。
- コントローラーの記述、それに対応した.json.jbuilderの記述を記事にしている。

※非同期通信の手順をjQuery導入から全て確認したい方のまとめは[こちら](https://kayoblog.org/programming_myapp_hidoukitushin/)

# APIとは
#### JSONなどの形式で返すサーバの仕組みのこと。

非同期で行われるリクエストに対して、
「求められたデータをレスポンスする仕組みを用意する仕組み」を、APIを作成することで実現。

RailsではHTMLを返すのがデフォルトだが、
JavaScriptから扱えるようにJSON形式でデータを返すようにすることもできる。


# APIを追加する方法
RailsでAPIを追加する方法は複数存在する。
今回はコントローラー（のアクション）に追加する方法。

#### 「元々あるコントローラに対して非同期通信の場合には非同期通信用のデータを返す」
HTMLを返すのではなくてJSONを返すように記述する。
※Railsでは１つのアクションのなかでHTMLやJSONのフォーマットごとに分岐できる。

　
# respond_toを使用してJSON形式のリクエストに対してのレスポンスを返す
アクションに対して実装する。
以下の場合はSongcolorをcreateする。
その後にリクエストをどの形式で返す（レスポンス）かを記述。

```ruby:＜例A＞#####_controller.rb（該当するコントローラー）
  def create
    @songcolor = Songcolor.create(color: params[:color], song_id: params[:song_id])
    respond_to do |format|
      format.json
    end
  end
```
　
　　　　▼▼▼詳しく▼▼▼
　
respond_toというメソッドを使用することで、
フォーマットに応じたレスポンスを作成することができる。
「JSON形式で返せるようにする」という実装になあたる。
今後これとセットでJSON形式のファイル「create.json.jbuilder」を作成する必要がある。
返すデータを記述する。また、ファイル名は対応させるためにアクション名と同様にする。
今回はcreateアクションに対応するので「create.json.jbuilder」になる。


```ruby:＜例＞さらに上記のコードの重要な範囲をピックアップ
    respond_to do |format|
      format.json
    end
```

アクション内に記述することで
〇〇（アクション）したら上記のrespond_to後のリクエストに応じて方法で返す。


　
　　
### ＜他の方法＞〇〇.json.jbuilderのファイルを作成しない方法もある。
下記のようにrenderに{ }をつけ完結させることもできる。
※グループごとに投稿できるチャットアプリを例にしている場合。

```ruby:＜例＞#####_controller.rb
respond_to do |format|
  format.json { 
    render json: { id: @user.id, name: @user.name }
  }
end
```
### .json.jbuilderのファイルを作成する場合

```ruby:＜例＞app/views/messages/show.json.jbuilder
json.content @message.content

=> { content: "@messageのcontent" }
```
jbuilderは左がキー・右がバリューのようなハッシュ
json.contentがkey、@message.contentがvalue

自分のアプリ＜例A＞では「json.color @songcolor.color」というキーとハッシュを記述。
受け渡して表示したい情報をデータから呼び出すには何が必要か考える必要がある。

 　
　

## 次の作業〇〇.json.jbuilderを作成する場合
アクションに対応した名前を〇〇に入れて
〇〇.json.jbuilderを作成する。

```:ターミナル
% アプリ名/views/messages/〇〇.json.jbuilder
```
中の記述は先ほど記載した内容を[参考](https://qiita.com/kusaharajiji/items/3b374c73c12233485feb#jsonjbuilder%E3%81%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B%E5%A0%B4%E5%90%88)に記述。


## jbuilderが読み込まれているか確認
![スクリーンショット 2020-10-15 18.41.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661441/590199cf-e5f3-36ef-ceb1-c13665a67d8f.png)
「Rendered」「jbuilder」の文字が見えると読み込まれている。
　
　

ここまでで一旦完了！！

その後の非同期通信の流れはまた記事を作成します。

# 最後に一言
 APIの仕組みとしてはコントローラーの中身の記述になる。
その後は情報の受け渡しになってくる。
jbuilderでデータの内容を決めて、Ajaxでデータの受け渡しをするのかなと思っている。
どこからどこまでがなんていう作業かというのもまだ勉強不足。

#### 今回のなかで理解不十分な点
- jbuilderのファイルを作成しないコントローラーのみで完結させる際の記述（キーとバリュー）
- jbuilderの中の書き方（これもキーとバリュー）
- respond_toメソッドでのHTMLとJSONの分岐の仕組み。（リクエストがくるのだと思うがその流れが不明）

このことに関して理解を深めたいと思いました。


# 関連リンク
非同期通信の流れをjQueryの導入から全て記載しているのは[こちら](https://kayoblog.org/programming_myapp_hidoukitushin/)
Cannot end a section without first starting one.エラー

【概要】
----------------------------------------
<b>1.結論</b>

<b>2.Cannot end a section without first starting one.とは何か</b>

<b>3.どのように解決するのか</b>

<b>4.開発環境</b>




1.結論
----------------------------------------
<b>{{-- 　 --}} で</b>コメントアウトする。
<br>

2.Cannot end a section without first starting one.とは何か
----------------------------------------
Google翻訳すると、<b>"最初にセクションを開始せずにセクションを終了することはできません"</b>という意味になります。
<br>

3.どのように解決するのか
----------------------------------------
```php:resorces/views/hoge/index.blade.php
  @section('content') #---❶
      @foreach($data as $item)
      <tr>
        <th>{{$item['name']}}</th>
        <td>{{$item['mail']}}</td>
      </tr>
      @endforeach
    </table>
  @endsection　#---❶

  <!--{{-- <p>必要な時だけ記述できます</p> #---❷(1)

   @include('components.message' , ['msg_title'=>'OK'])
        @slot('msg_title')
          タイトル
        @endslot

  @endsection --}}--> #---❷(2)
```
<br>

❶で@section @endsectionをコーディングしていました。そして❷の部分は"command + /"でコメントアウトしていました。しかし、Vscode上のblade.phpでは<!-- -->緑色でコメントアウトになるものの❷(2)がコメントアウト されてないためか、"Cannot end a section without first starting one."というエラーが起きてしまいます。@endsectionが適用されてないことになってしまいました。{!-- --}}だけ囲っても色がついたコメントアウトにならないので<-- {-- --} -->というコーディングにしました。  
<br>

4.開発環境
----------------------------------------
Mac catalina 10.15.4
Vscode
PHP 7.4.10
Laravel 8.9.0
Apache 2.4.41
<br>
SSHでポートフォワード接続して、ファイルの送受信をする


## 環境
Ubuntu 16.04.7 LTS (Xenial Xerus)
ruby 2.5.0p0

## やりたい事
Rubyプログラムをポートフォワードで指定したサーバーに転送した後、転送先のサーバーでRubyプログラムを実行させて、csvファイルを標準出力させます。そして、標準出力したcsvファイルを、自分のローカル環境に持ってくるという事をやります。

## コード
```ruby
def ssh_connect

    begin
　　　　 # ファイルを転送
        _cmd = system('scp -P 54322 -i /home/.ssh/id_rsa /home/syori.rb server@153.153.xx.xx:/home')

        # ポートフォワードの設定
        Net::SSH.start(
            '153.153.xx.xx',
            'username',
            :keys => '/home/.ssh/id_rsa',
            :port => 54322
            ) do |_a|
                _a.forward.local(2222,'192.168.xx.xx', 54323)
                _a.exec!('ruby syori.rb')
              end

        # ファイルを取得する
        _cmd = system('scp -P 54322 -i /home/.ssh/id_rsa server@153.153.xx.xx:/home/users.csv /home')

    rescue => ex
        print "***** " + self.class.name.to_s + "." + __method__.to_s + " *****\n"
        print(ex.class," -> ",ex.message)
    end
end
```

## 解説
#### system
RubyでLinuxコマンドを発行するメソッドです。戻り値は、ture/falseが返ってきます。

#### scp
ファイル転送するコマンド（プロトコル）です。ファイル転送というと、ひと昔はftpがよく使われていたと思いますが、ftpはログインする時のアカウント情報を暗号化できないため、セキュリティを高めるために、SSH機能が標準装備されているscpを使う事が基本になります。

#### scpのオプション
##### -P
ポート番号を指定します。SSHのポート番号は22が、ウェルノウンポート番号として指定されていますが、外向けに公開しているサーバーであれば、変な攻撃を受けないために、カスタマイズしている場合があると思います。接続するサーバーのSSHのポート番号を指定します。

##### -i
SSH通信で利用する公開鍵を保存しているパスを絶対パスで設定します。大抵、ホームの.sshに置かれます。

転送するファイル名を絶対パスで設定します。転送先の指定は、転送先のサーバー名:転送先のディレクトリを絶対パスで指定します。

#### ポートフォワードの解説

```
Net::SSH.start(
     フォワード元IPアドレス, 
     フォワード元のユーザー名,
     :keys => 接続元の秘密鍵の絶対パス,
     :port => 接続元のポート番号
     ) do |_a|
         _a.forward.local(フォワード元のポート番号（何でもいい）,
         　　　　　　　　　'ポートフォワード先のIPアドレス', 
　　　　　　　　　         フォワード先のポート番号)
         _a.exec!('接続先で実行したいコマンド')
     end
```
pythonで、モジュールのインポートと例外処理

### Pythonのモジュールインポートの環境作り
１、メインフォルダーにディレクリーパッケージをつくる
２、そのディレクリーパッケージにディレクリーフォルダーとファイルを作る。
　必ず__init__.pyを作る。
　Pythonがこのファイルを認識して、モジュールを呼び出すため
３、その中に、utils.pyも作る
４、3に任意のファイル a.py b.pyの２種類のファイルを作る。のちに定義した関数を呼び出すため
５、次に、ディレクリーパッケージに別のディレクリーフォルダも作る。
６、同様に、__init__.pyを作る.
例外処理は、古いパッケージまた新しいパッケージが混じってもエラー対応するため。

### モジュールを呼び出すコード
```python
from directly_package.directlyfolder1 import a.py　//a.pyは、directlyfolder1にある
from directly_package.directlyfolder2 import b.py
print(folder1.function()) //ファンクションの実行
print(folder2.function()) 

```
以下にディレクリーフォルダー内のファイルの内容とパス指定について。
条件によりパスの指定を変える必要がある。


### モジュールのパス指定コードの例
```python
from directly_package.directly folder import utils　//絶対パス
def x(): //任意のファンクションの定義xとする
return'x'
def y():　任意のファンクションの定義をyとする
    return utils.z('y')　//utils.pyに定義したdefを.zとしてreturn utilsに記述
```

例外処理の例

```python
try:
    from directly_package import utils
except ImportError:
    from directly_package import utils
utils.any_function('word')
```

### 明日にためすことは
setup.pyを作り、自分で作ったライブリーの作成をやってみます。
[Rails]Active Hashの導入

# はじめに
Active_Hashとは、都道府県名やカテゴリー選択などの変更されないデータをモデルファイル内に直接記述することで、データベースへ保存せずにデータを取り扱うことができるgemです。
Active_Hashを用いることで、モデルファイルに直接記述した変更されないデータに対して、ActiveRecordのメソッドを用いることができます。

# 目次
1.Active Hashのインストール
2.モデルの作成
3.マイグレーションファイルの編集
4.アソシエーションの設定
5.ビューファイルの編集

# 1. Active Hashのインストール
gemfileに以下を記述します。
その後、コマンドでbundle installを実行します。

```ruby:gemfile
gem 'active_hash'
```


# 2. モデルの作成
今回はPostモデルとCategoryモデルを作成します。
Postモデルはいつも通りに作成します。

##### ターミナル
```
rails g model post
```

Categoryモデルを作成する際は、「--skip-migration」オプションを使用します。
「--skip-migration」を使用することで、マイグレーションファイルの生成を行わないようにします。
今回、カテゴリーを情報をデータベースには保存をしないのでマイグレーションファイルを作成しません。

##### ターミナル
```
rails g model category --skip-migration
```

category.rbでCategoryクラスを定義し、ActiveHash::Baseクラスを継承します。
ActiveHash::Baseを継承することで、Categoryモデルに定義したオブジェクトに対してActiveRecordのメソッドが使用できるようになります。

```euby:app/models/category.rb
class Category < ActiveHash::Base
  self.data = [
    { id: 1, name: '---' },
    { id: 2, name: '化粧水' },
    { id: 3, name: '乳液' },
    { id: 4, name: 'オールインワン' },
    { id: 5, name: 'クレンジング' },
    { id: 6, name: '洗顔料' },
    { id: 7, name: '日焼け止め' },
    { id: 8, name: 'リップ' },
    { id: 9, name: '香水' },
    { id: 10, name: 'ヘアカラー' },
    { id: 11, name: 'ヘアスタイリング' },
    { id: 12, name: 'シャンプー・コンディショナー' },
    { id: 13, name: 'コンタクトレンズ' }
  ]
end
```

データは配列にハッシュの形で格納しています。

# 3. マイグレーションファイルの編集
postsテーブルにはcategory_idカラムを作成します。
_idになっているのはidに紐づいているカテゴリーを取得し、カテゴリーのidをpostsテーブルに保存するからです。
カラム型は**integer型**にします。

```ruby:db/migrate/20XXXXXXXXXXXX_create_posts.rb
~略~
t.integer :category_id, null: false
~略~
```

# 4. アソシエーションの設定
ActiveHashにはbelongs_to_active_hashメソッドが用意されています。
ActiveHashを使って作成したモデルに対してアソシエーションを設定する場合は、belongs_to_active_hashメソッドを使います。
ActiveHash::Associations::ActiveRecordExtensionsを記述することで、belongs_to_active_hashメソッドを使用できます。

```ruby:app/models/post.rb
class Post < ApplicationRecord
  extend ActiveHash::Associations::ActiveRecordExtensions
  belongs_to_active_hash :category
end
```

# 5. ビューファイルの編集
今回はデータをプルダウン形式で表示しました。
ですので、collection_selectメソッド使って表示します。

```ruby
<%= form.collection_select(保存されるカラム名, オブジェクトの配列, カラムに保存される項目(表示する際に参照するDBのカラム名), 選択肢に表示されるカラム名, オプション, htmlオプション(classなど)) %>
```

##### 例
```ruby:app/views/posts/new.html.erb
<%= f.collection_select(:category_id, Category.all, :id, :name, {}, {class:”category-select"}) %>
```

# 参考リンク
https://github.com/zilkey/active_hash
【Unity】Luaが終了するまで待機する方法【Fungus】

FungusをLuaから操作する際に、Luaが終了するまで待機する方法を説明します。

前提としてUniRx/UniTaskの導入が必要です。

# ステップ１　なぜ必要か？

Luaは非同期で処理されるため、Luaの終了をC#側で受け取るには

+ 終了を通知するメソッドをC#側で用意する必要がある。
+ Secene内のLuaEnvironmentの操作が必要である。
+ Luaに終了通知するC#のメソッドを記述する必要がある。

など手間がかかります。そこでFungus側のソースコードを修正して、上記の手間をなくそうと思います。

# ステップ２　LuaEnvironment.cs

LuaEnvironment.csに以下のメソッドを追加します。

```c#
public IEnumerator RunLuaFunction(Closure closure)
{

    DynValue co = interpreter.CreateCoroutine(closure);

    while (co.Coroutine.State != CoroutineState.Dead)
    {
        try
        {
            co.Coroutine.Resume();
        }
        catch (InterpreterException ex)
        {
            LogException(ex.DecoratedMessage, GetSourceCode());
        }

        yield return null;
    }
}
```

# ステップ３　LuaScript.cs

LuaScript.csに以下のメソッドを追加します。

```c#
using Cysharp.Threading.Tasks;
```

※usingの追加が必要です。

```c#
public async UniTask OnExecuteAsync()
{
    InitLuaScript();

    await luaEnvironment.RunLuaFunction(luaFunction);
}
```

# ステップ４　C#側の呼び出し方

Luaの実行方法は[この記事](https://qiita.com/Humimaro/items/76e1730dde5c359f61ba)のステップ６を参照してください。

```c#
public async void OnFungusAsync()
{
    Debug.Log($"開始");

    // Luaが終了するまで待機する。
    await _luaScript.OnExecuteAsync();

    Debug.Log($"終了");
}
```
AWS IoT CoreとAWS IoT Device Management基礎知識まとめ

# 記事について

AWS IoT Device Managementについての自分用まとめ
今後実際にいくつか使用予定があるため、その際にアップデート予定

# IoTでよく出てくる課題、要件

### 初期化時

- クラウド接続するための個別の認証情報をどうするか
- デバイスの情報をどう登録するか

### 動作時

- デバイスの設定変更したい
- デバイスの状態を可視化したい
- デバイスで発生している問題を調べたい
 
### 更新時

-  FW更新をどうするか

# AWS IoT Device Management

- IoT Coreに統合されている
    ※サービス一覧からIoT Device Managementを検索してジャンプするとIoT Coreが開く

- 大量のデバイス向けにデバイスの登録、グルーピング、OTA等のJob、queryベースの検索を提供する管理機能群

# 主な機能

## デバイス登録

膨大な数のIoTデバイスの登録において個別の証明書を発行、デバイスへの埋め込み作業を排除する
以前記事にしたフリートプロビジョニングや、JITR、JITP等のプロビジョニング方式
https://qiita.com/takmot/items/eda7c2f519581b40ec3f

## デバイスのグループ化

### 静的グループ

例えばビル内システムでは、
ビル単位、フロア単位、部屋単位のグループや、機種、機能、セキュリティ要件単位のグループ等
以下想像されるユースケース

- グループ単位のアクセスポリシー管理
- グループ単位のアクション実行（再起動、アップデート等）

### 動的グループ

指定されたグループ条件を満たすデバイスの追加、条件を満たさなくなったデバイスの削除を自動的に実行
動的グループを作る場合は後述するフリートインデックスを使用する必要がある
以下想像されるユースケース

- ステータスがエラーとなったデバイスをグルーピングして情報の確認、ログの収集
- 旧バージョンのファームウェアを持つ、バッテリー残量80%以上のデバイスをグルーピングしてアップデートを実行
- 料金プランでグルーピングして機能制限等の設定変更

## フリートインデックスを使用したデバイス検索

デバイスを指定した条件で絞込検索できる
特定のデバイス情報可視化や、絞り込んだデバイスを動的グループとして前述した動的グループに対する処理が実行できる
以下フリートインデックス作成方法
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/8aa1d369-3259-38d8-5ca8-42677303d1b2.png)
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/46129baa-a55b-9ee3-b7df-4b7003c018db.png)
以下、検索条件として設定できる項目

- モノの名前、説明、属性
- デバイスシャドウで管理されているデバイスのステータスや設定
- モノの接続状態
- グループ名、説明、属性

### 動的グループ作成

フリートインデックスを有効にすると動的グループ作成が可能
以下のようにクエリ条件を指定し、条件を満たしたデバイスをグルーピング
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/75218719-5c9e-b845-aedd-1720c627bf3f.png)

## Job

クラウドからJobとしてJSON形式データを送信しデバイスはJob内容に応じた処理を行う
Jobの状態、結果を通知機能で確認が可能
Jobはジョブドキュメント（JSON形式）で定義
ターゲットは、モノ、モノのグループ
Jobの種類は以下の2つ

- Snapshot
  1回限り実行
  Job作成時に存在するモノが対象
  ユースケース：
  - ビル、フロア等グループに対する一括設定変更
  - 異常が発生しているデバイスのグループに対する再起動

- Continuouus
  特定の条件に一致した場合に実行
  Job作成時、作成後の対象グループに存在するモノが対象
  タイムアウト設定可能
  ユースケース：
  - 期間内に接続中かつ、アイドル状態かつ、バッテリー残量80%以上になったデバイスのアップデート

## セキュアトンネリング

ファイアウォール内のIoTデバイスに対するリモートアクセスを可能にする
用途としては、デバイスに異常が発生し、デバイスのステータスやログでは原因がわからないような場合に
一時的にトンネルを作成、SSH等でアクセスしデバッグに使用する
デバイス側にLocalproxyアプリケーションをインストールしておく必要あり

# 参考

https://www.youtube.com/watch?v=ZHFcMgVv8rs
Javascirptのメソッドチェーンの説明（初心者向け）

#この記事の対象者
配列とメソッドはなんとなくわかる方


#メソッドチェーンとは
こんなやつです。

```test.html
<body>
    <script>
        arrayA = ["リンゴ","ゴリラ","ラッコ"];
        value = arrayA.slice(1).length;
        console.log(value) //2
    </script>
</body>
```

2行目の右辺のことですね。ドットを挟んで3つつながってます

```
value = arrayA.slice(1).length;
```

#解説

この**value = arrayA.slice(1).length;**が何を一体しているのかというと

１、配列arrayAに対して  **.slice(1)** で　"リンゴ"　を配列arrayAから削除した配列を新たに作成。
　　[**"リンゴ"**,"ゴリラ","ラッコ"]　　⇒　　["ゴリラ","ラッコ"]
２、その削除した配列に対して **.length** で配列の長さを取得。
　　["ゴリラ","ラッコ"]　⇒　配列の要素の数は２個

という仕組みになっています。


**左側から順番に処理をしていくだけですね。**
**この順番を必ず意識するようにしてください。**

見たことがないメソッドが出てきても基本的にこの考えで解決できると思います。
これがわかれば最初は良いと思います。



#ちなみに
左から順番にやっていくというのが分かっていれば

```
value = arrayA.slice(1).slice(1)
```

こういうへんてこな書き方も可能というのが理解できると思います。
railsで使ってたbefore_actionのような機能をdjangoでもやりたかった話【初学者が参考書片手にpython学習】

## はじめに
[大高隆・著「動かして学ぶ！Python Django開発入門」](https://www.amazon.co.jp/dp/B07YY5RDPC/ref=cm_sw_r_tw_dp_U_x_TCsYEbRH6SF0V)を使用して
python・Djangoの学習を始めた初学者です。
ruby・railsを使用して4ヶ月ほどプログラミングの勉強をしていましたが、
エンジニア転職にあたり、pythonを使用することになったのでこの本を片手に勉強を始めました。
ド級の素人なので、補足・ご指摘等コメントいただけると大変助かります。

## 概要
railsアプリを作成する際に使っていたbefore_actionのように、
決まった処理を指定した汎用ビューの前に差し込む。これをdjangoでもやりたかった。

具体的には、、、、
クラスベース汎用ビューのtemplate表示前に、セッションに特定の値があるか確認。
→あり：そのまま表示
→なし：index画面にリダイレクト
という処理にしたい。

## 考察
＠login_requiredでログインしてるか確認できるなら、
自分でも同じようなものが作れるのでは、、、？
いや、できないはずはない。
↓
どうやら「＠〜」はデコレータというものらしい。
そしてやはり自作できるっぽい。


### 共通して行いたい処理を記述。
今回は、「セッションの中に特定の値があるかどうか」。

```
def is_hoge_in_session(func):
    def hoge_checker(request):
        if 'hoge' in request.session:
            return func(request)
        else:
            return redirect("hogeApp:index")
    return hoge_checker
```

コードの中身については、偉大な先人の方々の解説がわかり易すいかと。
・[【Python】初心者向けにデコレータの解説](https://djangobrothers.com/blogs/python_decorator/)
・[DjangoにおけるDecoratorの使い方とその作り方](https://qiita.com/u_kan/items/bf492deeb063d3e11721)

### 対象のクラスビューの上に載せるだけ。

```
# method_decoratorをインポート
from django.utils.decorators import method_decorator

、、、(中略)、、、

@method_decorator(is_hoge_in_session, name='dispatch')
class HogeFugaView(LoginRequiredMixin, generic.ListView):
、、、(以下略)
```
ちなみにクラスベースビューで関数デコレータを扱う方法に関しては
下記サイトより知恵を授けていただきました。
[【Django】クラスベースビューで関数のデコレータを使用する方法](https://programming.sincoston.com/django-classbaseview-decorator/)

## 今回のまとめ
ドブに捨ててしまった時間
　→2時間
感想：
　→初学者でも、周りに開発中の言語についてのスペシャリストな先輩がいなくても、
　　大丈夫、私にはgoogle大先生がいる。あとは気合い。

## 偉大な参考記事
・[【Django】クラスベースビューで関数のデコレータを使用する方法](https://programming.sincoston.com/django-classbaseview-decorator/)
・[【Python】初心者向けにデコレータの解説](https://djangobrothers.com/blogs/python_decorator/)
・[DjangoにおけるDecoratorの使い方とその作り方](https://qiita.com/u_kan/items/bf492deeb063d3e11721)
膨大なIT資産情報を「自動で正確に管理」できる話【Device42　第一回】

#はじめに
　社内のIT資産管理をするためにExcelやWordやVisioなどで更新を繰り返しますが、いつしかそのリスト管理に振り回され多くの時間を割いてしまうことがあります。
　本記事ではそんなシステム管理者の負担を少しでも軽減する一つの方法としてDevice42というソフトを例に「情報収集を自動化」する技術をご紹介します。

<a id="anchor1"></a>
#1.Device42とは？
　アメリカのコネチカット州にある企業（その名も「Device42社」）が開発し、世界55カ国500社以上で展開しています。
　以下の機能がセットになっています。

- CMDB（構成管理データベース）
- DCIM（データセンターインフラ管理システム）
- ITAM（IT資産管理）
- IPAM（IPアドレス管理）

　一息で説明すると「無秩序に散らばった企業内のIT資産情報を正確に一元管理できるソフト」です。IT資産状況を正確に把握することで、レガシー環境からのリプレイス、最適化、管理工数ダウンを図ったり、機器のライフサイクルやソフトウェアライセンス違反の管理など、細かいところに手が届くため「真に強いIT環境づくり」を実現できます。
　そのためにDevice42では、

- エージェントレスでシステム機器や構成を検出（クライアントソフト不要）
- 検出を自動化することで常に最新情報を維持
- システムやネットワーク機器の配置関係を可視化

　をはじめとした機能があります。

<a id="anchor2"></a>
#2.主な機能
　Device42では大きく分けて7つの機能があり、それらを動的に紐づけることができます。

|<B>項目</B>|<B>機能</B>|
|----------|--------------------------|
|IPアドレス管理|・IPアドレスの管理（IPv4、IPv6）<br>・サブネットの管理<br>・VLANの管理<br>・MACアドレスの管理|
|ソフトウェア管理|・ライセンス毎の使用頻度の確認<br>・禁止ソフトウェアの検知<br>・ライセンス期限のアラート<br>・ソフトウェアの脆弱性管理|
|パスワード管理|・パスワードの自動生成<br>・256ビット暗号化対応<br>・パスワードの使用権限付与<br>・容易にパスワード検索が可能|
|ケーブル管理|・ケーブル接続状況の管理<br>・ケーブル種別の確認<br>・ポートの使用状況の管理<br>・パッチパネルの可視化|
|データセンタ/IT資産管理|・ルーム、ラック、パッチパネル管理<br>・HWのCPU、メモリ、HDD等の管理<br>・HW/SWの使用状況の管理<br>・機器同士の相互依存性の管理<br>・サポート期限・在庫の管理|
|電源供給管理|・各機器における電源状態の管理<br>・状況に応じたアラートの設定<br>・電源状態のモニター機能<br>・電源供給機器の管理|
|インパクト管理|・インパクトチャートによる状況確認<br>・機器、ソフトウェア、ユーザの相互依存性の追跡・可視化(マッピング)<br>・アラートのカスタマイズと提供<br>・パフォーマンスの問題点の確認|

<a id="anchor3"></a>
#3.使ってみた
　30日の制限はありますが、フリートライアルができます。<a href="https://www.device42.com/download_links/">Device42社から仮想アプライアンスをダウンロード</a>し、ESX環境にデプロイして試用してみました（私はVMware向けのアプライアンスを選択）。

① 登録したラックのポートや結線の情報が構成図として可視化できた！
![ラックレイアウト図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/789973/444a3178-7f79-03a2-288c-4191922e1358.png)

~~（見えるぞ…私にも配線が見える！）~~
<br>

② PCやスイッチなどネットワークにある機器の一覧。
　いつでも最新のレポートなので、棚卸の度に確認せずに済みます！
![デバイスリスト.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/789973/4d9f51e3-04b1-d15f-fa33-60545868eb22.jpeg)

~~（チャンスは最大限に生かす、それが私の主義だ。）~~

<a id="anchor4"></a>
#4.活用事例
　構成管理資料が形骸化していたとある企業では以下の問題が発生しましたが、Device42の導入で解決することができました。

- 構成管理情報は独自DB、それ以外はExcelといった細分化した管理体制
　　⇒各種管理機能の一元化

- 独自DBを操作する必要があったため作業が属人化していた
　　⇒可視化されたことで誰でも直感操作が可能

- 本番設定情報と資料情報に差異が発生し重大な障害に繋がった
　　⇒常に最新の設定情報を取得・更新しているため、差異がなくなった

- 手動でのデータ入力による多大な工数の発生
　　⇒データ入力工数の削減

<a id="anchor5"></a>
#5.終わりに
　ひとまず今回はDevice42の簡単なご紹介と、試用版を導入してみました。
　少し使ってみて「このネットワーク」の中にある「PCという機器」は「ビルA」の中の「ルームB」に置いてある「ラックC」に収められていて、どんな「ソフトウェア」がインストールされているか…というように、各DBを相互に関連させて情報管理していることが分かりました。

　レポートと構成図が常に自動で最新になる、というのはシステム管理者であれば非常に心強いですよね。
　次回はもう少し細かい機能や特長となる部分を掘り下げていこうと思います。

　最後まで記事をご覧いただき、ありがとうございました。

#シリーズ一覧
1. [膨大なIT資産情報を「自動で正確に管理」できる話【Device42　第一回】](https://qiita.com/daijiro_ABY3/items/0f68081239aaf0acdf5c)
1. [IT資産情報をDevice42で「検出」してみた【Device42　第二回】](https://qiita.com/daijiro_ABY3/items/6bba85346adfcfb94d22)
Herokuへのデプロイ【Ruby on Rails】初心者


### 開発環境：macOS Catalina/GitHub/MySQL
※Herokuへのユーザー登録完了後の手順です。
備忘録として残したいと思い、記事にしました。
初心者なので、至らない点があるかと思いますがその際はコメントいただけたらと思います。



# 1. Heroku　CLIをインストールする
コマンド

```
% brew tap heroku/brew && brew install heroku
```

バージョンの確認

```
% heroku --version
```

バージョンが出力されたらインストール完了

公式サイト：https://devcenter.heroku.com/articles/heroku-cli

# 2. ログインする

```
% heroku login --interactive
  Email: それぞれ入力
  password:　それぞれ入力
```

:information_desk_person:登録したメールアドレスがLogged in asの後に表示されていればログイン成功

# 3. Gemの導入
Gemfile ※一番下に入力

```ruby:Gemfile
group :production do
   gem 'rails_12factor'
end
```

:information_desk_person:bundle installと再起動をお忘れなく
 

:information_desk_person:Gitで管理している場合はコミットしておきます

# 4.　Heroku上にアプリケーションを作成する

```
% heroku create [アプリケーション名]
% git config --list | grep heroku
```

:information_desk_person:この時、"fatal: not in a git directory"以外が出力されていれば作成完了です！

# 5. MySQLを使えるようにするコマンド

```
% heroku addons:add cleardb
% heroku_cleardb=`heroku config:get CLEARDB_DATABASE_URL`
% heroku config:set DATABASE_URL=mysql2${heroku_cleardb:5}
```

:information_desk_person:URLの"mysql2"はGemの使用状況によって変更する
  **以降は非公開の値を管理する為の環境変数の設定などを行います。**


# 6. 公開を確認するコマンド

```
% heroku apps:info
```





参考：https://devcenter.heroku.com/articles/getting-started-with-rails6
STATISTICAL RELIABILITY THEORY ,   I.B.GERTSBAKH ,   DEKKER

```{r}

#statistical reliability theory p.198

library(survival)

data("kidney")

data=kidney

Z=as.matrix(data[,colnames(data) %in% c("age","sex","frail")])

x=kidney$time

status=as.numeric(data$status)

ZD=as.matrix(data[data$status==0,colnames(data) %in% c("age","sex","frail")])

ZC=as.matrix(data[data$status==1,colnames(data) %in% c("age","sex","frail")])

#exponential

param=rep(0.001,ncol(Z))

eta=0.1

ite=100


for(l in 1:ite){

dparam=-apply(ZD,2,sum)+apply(Z*c(x*exp(-Z%*%param)),2,sum)

ddparam=t(Z*c(x*exp(-Z%*%param)))%*%(Z)

param=param+eta*solve(ddparam)%*%dparam

loglik=-sum(ZD%*%param)-sum(x*exp(-Z%*%param))

print(loglik)

}


#weibull 分布(勾配上昇法)

f=function(param){

w=(log(x)-Z%*%param[2:length(param)])/param[1]

dparam=c(-r/param[1]-sum(w[status==0])/param[1]+sum(w*exp(w))/param[1],-apply(ZD,2,sum)/param[1]+apply(Z*c(exp(w)),2,sum)/param[1])

return(c(dparam))

}

X=c(10,rep(0.1,ncol(Z)))

r=length(status[status==0]) 

ite=10^6

eta=10^(-4)

for(l in 1:ite){

X=X+eta*f(X) 

w=(log(x)-Z%*%X[2:length(X)])/X[1]

loglik=-r*log(X[1])+sum(w[status==0])-sum(exp(w))

print(loglik)

}

#log-normal

loglik=function(param){

w=(log(x)-Z%*%param[2:length(param)])/param[1]

value=-r*log(param[1])-sum(w[status==0]^2)/2+sum(log(1-pnorm(w[status==1])))

return(value)

}

ite=10^5

eta=10^(-4)

X=c(10,rep(1,ncol(Z)))

for(l in 1:ite){

w=(log(x)-Z%*%X[2:length(X)])/X[1]

r_vec=t(Z[status==0,])%*%c(w[status==0])/X[1]+(1/X[1])*t(Z[status==1,])%*%c(dnorm(w[status==1])/(1-pnorm(w[status==1])))

dsig=-r/X[1]+sum(((log(x)-Z%*%X[2:length(X)])*w)[status==0])/(X[1]^2)+sum((dnorm(w[status==1])/(1-pnorm(w[status==1])))*w[status==1])/X[1]

X=X+eta*c(dsig,r_vec)

print(loglik(X))

}

```
Box APIをcurlで叩く

[CLI](https://qiita.com/YKInoMT/items/0d561115d0a9bd2d095e) だけだとよくわからんので curl で直接叩いて試す。

# 現在のユーザーを取得

https://ja.developer.box.com/reference/get-users-me/

一番簡単なやつだけど、トークンどうやって取得するのか？ってなるよね。

```zsh
% curl -i -X GET 'https://api.box.com/2.0/users/me' --header 'Authorization: Bearer xxxxxxxxxxxxxxxxxxxxxx'
```

# トークンの取得

## OAuth 2.0
OAuth 2.0 でトークン取得する方法は UI 通るので、curl だけではしんどそう。

とりあえず、トークンだけ作ってしまうほうが楽。（なんかしらGUI使わずに出来る方法があれば更新します。）

とりあえず流れとしては、
https://ja.developer.box.com/guides/authentication/oauth2/without-sdk/
に書いてある方法で対応すれば良い。

1. 承認URLにブラウザなどでアクセス
2. 必要に応じてユーザー認証
3. アクセスを許可する
4. リダイレクトされたURLからコードを取得
5. アクセストークンを作成

### 承認URL

https://ja.developer.box.com/reference/get-authorize/

承認URL は下記のような形式

```
https://account.box.com/api/oauth2/authorize?response_type=code&client_id=[client id]
```

client_id には開発者コンソールの
構成 > OAuth 2.0資格情報 > クライアントID
の値をセット。

![クライアントID](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84947/de429dad-3031-7c25-fc79-2970ed2000fd.png)

### 承認URLにアクセスしコードを取得

上記のURL にブラウザでアクセスし「Boxへのアクセスを許可」ボタンをクリックする。

![許可ボタン](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84947/5517e029-f036-1cf8-fb94-efd61df79a69.png)

許可ボタンを押すとリダイレクトURI にコードが付いた状態でリダイレクトされるのでコードを取得する

```
https://developer.box.com/auth/callback/?code=xxxxxxxxxxx
```

こんな感じで、リダイレクトURI に code= にコードが入ってくるので取得。

### コードからトークンに変換

```zsh
curl -i -X POST "https://api.box.com/oauth2/token" \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "client_id=[CLIENT_ID]" \
     -d "client_secret=[CLIENT_SECRET]" \
     -d "code=[CODE]" \
     -d "grant_type=authorization_code"
```

[CODE] に先程のコードを入れて、
[CLIENT_ID] と [CLIENT_SECRET] は先程と同様に
構成 > OAuth 2.0資格情報 > クライアントID
から取得した値をセット。

レスポンスにトークンが含まれているのでそれを使って API を実行する。

## JWT

[CLI 使う方法](https://qiita.com/YKInoMT/items/0d561115d0a9bd2d095e#token-%E3%81%AE%E5%8F%96%E5%BE%97)が楽。

```zsh
% box tokens:get
```

上記のコマンドでトークンが返却されるのでそれを使って API を叩く。
PATHを通すということ

#はじめに
なにかインストールして新たなコマンドを使おうと思ったら、`bash: [コマンド]: command not found`のように、コマンドがない...?なんてことがよく起こります。
その時に、**「PATHを通す」**というワードをよく耳にすると思いますが、そろそろスルーできないレベルになってきそうなので、それがどういうことなのか、また、それに関する周辺知識も含めて(すでに似たような記事はごまんとありますが。。)、自分用に書きます。

#PATHを通すとは
>コマンド検索パスを追加すること

らしいですが、これだけではよくわからない。。

#コマンド検索パスとは

>シェルがコマンドの実行ファイルを探しに行くパス

とのこと。

普段からよく使っているターミナル（Windowsだったらコマンドプロンプト）などのコンソールで入力する`cd`などのコマンド。

あれは、`/bin`ディレクトリに`cd`の実行ファイルが入っているから、コマンドが使えるようになってます。

実は、`/bin/cd`と実行ファイルのパスをコマンドとして入力しても同じらしいですが、そんな書き方しなくても`cd`だけでもその機能（ディレクトリの移動）を使いたいですよね。

`/bin/cd`のような書き方をしなくても`cd`だけで処理ができるのは、$PATHという環境変数（OSがデフォルトで持ってる変数）に格納されている、いくつかのパスのなかに、入力した文字列と同名の実行ファイルが格納されているディレクトリがあれば、`/bin/cd`のような書き方じゃなくても、シェルが処理を実行してくれるからなんですよね。

つまり、`cd`の例の流れとしては、

`cd`を入力
↓
シェルが環境変数`$PATH`を参照
↓
環境変数`$PATH`に格納されている`/bin`ディレクトリに`cd`実行ファイルがあることをシェルが確認
↓
シェルが`cd`を`/bin/cd`と同様のコマンドとして捉え、処理を実行


という感じです。

その、環境変数`$PATH`に格納されているパスを、コマンド検索パスといいます。

つまり、PATHを通すということは、**「`$PATH`にコマンドの実行ファイルがあるディレクトリのパスを追記してあげて、コマンドを使えるようにしてあげる」**ということなんですね。

#コマンド検索パスとコマンド実行ファイルの確認方法
新しいプログラムやライブラリをインストールして、そのコマンドを使用したいのなら、$PATHにそのコマンドの実行ファイルがあるディレクトリのパスを記載してあげればOKです。

でももしかしたら、すでに、パスが記載されているかもしれませんね。

その場合に`$PATH`を確認したいときは`echo $PATH`をすると、`$PATH`に格納されているパスが見れます。パスは`:`で区切られてます。このなかのディレクトリを漁れば、探せます。

~~~
echo $PATH

#出力結果
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
~~~

また、`which [実行コマンド]`でそのコマンドの実行ファイルのパスを表示してくれます。こっちの方が早いです。

~~~
which cd

#出力結果
/usr/bin/cd
~~~

これをやっても、見つからないのなら、PATHを通す必要があります。

#PATHの通し方
コマンドを入力しても、`bash: [コマンド]: command not found`のようにコマンドがない、とPCさんから言われたら、PATHを通してあげると解決します。

具体的には、`$PATH`を直接いじるのではなく、`.bash_profile`や`.bashrc`などのご自身のシェルの設定ファイルというものをいじります。（ここでは、`bash`を例にしてご説明します）

シェルの設定ファイルは、ログインしたとき（`.bash_profile`）や、シェルを切り替えたとき（`.bashrc`）に読み込まれるファイルで、このファイルに`$PATH`を編集するコマンドを記載することで、PATHを通していきます。

ちなみにこの設定ファイルたちは、ホームディレクトリに隠しファイルとして存在してます。ホームディレクトリ上（`cd ~`で移動できます）で`ls -a`で確認できます。（環境によっては、デフォルトでない場合もあるそうです）

##全体の流れ
先にPATHを通す全貌を記します。

1. シェルの設定ファイルを開く
2. 設定ファイルに`$PATH`を編集するコマンドを記載する
3. 追記した設定ファイルを実行する

##シェルの設定ファイルを開く
まずは、設定ファイルを開きましょう。
デフォルトでbashをシェルで使っているので、`.bash_profile`を開いて、そこに書き込んでいきます。

~~~
$ open ~/.bash_profile

# ~はホームディレクトリ
~~~

そのほかのシェルをご使用の方はご自身のシェルの設定ファイルに、また、ほかのシェルでbashに切り替えてbashを使っている方は、`.bashrc`に、それぞれ書き込みましょう。

自分の環境のシェルがわからない方は`echo $SHELL`で確認できます。

また、デフォルトで設定ファイルが存在しない場合は、ホームディレクトにご自身のシェルの設定ファイルを作成してください。（`touch [ファイル名]`で作成できます）

##設定ファイルに追記する
次に、開いた設定ファイルに以下の文を追記します。

~~~
export PATH=[通したいパス]:$PATH
~~~

`export`コマンドは環境変数を設定するためのコマンドで、`export [環境変数]=値`で、環境変数を設定します（ちなみに、`=`なので上書きされます）`:`区切りなので、通したいパスの後に`:`をつけて、その後に現状の`$PATH`を加えます。

##追記した設定ファイルを実行する
最後に、追記した設定ファイルを反映させます。以下の`source`コマンドを実行してください。

~~~
$ source ~/.bash_profile
~~~

以上で、PATHが通ったかと思いますので、`[コマンド] -v`みたいな感じで、コマンド起動ができるか確認してください。

#リファレンス
[PATHを通すとは？ (Mac OS X) Qiita](https://qiita.com/soarflat/items/09be6ab9cd91d366bf71)
[【zsh, bash】macでPATHを通す方法 - not found と出てしまったら Qiita](https://qiita.com/k3ntar0/items/eb8cdbd8eba9da388def)
Railsで生SQLをリードレプリカに投げる

switch_pointというgemを使用するのだが、
readmeにちらっとだけ書いてあって、例が示されてないのでわかりにくいがswitch_point_proxy.model_for_connectionってのを使えばいいみたい

[https://github.com/eagletmt/switch_point](https://github.com/eagletmt/switch_point)

例えばUserモデルだったら、

```ruby
use_switch_point :slave
```

みたいに追加して、

```ruby
rows = []

User.with_readonly do
  con = User.switch_point_proxy.model_for_connection.connection
  sql = "select * from users limit 1"
  rows = con.select_all(sql)
end
```

みたいな感じで行けるみたい
シンプルなWebアプリケーション開発 フレームワークとは

## フレームワークとは

フレームワークを使わずにウェブアプリを開発していた時代は、一部の才能あるエンジニアがアプリの構成や仕組みを考えていた。なのでプログラム経験の浅い人がウェブアプリを1から作成するのは難しかっし、ベテランエンジニアでも構成や仕組みを作るのに時間を費やしていた。
ただ、実のところ、ウェブアプリの基本的な構成や仕組みはどのアプリでも大差なかった。それならば、ウェブアプリの開発に必要な機能や、最適な構成などウェブアプリケーションの骨組みとなるもをまとめて提供してしまおうというのがフレームワークができた経緯だ。


## CakePHP
CakePHPは**規約**を重視するフレームワークになっている。ディレクトリ構成、ファイル名、関数名をCakePHPの規約に沿って記述することで自動的に処理が動いたり開発にかかる手間を省いてくれる。

## ライブラリとフレームワークの違い
ライブラリもフレームワークも機能をまとめたものという意味では同じである。決定的な違いは、目的でにあると思う。
ライブラリがある部品を追加するための機能群だとすると、フレームワークはウェブアプリケーションの骨組みを作る機能群になっている。
イメージは、フレームワークはケーキの生地の部分を作るための素材群で、ライブラリはイチゴとか生クリームとかケーキを装飾するもの。
Redis の WebAPI (Express,TypeScript)

こちらで定めた仕様を満たすサーバーサイドのプログラムです。
[Redis の WebAPI を作成](https://qiita.com/ekzemplaro/items/1746b31beef382023f2d)
次のプログラムを TypeScript に変更しました。
[Redis の WebAPI (Express)](https://qiita.com/ekzemplaro/items/34f267e21e8195a2ea63)

## サーバープログラム

フォルダー構成

```text
$ tree
.
├── app.ts
└── routes
    └── index.ts
```

```ts:app.ts
//-------------------------------------------------------------------------
//	app.ts
//
//					May/30/2021
//-------------------------------------------------------------------------
var express = require('express')
var routes = require('./routes')
var cfenv = require('cfenv')

var app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: true }))

app.use(express.static(__dirname + '/public'))

const appEnv = cfenv.getAppEnv()

app.post('/read',routes.read)
app.post('/list',routes.list)
app.post('/insert',routes.insert)

app.listen(appEnv.port, '0.0.0.0', function() {
  console.log("server starting on " + appEnv.url)
})

//-------------------------------------------------------------------------
```

```ts:routes/index.ts
// -----------------------------------------------------------------------
/*
	routes/index.ts

						May/30/2023
*/
// -----------------------------------------------------------------------
const redis = require("redis")
const client = redis.createClient()

exports.read = async function(req: any,res: any)
{
	console.error ("*** read *** start ***")
	await client.connect()

	var key:string = "" 

	if (req.body.key) {
		key = req.body.key
		}

	var dict_aa: {[key: string]: any} = {}

	const value = await client.get(key)
	dict_aa["key"] = value

	const str_out = JSON.stringify(dict_aa)

	res.send(str_out)

	await client.disconnect()
	console.error ("*** read *** end ***")
}

// -----------------------------------------------------------------------
exports.list = async function(req:any ,res:any)
{
	console.error ("*** list *** start ***")
	await client.connect()

	const keys = await client.keys('*')

	const str_out = JSON.stringify(keys)
	res.send(str_out)
	await client.disconnect()
	console.error ("*** list *** end ***")
}

// -----------------------------------------------------------------------
exports.insert = async function(req:any ,res:any)
{
	console.error ("*** insert *** start ***")
	await client.connect()

	var key:string = ""
	var value:string = ""

	if (req.body.key) {
		key = req.body.key
		}

	if (req.body.value) {
		value = req.body.value
		}

	await client.set(key, value, redis.print)

	res.send(value)

	await client.disconnect()
	console.error ("*** insert *** end ***")
}

// -----------------------------------------------------------------------
```

## サーバーの起動

```text
$ export NODE_PATH=/usr/local/lib/node_modules
$ ts-node app.ts
server starting on http://localhost:3000
```

## 確認したバージョン

```text
$ node -v
v20.2.0

$ tsc -v
Version 4.8.4
```
Twig よく使う書き方まとめ

##経緯
EC-CUBEを使用する案件でTwigを使用する機会があり、そもそもTwigとはなんぞや状態だったので、簡単にまとめてみました。

##Twigとは?
Twigは簡素で読みやすいデザイナーにもフレンドリーなPHPテンプレート言語です。
以下、Twigでよく使う書き方の一例です。

#####コメントアウト
```index.twig
{#コメント#}
```
#####変数の取得
```index.twig
{{変数}}
```

#####配列の取得
```index.twig
{{変数名,キー名}}
```

#####変数の作成
```index.twig
{% set 変数名 = 値 %}
```

#####条件分岐処理
```index.twig
{% if 条件式 %}
...
{% endif %}
```

#####繰り返し処理
```index.twig
{% for 条件式 %}
...
{% endfor %}
```

#####値の出力
```index.twig
{{dump(変数名など)}}
```

#####フィルター処理
```index.twig
{{処理したいデータ[フィルター名]}}
```

#####ブロック処理
```index.twig
{% block　ブロック名 %}
...
{% endblock %}
```

#####継承処理
```index.twig
{% extends 'ファイルパス' %}
```

#####挿入処理
```index.twig
{% include 'ファイルパス' %}
```
Composer requireした際のCannot create cache directory, or directory is not writable.というエラーの対処

# エラー内容

ローカルにインストールしているUbuntuで `composer require` をしたら以下のWarningエラーが出ました。

```
Cannot create cache directory /home/path/.composer/cache/repo/https---repo.packagist.org/, or directory is not writable. Proceeding without cache
Cannot create cache directory /home/path/.composer/cache/files/, or directory is not writable. Proceeding without cache
```

内容を見ると「キャッシュディレクトリを作れない、もしくは、ディレクトリの書き込み権限がない」と書かれています。

# ユーザーに権限を与える

権限がないので、権限を与えてあげるとエラーが出なくなりました。

```
$ sudo chown -R $USER $HOME/.composer
```

sudo権限が無いと他の方法を探すしか無いかもしれません。

# 発生原因

composerでもうすぐバージョン2が出そうだから、今のうちにバージョン1の最新版にしておけよと言われたので、以下のコマンドでアップデートをしました。

```
$ sudo composer self-update
```

その後、新しくパッケージをインストールしようとしたら今回のエラーが表示されたので、恐らく `self-update` が原因だったのではないかと考えています。

今回は `composer require` でのエラーでしたが、 `composer update` でも発生するかもしれません。
client-goを利用して、KubernetesのNginxのDeployentsをApplyするサンプル


```main.go
package main

import (
	"context"
	"fmt"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/client-go/dynamic"
	"k8s.io/client-go/tools/clientcmd"
	"os"
	"path/filepath"
)

func main() {
	// Kubeconfigのファイルパスを指定
	kubeconfig := filepath.Join(os.Getenv("HOME"), ".kube", "config")
	config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
	if err != nil {
		panic(err)
	}
	client, err := dynamic.NewForConfig(config)
	if err != nil {
		panic(err)
	}

	namespace := "default"

	deploymentRes := schema.GroupVersionResource{Group:"apps", Version: "v1", Resource: "deployments"}


	deployment := &unstructured.Unstructured{
		Object: map[string]interface{}{
			"apiVersion": "apps/v1",
			"kind":       "Deployment",
			"metadata": map[string]interface{}{
				"name": "demo-deployment",
			},
			"spec": map[string]interface{}{
				"replicas": 2,
				"selector": map[string]interface{}{
					"matchLabels": map[string]interface{}{
						"app": "demo",
					},
				},
				"template": map[string]interface{}{
					"metadata": map[string]interface{}{
						"labels": map[string]interface{}{
							"app": "demo",
						},
					},

					"spec": map[string]interface{}{
						"containers": []map[string]interface{}{
							{
								"name":  "web",
								"image": "nginx:1.12",
								"ports": []map[string]interface{}{
									{
										"name":          "http",
										"protocol":      "TCP",
										"containerPort": 80,
									},
								},
							},
						},
					},
				},
			},
		},
	}

	fmt.Println("Creating deployment...")
	result, err := client.Resource(deploymentRes).Namespace(namespace).Create(context.TODO(), deployment, metav1.CreateOptions{})
	if err != nil {
		panic(err)
	}
	fmt.Printf("Created deployment %q.\n", result.GetName())

}
```

```
yuta:~/go-kubernentes (master *+=) $ kubectl get deployments.apps 
NAME              READY   UP-TO-DATE   AVAILABLE   AGE
demo-deployment   2/2     2            2           81s
external-dns      1/1     1            1           19d
```