OmniAICreator/Qiita-1.07M huggingface dataset:
【Rails】find_or_initialize_byメソッドを使ってインスタンスを作成する時のポイント

現在、amazonAPIを利用した口コミの共有サービスを作成中です。

その中で、「商品を検索し表示させる」という処理があるのですが、その際に役立った`find_or_initialize_by`メソッドについて簡単に整理します。

- 参考記事 [Railsガイド](https://railsguides.jp/active_record_querying.html#find-or-initialize-by)

#find_or_initialize_byメソッドとは

`find_or_initialize_byメソッド`とは、条件に合致したインスタンスがデータベースに保存されているかどうかをチェックしています。

この際、

- データベースに保存されている場合は`find`メソッド
- データベースに保存されていない場合は'new'メソッド

として、インスタンスの状況によって適用されるメソッドが異なることがポイントです。インスタンスが保存されている場合、findメソッドが適用されるのでインスタンスに保存済みのデータ(idなど)を含めることができます。

`インスタンス = persisted?`や`インスタンス = new_record?`でデータベースの保存状況を真偽値で取得できます。

#find_or_initialize_byメソッドの使い道

前述の通り、`find_or_initialize_by`は条件分岐がポイントとなるので、データベースの保存状況でインスタンスに変化を与えたい場合に有用となります。

例えば私の場合ですと、APIから商品データを取得し一覧表示しています。

その際に、データベース保存済みなら「商品削除ボタン」を表示、データベースに保存していない新規のインスタンスなら「商品登録ボタン」を表示したいケースで、`find_or_initialize_by`を使用しています。

```ruby:products_controller.rb
def create
  @product = Product.find_or_initialize_by(asin: params[:product_asin])
  unless @product.persisted?
    # @product が保存されていない場合、先に @product を保存する
    products = Amazon::Ecs.item_lookup(
      params[:product_asin],
      response_group: 'Medium',
      country: 'jp'
    )

    products.items.each do |item|
      @product = Product.new(
        title: item.get('ItemAttributes/Title'),
        image_url: item.get('LargeImage/URL'),
        url: item.get('DetailPageURL'),
        asin: item.get('ASIN'),
        brand_amazon_name: item.get('ItemAttributes/Brand'), 
        price: item.get('OfferSummary/LowestNewPrice/Amount'), 
      )
    @product.save
    end
  end  
end
```

```ruby:_products.html.erb
<!--商品登録削除ボタン-->
<div class="buttons text-center">
<% if product.persisted? %>
  <%= form_tag(product_path(product.id), method: :delete) do %>
    <%= hidden_field_tag :product_id, product.id %>
    <%= submit_tag '削除', class: 'btn btn-danger' %>
  <% end %>
<% else %>
  <%= form_tag(products_path) do %>
    <%= hidden_field_tag :product_asin, product.asin %>
    <%= submit_tag '登録', class: 'btn btn-primary' %>
  <% end %>
<% end %>

```

#(+α)find_or_create_byメソッドについて

`find_or_create_by`メソッドは、`find_or_initialize_by`と似た内容のメソッドなので、今後のために簡単に整理。

条件に合致したインスタンスがデータベースに保存されているかどうかをチェックしている点は、両者とも同じです。

その際に、`find_or_create_by`メソッドは、

- データベースに保存されている場合は`find`メソッド
- データベースに保存されていない場合は**'create'**メソッド

となることがポイントです。「データベースに保存されていない場合は**'create'**メソッド」となるのですね。

条件に合致した情報をゴリゴリとデータベースに保存していくというケースに適しているのでしょう。

#まとめ

find_or_initialize_byメソッドは、「APIを利用して情報取得→整形しインスタンス作成」のようなケースで役立つことがわかりました。
プログラミング初心者がKaggleチュートリアルに挑戦してみた

# はじめに
はじめまして。初めてQiitaに投稿します。
一週間前から、機械学習に興味を持ち、pythonをかじり始めました。
Qiitaの存在を知ったのもその頃なので、技術系ブログ作法というかマナーというか、そういうものが抜けていたら、こっそり教えていただけると幸いです。

<b>投稿者の紹介</b>
機械学習はおろか、プログラミングもほぼ初心者。
数年前に、[ドットインストール](https://dotinstall.com/)を視聴して、HTMLやCSS、PHP、MY SQL等のコードを真似て、遊んでいた程度。
（当時は全コース無償提供されていました。）
統計学どころか基本的な数学の知識にも乏しい。英語も儘ならず。

<b>環境</b>
Windows OS
jupyter notebook

<b>pythonとの出会い</b>
『[機械学習エンジニアになりたい人のための本](https://www.amazon.co.jp/機械学習エンジニアになりたい人のための本-AIを天職にする-AI-TECHNOLOGY-石井/dp/479815671X/ref=sr_1_fkmr1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&keywords=%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AB%E3%81%AA%E3%81%84%E3%81%9F%E3%81%84&qid=1555245102&s=gateway&sr=8-1-fkmr1)』を読み、機械学習にはpythonが適していることを知りました。
現在、[Progate](https://prog-8.com/)や[Udemy](https://www.udemy.com/ja)で学びながら、[Kaggle](https://www.kaggle.com/)のタイタニック号の課題にサブミットする日々です。

# Titanic:Machine Learning from Disaster との闘い
まだまだ自分でコードを書くこともできないのに、チュートリアルならできるだろうとたかをくくり、学習を初めて5日あまりでKaggleのアカウントを作成しました。
<b>甘かった・・・</b>

Qiitaで関連記事をとりあえず読み漁ります。何が関連しているのかすら分からないまま読みます。
[Kaggle入門者へ　タイタニックチュートリアルを比較してみた](https://qiita.com/kyogoku_meta/items/572bafeded081b3825dc)
この記事を参考に、様々な手法が用いられるのを確認しました。

<b>まず最初に</b>
[【Kaggle初心者入門編】タイタニック号で生き残るのは誰？](https://www.codexa.net/kaggle-titanic-beginner/)
上記のコードを一つずつ理解しながら打ち込んでいき、無事にcsvファイルを提出。
参考記事と同じ、<b>0.71770</b>のスコアを確認できました。
これをサンプルと呼ぶことにします。

<b>次は自分でコードを変えていきます。</b>
細かなことはリンク先を参照していただくとして割愛しますが、最初の提出分では’Age’の欠損値には中央値を入れています。
’Name’に含まれるMr.などの敬称の情報で年齢を推定できるとあったので、これに挑戦してみることにしました。
ここで、初心者あるあるにぶつかります。
<b>コードが全部載っていないと真似できない・・・・・・</b>

[A Data Science Framework: To Achieve 99% Accuracy](https://www.kaggle.com/ldfreeman3/a-data-science-framework-to-achieve-99-accuracy)
[kaggle/titanic 欠損値の補完と特徴量エンジニアリング](https://qiita.com/xxx_boy/items/36e4f6f52e0aad116649)
この2つの記事を参考にして進めました。そもそも見たことのないコードの書き方だと、どういう風にサンプルを変更していけば良いか分からないので、理解でき、納得して書けるコードを探しました。

まず、’Name’から’Title’を抽出し、新たに列名として追加します。

```
train['Title'] = train['Name'].str.split(", ", expand=True)[1].str.split(" ", expand=True)[0]
```

次に、主要な'Title'毎に格納し、'Age'の平均値を出します。

```
train_mr = train[train['Title'] == 'Mr.']
train_mr['Age'].dropna().mean()
```

'Mr.'の平均値は32.368.9.452261306
となりました。
この32という数値で、欠損したセルを埋めていきます。

```
train_mr['Age'] = train_mr['Age'].fillna(32)
```

さらに、元の学習データを補完していきます。

```
train['Age'][train['Title'] == 'Mr.' ] = train_mr['Age']
```

後は、サンプルと同様、決定木を用いて分析しています。

提出結果はというと、<b>0.73205</b>でした。
1.５%ほど良くなりました。

# まとめ
・初心者はコードを真似て、Kaggleチュートリアルにサブミットすることができる。
・基本的なコードの書き方を知らないため、なかなか応用がきかない。
・ひたすら試行錯誤すればなんとかなる。
・とりあえず、現在の分析方法は、決定木しか分からない。

<b>・'Age'は、平均値や中央値で埋めるより、'Title'から推定した方が結果が良くなる。</b>




まだまだタイタニック号の課題への挑戦は続きます・・・・・・。
Xamarin+Firebaseでソシャゲーっぽいもの作ってみた

[終：どこまでショボいアプリがAppleの審査に通るのか試してみた](https://qiita.com/megumu-u/items/576e0967bc357314df1b) の記事の補足記事です。

記事中で開発した「二つ名オンライン（以下、FNO）」はFirebaseを利用して作っています。

クライアントはXamarinで作り、サーバーサイドはFirebaseで作りました。
ちなみにリリース時点ではSparkプラン（無料）です。

# 使ってるサービスと用途

<dl>
<dt>FireStore</dt>
<dd>
データの保存。二つ名の保存、戦う相手のマッチングと結果の書き込み等々、全部クライアントでやってます。
<br><br>
データ保存時の統合モードがどれだけコンフリクトを回避できるのかなと思って試してみましたが、同じフィールドに同時に書き込みすると当然ですが後勝ちで上書きされる気がします。トランザクションを使って、競合時の処理をそこに書けば回避できる気がします。<br>
ちなみにオフライン動作もONにしてるので、アプリが起動していれば機内モードにしても継続して動作します。機内モードをOFFにすると割とすぐに更新かかりました。
</dd>
<dt><br>Functions</dt>
<dd>
FireStoreを監視して、戦い終了後にCloud Messagingで相手に通知を飛ばします。<br><br>
データのお掃除バッチもFunctionsに書いて、Google App Scriptから定期的に呼んでます。GCPには
Cloud Schedulerというサービスもあるようですが（執筆時点ではベータ版）、今回は厳しい要件ないのでGoogle App Scriptでやってます。<br>
一番の懸念はSparkプランでは４万秒/月という制約に対し、1回のCloud MessagingにFunctionsが5秒ぐらいかかること。計算すると1日あたり300回も通知を飛ばせない。Sparkプランでは私の個人アプリですら限界を迎えると想像してます。。。
</dd>
<dt><br>Cloud Messaging</dt>
<dd>
戦い終了後にCloud Messagingで相手に通知を飛ばします。<br><br>
前述の通り、Functionsから飛ばしてます。最初全くドキュメント読まずに実装して、APNsのデバイストークンで良いと思い込んでてハマりました。FCMのトークンでラップする感じなんですね。
</dd>
<dt><br>
<dt>Remote Config</dt>
<dd>
主にゲームバランスに関わるパラメータを保存してます。<br>
FireStoreでも良いのですが、SparkプランなのでFireStoreの呼び出し回数を節約したくてこちらを使ってます。Remote ConfigはSparkプランでも無制限です。<br>
</dd>
<dt><br>
<dt>Analytics</dt>
<dd>
利用状況把握が目的ですが、本当にやりたかったのはIn-App Messageとの連携。<br>
さあ実装してみようとしたところ、Xamarin向けのIn-App Messageのライブラリがまだなかったので断念・・・<br>
何かを達成したらメッセージを表示するとか、FNOのLINEスタンプを作ったらお知らせを出すとか、やりたかった・・・
</dd>
<dt><br>Authentication</dt>
<dd>
FireStore操作のために認証してます。<br>
と言っても、各アプリ利用者ごとにユーザーを作るわけではなく事前に１アカウントだけ登録して、全員そのアカウントを通してアクセスしてます。
</dd>
</dl>


細かい説明は省きますが、実装は公開してるので気になる方は見てみてください。
決して実装に自信があるわけではないですが何かの参考になればと。
→ https://github.com/uemegu/FNO

**FireStore**：[この辺](https://github.com/uemegu/FNO/blob/master/FNO.iOS/StorageService.cs)で実装してます
**Functions**：GitHubには入れてません
**Cloud Messaging**：[この辺](https://github.com/uemegu/FNO/blob/master/FNO.iOS/AppDelegate.cs#L84)で実装してます
**Remote Config**：[この辺](https://github.com/uemegu/FNO/blob/master/FNO.iOS/AppDelegate.cs#L96)で実装してます
**Authentication**：[ここ](https://github.com/uemegu/FNO/blob/master/FNO.iOS/StorageService.cs#L28)で実装してます


もちろんFirebaseアカウント周りとかは消してますが、オフラインで動作する状態にはしてます。


# なぜ、Firebase

Firebaseを採用した理由はFireStoreがあるからでした。

リアルタイムでデータ反映したい、でもサーバーの実装なんて絶対にやりたくない。

AWSのAppSyncは仕事で使ったことあるけど、他はどうかなとAzureとGoogleを調べる。

Azureだとドキュメント見た感じ、SignalR Service が近いのかなと思ったのですがクライアントだけの実装では無理そう。

GoogleのFirebaseにはFireStoreがあり、しかも結構無料枠が大きい。

ということでFireStoreを採用してみましたが、感想としてはかなり手軽。
レコードのインサート時に勝手にID発行してくれるのも嬉しかった。

ただ、あまりに手軽すぎるので、うっかりするとセキュリティやばそう。
AppSyncもそうですが「認証漏れたら何でもできまっせ」という作りになってるとヤバみ。

# まとめ

Firebaseを商用利用されてる方はたくさんいると思いますが、無料枠が大きいので個人でちょろっと遊ぶ分にも最高でした。

当初はFireStore以外は特に使うつもりなかったのですが、プッシュ通知もやってみたくなってFunctionsを試したら楽しくなって、なるべく多くのサービス使おうと試してみてました。
どれもサクサク導入できて非常に楽でした。

アプリを運用してみて何か発見があればまた追記します。

# 追記：2019年4月16日

FunctionsでCloud Messagingを送るのに5秒ぐらいかかると書いてましたが、今ログを見ると500msec程度になってました。見間違えてたってことはないと思うのですが・・・
もしかして意外と知られてない？UiPathの機能

# はじめに
・UiPath使用歴：約7ヶ月ぐらい
UiPath関係の記事を見てた時に「あれ、もしかしてこの機能って知られてない？」って思う事がちょいちょいあったので
備忘録もかねて残しておきます

# WriteCellによる新規シート作成
「Excelで任意の名称をつけた新規シートを作成したい」っていう場面は結構あると思います。
公式のアクティビティガイドにも載ってますが、
存在しないシートに対して書き込み処理を行うと、勝手に新規シートを作ってくれます。
https://activities.uipath.com/lang-ja/docs/write-cell

## サンプル_新規シートを作る
![image1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161676/655a6163-4823-262c-825b-268cab78233f.png)

こうすると以下のようにシートが追加されます
![image2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161676/c188b19e-1f02-956c-59a9-20b42dfbb688.png)

注意点としては、新規で作成されるシートは
**既存シートの左側に作成されます**

なので以下のように連続でシートを作成すると、左に向かって増えていきます。
![image4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161676/87acfc31-0b65-ec95-d354-509039838208.png)
![image3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161676/3dde3f81-0a61-8f88-7e5a-7988b33ce243.png)

実際に作る時は右に向かって増えるレイアウトが多いと思うので
作った後に「移動またはコピー」(Alt+E M)を使って、末尾に移動させる処理を組みこむと良い感じになります。


#On Element Appearを使った待機処理
いわゆるウィンドウなどが表示されるまで待ってくれるのがこのアクティビティです。
設定値をうまく変える事で、上書き保存ダイアログなど、特定条件の場合に表示される項目についても
良い感じに対応できるようになります。

##サンプル_メモ帳の表示を待つ
簡単な例だとこんな感じになります。
![image5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161676/537a3372-7151-a73c-ce05-557349900b54.png)
![image7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161676/a0a45010-4789-b7dc-f374-6f569f094fc1.png)

このアクティビティで重要なのが以下のオプション項目
![image6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161676/45ba4f96-bc70-0d5c-e1bd-59ed5f9f60f6.png)

**RepeatForever**
Trueの場合、On Element Appear内に配置したアクティビティを「ずっと」繰り返します。
表示の待機など、一発限りの場合は必ずFalseにしてください。そうしないとロボットがこのアクティビティで止まります。
(むしろTrueで使う場面が全くないけど、何故かデフォルト値がTrueという謎仕様)

**WaitActivate**
要素がアクティブになるまで待機させるかのオプションになります。
アクティブにならないと操作を受けつけない、っていう場合にこれを付けておくといい感じで待ってくれます。

**WaitVisible**
要素が「画面上に」表示されるまで待機させるかのオプションになります。
意外と重要で、上記のメモ帳の例だと
このオプションのチェック無しだと最小化状態でも存在している扱いになったりします。

そして最大の注意点として、ウィンドウの下部が隠れている場合は**非表示**扱いになります。
なので以下のような状態だと、そのままTimeOutが起きます。
![image13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161676/57986820-fa8f-cdbb-b808-dae5cc72875e.png)

##サンプル_不特定に表示されるウィンドウへの対応
ContinueOnErrorオプションを活用する事で、
表示されるかどうか分からないウィンドウにも対応できます。
![image14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161676/df338037-9f43-f03b-1376-9bd5fbb1f34e.png)

![image15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161676/4d816dc0-3d6e-3293-f3ee-c5dce99fc2a1.png)

ContinueOnErrorをTrueにしておくと、
非表示の場合はTimeOut値を超えた場合、そのまま次処理に行ってくれます。
「いちいちElementExistsで判定してIFで分岐させるのが面倒……」っていう時に活躍してくれます。


#最後に
とりあえず今後も適当にネタが出来たら書いていこうと思います。
ちょっとでも誰かの助けになれば嬉しいです。
Django channelsでルーティングをDjango風に２つに分ける

Djangoでこまごまとしたappをいっぱい書いているとDjangoのルーティングの仕方が書きやすくていいなーと思ってて
ちょろっとchannels触ってみたら違うやり方でルートに置いた`routing.py`に全部直書きっぽくて、うーんとなったので書きやすいように書いてみた


# 環境

いらないものは省略してます

```
$  tree -L 2                                                                                                                                      
.
├── db.sqlite3
├── app1
│   ├── consumers.py    <-- これは後半に追加する
│   ├── routing.py
│   ├── urls.py
│   └── views.py
├── manage.py
└── project
    ├── consumers.py
    ├── routing.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

```


# 理想

`project/routing.py`にappごとのルーティングを記述
`app1/routing.py`に細かいルーティングを記述
できるだけDjangoっぽく書きたい

# 見てみる

まず普通の書き方

```python:project/routing.py

application = ProtocolTypeRouter({
    'websocket': AuthMiddlewareStack(
        URLRouter([
            path('ws/app1/<val>/', app1.consumers.MyConsumer, name='ws_app1'),
        ])
    ),
})
```

このpathをincludeにはしてみたけどだめっぽい。

最終的に`URLRoute`にpathが入ったlistが行けば解決しそう。

# ちょっと書いてみる

`app1/routing.py`を作る。いつもどおりに書いてみる

```python:app1/routing.py
urlpatterns = [
    path('<val>/', consumers.MyConsumer, name='ws_app1'),
]
```

これで`project/routing.py`に`include('ws/app1', ~~)`的なことがしたい。

pathに先頭のパスを追加できないかな・・・

```python:shell
>> from django.urls import path
>> from app1 import consumers
>> 
>> a = path('<val>/', consumers.MyConsumer)
>> a
<URLPattern '<val>/'>
>> a.pattern
<django.urls.resolvers.RoutePattern object at 0x7fdad25a00f0>
>> a.pattern.regex
re.compile('^(?P<val>[^/]+)/$')
```

うーん、この時点でパスの表記が正規表現に落とし込んであるみたいなので追加するのはダルそう。取り出すのも

`app1/routing.py`の方はpathのリストじゃなくて必要事項のタプルとかにするか。

```python:app1/routing.py
urlpatterns = [
    ('<val>/', consumers.ChatConsumer, 'ws_app1'),
]

```

# また見てみる

pathは中で何してるのかな
上のを見る通り`URLPattern`オブジェクトを返してますね。これのリストを作ればいいっぽい。

```python:そーす
    pattern = Pattern(route, name=name, is_endpoint=True)
    return URLPattern(pattern, view, kwargs, name)
```
これをやればいい

- importがかさまないようにもとのincludeと同じように文字列で受け取る(モジュールが来ても対応してる)
- パターンのlistの名前は`urlpatterns`にする(変更できる)
- リストを最終的につなぐので`itertools.chain`を使う

```python:project/routing.py
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
from django.urls.resolvers import URLPattern, RoutePattern
from itertools import chain
from importlib import import_module

def include_(path: str, routing: str, pattern_list_name: str = 'urlpatterns'):
    if isinstance(routing, str):
        routing = import_module(routing)
    urlpatterns = getattr(routing, pattern_list_name)
    return [URLPattern(RoutePattern(path+i[0], i[2], True), i[1], None, i[2]) for i in urlpatterns]


application = ProtocolTypeRouter({
    'websocket': AuthMiddlewareStack(
        URLRouter(list(chain(
            include_('ws/app1/', 'app1.routing'),
        )))
    ),
})
【祝】コーダー復帰しました

2019/01より以前勤めていた制作会社にてコーダー、業務委託にてお仕事をさせていただいています。フリーランスデビューです。

担当している業務は、中小企業のコーポレートサイトやサービスの紹介サイト等です。
基本的に業務ではhtml,css,javascript(jQuery)を使っていますが、将来を考えVue.jsやReactの勉強もしていきたいと思っています。

こちらのブログでは、日々の仕事の中で気付いたことや気になることを書いていく予定です。
irisでマハラノビスの実装

irisを使ってマハラノビスでデータの判定。
何シグマ離れていたかで判定する方法もあるが、異常パターンが分かっているときなどは距離の離れ具合を閾値にして判定してもいいと思う。

```R
virginica <- iris[106:150,1:4]
#テストデータとしてvirginicaを5つ、versicolorを5つ含むデータを作った。
test <- iris[96:105,1:4]

#分散共分散行列と列平均を求めて、基準データについてプロットする
plot(mahalanobis(virginica,colMeans(virginica),var(virginica)))
```
![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275572/901b6d12-fb28-4e03-21b8-6d91cb9997e7.png)

y値が12という外れた値があるが、だいたい10以下で収まっていそう。

```R
which(6 >= mahalanobis(virginica,colMeans(virginica),var(virginica))) / nrow(virginica)
#0.8222222
#6を判断基準としたとき82%が正常と判断される。

which(8 >= mahalanobis(virginica,colMeans(virginica),var(virginica))) / nrow(virginica)
#0.8888889

which(10 >= mahalanobis(virginica,colMeans(virginica),var(virginica))) / nrow(virginica)
#0.9777778

which(12 >= mahalanobis(virginica,colMeans(virginica),var(virginica))) / nrow(virginica)
#0.9777778
```
基準は10に設定してよさそう。

```R
plot(mahalanobis(test,colMeans(virginica),var(virginica)))
abline(h=10)
pa <- which(10 >= mahalanobis(test,colMeans(virginica),var(virginica)))
length(pa) / nrow(test)
#0.4
```

![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275572/ee5017b7-6c00-1a92-42d9-2e667ba9abea.png)

一つ間違えてしまっていますが、本来のグループでないものは見つけられています。
データによって距離の設定も変わると思いますが、こんな判断基準もあるのではないでしょうか？
TensorFlow から bfloat16 のデータをつくって FPGA で使う

TensorFlow からごくごく簡単な MNIST のモデルを作り bfloat16 に変換して、最終的には FPGA(Zybo) で動くようにしてみた。

# MNIST のデータ
散々書かれているので省略。
https://github.com/ryos36/polyphony-with-tf-mnist
にソース等を置いた。とにかく浮動小数点のデータを作ればよい

# bfloat16 に変換
Session で eval とすれば NumPy 形式に落としてくれる。tf.cast でキャストすればよい。

```python:bfloat16.py
import numpy as np
import tensorflow as tf

w_np = np.loadtxt('w_value.txt', delimiter=',')
b_np = np.loadtxt('b_value.txt', delimiter=',')

print(type(w_np), type(w_np[0][0]))

w_b = tf.cast(w_np, tf.bfloat16)
b_b = tf.cast(b_np, tf.bfloat16)

print(type(w_b), type(w_b[0][0]))

with tf.Session() as sess:
    w_b_np = w_b.eval()
    b_b_np = b_b.eval()

print(type(w_b_np[0][0]))
```

# NumPy でセーブしたものをちょちょいと加工

ヘッダ付きのバイナリ形式でセーブされる。pickle?
```python:save.py
np.save('w_b_value.npy', w_b_np)
np.save('b_b_value.npy', b_b_np)
```
dd で 128バイトスキップする。
# Python で予測用プログラムを作る

```python:mnist7
def do_mnist7_mem(a:List[bit16], _mem:List[bit16], lst_len = LEN):
    rom_w = W_PARAM
    rom_b = B_PARAM
    mem = [0] * 10

    xi = 0
    for i in range(lst_len):
        x = a[i]
        for j in range(10):
            mem[j] = bfloat.mul_add(x, rom_w[xi + j], mem[j])

        xi += 10

    for j in range(10):
        _mem[j] = bfloat.add(mem[j], rom_b[j])
```

# コンパイルし Zybo にもっていく
持っていくときに少し細工。これで Vivado の BRAM の I/F とリセット極性が設定される。あと BRAM 用にクロックも追加。

```verilog:インタフェース
    input wire clk,
(* X_INTERFACE_INFO = "xilinx.com:signal:reset:1.0 rst RST" *)
(* X_INTERFACE_PARAMETER = "POLARITY ACTIVE_HIGH" *)
    input wire rst,
    input wire do_mnist7_mem_ready,
    input wire do_mnist7_mem_accept,
    output reg do_mnist7_mem_valid,
(* X_INTERFACE_INFO = "xilinx.com:interface:bram:1.0 bram_in CLK" *)
    output wire do_mnist7_in_a_clk,
(* X_INTERFACE_INFO = "xilinx.com:interface:bram:1.0 bram_in DOUT" *)
    input wire signed [15:0] do_mnist7_mem_in_a_q,
    input wire [10:0] do_mnist7_mem_in_a_len,
(* X_INTERFACE_INFO = "xilinx.com:interface:bram:1.0 bram_in ADDR" *)
    output wire signed [10:0] do_mnist7_mem_in_a_addr,
(* X_INTERFACE_INFO = "xilinx.com:interface:bram:1.0 bram_in DIN" *)
    output wire signed [15:0] do_mnist7_mem_in_a_d,
(* X_INTERFACE_INFO = "xilinx.com:interface:bram:1.0 bram_in WE" *)
    output wire do_mnist7_mem_in_a_we,
(* X_INTERFACE_INFO = "xilinx.com:interface:bram:1.0 bram_in EN" *)
    output wire do_mnist7_mem_in_a_req,

<中略>

  assign do_mnist7_in_a_clk = clk;

```

# おそるべし Polyphony の最適化 
かなり最適化が効いてほとんど assign になる。ただ DSP をつかってくれない。
そこで、ちょっとこれも Verilog を細工して DSP を使うようにしてみる。

```verilog:
  assign new_n_inl1_inl13 = (t622_inl1_inl1 * t623_inl1_inl1);
```

の部分を reg にしてステートを一つ入れてみた。たしかに DSP を使うようにはなった。ただ、結局 fmax のボトルネックはメモリアクセスなのでこの改造は意味がなかった。

# unroll してみる
これは失敗に終わる。よーく考えたらメモリアクセスを同時にできないと意味がない。ここは将来的な検討項目。

# システム全体はこんな感じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99921/d1c5baa2-7457-fdc2-6ba6-137b6586f49c.png)

# VIO で確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99921/260afce5-c2f0-7733-6d43-e340367663b8.png)

10進だからわかりづらい。

# 今後の展開
Retro FORTH と連携する。AXI Stream と連携する。unroll 対応をする。といったところか。
現時点でも使えているので、パラメタのリアルタイムの可視化とかできそうな気がしている。
postgresql導入

# postgresql導入

主に下記の記事参照
https://orfool.com/programing/2172/

## まずpostgreインストール

```
$ sudo yum install postgresql postgresql-server postgresql-devel postgresql-contrib
```

##次にポスグレ起動
```
$ sudo service postgresql start
```

##次にエラーメッセージが出るのでそれに従う
```
$ sudo service postgresql initdb
```

## 最後これで完璧

```
sudo service postgresql start
```
素の alpine でのコネクション確認

最近 ECS を使おうと docker を色々と触っているので、その知見を溜めておく。

今回は alpine で一切ツールを導入(`apk add`)せずにコネクション確認をするかというお話。「ヘルスチェック」ではなく「コネクション確認」という言葉を使っているのは、[docker が持っているヘルスチェック機能](https://docs.docker.com/engine/reference/builder/#healthcheck)とは違う話をするため。
応用はできるけど、もともとの動機は「アプリサーバーがDBマイグレーションを行う際に通信できる常態か知りたい」だった。

tl;dr
-----

`nc` コマンドを使おう。
デフォルトでインストールされていて、なんなら UDP での接続チェックなんてのもできる。

一定の時間、コネクション確認するスクリプトは次の通り。

```bash
host=${1:-"127.0.0.1"}
port=${2:-80}

retry=0
while [ $retry -lt 10 ];
do
	sleep $retry
	echo "connection check to $host:$port"
	nc -zn $host $port
	[ $? -eq 0 ] && exit 0

	retry=`expr $retry + 1`
	echo "failed; sleep for ${retry}s"
done && exit 1
```
というわけで、以下は道のり
を書こうと思ったけど、まぁまた今度
ITインフラについて4日間でわかったこと。

##**はじめに**
ITインフラについて4日間前まで、まったく知らなかった自分が、
基礎の基礎を書きました。
至らない点がありましたら、ご指摘頂ければ幸いです。
また学習していく中で参考にしたサイトをまとめました。
##**ITインフラとは**
ITを支える基盤となるもの、それがITインフラです。
具体的にはPC、サーバー、キーボード、LANといった各種ハードウェア。
OSといったソフトウェア、データベースといったミドルウェアです。

このような「基盤」がある上で、
「ニュースのwebサイトを閲覧したい！」
「SNSで情報を発信したい！」
ということが実現できます。

またwebサイトの記事を読み込むときの速度、
つまり「通信回線の速さ」もITインフラです。

http://ikikatadatabase.com/archives/4860
https://www.n-itech.com/feature/about_itinfra.html
以上2つのサイトを参考・引用しました。
##**ITインフラエンジニアってどんな仕事？**
1クライアントが、Webサイトへ新規のアカウントを作成したい、と要求します。
　　　　　　↓
2サーバーが処理をします。
Webサーバーがクライアントからの要求を受け取り、APサーバーが要求を処理し、
処理内容をDBサーバーに書き込みます。
DBサーバーはAPサーバーに書き込み終了を通知し、
APサーバーは処理結果をWebサーバーに返し、Webサーバーは結果をクライアントに応答します。
　　　　　　↓
3クライアントのWebブラウザに新規のアカウントの作成画面が表示されます。

2の各種サーバを構築するのがITインフラエンジニアの仕事です。
また1から3までの工程を構築するのこともITインフラエンジニアの仕事です。
ITインフラエンジニアは、何かをしたいという要求に答えるための基盤を作る仕事です。

「ニュースのwebサイトを閲覧したい！」という要求に、
PCを用意したり、サーバーの処理を考えたりすることです。

ITインフラエンジニアは企業によって呼び名が違い、以下３つの総称として言われることもある。

- ネットワークエンジニア
　ネットワーク機器のスペシャリスト

- データベースエンジニア
　リレーショナルデータベースのスペシャリスト

- サーバーエンジニア
　Linux、Windowsサーバーを構築するスペシャリスト

https://qiita.com/shuntaro_tamura/items/e1a20e33c57c71679688
https://wa3.i-3-i.info/word14407.html
https://mynavi-creator.jp/blog/article/mission-of-infrastructure-engineer
以上3つのサイトを参考・引用しました。

##**初心者は運用・保守から経験を積む**
ITインフラエンジニアの役割は３つあります。
・設計
・構築
・運用・保守
上が一番経験力・知識を求められます。
その中でインフラエンジニアが初めて携わる、運用・保守について書きます。

「運用」とは、
システムが作動するように監視・メンテナンスをする仕事。
「保守」とは、
トラブルが起きた時に、原因を見極め、対処する仕事。

この２つが運用・保守の業務です。


https://daini2.co.jp/syokusyu/article-0287-author-uzuz03/#i-2
以上のサイトから参考・引用しました。

##**資格学習・学習サイト**
ITインフラ初心者が目指す資格
・CCNA　シーシーエヌエー
・LPICレベル１　エルピックレベル１

学習サイト
Ping-t　LPICレベル1が無料で閲覧できます。
Qiita　情報の共有や情報の閲覧、または自分の情報をアウトプットできます。

https://mynavi-creator.jp/blog/article/mission-of-infrastructure-engineer
https://daini2.co.jp/syokusyu/article-0287-author-uzuz03/#i-2
以上2つのサイトから参考・引用しました。

##**まとめ**
　　　　　・ITインフラとは　→　PCやDBサーバーといった基盤のこと。

・ITインフラエンジニアとは　→　webサイトやSNSを利用したい人のために、
　　　　　　　　　　　　　　 　ITインフラを整備する人。

・初心者は運用・保守から経験を積んでいく。

・資格は「CCNA」、「LPIC」があり、学習サイトは「Ping-tが」ある。
・IT全般またはITインフラについて知りたい・共有したい場合は「Qiita」がある。


##**これから先の自分**
Qiitaの使い方や、交流の仕方を調べながら、他のサイトも使いながら学習する。
Cloud Runを試してみる

#Cloud Runとは

Google Cloud Next '19 San Francisco で発表された、GCPの新サービス、
Cloud Runを試してみる。
コンテナを作成しデプロイするだけで、サーバレスで実行できるようになるらしい。
コンテナ上でアプリケーションが動くため、どんな言語で作成されたものでも実行可能。

### 公式チュートリアル
https://cloud.google.com/run/docs/quickstarts


# Dockerイメージを作成する
以下の3ファイルを作成

```python:requirements.txt
Flask==1.0.2
gunicorn==19.9.0
```


```dockerfile:Dockerfile
FROM python:3.7

ENV PORT=8080
WORKDIR /usr/src/app

COPY requirements.txt ./
COPY app.py ./
RUN pip install --no-cache-dir -r requirements.txt

CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 app:app
```

```python:app.py
from flask import Flask

app = Flask(__name__)

@app.route('/')
@app.route('/<id>')
def hello(word=’World’):
    return f'Hello {word}!!'

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=int(os.environ.get('PORT', 8080)))
```

ビルドして、GCRにプッシュ

```bash
PROJECT_ID=<YOUR_PROJECT>
IMAGE=cloud-run-sample

docker build -t gcr.io/${PROJECT_ID}/${IMAGE} .

gcloud docker -- push gcr.io/${PROJECT_ID}/${IMAGE}
```

# デプロイ
GCPコンソールからCloud Runを選択、「CREATE SERVICE」を選択
先程ビルドしたコンテナイメージを選択し、サービス名、ロケーションを入力。
「未認証の呼び出しを許可」にチェックを入れ、作成。
デプロイが終わると、URLが割り当てられるので、ブラウザでアクセスし、
アプリケーションが動いていることが確認できる。

# まとめ
コンテナさえあれば簡単にデプロイできる。
初めてアクセスするときは5～10秒くらいかかる。コンテナ起動の時間なのか？
Cloud Functionsとどう使い分けるべきか検証したい。
SVG 微妙に書き方に困惑したところメモ

いつもはイラレなどで書き出してしまうところを、ちょっと中身をみて編集してみた時に困惑したのでメモ。

line、rect、polygon、circle、ellipseは、なんとなくわかったのですが、
困惑したのは、path。。。
下記の記事を参考にして理解しました。

http://www.tohoho-web.com/ex/svg.html

###困惑したところ
ソースをパッとみた感じ（調べる前）では、pathタグに`d=`でクリッカブルマップ（イメージマップ）みたいに座標みたいな数字を入れているみたいだったので、適当に数字いじってみたのですが、ぐちゃぐちゃになりました。
気になったは、MとかLとか入っていること。。。

###パス描画の命令を記述
MとかLとかは命令とのこと。
参考サイトではこう書いてありました。

- M (x y)+ : x, y に移動 (Move to)
- L (x y)+ : x, y に線を引く (Lineto)
- H (x)+ : 水平方向に線を引く (Horizontal lineto)
- V (y)+ : 垂直方向に線を引く (Vertical lineto)
- S (x1 y1 x y)+ : 制御点(x1, y1)、終点(x, y) とする二次ベジェ曲線 (Shorhand/smooth curveto)
- C (x1 y1 x2 y2 x y)+ : 制御点1(x1, y1)、制御点2(x2, y2)、終点(x, y) とする三次ベジェ曲線 (Curveto)
- Z : パスを閉じる (Closepath)

ここでなるほど〜と理解。
座標をただ入力するのと違い、描画を命令するということが違いであり、僕の大きな勘違いだったことを理解しました。

###参考に書く

```
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg">
<path d="M 5 20 L 20 5 L 35 20 L 20 35 Z" stroke="red" fill="transparent" stroke-width="4" />
</svg>
```
とりあえずこんな感じ
![img01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287209/1f135664-4c2d-9d69-1d70-90f742934498.png)

そして、座標を入力するのとは違う点

```
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg">
<path d="M 5 20 L 20 5 L 35 20 L 20 35 Z M 20 45 L 45 20 L 70 45 L 45 70 Z" stroke="red" fill="transparent" stroke-width="2" />
</svg>
```
![スクリーンショット 2019-04-15 0.14.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287209/7c748ab3-bbef-cc8c-d616-eece5de27b88.png)

１つ目のソースの後に、またMで位置を指定すると、pathタグ1つで2つのオブジェクトが描ける。

###まとめ
いつもイラレなどのソフトで作成していたので、さらっとやっていましたが、勉強になりました。何かに困ったら、ソースみてみるのが良いですね。
Railsでデプロイする際に躓いた箇所

Railsでデプロイする際に躓いた箇所がいくつか（というより沢山）あったので自分用メモも兼ねて書きます。

# secret_key_base周り

Rails5.2からsecrets.ymlの代わりにcredentials.yml.encが生成されるようになりました。
rails newされると自動でapp/configにcredentials.yml.encとmaster.keyが生成されます。
master.keyが無い状態でrails credentials:editコマンドを実行するとmaster.keyが生成されますが、生成されたmaster.keyで復号できず困りました。

[Rails 5.2 で ActiveSupport::MessageEncryptor::InvalidMessage](https://qiita.com/scivola/items/cc06ddbfd94d3118f693)

こちらの記事にある通り、ローカルにあるmaster.keyの中身をコピーしてproduction環境のmaster.keyに貼り付けたところいけました。

# MySQLでAccess denied

```
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
```

このようなエラーが出てきて入れず。

[mysql5.7でパスワードを変更する](https://qiita.com/RyochanUedasan/items/9a49309019475536d22a)

どうやら自動で仮パスワードが発行されているようなので調べてみると、

```
cat /var/log/mysqld.log | grep password
2019-04-14T11:01:59.067618Z 1 [Note] A temporary password is generated for root@localhost: **********
```

となっていたのでこちらの仮パスワードで無事いけました。

# Unicornが起動できない

Unicornを起動しようとしたところ以下のようなエラーが。

```
master failed to start, check stderr log for details
```

log/unicorn.logをチェックしたところ、

```
/home/fkdolly/.rbenv/versions/2.3.3/lib/ruby/gems/2.3.0/gems/unicorn-5.5.0/lib/unicorn.rb:49:in `block in builder': wrong number of arguments (given 0, expected 2) (ArgumentError)
```

調べてみるとUnicorn 5.5.0で出ているエラーのようでした。
[Unicorn で Rails アプリが起動しなかったので対処](https://loumo.jp/wp/archive/20190318210002/)
[Unicorn Refreshing Gem List](https://stackoverflow.com/questions/55031954/unicorn-refreshing-gem-list)

```
bundle exec gem list | grep unicorn
unicorn (5.5.0)
```

同じく5.5.0でしたので、

```ruby:Gemfile
group :production, :staging do
    gem 'unicorn', '5.4.1'
end
```

```
bundle install
```

これでいけるかなと思ったらまだエラー。
5.5.0を削除するのを忘れていました。

```
bundle exec gem uninstall unicorn -v '5.5.0'
bundle update
```

これで無事に起動できました。
【第5章】rails tutorial 備忘録

##レイアウト

###bootstrap
[containerとcontainer_fluidの違い](https://www.ipentec.com/document/html-css-bootstrap-container)

### yield
ページごとの内容を挿入する

##link_to
<%= link_to "表示文字列”,"パス",class:"class名"　%>

##link_to image_tag

<%= link_to image_tag("画像名",
alt:"alt名"　%>
app/assets/image/にあるところから画像を探して、表示してくれる。

## mv コマンド

[参考サイト](https://eng-entrance.com/linux_command_mv)

## bootstrap

gemgileに
gem 'bootstrap-sass', '3.3.7'を追加

```
 $touch app/assets/stylesheets/custom.scss
```
でカスタムCSSを作り、そこへcssを記載する。

そこへ

```ruby:app/assets/stylesheets/custom.scss
@import "bootstrap-sprockets";
@import "bootstrap";
を記載する。
```

##CSSを追加

###remとem

@@@@@@@

letter-spacing
text-transform


##パーシャル（partial）

```ruby:app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title><%= full_title(yield(:title)) %></title>
    <%= csrf_meta_tags %>

    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
  
ここから
<!--[if lt IE 9]>
      <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/r29/html5.min.js">
      </script>
    <![endif]-->
ここまでを
↓
<%= render 'layouts/shim' %>
に置き換え、切り出す。


    </head>

ここから
    <header class="navbar navbar-fixed-top navbar-inverse">
    <div class="container">
    <%= link_to "sample app","#",id:"logo" %>
    <nav>
    <ul class ="nav navbar-nav navbar-right">
    <li><%= link_to "Home",'#' %></li>
    <li><%= link_to "About",'#' %></li>
    <li><%= link_to "Log in",'#' %></li>
    </ul>
    </nav>
    </div>
    </header>
ここまでを
↓
<%= render 'layouts/header' %>
に置き換え、切り出す


  <body>
  <div class = "container">
    <%= yield %>
    </div>
  </body>
</html>
```

切り出したものを
layouts/_shim.html.erb
layouts/_header.html.erb
のファイルに記載する。


## アセットパイプライン

三つのassetsがある
１　app/assets 今あるアプリケーション固有のアセット

２　lib/assets 自分の開発チームによって作られたライブラリ用のアセット

３　vendor/assets サードパーティのアセット

##マニフェストファイル
上記のアセットをどのように一つにまとめるかを指示できる

## sass
このあと、progateでやろう。


## ルートURL

root_pathは　「/」を返す。
root_urlは「http://www.example.com/」(
完全なurl）を返す

HTTPの標準では、リダイレクトの時は、完全なurlが求められるが、path書式でも動く。


get 'static_page/help'を

get '/help' ,to: 'static_pages#help’に変換すると

テストとviewsで名前付きurl(
help_path)が使えるようになる。

テストで使うルートの書式を名前付きルートに変えてみる。

```ruby:
<%= link_to "About",   'about_path' %>
```

###注意！
名前ルートを''で囲わないこと。


## 統合テスト
アプリケーションにアクセスするところから
隅々までテストする

rails g controllerで自動作成されたテストと内容は同じで、

```
require 'test_helper'

class SiteLayoutTest < ActionDispatch::IntegrationTest
  # test "the truth" do
  #   assert true
  # end
end
```

actionDispatch::IntegrationTestを継承したクラスが記載されている。


単体テスト、機能テスト、統合テストと
様々なテストがある。

[テストの種類と動作に関する記事](https://qiita.com/duka/items/2d724ea2226984cb544f)

##調べる
各テストのクラスがどんなクラスを継承しているか確認する
継承したクラスによって、意味や動きはどう変わるのか

何をrails newしたら、どのtestファイルが作成されるのかも整理する
ポーリングとは

参考サイト:
http://ur2.link/2lav
https://www.fe-siken.com/kakomon/29_aki/q17.html

#ポーリングとは？
複数の機器やソフトウェアを円滑に連携させる制御方式の一つ。
<font color="red">主となるシステム</font>が<font color="red">他のシステム</font>に対して一定間隔で順繰りに<font color="red">要求がないか尋ねる</font>方式。

#ポーリングを行わないと……
複数のシステムが独立に動作して主システムと通信しているような状況では、各システムが自らのタイミングで通信を行うと処理や信号が<font color="red">他のシステムと競合して不具合を生じる</font>場合がある。

#復習問題
ソフトウェア制御における，ポーリング制御はどれか。

ア：CPUが状態レジスタ又はビジー信号などを読み出して，入出力装置の状態を監視する。

イ：実行中の処理を一時的に中断して，緊急度の高い別の処理を実行する。

ウ：送信側のタスクがメモリにデータを格納し，受信側のタスクにそのアドレスを伝える。

エ：複数のタスクが利用する共有資源を，一つのタスクが占有できるようにする。
[Android]ShareCompatを使ってシェア（共有）する場合の画像の渡し方、コールバックの受け取り方

↓これの事

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9104/3edbd859-bf86-d021-8732-1e187236bdd7.png width=220>

わりとたくさん情報がありそうな気がしたが、意外と出てこなかったので、メモ書き。

## ライブラリ

- com.android.support:support-compat:28.0.0

## 実装

```java:SomeActivity.java
// アクティビティ内から実行する前提のコード
private void showShareChooser() {
	File tempFile = new File(getApplicationContext().getExternalCacheDir(), tempImgFilePath);

	// ファイルをシェアするためにURIを取得する場合は、FileProviderを通じて、後述するオーソリティの名前を指定して取得する必要がある
	Uri uri = FileProvider.getUriForFile(getApplicationContext()
			, getApplicationContext().getPackageName() + ".provider"
			, tempFile);

	ShareCompat.IntentBuilder builder = ShareCompat.IntentBuilder.from(this);
	builder.setChooserTitle(chooserTitle) // シェアする時のタイトル
			.setSubject(subject) // 件名。使われ方はシェアされた側のアプリによる
			.setText(text) // 本文。使われ方はシェアされた側のアプリによる
			.setStream(uri) // ファイルをシェアする時は、そのURIを指定
			.setType("image/jpeg"); // ストリームで指定したファイルのMIMEタイプ

	// URIに対する読み取り権限を付与する
	Intent intent = builder.createChooserIntent().addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

	// コールバックを受け取りたい場合は、そのインテントを使ってアクティビティを開始する
	if (intent.resolveActivity(getPackageManager()) != null) {
		startActivityForResult(intent, SNS_SHARE);
	}

	// 結果を受け取らなくても良い場合は、ビルダーからそのまま開始できる
	// builder.startChooser();
}
```

戻りを受け取る場合は、 通常どおり `onActivityResult` で受け取れる。

```java
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
	switch (requestCode) {
		case SNS_SHARE:
			// 戻りを受け取って何らか処理する
			// resultCode は必ずゼロになるので、 RESULT_OK で判定しない
			doSomething();
			break;

		default:
			super.onActivityResult(requestCode, resultCode, data);
			break;
	}
}
```

## ファイルを共有する場合

画像などを共有する場合は、Bitmapをそのまま共有したりできないため、一旦ファイルに保存する必要がある。
また、以下のように保存先からの読み出しを許可する必要がある。

まず、パスをXMLで指定する。

```xml:src/main/res/xml/provider_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-cache-path name="cache" path="." />
</paths>
```

`external-cache-path` などは保存先に応じて変わる。
英語だけど[FileProviderの公式リファレンス](https://developer.android.com/reference/android/support/v4/content/FileProvider)を参照。
次に、そのプロバイダを `AndroidManifest.xml` で指定する。

```xml:AndroidManifest.xml
<manifest
    package="com.example"
    xmlns:android="http://schemas.android.com/apk/res/android">
:
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths"/>
        </provider>
:
    </application>
:
</manifest>
```

## 参考

- [FileProvider  |  Android Developers](https://developer.android.com/reference/android/support/v4/content/FileProvider)
- [Sharing Content between Android Apps – Android Developers – Medium](https://medium.com/androiddevelopers/sharing-content-between-android-apps-2e6db9d1368b)
XcodeでTODO:などの警告を表示させる方法

#はじめに
警告の表示方法についての備忘録です。

#方法1
Swift4.2までは#warning("")などが使えなかったので、お決まりのスクリプトです。
使用方法はBuildPhaseのRunScriptに以下を追加。

```bash

TAGS="TODO:|FIXME:"
ERRORTAG="ERROR:"
find "${SRCROOT}" \( -name "*.h" -or -name "*.m" -or -name "*.swift" \) -print0 | xargs -0 egrep --with-filename --line-number --only-matching "($TAGS).*\$|($ERRORTAG).*\$" | perl -p -e "s/($TAGS)/ warning: \$1/" | perl -p -e "s/($ERRORTAG)/ error: \$1/"

```

####使い方

**`// TODO:`**
**`// FIXME:`**
**`// ERROR:`**

を使用した場合に警告およびエラーがビルド実行時に表示されるようになります。

####結果

<img width="736" alt="スクリーンショット 2019-04-14 23.42.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184792/585975b5-8043-2b95-7797-7ec6de533a1d.png">

#方法2

エディタプレースホルダーを使用する強引なやり方です。
ビルドが通らないので使い方は限られますし、本来の使い方ではないですね。
予測変換で出したコードの引数とかに出てくるこれですね。

<img width="655" alt="スクリーンショット 2019-04-15 0.02.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184792/69818546-c843-8489-28a0-1fd275366cfc.png">

生成方法は至って簡単。
以下のように文字を`<#` `#>`で挟めばエディタプレースホルダーとして変換されます。

####使い方

```swift
<#hogehoge#>
```

####結果

<img width="748" alt="スクリーンショット 2019-04-14 23.51.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184792/2cee98cf-6ad8-8110-3482-f559fba0a44b.png">

#方法3

Swift4.2以降で使えるようになったやつです。


####使い方

```
 #warning("hogehoge")
 #error("fugafuga")
```

####結果

<img width="749" alt="スクリーンショット 2019-04-14 23.56.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184792/f067a5d5-58e8-52f0-5229-631573532c6f.png">


#まとめ
個人的にはまだ方法1のやり方8割で、2割で方法3のやり方でやっています。
まず方法2はやらないですね。
警告内容も該当箇所いかないとわからないですし。
(なぜ書いたんだって話になりますが...)

簡易的な備忘録でしたが、ご覧いただきありがとうございました。

ひっそりとブログも始めました。
[kazyblog](https://kazyblog.com/)
MTBFとMTTR

参考サイト：
全体の稼働率＝1-(1-0.9)×(1-0.8)＝1-(0.1×0.2)＝1-0.02＝0.98
https://www.fe-siken.com/kakomon/25_haru/q15.html

#MTBFとは
Mean Time Between Failures。
<font color="red">平均故障間隔</font>。

#MTTRとは
Mean Time To Repair。
<font color="red">平均修理時間</font>。

#稼働率
すべての時間の中で稼働している時間の割合を表す。
次の式で求めることができる。
>稼働率 = MTBF / ( MTBF + MTTR )

#直列システムの稼働率
それぞれの稼働率を掛け合わせることで計算することができる。

\---[ A ]---[ B ]---

例えば、Aの稼働率 0.9、Bの稼働率 0.8なら、
>全体のシステム稼働率＝0.9×0.8＝0.72

またA・Bの他にCが接続されている場合は、A×B×Cと計算する。

#並列システムの稼働率
>全体の稼働率 = 1 - ( 1 - Aの稼働率 ) × ( 1 - B の稼働率 )

例えば、Aの稼働率 0.9、Bの稼働率 0.8なら、
>全体の稼働率 
= 1 - ( 1 - 0.9 ) × ( 1 - 0.8 ) 
= 1 - ( 0.1 × 0.2 )
= 1 - 0.02 
= 0.98

#復習問題
MTBFが45時間でMTTRが5時間の装置がある。この装置を二つ直列に接続したシステムの稼働率は幾らか。
エンジニア初心者がRailsでランキング機能実装の際につまづいたところ

CDの発売日を管理できるサービスを作っていて、発売日が過ぎたときにランキングから除外しなきゃ！と思ったものの微妙に詰まったのでここに備忘録として書き残しておきます。💁

環境:cloud9(IDE)EC2(仮想サーバー)rails(rubyFW)mysql(DB)

まず大前提の知識としてModelはDBの情報を引っ張ってくるということです！（今更）
MVCのそれぞれの役割をしっかり理解しておくことは本当に重要で、理解してプログラミングをしていると今自分が何をやっているのか頭の中で整理できます。

今回は実際に色々試した過程を書きます。

大まかな流れとして、
1.DB設計を考える 2.mysql(DB)でコマンドを色々試す→３.処理が成功したらmodelに実装
という形で行いました。

<h1>1.DB設計を考える</h1>

ランキングは中間テーブル(relationships)で集計しているので、中間テーブルに発売日カラムを登録することで発売日でフィルターをかけることができるのでは？

<h1>2.mysqlでコマンドを色々試す</h1>

▼カラム追加(mysql)
```alter table relationships add sales_date  date;```
楽天apiから発売日情報を文字列型で引っ張って来ているのでエラーになってしまった。

``` alter table relationships add sales_date varchar(255); ```
文字列型で登録〜うん良さそう

▼発売日を過ぎたものは非表示にするコマンドをチェック
私が実際にやったときはmodelの記述を先に行ってしまったのですごい時間を食ってしまった…先にこっちで確認すべきだった…良い学び

``` select * from relationships where sales_date > date_format(current_date(),'%Y年%m月%d日');```
処理内容としては、現在日時をdate_formatを用いて年月日に変更し、sales_dateと比較演算子を用いて比較しています。これをそのままmodelに実装します。

<h1>3.処理が成功したらmodelに実装</h1>

▼記述方法


```ruby:relationship.rb
def Relationship.ranking
  Relationship.where().group().order().limit().count()
end
```

前述の通り、modelはdbから情報を引っ張ってくるので書き方としてはかなりdbに近いです。
まずwhereで絞り込み、groupで重複した値をまとめ、orderで並べ替え、limitで表示制限をして最後のcountでCDの登録された数を数えるといった流れです。実際のコードを書いていきます。

```ruby:relationship.rb
def self.ranking
  self.where("sales_date > date_format(current_date(),'%Y年%m月%d日')").group(:item_id).order('count_item_id DESC').limit(12).count(:item_id)
end
```
where以外はそこまで特別なことはしていないので省きます。
結論から書くとwhereにdbで成功した文をダブルクォーテーションで囲むだけでOKです！笑
これでできたときは拍子抜けしました…それと同時にMVCの理解度が低かったとかなり痛感しました。
modelはdbの情報を引っ張ってくるわけだからdbで実際に成功した文をそのまま書けば確かに間違いはないですねｗ

<h1>まとめ</h1>
MVCの役割を理解することの重要性を書きたかったのですがシッチャカメッチャカになっちゃった感。。。
まあそれなりに自分の考えは整理できた気がするので良しとします笑
反省点としては何を書くのか考えていなかったこと、考えをまとめていなかったことの二点ですかね😨精進します！
今週のPython学習内容

これは、今週個人的に学習した内容をアウトプットした記事です
## print()関数で複数の文字列を改行なしで出力する方法

print()関数のオプション引数 end=”” を渡す.""の中に半角スペースを入れることで、半角空けながら改行なしで出力する。
     
     例；
     for n in range(2):
        print (n,end=" ")

    結果；
    0 1

## 対象の文字列が、ある文字列のリストに現れる回数を数える方法

    回数を数えるmatchingStringsメソッド(stringsはある文字列のリスト、queriesは対象文字列のリスト)；
    for querie in queries:
        x.append(strings.count(querie))


## mapの使い方
map()は、リストの要素に演算を適用してくれる関数です。
    
    例；
    >>> def square(x):
    ...     return x * x
    ...
    >>> list(map(square, range(1, 6)))
    [1, 4, 9, 16, 25]
Mongoid 特定Collectionにのみインデックスを作る

[@koshi_life](https://twitter.com/koshi_life) です。

Mongoid で特定Collectionにインデックスを作るやり方の備忘です。
参考: https://docs.mongodb.com/mongoid/master/tutorials/mongoid-indexes/

Mongoid では以下コマンドで各モデルで定義しているインデックスを作成することができます。

```
$ rake db:mongoid:create_indexes
```

しかしながら、既に投入されているデータにより、インデックス制約(ユニーク等)に違反している場合は以下のようにインデックス作成に失敗します。

```
$ rake db:mongoid:create_indexes
rake aborted!
Mongo::Error::OperationFailure: E11000 duplicate key error collection: test.users index: email_unique dup key: { : "yamada@example.com" } (11000)
```

ユニーク制約のデータ整理に時間がかかるなどで、
一旦インデックス定義可能なコレクションにのみインデックスを作成方法は以下です。

`Model.create_indexes`

```
$ rails c
irb(main):001:0> Message.create_indexes
=> true
```

## モデルの例

- Userモデル

```user.rb
class User
  include Mongoid::Document

  field :name, type: String
  field :email, type: String, default: ''

  # インデックス: email は重複不可。空白はOK。
  index({ email: 1 }, { name: 'email_unique', unique: true, sparse: true})

end
```

- Messageモデル

```message.rb
class Message
  include Mongoid::Document

  field :message_id
  field :subject
  field :body

  belongs_to :user

  # インデックス: user毎に message_id は一意とする
  index({ user: 1, message_id: 1 }, { name: 'message_unique', unique: true })
end
```
Nextcloudの管理用CLI「occ」詳細： バックグラウンド動作モード制御に関するコマンド群

# はじめに
NextcloudにはCLI環境として`occ`というものがあり、さまざまな設定、管理を行うことができます。 ここではoccで使える様々なコマンド群のうち、Nextcloudのバックグラウンド動作モード制御に関するコマンド群についてまとめてみます。

※occ の使い方については、 [Nextcloudの管理用CLI「occ」コマンドについて](https://qiita.com/S_Katz/items/99b9319127d956b22e7b)の記事を参照ください。

# 環境について
ここで記載するoccを実行するNextcloudのバージョンは、2019年4月13日現在で最新の`15.0.7`を利用します。  
WebサーバはNginxを利用した環境で実施しております。ApacheをWebサーバとして利用している場合は、`sudo -u` のユーザIDを`apache`に読み替えてください。

# バックグラウンド動作モード制御に関するコマンド群
バックグラウンド動作モード制御に関するコマンドは以下のようなものがあります。

- background:ajax
- background:cron
- background:webcron

## background:ajax
Nextcloudのバックグランド動作モードを `AJAX` にします。標準的なインストールにおいてはこのモードがデフォルトとなります。
このモードは、各ページの読み込み時にタスクを実行するため信頼性は低いですが、サービスの登録ができない、システムへのアクセスができないといった状況では選択肢となります。 

### 使い方
`background:ajax`

### 使用例

```
$ sudo -u nginx php /var/www/html/nextcloud/occ background:ajax   
Set mode for background jobs to 'ajax'
```

## background:webcron
Nextcloudのバックグランド動作モードを `Webcron` にします。
このモードは、HTTP経由で　`cron.php` を実行させるようにします。Webcron のサービスは別途準備、登録する必要があります。
利用が制限されたレンタルサーバで運用するなど、cron を自由に設定できない場合にはこのモードを利用します。  

### 使い方
`background:webcron`

### 使用例

```
$ sudo -u nginx php /var/www/html/nextcloud/occ background:webcron   
Set mode for background jobs to 'webcron'
```

## background:cron
Nextcloudのバックグランド動作モードを `Cron` にします。
このモードは、cron を利用して　`cron.php` を実行させます。cron の登録は別途OSにて適切に設定する必要があります。  

### 使い方
`background:cron`

### 使用例

```
$ sudo -u nginx php /var/www/html/nextcloud/occ background:cron   
Set mode for background jobs to 'cron'
```

**★この記事は、[スタイルズ社のNextcloudサイト](https://nextcloud.stylez.co.jp/) の [Nextcloudブログ](https://nextcloud.stylez.co.jp/nextcloudblog)にも公開しております！**
PHPでお手軽カウンター


こんな感じでファイルを作る。

```php:functions.php

<?php

function counter(){

  //日付を取得
  $base_day = date("Y/m/d");

  //IPアドレス取得
  $remoteAddr = $_SERVER['REMOTE_ADDR'];

  //空ファイルを用意する
  $filepath = "count.dat";

  //ファイルを開いて変数にデータを入れる
  $fp = fopen($filepath,"r+b");
  flock ($fp,LOCK_EX);
  $line = fgets($fp);
  list($reg_day, $total, $today, $yesterday, $reg_remoteAddr) = explode(",", $line);

  //日付が変わったら今日のカウントをゼロにして、昨日のカウントを入れ替える
  if ($base_day != $reg_day){
    $yesterday = $today;
    $today = 0;
  }
  //IPアドレスが一致してなかったら（連続カウント防止）
  if ($remoteAddr!=$reg_remoteAddr) {

    //合計と今日のカウントを１増やす
    $total++;
    $today++;

    //ファイルの中身を空にする
    ftruncate($fp,0);

    //ファイルポインタを先頭に戻す
    rewind($fp);

    //ファイルに書き込んで閉じる
    fwrite($fp,"$base_day,$total,$today,$yesterday,$remoteAddr");
    fclose($fp);
  }

  //カウントを表示させる
  echo "今日{$today}&nbsp;";
  echo "昨日{$yesterday}&nbsp;";
  echo "合計{$total}";
}
```

カウンターを表示させたい場所で実行。

```php:index.php
<?php
include("functions.php");
counter();
?>
```

「count.dat」の空ファイルを作り、functions.phpと同じ位置に配置させる。
【selenium】python初心者がインスタ自動いいねツールを勝手に改修した話

#経緯
一時期、某クラウドソーシングサイトの依頼で大流行りしていた「インスタ自動いいねツール」を試しに作りたいなーとググったところ、[偉大なる先駆者様](https://review-of-my-life.blogspot.com/2017/12/selenium-instagram.html)を発見。

pythonを私用でちゃんと使うのは初めてでしたが、記事がとてもわかりやすくコードまで書いてくださっているのですんなりできました。

そこで欲をかいた私は、もうちょっと自分用にカスタマイズしたいなーっと以下を実装してみます。

・現在表示されている分以上のループをしたい（次の読み込み分もいいねをつけたい）
・いいね済かどうかを判定したい

#やること

・selectorやpathを修正
・指定した回数分いいねを押す
・既にいいねされていたり、読み込みきれていないものは「次へ」

※2020/01/20：パスとmax値を修正
#コード

```sample.py
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import urllib.parse
import time

#Webdriver
browser = webdriver.Chrome(executable_path='[chromedriver.exeのパス]')

#URL
MAIN_URL = "https://www.instagram.com/"
TAG_SEARCH_URL = MAIN_URL + "explore/tags/{}/?hl=ja"

#selectors
LOGIN_PATH = '//*[@id="react-root"]/section/main/article/div[2]/div[2]/p/a'
LIKE_PATH = '//button[@class="wpO6b "]/*[name()="svg"][@aria-label="いいね！"]'
LIKE_BUTTON_PATH = '//button[@class="wpO6b "]'

MEDIA_SELECTOR = 'div._9AhH0' #表示されているメディアのwebelement
NEXT_PAGE_SELECTOR = 'a.coreSpriteRightPaginationArrow' #次へボタン

#USER INFO
username = "[username]"
password = "[password]"
#params
tagName = "[タグ名]"
likedCounter = 0
likedMax = 100

if __name__ == '__main__':

    #login 
    browser.get(MAIN_URL)
    time.sleep(3)
    browser.find_element_by_xpath(LOGIN_PATH).click()
    time.sleep(3)
    usernameField = browser.find_element_by_name('username')
    usernameField.send_keys(username)
    passwordField = browser.find_element_by_name('password')
    passwordField.send_keys(password)
    passwordField.send_keys(Keys.RETURN)

    #tag search
    time.sleep(3)
    encodedTag = urllib.parse.quote(tagName) #普通にURLに日本語は入れられないので、エンコードする
    encodedURL = TAG_SEARCH_URL.format(encodedTag)
    print("encodedURL:{}".format(encodedURL))
    browser.get(encodedURL)

    #media click
    time.sleep(3)
    browser.implicitly_wait(10)
    browser.find_element_by_css_selector(MEDIA_SELECTOR).click()
    
    #次へボタンが表示されないか、いいねが一定数いくまで
    while likedCounter < likedMax:
        time.sleep(3)
        try:
            browser.find_element_by_xpath(LIKE_PATH)
            browser.find_element_by_xpath(LIKE_BUTTON_PATH).click()
            likedCounter += 1
            print("liked {}".format(likedCounter))
        except:
            #読み込まれなかったり既にいいねしているならパス
            print("pass")
            pass

        #次へ
        try:
            browser.find_element_by_css_selector(NEXT_PAGE_SELECTOR).click()
        except:
            break

    print("You liked {} media".format(likedCounter))
```


#課題点

・全体的に高速化したい
　→あんまり早すぎると規制されるので悩みどころ
・既いいね時、次へ進むまでの時間が長い
・exceptでpassするのが個人的にいただけない。
ddコマンドでファイル書き込みの参考値を出す

出します。
参考までに、自分のMacと手元にあったRaspberry Piで試す。

以下の記事を参考にしました。
https://qiita.com/kumai@github/items/47c6d941ccbb053d0b3d

## 試す機器の参考スペック
MacBookAir2014 4core 4GB (だった気がする
RSRaspberryPi3 4core 1GB

**試すコマンド**

```bash
# 1GBでどの程度になるか確認する
dd if=/dev/zero of=./kusatest count=1 bs=1073741824 oflag=direct
```

```bash:macos
$ dd if=/dev/zero of=./kusatest count=1 bs=1073741824 
1+0 records in
1+0 records out
1073741824 bytes transferred in 10.509043 secs (102173131 bytes/sec)
```

```bash:Raspbian
pi@raspberrypi:~ $ dd if=/dev/zero of=./kusatest count=1 bs=1073741824 oflag=direct
dd: 大きさ 1073741824 バイトの入力バッファによりメモリを使い果たしました (1.0 GiB)
```

**試すコマンド**


```bash
# 入力量を変更して試す
dd if=/dev/zero of=./kusatest count=1000 bs=1048576 oflag=direct
```

```bash:macos
$ dd if=/dev/zero of=./kusatest count=1000 bs=1048576 
1000+0 records in
1000+0 records out
1048576000 bytes transferred in 7.803978 secs (134364295 bytes/sec)
```

```bash:Raspbian
pi@raspberrypi:~ $ dd if=/dev/zero of=./kusatest count=1000 bs=1048576 oflag=direct
1000+0 レコード入力
1000+0 レコード出力
1048576000 バイト (1.0 GB) コピーされました、 102.271 秒、 10.3 MB/秒
```

**参考)ラズパイのvmstatの推移**
boの数値が多少上下あるものの、ほぼ一定の数値となっています

```
pi@raspberrypi:~ $ vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0      0 680608  23656 143388    0    0     0     0  854  254  0  0 99  0  0
 0  1      0 679476  23656 143388    0    0     0  3072 1237  264  0  1 93  6  0
 0  1      0 679476  23656 143388    0    0     0 10240  764  306  0  0 75 25  0
```
Glideで1項目を「画面展開→画面展開」する方法（別シート・別項目を参照する）

# はじめに
[【2019年4月版】Google SpreadSheetから音速でPWAが吐きだせるってホントに？！](https://qiita.com/koinori/items/270b4cd63b74d91218da)
を拝見して面白そうだったので、自分が欲しいと思っていたアプリ（というよりデータ集）を作ってみました。
本当にあっという間に作れてしまって最高ですね！！！

作成時に疑問に思った点は [公式サンプルアプリ](https://www.glideapps.com/samples) を眺めて解決したのですが、それについて書いてみます。


# 作成アプリとソーススプレッドシート
まずは参考用に以下リンクです。以降の文章で言葉不足で不明点がありましたら参考にしてください。

- 【アプリ】[非公式 BLEACH キャラクターまとめ](https://unofficialbcl.glideapp.io/)
- 【ソース】[スプレッドシート](https://docs.google.com/spreadsheets/d/1VzZUEPSzROhjd7VHih0Cqyx-WbPxokdpZuXtHZhLIVg/edit?usp=sharing)


# 【疑問】メニューで項目をタップした後、更に別項目へ展開する機能の実装方法は？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293799/89c7a405-b987-6dcd-d206-745da28b0249.png)

単純にスプレッドシート作っただけだと、この「画面展開→画面展開……」と続ける方法がわからなかったんですよね。
別メニューの画面へリンクが飛ぶわけでもないし……。


# 【解】List Referenceコンポーネントを使用する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293799/77cf36b7-62e8-1d7a-b3dc-8782b7a98ad0.png)

List Referenceコンポーネント、もしくはInline listコンポーネント（後述します）を使用することで、画面展開機能が使えました。
一定の条件を満たさないとコンポーネントの候補にも挙がってこないようなので、以下に手順を記載します。


## Step1：展開したい先のデータを用意する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293799/0ba4d3d9-7eec-c9a5-2177-a329aad5edeb.png)

この例では所属組織の説明を表示したかったので、そんなシートを作りました。


## Step2：項目名を「項目名=参照先シート名:参照先項目名:Multiple」にする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293799/bc2d2942-2c51-fa9f-7fd3-20cc2264f133.png)

サンプルアプリのスプレッドシートを見ると `項目名=参照先シート名:参照先項目名:Multiple`としているようなので、それを真似しました。
（……仕様ドキュメントを見ましたという解決方法でなくて申し訳ない。。。
　これが何仕様に基づいての記法なのか、ご存知の方いらっしゃったらコメントください）

## Step3：参照元項目内容を、参照先項目内容と同一にする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293799/18e7cd47-6456-2ebb-696f-345426bf483a.png)

## Step4：List Referenceコンポーネントが表示されるようになるので、それを使う

List Referenceコンポーネントを追加してからは、他の項目と同様に編集します。
疑問だった機能を実装することができました！

![screen.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293799/01fdf9f5-3fd6-119d-367e-1e244ad5753e.gif)


# （余談）Inline listコンポーネントというのもある

「単行本」メニューには、次の動画のように「登場キャラクター」という項目があります。

![screen2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293799/aacba2ef-a1e6-3b8f-840f-e03abc98e003.gif)

この項目はInline listコンポーネントを使っています。
これも別シート・別項目を参照して拾ってきてくれる機能です。
項目名に`項目名=参照先シート名:参照先項目名:Multiple`を指定するのは同じです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293799/d8623e23-da97-6b16-bf26-e5a6f9443cb0.png)

「『出番』シートにあるn巻のキャラクターを拾ってきてね～」で勝手に参照してくれるの最高ですね……。
現時点のサンプルがキャラクター偏りすぎでその効果が全然現れていませんが！！


# おわりに

プログラミングよりデータ準備するほうが時間かかるぅ～～！！（アプリいじる時間が30分ならデータ作成で2時間かかってる）
こういう作品のファンアプリなら、Allow Editingをtrueにしたりスプレッドシート公開して、色んな人で協力してデータ入力するのが良いのでしょうね……。