OmniAICreator/Qiita-1.07M huggingface dataset:
【Google Chrome】拡張機能の作成方法を分かりやすく解説してみた Part. 3

#アクセスしたページのh1（見出し）の数と内容をアラートで表示する

前回は軽いスクリプトとポップアップを作成した所で終わっていましたね。今回は見出し通りアクセスしたページのh1要素の数と内容をアラート上に出力させてみます。

前の状態のままやってもいいのですが、ごちゃごちゃしちゃうので**example_extension**フォルダ上のファイルを全て消去しちゃいましょう。

では、もう一度**manifest.json**を一から作りましょう。

```json:manifest.json
{
    "manifest_version" : 2 ,
    "name" : "showh1" ,
    "version" : "1.0"
}
```

**manifest.json**を作成する上で、必ず書かないと行けないのが上記の三つです。


```json:manifest.json
{
    "manifest_version" : 2 ,
    "name" : "showh1" ,
    "version" : "1.0" ,

    "permissions" : ["activeTab"] ,

    "content_scripts" : [
        {
        "matches" : ["<all_urls>"] ,
        "js" : ["contentScript.js"]
        }
      ]
}
```

続けて記述してください。
(新) **"content_script"** // **"matches"** (パターンマッチ）で指定したURLにアクセスした場合の処理等
(新) **"matches"** // **"＜all_urls＞"** 全てのURLを指定する
(新) **"js"** // **"matches"**で指定したURLにアクセスした際に実行するJavaScriptスクリプトのファイルを指定したりする

**contentScript.js**を指定したので、フォルダ上に**contentScript.js**ファイルを作成しエディタで開いて下さい。

それから**"matches"**のパターンマッチングの例です。UNIXやUNIXライクなOSを使った事がある方は見なくても良いかもしれません。よく分からないという方は目を通して見てください(´・ω・`)
引用（Google Chrome 公式）：
https://developer.chrome.com/docs/extensions/mv2/match_patterns/

```
/*
httpプロトコル全般のサイトにアクセスした時
例：
http://www.google.com/
http://example.org/foo/bar.html
*/

http://*/* 

```

```
/*
httpプロトコル全般で/fooが必ず入っているサイトにアクセスした時
例：
http://example.com/foo/bar.html
http://www.google.com/foo
*/

http://*/foo*

```

```
/*
省略
例：
https://www.google.com/foo/baz/bar
https://docs.google.com/foobar
*/

https://*.google.com/foo*bar

```

```
/*
そのまんまで全てのサイト対象です
*/

<all_urls>

```



現在のファイル構成(**example_extensions**フォルダ)：
![16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/989394/c50331ae-f598-dfe1-351a-d329580d21a0.png)
**contentScript.js**に下記のコードを入力して下さい。

```javascript:contentScript.js
(function(){
    const h1 = document.querySelectorAll("h1");
    let h1Text = "";

    for ( let i of h1 ) {
        h1Text += `${i.innerText}\n`;
    }

    alert(`h1の数 : ${h1.length} \n${h1Text}`);
})();
```

バッククォーテーションの中に**${変数}**が入っていますがこれは**テンプレートリテラル**という簡単に変数を文字列中に埋め込める便利な機能です。皆さんも是非使ってみてください（知ってるわ！）
ここまでの仕組みとしては**"matches"**で指定したURLにアクセスすると、Google Chromeが**"js"**で指定したcontentScript.jsを実行してくれる感じです。**"matches"**に＜all_urls＞を指定して"js"にcontentScript.jsを指定したのでどのサイトでもcontentScript.jsが実行されます。

それでは実行してみましょう。
前々回と同じ様に**"chrome://extensions"**にアクセスして、**example_extensions**フォルダを指定してあげてください。

showh1拡張機能の導入が終わったら**google.com**にアクセスしてみましょう。

![17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/989394/d8b3b069-5dfa-a40d-1805-342adaef0bd2.png)

h1の数が記載されたアラートが出現しましたね...！
次は「あ」とでも検索してみましょう（）
![18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/989394/b0fcd3bc-f386-28dc-8bed-bfd32b6c944d.png)

おぉ～！
更に拡張機能らしくなってくれましたねぇ(´・ω・`)
今日はここで終わります。お疲れ様でした( ^^) _旦~~
Railsでフォロー機能を作る方法

#前提
☆必要なテーブル
・usersテーブル
・relationshipsテーブル(中間テーブルです)
☆ポイント
・アソシエーションが普通の「多対多」とは違う事


#流れ
1. relationshipモデルを作る
2. relationshipのマイグレーションファイルを編集＆実行
3. userモデルとrelationshipsモデルにアソシエーションを書く
4. userモデルにフォロー機能のメソッドを書く
5. seedsにfollow
6. relationshipsコントローラーを作成、編集する
7. フォロー・フォロワー数、フォローボタンをviewに設置
8. ルーティングを書く
9. usersコントローラーにフォロー機能を書く 




#1. relationshipモデルを作る
userテーブル同士で「多対多」の関係を作るために中間テーブルであるrelationshipsをアソシエーションを使って実行する。なぜなら、フォロワーもまたuserだからです。
まずは、relationshipsモデルを作っていきます。

```:ターミナル
$ rails g model Relationship follower_id:integer followed_id:integer
```
relationshipsテーブルのカラムは

|カラム|タイプ|
|---|---|
|follower_id|integer|
|followed_id|integer|
となる。


#2. relationshipのマイグレーションファイルを編集＆実行
下記のように編集してください

```ruby:db/migrate/_creation_relationships.rb
class CreateRelationships < ActiveRecord::Migration[5.2]
  def change
    create_table :relationships do |t|
      t.integer :follower_id
      t.integer :followed_id

      t.timestamps


    end
    add_index :relationships, :follower_id
    add_index :relationships, :followed_id
    add_index :relationships, [:follower_id, :followed_id], unique: true
　 #add_index :テーブル名,カラム名
  end
end
```
add_indexを使うことによりデータの読み込み・取得が早くなる。
これが終わったらマイグレーションファイルをリセットし、seedでデータベースに初期データを投入する

```:ターミナル
$ rails db:migrate:reset db:seed
```

#3. userモデルとrelationshipsモデルにアソシエーションを書く
まずは、
relationshipsモデルにアソシエーションを書いていく。

```ruby:models/user.rb
#自分がフォローした人を取り出す
has_many :active_relationships, foreign_key: "follower_id",
                                class_name: "Relationship",
                                dependent: :destroy
```
class_name: "Relationship"を使うことによりRelationshipクラスを直接指定することができる



```ruby:models/relationship.rb
class Relationship < ApplicationRecord

 belongs_to :follower, class_name: "User"
 belongs_to :followed, class_name: "User"

 validates :follower_id, presence: true
 validates :followed__id, presence: true
end
```
**class_name: 'User'**と補足設定することで、follower/followedクラスという存在しないクラスを参照することを防ぎ、Userクラスであることを明示している。
要するに「follower/followedモデルなんて存在しないので、userモデルにbelongs_toしてね！」ということを示している。

```ruby:models/user.rb
has_many :active_relationships, foreign_key: "follower_id",
                                class_name: "Relationship",
                                dependent: :destroy

#
has_many :followed_users, through: :active_relationships, source: :followed
```

#4. userモデルにフォロー機能のメソッドを書く
#5. seedsにfollow
#6. relationshipsコントローラーを作成、編集する
#7. フォロー・フォロワー数、フォローボタンをviewに設置
#8. ルーティングを書く
#9. usersコントローラーにフォロー機能を書く
manimの作法 その6

#概要

manimの作法、調べてみた。
ThreeDScene、使ってみた。

#サンプルコード


```
from manimlib.imports import *

class test(ThreeDScene):
	def construct(self):
		sphere = Sphere()
		cube = Cube()
		prism = Prism()
		cylinder = ParametricSurface(lambda u, v: np.array([np.cos(TAU * v), np.sin(TAU * v), 1.0 * (1 - u)]), resolution=(6, 32))
		axes = ThreeDAxes()
		self.set_camera_orientation(phi = 75 * DEGREES, theta = 30 * DEGREES)
		self.add(axes)
		self.play(ShowCreation(cube))
		self.wait()
		self.remove(cube)
		self.play(ShowCreation(sphere))
		self.wait()
		self.remove(sphere)
		self.play(ShowCreation(prism))
		self.wait()
		self.remove(prism)
		self.play(ShowCreation(cylinder))
		self.wait()
```

#生成した動画

https://www.youtube.com/watch?v=PRh6v5Uu9EQ

以上。
RxSwiftでUITextFieldの最大文字数を設定する

```swift:
        //TextFieldの最大文字数設定
        textField.rx.text
            .map { text in
                if let text = text, text.count > 4 {
                    return String(text.prefix(4))
                } else {
                    return text ?? ""
                }
            }
            .bind(to: textField.rx.text) // 既に入力されているのと同じ数字を入力した場合、nextイベントは流れないので無限ループする事はない
            .disposed(by: disposeBag)
```

### 補足

- 試していませんが、日本語入力の場合はこれだとうまくいかない可能性があるので別途考慮が必要になると思われます。
- `textField.rx.controlEvent(.editingChanged)`なども使えます。

### 参考

[RxSwift/RxCocoa: prevent UITextField from having more than … characters](https://stackoverflow.com/questions/48790405/rxswift-rxcocoa-prevent-uitextfield-from-having-more-than-characters)
[[iOS] UITextFieldの最大文字数を設定する](http://chicketen.blog.jp/archives/50002171.html)
[【Swift】 UITextFieldに文字数制限を設ける方法
](https://qiita.com/ydzum1123/items/3578a886c70dc23f121c)
pythonでラスタデータのバンドの情報をぶっこ抜く

## はじめに

GPV（ラスターデータ）をQGISで開いた時のプロパティで確認できる以下のバンド情報をpythonでぶっこ抜きたいと思ったので、その方法のメモ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61492/6b7eba08-10d2-a763-5958-9cb55cf07042.png)


## 方法

```
from osgeo import gdal
data = gdal.Open("パス")

band = バンド数
data.GetRasterBand(band).GetMetadata()

```


## 結果
結果は辞書形式で取得されます。
以下はバンド１の情報。



`{'GRIB_COMMENT': 'Geopotential height [gpm]', 'GRIB_DISCIPLINE': '0(Meteorological)', 'GRIB_ELEMENT': 'HGT', 'GRIB_FORECAST_SECONDS': '0 sec', 'GRIB_IDS': 'CENTER=34(Tokyo) SUBCENTER=0 MASTER_TABLE=2 LOCAL_TABLE=1 SIGNF_REF_TIME=1(Start_of_Forecast) REF_TIME=2017-12-05T00:00:00Z PROD_STATUS=0(Operational) TYPE=1(Forecast)', 'GRIB_PDS_PDTN': '0', 'GRIB_PDS_TEMPLATE_ASSEMBLED_VALUES': '3 5 1 31 255 0 50 1 0 100 -2 1000 255 -127 -2147483647', 'GRIB_PDS_TEMPLATE_NUMBERS': '3 5 1 31 255 0 0 50 1 0 0 0 0 100 130 0 0 3 232 255 255 255 255 255 255', 'GRIB_REF_TIME': '1512432000 sec UTC', 'GRIB_SHORT_NAME': '100000-ISBL', 'GRIB_UNIT': '[gpm]', 'GRIB_VALID_TIME': '1512432000 sec UTC', 'STATISTICS_MAXIMUM': '250.91836547852', 'STATISTICS_MEAN': '118.31441361789', 'STATISTICS_MINIMUM': '-55.081642150879', 'STATISTICS_STDDEV': '60.506839414168', 'STATISTICS_VALID_PERCENT': '100'}
`

見やすくするとこうですね
`GRIB_COMMENT : Geopotential height [gpm]
GRIB_DISCIPLINE : 0(Meteorological)
GRIB_ELEMENT : HGT
GRIB_FORECAST_SECONDS : 0 sec
GRIB_IDS : CENTER=34(Tokyo) SUBCENTER=0 MASTER_TABLE=2 LOCAL_TABLE=1 SIGNF_REF_TIME=1(Start_of_Forecast) REF_TIME=2017-12-05T00:00:00Z PROD_STATUS=0(Operational) TYPE=1(Forecast)
GRIB_PDS_PDTN : 0
GRIB_PDS_TEMPLATE_ASSEMBLED_VALUES : 3 5 1 31 255 0 50 1 0 100 -2 1000 255 -127 -2147483647
GRIB_PDS_TEMPLATE_NUMBERS : 3 5 1 31 255 0 0 50 1 0 0 0 0 100 130 0 0 3 232 255 255 255 255 255 255
GRIB_REF_TIME : 1512432000 sec UTC
GRIB_SHORT_NAME : 100000-ISBL
GRIB_UNIT : [gpm]
GRIB_VALID_TIME : 1512432000 sec UTC
STATISTICS_MAXIMUM : 250.91836547852
STATISTICS_MEAN : 118.31441361789
STATISTICS_MINIMUM : -55.081642150879
STATISTICS_STDDEV : 60.506839414168
STATISTICS_VALID_PERCENT : 100
`

無事ぶっこぬけました。


各情報の詳細は[こちら](https://gdal.org/drivers/raster/grib.html)をご覧ください
ESモジュールが読み込めないときに試してみたいApache 2.4の設定

当記事では、ESモジュール（JavaScript modules・ES6モジュール・ESMなどとも呼ばれる）を使ってみたところ、ブラウザのコンソールに以下のようなエラーが表示され、モジュールの読み込みに失敗したときの対処方法を紹介します。

```
Failed to load module script: The server responded with a non-JavaScript MIME type of "".
Strict MIME type checking is enforced for module scripts per HTML spec.
```





## 1. 注意事項

これから紹介する対処方法を試してみるときは以下の2点に注意してください。





### 1-1. 動作確認済み環境

直ることを確認した環境は以下の通りです。

- OS: Windows 10 Home 64bit版
- Webサーバー: Apache HTTP Server v2.4.46（インストーラー不使用。バイナリを直接ダウンロード・配置して構築）
- ブラウザ: Google Chrome v87.0.4280.88 64bit版





### 1-2. 原理不明

私自身、何故この設定で動くのかよく分かっていません。





## 2. 対処方法

Apache HTTP Serverの設定ファイルであるhttpd.confに以下のようなディレクティブを追加してください。

```conf:httpd.conf
LoadModule mime_module "./modules/mod_mime.so"

<FilesMatch "\.mjs$">
    AddType text/javascript .mjs
</FilesMatch>
```

エラーが出ている原因はJavaScriptをモジュールとして読み込むときにMIMEタイプが設定されていないのが原因っぽい（確証はありません）ので、AddTypeディレクティブで`text/javascript`というMIMEタイプを設定することでエラーを回避しています。

なお、既にmod_mimeモジュール（mime_module）を読み込んでいるときは重複して読み込ませる必要はありません。重複したLoadModuleディレクティブは無視されます。





### 2-1. FileMatchセクションの必要性

AddTypeディレクティブをFileMatchセクションで囲んでいるのは、AddTypeディレクティブの脆弱性回避のためです。FileMatchセクションで囲んでいないと、例えばtest.mjs.phなどという意味不明な拡張子を持つファイルもESモジュールとして読み込んでしまいます。詳しくは以下記事を参照してください。

[AddType, AddHandler, SetHandlerの違い – senooken.jp](https://senooken.jp/post/2019/06/01/)





### 2-2. AddTypeディレクティブの第2引数は`.mjs`じゃないと駄目

ESモジュールの拡張子は.js、あるいは.mjsを使うことになっているようです。

[JavaScript モジュール - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Modules#%E4%BD%99%E8%AB%87_%E2%80%94_.mjs_%E5%AF%BE_.js)

上記ディレクティブを見た感じだと、拡張子が.mjsでないとESモジュールとして読み込まれないように思われますが、実際は.js・.mjsの両方に対応できています。理由は謎です（ESモジュールとして読み込むときは内部的に.mjsとして解釈しているのかも？）。

また、AddTypeディレクティブの第2引数を`.js`に直した場合は.jsも.mjsもESモジュールとして読み込めなくなります。理由は謎です（.jsは既定されているからかも？）。





### 2-3. AddHandlerディレクティブ・SetHandlerディレクティブは駄目

AddTypeディレクティブと似ているAddHandlerディレクティブ・SetHandlerディレクティブは、任意の拡張子を任意のハンドラに割り当てるディレクティブなので、当問題の解決には使えません。





### 2-4. TypeConfigディレクティブとmime.typesで代替できるかも

当記事で書かれている方法はTypeConfigディレクティブとmime.typesで代替できるかもしれません。ただ、MIMEタイプを追加するときはmime.typesを弄るのではなく、AddTypeディレクティブで追加したほうが良いみたいです。

[mod_mime - Apache HTTP サーバ バージョン 2.4](https://httpd.apache.org/docs/2.4/ja/mod/mod_mime.html#typesconfig)
地方と都市部を経験してみた独断と偏見の話


こんにちは。
やってみたかったんだよね、身の上話。
誰かに届け、ということでつらつら書きます。

技術的な話は一切出てきませんので悪しからず。

#はじめに
外国語学部という生粋の文系大学を卒業後、なんだかんだエンジニア歴も５年目です。
現在は神奈川在住で、メインreact、サブjavaで割と大きめなサービスの開発・運用をやっています。
私自身、めちゃくちゃコードが書けるとか、インフラの知識がちょーあるとかそういうのではありません。
５年目ならこれぐらいだろう、と想像していただければ、その通り。
まあまあこなせる、たまにやらかす、平々凡々エンジニアです。

#地方SIerに就職しました
そもそもなんでエンジニアに？という話はさておき、
新卒で３年間、海が近い地方都市で受託開発をしていました。従業員数は５０名程。
WEBシステムを扱う部署に配属されて、
PHP、mysql、jQuery、、、フレームワークとライブラリに頼りきった、初心者にはうってつけの開発環境でした。

継続的に案件もあり、日々成長を実感でき、
辞めなくてもそれなりに暮らしていけました。

ただし、辞めるという選択をしたんです。

結論から言います。

<b><font color="Red">給料がしんどい。それ以外は最高。</font></b>

以下、独断と偏見を個人の経験だけで記載します。
「地方」という雑なくくりですみません。

##地方デメリット

まずは手始めにして最大の問題です。

- 給料がしんどい

ある程度、仕方がないことではあると思うんです。
未経験で拾ってもらった身であるにも関わらず生意気言ってやがりますが、
給与明細と寸志でモチベーションが上がった記憶がありません。

社員が豊かに暮らすための還元をしていないので優秀な人ほど消えていきました。
無駄使いするから悪い、というこちら側への批判は受け付けません。
娯楽への消費がままならない生活など豊かではないのです。

##地方メリット

ただ、いいところはたくさんあります。

- 人間関係良好

上司・同僚・先輩・後輩、たまに変な人もいるけど、基本みんな穏やかです。
人間関係で悩むことが皆無でした。自然がそうさせている、と行っても過言ではありません。

- コミュニケーションが取りやすい

社内、顧客どちらとも物理的・心理的距離が近い。話やすい。
近いが故に無理難題言われることもあるけれどそれはご愛嬌。死ぬレベルじゃありません。
前職は一次二次受けが基本だったので、お客さんとやりとりが直でできるのでやりやすかったです。

- 上流工程（というか全て）担当できちゃう

アイデア段階からローンチまで担当できちゃう。これがかなり楽しい。
人が作ったものなんて触りたくないので小規模・中規模案件を舵取りして初めっから作るのは
とても気持ちがいいものです。
これは人が足らないということでもありますが、大丈夫です。死ぬレベルじゃありません。
営業に同行して出張も何回かありました。

- 意見が通りやすい

これを使いたい！これを買いたい！という意見は通りやすかったように思います。
おそらく当時３年目の新米エンジニアが装備するには恐れ多い最新スペックPCに囲まれて仕事をしていました。
家電量販店のポイントを全部もらえたりもしました。(速攻使いました）
また、扱う技術選定なんかもやりやすかったです。

- 車通勤

ドアドア４５分ぐらいの通勤時間でしたが、車で通勤できるのは結構楽。
まあ、車社会なので、当たり前といえば当たり前ですが、
満員電車ではないので、ストレスフリーです。帰りは海沿いを走って帰ります。

#都市部大企業に転職しました

結局、自由に扱えるお金の量を増やしたかったんだと思います。
引っ越しして転職しました。
前職で鍛えられたおかげか、エンジニア不足の世の中のおかげか、
職を得ることができました。

得たものもあれば、失ったものもある。世の中上手く生きられないものでしょうか。
これも会社によると思いますが、あえて都市部でくくります。

##都市部デメリット

ここでいう都市部とは、県庁所在地とかそういういう意味ではありません。
いわゆるトーキョーのことです。

- 人間関係不調

嫌いな人が増えました。

- コミュニケーション能力の乖離

コミュニケーション力のある未経験者、
コミュニケーション力のない玄人、
がたくさんいて気疲れします。
従業員がたくさんいたらそりゃそうだよね。

- 上流工程（？）

上流工程ってなんだっけ？となるぐらい、
まだまだ舵取りのポジションが遠いです。
確かに設計書を起こすこともありますがそれもごく稀な案件のみ。
サービスへの愛着は少しはあるものの、すごい楽しい！！！となってません。
ひたすら実装とテスト。
（だって優秀な人がたくさん上にいるからね）

- 意見が通りにくい

大きい会社になればなるほど、すでに培った素晴らしい経験が物語ってしまいます。
会社の方針をなかなかエンジニアが決められません。
提案に漕ぎ着けても優先順位と工数によって切り捨てられてしまいます。
僕たちはこれがやりたいのにいいいいいと歯軋りをする毎日です。

- 電車通勤

１０時出社にも関わらず、満員電車です。死罪。

##都市部メリット

もう、これにつきます。

- 給料が高い

嘘でしょ！？と思いました。
あくまで地方と比べた場合、ですが、そもそものベースが高い。
扱うサービスにもよりけりなのかもしれません。
単純に転職前とは比べ物にならない額だったので驚きです。

そして評価制度がしっかりしていました。
ここまでやればこのぐらいもらえる、と透明性を持って提示されているため、
モチベーションは保ちやすいと思います。

確かに責任の度合いは現在の方が高いと思いますし、
担当フェーズが多少違うとはいえ、
エンジニアとしてやっていることはあまり変わらないと思います。
となると、この還元率の差はなんなのでしょうか。
時空が歪んでいるんでしょうか。

#終わりに

さて、

給料がしんどくて都市部に来てみましたが、
今は、なるべく都市部で働きたくはないと思ってます。

地方が性に合っていた、といえばそれまでですが、
都市部とは違った「やりがい」が必ずありますし、給料以外のストレスは少なかったからです。

これで給料がついてくるのであれば諸手を挙げて再び移住します。

ただ、どちらがいいとか、どちらの方が正解とか、そういうものでもないと思います。
何が重要でどこに重きを置いていくかは、
人それぞれだったりタイミングの問題だったりするはずです。

ということで、今現在の自身の最適解に至った気がするのです。

<b><font color="Red">フリーランスの流れに乗る時は、今。</font></b>

地方に住み、都市部の案件を受注し、
心穏やかに豊かに暮らす、多分これがやりたいこと・・・なんだよね・・・？

以上、地方に就職し、都市部に転職し、何が豊かかわからなくなったエンジニアの日記でした。

模索は続く・・・
GASを使ってHerokuにデプロイしたアプリケーションを定期的に実行する 

本稿では、GAS（Google Apps Script）を使ってHerokuにデプロイしたアプリケーションを定期的に実行するスクリプトを作成した際の備忘録的な内容となっています。
あくまでGASの内容なので、Herokuアプリケーションの作成・デプロイといった内容には触れません。

※Herokuアプリケーションの作成・デプロイ方法については過去記事がありますので、ご参考までに。。。
[Flask+gunicornを使って作成したTwitter連携アプリをHerokuにデプロイした話](https://qiita.com/Rinkey3/items/ba4611234056b1abe8a0)


#前提条件

+ 定期的に実行したいHerokuアプリケーションがデプロイ済みであること
+ Googleアカウントを作成済みであること

#GASプロジェクトの作成
GASプロジェクトを作成します。
<ol><li>`Google アプリ`から`ドライブ`を選択する。</li>
<li>`新規`をクリックし、コンテキストメニューを`その他` → `Google Apps Script`の順に選択する。
<img width="400" alt="drive_select.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/765001/89e41fa8-499c-4683-5e56-207ec00548f7.jpeg">
</li>
<li>画像のように無題のプロジェクトが作成され、スクリプトエディタが起動する。
<img width="400" alt="script_editor.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/765001/92c6532a-a0ae-bdeb-4e8e-65c7851aeb6d.jpeg">
</li>
<li>`保存`をクリックするとプロジェクト名の設定ダイアログが表示されるので、プロジェクト名を`test_script`に設定し`OK`をクリックする。
<img width="400" alt="edit_project_name.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/765001/3435f3ce-355b-74ea-c8d7-c08021f3b1d7.jpeg">
</li></ol>

#GASスクリプトの作成
GASスクリプトを作成します。
<ol><li>スクリプトエディタに以下のコードを記述する。

```javascript:コード.gs
function setTrigger() {
  var setTime = new Date();
  setTime.setHours(setTime.getHours() + 1);
  setTime.setMinutes(00);
  setTime.setSeconds(00);
  ScriptApp.newTrigger('sendMessage').timeBased().at(setTime).create();
}

function delTrigger() {
  const triggers = ScriptApp.getProjectTriggers();
  for(const trigger of triggers) {
    if(trigger.getHandlerFunction() == 'sendMessage') {
      ScriptApp.deleteTrigger(trigger);
    }
  }
}

function sendMessage() {
  delTrigger();
  setTrigger();
  var options = {
    muteHttpExceptions:true
  };
  var url = 'https://AppName.herokuapp.com/';
  var data = UrlFetchApp.fetch(url, options).getContentText();
}
```

`sendMessage()`のURL文字列に含まれている`AppName`はご自身のHerokuアプリケーションのアプリ名に置き換えてください。
</li>

<li>`保存`をクリックしてスクリプトを保存する。
</li></ol>

#GASスクリプトの実行
作成したスクリプトを実行します。
<ol><li>`関数を選択`コンボボックスから`SendMessage`を選択し、`実行`をクリックする。
</li></ol>

#実行結果の確認
スクリプトの実行結果を確認します。
<ol><li>`現在のプロジェクトのトリガー`をクリックする。</li>
<li>遷移先のページにトリガーが追加されていればOK。
<img width="400" alt="trigger.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/765001/3e4db20a-1dda-7a52-5982-cadd297248b5.jpeg">
</li></ol>

#解説
+ sendMessage()<br>
このスクリプトのメイン関数です。以下の3つの機能を実行します。<br>
    + delTrigger()で実行済みのトリガーをすべて削除します。
    + setTrigger()で次回実行時のトリガーを作成します。
    + 指定したURLへwebhookを飛ばします。<br>
+ setTrigger()<br>
sendMessage()実行時に呼び出され、変数`setTime`で設定した時間にトリガーを作成します。<br>
Date型の`setXxxs()`関数によって年月日時分秒を設定可能です。<br>
サンプルコードでは、`現在時刻+1時0分0秒`にトリガーが設定されるようになっています。<br>
トリガーは定期的に作成されるため、上記を言い換えると`毎時0分`にトリガーが設定されます。<br>
+ delTrigger()<br>
sendMessage()実行時に呼び出され、このスクリプトによって作成されたトリガーをすべて削除します。<br>
本関数実行後に新しいトリガーが作成されるため、トリガー一覧には常に実行予定のトリガーしか存在しません。

#参考
+ [クレジットカードを使わないでlinebotを作ったときの話](https://qiita.com/esu_eichi/items/3077a6b809015c1b3d30)
+ [【GAS】毎日12:00ちょうどに定期実行したい！分単位で時間指定して定期実行を実現する方法。](https://www.pnkts.net/2019/09/23/gas-set-trigger)
+ [Google Apps Scriptで使用済みのトリガーを削除する方法](https://tonari-it.com/gas-trigger-delete/)
Pythonでリスト内の辞書型から特定キーのバリューをリストで取得

Pythonの**基礎的**な所のメモです :memo:
Python素人なので間違っている所あれば優し目で教えて下さい。:penguin:

```python

hashira = [{'Name': '富岡義勇', 'Kokyuu': '水' }, 
           {'Name': '胡蝶しのぶ', 'Kokyuu': '蟲' },
           {'Name': '煉獄杏寿郎', 'Kokyuu': '炎' },
           {'Name': '宇髄天元', 'Kokyuu': '音' },
           {'Name': '時透無一郎', 'Kokyuu': '霞' },
           {'Name': '甘露寺蜜璃', 'Kokyuu': '恋' },
           {'Name': '悲鳴嶼行冥', 'Kokyuu': '岩' },
           {'Name': '伊黒小芭内', 'Kokyuu': '蛇' },
           {'Name': '不死川実', 'Kokyuu': '風' }]
```

柱の名前を取得！

```python
name = [d.get('Name') for d in hashira]
print(name)
# => ['富岡義勇', '胡蝶しのぶ', '煉獄杏寿郎', '宇髄天元', '時透無一郎', '甘露寺蜜璃', '悲鳴嶼行冥', '伊黒小芭内', '不死川実']
```
共通キーがある場合は`get(キー名)`ではなく`[キー名]`で値で取得も出来る！

```python
kokyuu = [d['Kokyuu'] for d in hashira]
print(kokyuu)
# => ['水', '蟲', '炎', '音', '霞', '恋', '岩', '蛇', '風']
```

次は主要キャラ達

```python

kisatsutai = [{'Name': '竈門炭治郎', 'Kokyuu': '水' },
              {'Name': '竈門禰豆子' }, 
              {'Name': '嘴平伊之助', 'Kokyuu': '獣' },
              {'Name': '我妻善逸', 'Kokyuu': '雷' }]

# 禰豆子は呼吸が使えない。
```

柱と同じようにKokyuuを取得してみます。

```python
name = [d.get('Name') for d in kisatsutai]
print(name)
# ['水', None, '獣', '雷']
```
見ての通り、`get()`メソッドはデフォルトではキーが存在しないときは`None`を返します。

`get()`の第二引数でデフォルト値を渡す事も可能

```python
name = [d.get('Name', 'ムーー') for d in hashira]
print(name)
# => ['水', 'ムーー', '獣', '雷']
```

では、`get(キー名)`ではなく`[キー名]`なら？
指定したキーを持たない要素が存在する場合はエラーになります。

```python
kokyuu = [d['Kokyuu'] for d in kisatsutai]
print(kokyuu)
# => KeyError: 'Kokyuu'
```

if文を使って指定したキーを持たない要素を除外することも可能！

```python
name = [d['Kokyuu'] for d in kisatsutai if 'Kokyuu' in d]

print(name)
# => ['水', '獣', '雷']
```

以上、[劇場版鬼滅の刃](https://kimetsu.com/anime/)を２回見たPython素人がお送りいたしました。
=> MX/4D面白かったです。

<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550573/bc3ffa66-816b-ee70-cbfd-283debf90a96.jpeg">

【参考】
・[Pythonで辞書のリストから特定のキーの値のリストを取得](https://note.nkmk.me/python-dict-list-values/)
暗号アルゴリズムの分類を図解する

仕事でとある暗号アルゴリズムを使うことになったのですが、私はそもそも暗号技術について詳しくない事に気づきました。そこで、代表的な暗号アルゴリズムについて、それぞれの関連性や歴史をざっと調べ、個人的なまとめとして図解してみました。

この記事ではその作成した図を載せます。
それだけです。入門向けな内容なのに、記事が入門向けでなく、すみません。

それぞれの暗号アルゴリズムの詳細について知りたい方は、この図をもとにWikipediaなどを参照ください。
（ほとんどWikipediaからこの図を作ったので）

図の制作ツールは、[PlantUML](https://plantuml.com/)です。


### 暗号アルゴリズムの分類

|大分類 | 解説|
|---|---|
| ブロック暗号/Block cipher |固定長のデータ（ブロックと呼ぶ）を単位として処理する暗号の総称
| ストリーム暗号/stream cipher | ビット単位やバイト単位で処理を行う暗号



### 暗号アルゴリズムの分類の図解
画像クリックしてから、拡大して頂くほうが見やすいです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91988/17c17362-1e2e-78b1-aee5-98fc9663525d.png)



### 参考
- [暗号学的ハッシュ関数 - Wikipedia](https://ja.wikipedia.org/wiki/%E6%9A%97%E5%8F%B7%E5%AD%A6%E7%9A%84%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E9%96%A2%E6%95%B0)
- [ブロック暗号 - Wikipedia](https://ja.wikipedia.org/wiki/%E3%83%96%E3%83%AD%E3%83%83%E3%82%AF%E6%9A%97%E5%8F%B7)
人を育てて、成果を最大にするマネジメント　～HIGH OUTPUT MANAGEMENT～

#HIGH OUTPUT MANAGEMENTとは
元インテルCEOのアンドリューグローブによってまとめられた経営書であり、マネージャーの仕事は何かが著者の体験をもとに書かれている。約40年前に書かれたものだが、「マネージメント」や「組織論」を学びたい中間管理職（ミドルマネージャー）が読むべき一冊。ただし、具体的な手法が書かれているわけではなく、マネージメントは状況によって変わってくることは知っておいて欲しい。

#マネージャーのアウトプット
HIGH OUTPUT MANAGEMENTではマネージャーのアウトプットを以下のように定義している。
>**マネージャーのアウトプット＝
自分の組織のアウトプット＋自分の影響力が及ぶ隣接組織のアウトプット**

そしてマネージャーとしてやるべきことは部下の「教育」と「モチベーションの向上」であると述べており、そのための手段としてはミーティングを通じてのみ遂行できるとしている。

#ポイント１：インジケーター（指標）で状況を把握しろ
マネージャーが業務をうまく運営する（問題を早く対処する）ためには良いインジケーター、つまりは状況を測定するものが必要である。良いインジケーターは作業単位のアウトプットを測定するものであって、それに含まれる活動だけをみるのではない。そして、マネージャーの仕事とは、これを管理し、問題が発生する前に対策を打つことである。

そこで重要になってくるのは情報収集であり、ミーティングこそマネージャーが仕事を遂行する手段である。ただし、最も役立つ情報はたまたま交わすちょっとした会話にあるという。レポート形式の情報は過去の情報をまとめたものであり、情報はタイムリーであるほうが価値が高いのである。


#ポイント２：マネージャーはテコ作用を高めろ

>**マネージャーアウトプット ＝ 
（マネージャーの活動1 ✖ 活動のテコ作用）＋ (マネージャーの活動2 ✖ 活動のテコ作用)・・・**

アウトプットを高めるには

 - 仕事を遂行する速度を上げる。
 - テコ作用を増加させる。(ex.権限、影響力、行動のタイミングなど)
 - テコ作用の高い活動をする。（ex.教育、適切な評価など）

高いアウトプットを上げるためには、マネージャーが行う活動にどういうテコ作用が働いているのかを敏感に知ることが重要である。

#ポイント３：最も重要な仕事は部下から最大の業績を引き出すことだ

経営管理とはチーム活動であり、チームの構成員たちが耐えず最善を尽くそうと努力しないかぎり、すべて無益になる。**人が仕事をしないときの理由は２つしかない。能力がないか、意欲がないかのいずれかである。**ここでマネージャーとしての取り組み方は２つある。それは「教育」と「モチベーション」である。

■タスク習熟度にあったマネージメント
効果的なマネジメントスタイルを決定する基本的な変動要因は部下のタスク習熟度で決める。タスク習熟度が低い部下には「"何を" "いつ" "どうして"を示す」。タスク習熟度が中の部下には「双方のコミュニケーションによって活動を支援し、お互いの判断を重視する」。タスク習熟度が高い部下は「目標を設定してモニタリングする。（関与を最小限に）」

■ワン・オン・ワンは大きなテコ作用
定期的な上司と部下のミーティングをタスク習熟度にあわせ週１~3週に1回程度で行う。目的は相互の情報交換であり、特定の問題や状況について話すことによってマネージャーはスキルやノウハウを部下に教え、物事のアプローチ方法を伝えることができる。
その際の重点はトラブルの存在を知らせてくれるインジケータに置くべきだとしている。上司と部下の間に共通の情報ができ、類似した物事の取扱処理方法が確立されるため、テコ作用は大きいものになる。
プロパティの中身を特定の型へ変換可能かどうか調べたいとき

#コード
Swift 


```
let string = "あいうえお"
let int = 10

//stringか調べたいとき
if String(string) != nil{
    print("String型です")
} else{
    print("String型ではありません")
}
//String型です

//Int型か調べたいとき
if Int(string) != nil{
    print("String型です")
} else{
    print("String型ではありません")
}
//String型ではありません
```

##型の確認方法
```
//String型か調べたいとき
if int is String{
    print("String型です")
} else{
    print("String型ではありません")  //こちらが呼ばれる
}

//Int型か調べたいとき
if string is Int{
    print("Int型です")   
} else{
    print("Int型ではありません")     //こちらが呼ばれる
}
```
laravel (A) and (B or C)

Laravel5のQueryBuilderは非常に便利ですが、複雑なwhere条件を書こうとするとwhereRawに頼ってしまいがちです。

しかし可読性を保つためなるべくwhereやorWhereで書いた方が良いと思います。

単純なAnd検索であれば、

$query->where('column1', '=', $value1)
->where('column2', '=', $value2)
単純なOr検索であれば、

$query->where('column1', '=', $value1)
->orWhere('column2', '=', $value2)
 

しかし、Laravel5を始めたばかりの人が必ず悩むのが(A or B) and (C or D)の条件です。

こういった複合系は次のようにクロージャで書けます。

$query->where(function($query) use($value1, $value2){
    $query->where('column1', '=', $value1)
          ->orWhere('column2', '=', $value2)
});

$query->where(function($query) use($value3, $value4){
    $query->where('column1', '=', $value3)
          ->orWhere('column2', '=', $value4)
});
useを使ってクロージャへ変数を渡してやるのがポイントです。
railsコンソールでカラムに情報を上書き出来ない、、、



目的：user_idカラムがnilのため、1を入れたい

■操作したいデータ

Notification id: 2, shown_from_at: "2021-01-04 02:32:00", shown_to_at: "2021-01-05 02:32:00", subject: "テストだよ", body: "テストテスト", created_at: "2021-01-04 02:32:55", updated_at: "2021-01-04 07:23:28", important_notification: true, user_id: nil


```:railsコンソール
Notification.find(2).update(user_id: 1)
user_idに1を上書き

  Notification Load (1.4ms)  SELECT "notifications".* FROM "notifications" WHERE "notifications"."id" = $1 LIMIT $2  [["id", 2], ["LIMIT", 1]]
=> false

```

何が起きているのかを確認

```:railsコンソール
notification = Notification.find(2)
notification.user_id = 1
notification.valid?
notification.errors.full_messages
```

```:railsコンソール
結果は下記になります。
irb(main):017:0> notification = Notification.find(2)
 Notification Load (0.5ms) SELECT "notifications".* FROM "notifications" WHERE "notifications"."id" = $1 LIMIT $2 [["id", 2], ["LIMIT", 1]]
irb(main):018:0> notification.user_id = 1
irb(main):019:0> notification.valid?
=> false
irb(main):020:0> notification.errors.full_messages
=> ["表示期間(from)は不正な値です", "表示期間(to)は不正な値です"]

```

上記の内容から、「shown_from_at: "2021-01-04 02:32:00", shown_to_at: "2021-01-05」が定義しているフォーマットと違うため、エラーが起きているのではないか？と発覚

指定しているのは「yyyy/mm/dd HH:MM」フォーマットのため、値を入れる際は正しいフォーマットで指定することでエラーを回避できた。

```:railsコンソール
Notification.find(2).update( shown_from_at: "2021/01/04 02:32",shown_to_at: "2021/01/05 02:32", user_id: 1)
# user_idに1を上書き

  Notification Load (0.3ms)  SELECT "notifications".* FROM "notifications" WHERE "notifications"."id" = $1 LIMIT $2  [["id", 2], ["LIMIT", 1]]
   (0.1ms)  BEGIN

  Notification Update (0.3ms)  UPDATE "notifications" SET "shown_from_at" = $1, "shown_to_at" = $2, "user_id" = $3, "updated_at" = $4 WHERE "notifications"."id" = $5  [["shown_from_at", "2021-01-03 17:32:00"], ["shown_to_at", "2021-01-04 17:32:00"], ["user_id", 1], ["updated_at", "2021-01-04 08:24:25.802888"], ["id", 2]]
   (0.3ms)  COMMIT
=> true
```
vim

# 勉強の記録
vimの操作　2021/1/4
## 勉強した内容
- vimをコマンドで操作しよう

## 何をベースに勉強してるか
- [N予備校 プログラミング入門](https://www.nnn.ed.nico/courses/668/chapters/9515)

## 内容の詳細
vimを操作して文字を消したり貼り付けたり。

### わかったことについて
- ワンキーや組み合わせで、文字を消したり貼り付けたり
行そのものを消したりは面白いと思った。


### むずかしかったよ
- チュートリアルを授業に沿ってやってみたけど、難しいって思える場所はなかった。
- 想像以上のコマンド数で驚いた、全部覚えられる気はしない笑

## 次回やる予定のこと
- シェルプログラミングとやらをやるみたい！
Slackで通知用のcurl取得まで（備忘録）

良く忘れるやつ

## 1. Create App

![slack-app-01.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587858/fb59f57b-3044-37a4-499e-dda104377d20.png)

## 2. アプリ名とワークスペースの決定

![slack-app-02.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587858/be052e8f-ba9a-eea2-ff07-21aa124d444f.png)

## 3. ActivateしてAdd New Webhook to Workspace

![slack-app-03.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587858/2f8dd47e-f142-dba7-1cde-cfac60c6c878.png)

## 4. チャンネルを指定して、Webhook作成

![slack-app-04.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587858/3b210b1a-a735-5185-9f2c-1f8b21d8bcb4.png)

## 5. curlコマンド取得

![slack-app-05.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587858/15d2d78a-2449-2aee-b923-344d212930b8.png)
FIT SDKのC++の静的ライブラリをビルドする

# 概要

Fit SDK 21.40(c++)には、DeveloperField使用時にクラッシュするバグがある。
→ **[Fit SDK 21.47](https://forums.garmin.com/developer/fit-sdk/b/news-announcements/posts/fit-sdk-21-47-00-release)で修正されました。**

- [Crash on encode when adding DeveloperField to LapMesg or SessionMesg [Fit SDK c++ iOS]](https://forums.garmin.com/developer/fit-sdk/f/discussion/249212/crash-on-encode-when-adding-developerfield-to-lapmesg-or-sessionmesg-fit-sdk-c-ios/)

これを回避するために、c++のソースコードを修正して静的ライブラリをビルドする。

# 環境
- OS: macOS Catalina
- Xcode: 12.2
- [FitSDK: 21.40](https://developer.garmin.com/fit/download/)

# FitSDKのソースコード修正

i386アーキテクチャを削除(Xcode12でビルドエラーになるため)

```
$ cd cpp/MacStaticLib/
$ find . \( -name "*.xcconfig" -o -name "*.pbxproj" \) | xargs sed -i '' -e 's/-arch i386//g' -e 's/i386//g'
```

```cpp/MacStaticLib/build.py
    # Compile the project
    # subprocess.call([XCODEBUILDER, XCODEPROJECT, project, XCODETARGET, p[TARGET]])
    subprocess.call([XCODEBUILDER, "-UseModernBuildSystem=NO", XCODEPROJECT, project, XCODETARGET, p[TARGET]])
```

```cpp/fit_developer_field_definition.hpp
    FIT_BOOL operator!=(const DeveloperFieldDefinition& field) const;
    // ↓ Added
    DeveloperFieldDefinition& operator=(const DeveloperFieldDefinition& other);
```

```cpp/fit_developer_field_definition.cpp
FIT_BOOL DeveloperFieldDefinition::operator!=(const DeveloperFieldDefinition& field) const
{
    return !(*this == field);
}

// ↓ Added
DeveloperFieldDefinition& DeveloperFieldDefinition::operator=(const DeveloperFieldDefinition& other) 
{
    if (this != &other){
        num = other.num;
        size = other.size;
        developerDataIndex = other.developerDataIndex;
        if (mesg != nullptr){
            delete mesg;
            mesg = nullptr;
        }

        if (other.mesg != nullptr) {
            mesg = new FieldDescriptionMesg(*other.mesg);
        }
        
        if (developer != nullptr){
            delete developer;
            developer = nullptr;
        }

        if (other.developer != nullptr){
            developer = new DeveloperDataIdMesg( *other.developer );
        }
    }
    return *this;
}
```

# Build static lib

```
$ cd cpp/MacStaticLib
$ python build.py
```
push前にrubocopを実行するときのコマンド

この記事はメモ記事です。 _φ(･ _ ･

# push前にrubocopを実行するときのコマンド
`bundle exec rubocop -a path_to_a_target_file`
オプションの`-a`は、インデントとか軽いミスを自動で直して欲しい時につけると便利。

こんな感じで結果が返ってきます↓ 自動で修正してくれました＾＾
`1 file inspected, 1 offense detected, 1 offense corrected`
Elasticsearch > ReindexとUpdate_by_query



_reindexと_update_by_query

このキーワードは時々出てくるが混乱するのでメモ
ほぼ[参考先](https://www.elastic.co/jp/blog/reindex-is-coming)のページの情報ですが、忘れないために。


## _reindex はドキュメントをコピー

_reindex APIは、ドキュメントをあるindexから他にコピーするだけの便利な機能です。

ドキュメントをあるindexから他のindexにコピーしたり、あらたな情報をfieldとして加えたり、index作成時に決められた設定を、indexの再作成により変更できます。


## _update_by_queryはドキュメントを変更

_update_by_queryは、ドキュメントをひとつのindexから読み取り、同じindexに書き戻します。
多くのドキュメントに含まれるfieldの更新や、mappingの変更をオンラインで行えます。

また、Enrichなどの情報を元に更新することもできます。



# 参考
[Reindexが登場\! \| Elastic Blog](https://www.elastic.co/jp/blog/reindex-is-coming)
Python標準入力

競プロやコーディングテストで使用していた自分用のメモになります。
よくあるパターンを３つ簡素にまとめています。

# パターン１

```python
(入力例)
123 789
------------------------------------------
#解法１
nums = list(map(int, input().split())) 
print(nums[0]) # Int:123
print(nums[1]) # Int:738

#解法２(個数が既知のとき)
x,y = list(map(int, input().split()))
print(x) # Int:123
print(y) # Int:738
``` 

#パターン２

```python
(入力例)
1
2
3
4
------------------------
import sys
nums = []
for l in sys.stdin:
    nums.append(int(l))
print(nums) # Int:[1,2,3,4]
````

#パターン３
```python
(入力例)
1 2
3 4
5 6
7 8
9 0
--------------------------------------
#解法１(行数が未知)
import sys
nums = []
for l in sys.stdin:
  l_tmp = l.replace("\n","").split()
  l_tmp = list(map(int,l_tmp))
  nums.append(l_tmp)
print(nums) # Int:[[1, 2], [3, 4], [5, 6], [7, 8], [9, 0]]

#解法２(行数が既知)
xy = [map(int, input().split()) for _ in range(5)]
x, y = [list(i) for i in zip(*xy)]
print(x) # Int:[1, 3, 5, 7, 9]
print(y) # Int:[2, 4, 6, 8, 0]
```

```python
(入力例)
a
!a
b
!c
d
!d
--------------------------------------
#解法１(行数が未知)
import sys
nums = []
for l in sys.stdin:
  l_tmp = l.replace("\n","").split()
  nums.append(l_tmp)
print(nums) # str:[['a'], ['!a'], ['b'], ['!c'], ['d'], ['!d']]
```

#よく使う実装のメモ

####★各桁の値の取得
```python
num = 242092
num_s = str(num)
for i in range(len(num_s)):
  print(num_s[i]) # str:2,4,2,0,9,2
```

####★ソート系
```python
list = [1,9,4,2,3,7]
list_upper = sorted(list) #[1, 2, 3, 4, 7, 9]
list_down = sorted(list,reverse=True) #[9, 7, 4, 3, 2, 1]
```

####★Dequeで高速化を図る.
https://note.nkmk.me/python-collections-deque/
要素の追加・取り出し（削除）・アクセス（取得）が両端のみ → deque
両端以外の要素に頻繁にアクセス → リスト

```python
from collections import deque
myList = [1,2,3]
myDeque = deque(myList)
last = myDeque.pop()
first = myDeque.popleft()
print(first,last) # Int:1,3
```
全力回避フラグちゃん! の動画再生数の分布を調べてみた【Python】【グラフ化】

# はじめに

[前回の記事](https://qiita.com/mypsychology0/items/7f5dace26c4c375754e5)で再生回数をプロットしてみましたが，今回API を用いて自動的にデータセットが作成できるようになったこと，再生回数の分布が単に気になったということで，今回の記事を作成するに至りました．

## 注意事項
また，2021/1/3 の動画公開前時点で記録しているため，現在の情報と異なる可能性があることと，
とりあえずヒストグラムを使用して分布を見ようとしただけであることをご了承ください．

# 用いたデータセット

全力回避フラグちゃん! チャンネルからYouTube Data API v3 を用いて取得した再生回数をもとにしました．


## プログラム

ヒストグラムを作成するプログラムです．

```py:グラフ作成プログラム
%matplotlib inline
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import datetime
import matplotlib.dates as mdates
import matplotlib.patches as mpatches
from matplotlib.path import Path
from pandas.plotting import register_matplotlib_converters
register_matplotlib_converters()

bins = 40
maxy = 30

#データセット対象のCSV ファイル
file = "2021-01-03_flag_videos_datasets.csv"
#Date, 再生回数
num_play = pd.read_csv(file, header=0, encoding='UTF8', usecols=[3, 5], parse_dates=[0])
num_play = num_play.dropna(how='all')


# debug
#print(num_play)
#num_play.to_csv('exam_num_play.csv')

#Plot するグラフ
#Date
x = num_play[num_play.columns[0]]
#print(type(x[0]))

#再生回数
y1 = num_play[num_play.columns[1]]

#グラフの大きさ
plt.figure(figsize=(20.0, 10.0), dpi=300)
#フォント設定
plt.rcParams['font.family'] = 'Times New Roman'


# グラフプロット
## 再生回数を棒グラフでプロット
play_hist = plt.hist(y1, bins=bins, color="lightblue")

        
# 軸の範囲
plt.ylim([0, maxy])

# グラフタイトル
plt.title("全力回避フラグちゃん! 動画集計データ", fontname="MS Gothic", fontsize=20)

# 軸メモリ
plt.tick_params(axis='x', labelsize=20, labelrotation=45)
plt.tick_params(axis='y', labelsize=20)

# ラベル名
plt.xlabel("再生回数", fontsize=20, fontname="MS Gothic")
plt.ylabel("数量", fontname="MS Gothic", fontsize=20)

## 平均値と中央値を横線でプロット
avg = plt.vlines(num_play.mean(axis=0), 0, maxy, 'b', linestyles='dashed')

# 凡例
avg_title = "平均値"

plt.legend([avg], [avg_title], bbox_to_anchor=(1.0, 1.0), prop={"family":"MS Gothic", 'size':20}, markerscale=3)

#画像保存
plt.savefig("flag_video_hist_graph.png", bbox_inches="tight", pad_inches=0.0)
```

#グラフ化した結果

以下のグラフが本記事の成果となります．
横軸が再生回数，縦軸はその再生回数に属する動画の数です．
平均値は小数点以下切り捨てで760, 946 回です．

![flag_video_hist_graph.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/989429/3c4b643d-3d52-57c9-7683-82674a885eae.png)

# 簡単な考察？

...グラフの概形を見ると，ポアソン分布に見える...見えなくもない...
まったく存在しない再生回数の階級も存在するが...
サンプルが足りないかもしれないが，これ以上動画はない．

# 簡単な結論

テキトーになりますが，今回の記事の結論です．

- 全力回避フラグちゃん! の動画の再生数をヒストグラムとしてプロットすると，ポアソン分布の概形が見えてくる
- つまり，再生回数はポアソン分布に従う？？？

# 今後の予定
今後も日時的に再生数を取得し，ヒストグラム化していく予定です．
新しい発見があったらまた記事を作成します．

# おわりに

ここまで読んでいる人はいないと思いますが，もしいたらまずは，以下のリンクから<b>全力回避フラグちゃん!</b> チャンネルとフラグちゃんのTwitter をフォローしてください．この記事を読むより大切なことです．
大事なことなのでもう一度，<b>チャンネル登録</b>と<b>Twitter のフォロー</b>をよろしくお願いいたします．

# 関連リンク
- 全力回避フラグちゃん! https://www.youtube.com/channel/UCo_nZN5yB0rmfoPBVjYRMmw/videos
- 株式会社Plott / Plott Inc. https://plott.tokyo/#top
- フラグちゃんのTwitter https://twitter.com/flag__chan
- Github  https://github.com/uky007/flag_analysis
多分これがオブジェクト指向

## はじめに
この記事は、[オブジェクト指向でなぜつくるのか](https://www.amazon.co.jp/%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%8C%87%E5%90%91%E3%81%A7%E3%81%AA%E3%81%9C%E3%81%A4%E3%81%8F%E3%82%8B%E3%81%AE%E3%81%8B-%E7%AC%AC2%E7%89%88-%E5%B9%B3%E6%BE%A4-%E7%AB%A0/dp/4822284654)という著書と、[黒本著者が教える やさしくない!? Java](https://www.youtube.com/channel/UC42DlV-0RDb6fJ8A3IbAang/videos)のYoutubeチャンネルを見たもの、私の経験に基づく理解を整理したいと思って執筆しました。
上記はとてもわかりやすかったので、是非ご覧になってください。

あと、以下の説明で出てくるサンプルコードはすべてJavaです。
なるべくJava特有の書き方は避けますが、ご了承ください。

## 対象
オブジェクト指向言語のプログラミング経験がある人
でもオブジェクト指向がよくわからない人

## オブジェクト指向とは
プログラミングや設計に留まらず、深い話になると哲学にまで発展するような難しいもののようです。
では私のような、ただのプログラマーが哲学まで理解する必要があるのかというと、それはNOです。

プログラミングする上では、
**オブジェクト指向＝プログラムを意味のある単位で分割すること**
ということで考えておけば私は良いと思います。

### ちなみに
「はじめに」で登場した著書とチャンネルでも仰っていますが、オブジェクト指向やプログラミングを例え話で説明される機会が多いと思います。
よくある説明で、オブジェクト指向は現実世界を表現したものだ！というのがありますが、それが正確な説明であるかどうかは私には判断付きませんが、少なくとも私には理解しづらいです。

確かに現実世界に表現が似ているものはありますが、現実世界とプログラミング、結び付けるには想像力が豊かでないと難しい気がします。
ということで、プログラムベースの話をしていけたらと思います。


## なぜオブジェクト指向を使うのか
例えば、以下のようなコードがあったとします。

```java
public class Main {
    public static void main(String[] args) throws Exception {
        String name = "Taro";
        System.out.println(name);
    }
}
```
「Taro」というnameがコンソールに表示されるだけのプログラムです。
ここに、weight情報を追加してみましょう。

```java
public class Main {
    public static void main(String[] args) throws Exception {
        String name = "Taro";
        String weight = "70kg";
        System.out.println(name + "の体重は" + weight);
    }
}
```
体重がString型...?という突っ込みはおいといて、「Taroの体重は70kg」と出力されます。
ここにJiroを追加します。

```java
public class Main {
    public static void main(String[] args) throws Exception {
        String name1 = "Taro";
        String weight1 = "70kg";
        System.out.println(name1 + "の体重は" + weight1);
        String name2 = "Jiro";
        String weight2 = "15kg";
        System.out.println(name2 + "の体重は" + weight2);
    }
}
```
name1とweight1、name2とweight2でそれぞれセットなのですが、この書き方だと変数名でなんとなくそれっぽいだけで、プログラムとしてはセットが担保されていません。
ここでクラスを定義してみます。

```java
public class Main {
    public static class Human {
        public String name;
        public String weight;
        
        public Human(String name, String weight) {
            this.name = name;
            this.weight = weight;
        }
        
        public void print() {
            System.out.println(this.name + "の体重は" + this.weight);
        }
    }
    
    public static void main(String[] args) throws Exception {
        Human taro = new Human("taro", "70kg");
        taro.print();
        Human jiro = new Human("jiro", "15kg");
        jiro.print();
    }
}
```
実行結果は変わりませんし、コード量は増えました。
ですが、nameとweightがセットになりました。
このように関連するデータと処理を一つのまとまりにすること、これがオブジェクト指向の根本的なところであり、それによって保守性が上がる(プログラムがメンテナンスしやすくなる)ことが、オブジェクト指向を使う大きな理由だと思います。

## ほかにも
他にもオブジェクト指向には様々なメリットがあります。
上記の例ではコード量が増えていましたが、減る場合もありますし、複数人で分担して開発を進めるうえで大事な仕組みも備わっています。

### オブジェクト指向の様々な仕組み
ここではキーワードだけ羅列します。

- クラス
    - カプセル化
    - データ隠蔽
    - 抽象化
    - 情報隠蔽
- ポリモーフィズム
- 継承

もし次回があれば、上記内容を掘り下げた記事を書きたいなと思います。
Matplotlib で画像に等高線を描画したいがうまくいかないメモ


https://docs.astropy.org/en/stable/visualization/wcsaxes/images_contours.html

ありがとうございます.

```
%matplotlib widget
import matplotlib.pyplot as plt


fig, ax = plt.subplots()
im = ax.contour(image, levels=np.linspace(0, 100, 10), alpha=0.5)
plt.show()
```

ただし, こちらで試した限りでは(jupyterlab + `widget` magic で表示), なぜか画像の上下が逆になりました.
また, contour だと等高線だけしか描画されない.
Matplotlib のバグ?

とりあえずは `contourf` で fill した画像で凌ぐしかなさそうです...
webアプリを再リリースして学んだこと３つのこと

#始めに
今回、作ったwebアプリを公開してあまりに反響がなくすぐに閉鎖しまたすぐに公開した話をします。

##作ったwebアプリ
![new-elder-top.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480294/dce931e7-100f-cbc8-679b-82a605c7197b.png)

人生経験を募集したり、エッセイを書いたりするサービスです。
エッセイを書くほどでもない...というときはツイッターのような一言だけつぶやく機能もあります。

URL:
https://e-elder.herokuapp.com/

##公開した直後は...
全く反響がありませんでした。qiitaでも宣伝してみたのですがいいねもコメントも全く付きませんでした。
サービスサファリに掲載依頼したのですが落ちました。

あまりの反響のなさにherokuのアプリデータまでけしてしまいました。

##なぜまたリリースしたか
今回なぜ失敗したかを考えてみようと思い
先輩方の記事を読んでいるとwebアプリは最低１、２年運用しないとなかなか当たらないと書かれてました。

今までqiitaで宣伝をしてバズり急速にユーザーを増やしていったサービスばかり見ていたため、公開した直後から反響がないと絶対に成功しないと考えてました。
ただ実際、そのようになるのは一握りで今人気なサイトも最初はばずったりしなかったものもあるそうです。

参考：
[Webサービス個人開発するなら読みたい情報源13](https://qiita.com/curryperformer-kato/items/a7dc9a41200b6c9c1912#web%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%A7%E8%B5%B7%E6%A5%AD%E3%81%97%E3%81%9F%E3%81%84%E4%BA%BA%E3%81%AB%E8%AA%AD%E3%82%93%E3%81%A7%E6%AC%B2%E3%81%97%E3%81%84%EF%BC%92%EF%BC%90%E3%81%AE%E3%82%B3%E3%83%88)

##再リリースした際の変更点
###トップページにコンテンツを絶対に置かない
これは前々からわかってはいましたが
今回は自分である程度コンテンツが作れたのでトップページにコンテンツを堂々置いてました。
しかし登録すればコンテンツ量が少ないのはまるわかりになってしまうので
最初のほうは絶対トップページにコンテンツはおかないほうがいいと思いました

###一覧ページも廃止
登録した後でもコンテンツが少ないことがユーザーにばれたら使われなくなります。
なのでエッセイ一覧、募集一覧、一言一覧すべて見れなくして

コンテンツを見るにはサイト内にある検索バーでしかできないようにしました。

##終わりに
今回学んだことは
webアプリは最低１、２年運用しないとなかなか当たらない
何が何でもトップページにコンテンツを絶対に置かない
ユーザーには登録したとしてもコンテンツ量が図りにくいよう設計する

ですかね。

ということで人生経験を共有するサービス「Elder」使ってください！
URL:
https://e-elder.herokuapp.com/
node.jsにnodemonをインストールするが動かない人へ

node.jsにnodemonを入れると変更を監視してくれるので開発効率が上がる。
しかしnodemonをinstallしても動かない人一旦アンインストールして以下を試して欲しい。

#####エラー内容
```
bash: nodemon: command not found
```


#####解決方法
```
//アンインストールする
npm uninstall nodemon

//グローバルしてインストール
sudo npm install -g --force nodemon
```

ローカル開発環境にVSで開発するのが主流だと思うが、当方いつでもどこでも開発したいのでC9で開発しようと思ったらこのエラーにぶち当たった。
誰かの役に立てば。
Mac mini の初期設定

この記事は自分用が今後pcを買ったときのために書くものです。

参考にさせていただいた記事です。
[Mac を買ったら必ずやっておきたい初期設定](https://qiita.com/ucan-lab/items/c1a12c20c878d6fb1e21
)

設定の位置やbrewのコマンドなど変更点がそれなりにありました。

##環境
Mac mini (M1, 2020)
macOS Big Sur 11.1

##カーソルセンスの導入
デフォルトではカーソルの動きがとても遅いのでまず最初にカーソルセンスを導入、設定は好みで適当に

##Mac システム環境設定
###一般
* スクロールバーの表示
    * 常に表示
* スクロールバーのクリック時
    * クリックされた部分へジャンプ
* 書類を閉じるときに変更内容を保持するかどうかを確認
    * 有効
* 最近使った項目
    * 5

###Dockとメニューバー
* Dockを自動的に表示/非表示
    * 有効
* 最近使ったアプリケーションをDockに表示
    * 無効
* Bluetooth メニューバーに表示
    * 有効
* 時計
    * 24時間表示
    * 秒を表示
* Spotlight
    * 無効
* Siri
    * 無効

###キーボード
* キーボード
    * キーのリピート
        * 最速
    * リピート入力認識までの時間
        * 最短

* ユーザ辞書
    * チェックボックスを 4 つとも外す

* 入力ソース
    * 日本語
        * 入力モード
            * 英字
                * 有効
        * ライブ変換
            * 無効
        * タイプミスを修正
            * 無効
    * ドイツ語を追加

###マウス
* 副ボタンのクリック
    * 有効
* スマートズーム
    * 有効
* ページ間をスワイプ
    * 2本指
* フルスクリーンアプリケーション間をスワイプ
    * 無効

###省エネルギー
* 15分

###共有
* コンピュータ名の変更

##Finder
###Finder環境設定
* サイドバー
    * 最近の項目
        * 無効
    * アプリケーション
        * 無効
    * ハードディスク
        * 有効
* 詳細
    * すべてのファイル名拡張子を表示
        * 有効

###表示
* 表示オプションを表示 > 常にカラム表示で開く

###Macintosh HD
* <kbd>command</kbd> + <kbd>shift</kbd> + <kbd>.</kbd> で隠しファイルを表示

##ミッションコントロール
* 要らないアプリを消したりまとめたりする

##Homebrew
* https://brew.sh/index_ja からインストール

```zsh
Warning: /opt/homebrew/bin is not in your PATH.
```

という表示が出たので次のようにPATHを通します。
.zshrc ファイルがなかったので作り

```text
export PATH=$PATH:/opt/homebrew/bin
```
と書きました。

cask コマンドがオプションに変更になっていたらしく少し手間取りました。
参考( https://qiita.com/horit/items/03e6ae6599253afcd75c )

##Chrome
* https://www.google.com/intl/ja_jp/chrome

```zsh
% brew install --cask google-chrome
```
デフォルトのブラウザに設定。サインインして同期。

##Slack
* https://slack.com/intl/ja-jp

```zsh
% brew install --cask slack
```

##Visual Studio Code
* https://azure.microsoft.com/ja-jp/products/visual-studio-code/

```zsh
% brew install --cask visual-studio-code
```

VSCodeの設定は別の記事にして後日リンクを貼ることにします。

記事になりました。
https://qiita.com/cubinglover/items/5b4d05ca0f77c60f1d79

##おわりに
参考にした記事からも変更点があったのでそれなりに時間がかかってしまいました。前回 mba のセットアップをしたときは pc に関して本当に無知でぐちゃぐちゃ ( 物理ではない ) にしてしまったので今度は大事にしたいです。

###追記
2021/01/05 軽微な修正 競プロ環境構築記事のリンク追加
はじめてのFreeBSDでIPv6

フレッツ光環境にFreeBSD/i386 12.2Rをインストールして、IPv6を試します。プロバイダーはNIFTYです。

ルーターはIPv6パススルーが設定してあります。IPv6パススルーとはルーター自体はIPv6を話さず、届いたIPv6パケットをそのまま転送する、ブリッジ的な機能になります。

/etc/rc.confに以下を追加して、リブートします。

```
ifconfig_fxp0_ipv6="inet6 accept_rtadv"
rtsold_enable="YES"
```

rtsoldが起動しています。

```
% ps -ax | grep rtsold
 683  -  ICs   0:00.01 /usr/sbin/rtsold -a
 687  -  Is    0:00.00 rtsold: rtsold.llflags (rtsold)
 689  -  Is    0:00.00 rtsold: rtsold.script (rtsold)
 690  -  Is    0:00.00 rtsold: rtsold.sendmsg (rtsold)
 691  -  Is    0:00.01 rtsold: system.syslog (rtsold)
1059  0  S+    0:00.01 grep rtsold
```

ifconfig fxp0でIPv6のアドレスが設定されているのが確認できます。

DNSサーバーはIPv4はルーター自体がフォワードするようになっていますが、IPv6はプロバイダー側のDNSサーバがプロバイダー側のIPv6ルーターからRAで渡されるようです。

RAで渡させるIPv6のDNSは自動的にresolv.confには入らないようです。

IPv4だけをresolv.confに書いて、IPv4で問い合わせしてもIPv6のアドレスは返ってきます。

```
% host update.freebsd.org
update.freebsd.org has address 163.237.247.16
update.freebsd.org has address 204.15.11.117
update.freebsd.org has IPv6 address 2620:11c:5001:1118:1337::117
update.freebsd.org has IPv6 address 2001:4978:1000::2319:16
```

googleのIPv6のパブリックDNSサーバでひいてみます。

```
% host update.freebsd.org 2001:4860:4860::8888
Using domain server:
Name: 2001:4860:4860::8888
Address: 2001:4860:4860::8888#53
Aliases: 

update.freebsd.org has address 204.15.11.117
update.freebsd.org has address 163.237.247.16
update.freebsd.org has IPv6 address 2001:4978:1000::2319:16
update.freebsd.org has IPv6 address 2620:11c:5001:1118:1337::117
```

ping6コマンドでupdate.freebsd.orgに到達が確認できます。

ip6addrctl showでポリシーテーブルの確認ができます。

IPv4のarpコマンドに相当するコマンドはndpになるようです。

デフォルトではfreebsd-updateはIPv6で行われます。
初心者がインフラを学ぶ意義

インフラ知識を身につけると以下のようなことができるようになります。

#テスト環境をすぐ構築するなど開発の自由度があがる
インフラの知識が全くない状態だと、自分の作ったアプリケーションを実践に近い環境で試したくなっても、簡単には試せません。インフラ知識を身につけることで、人に迷惑をかけることなく様々な実験ができます。

#障害に強くなる
システムトラブルがあったときに、どこに問題があるのかの特定が容易になる

#システム全体での幅広い対応ができるようになる
リソース不足などの対応をアプリケーション側だけでなくシステム全体で対応することができる

#希少性の高い人材となる
いうまでもなくスキルの幅が広がるので、より希少性の高い人材となりますので、収入面などでも有利になります。

このようなメリットが開発者がインフラを理解することにはあります。学びたくなりますね〜
【Ruby on Rails】sessionメソッドの使い方

#はじめに
rails初学者のkosukeです。
railsを学習していて`session`の使い方が、あやふやになることがあるので備忘録としてまとめておきます。

#セッションとは
セッションは主にログイン機能に使用されるもので、ログイン状態を保持することができます。
セッションを保持することで、一度ログインしたらログアウトするまで登録されたユーザーとしての扱いを受けることができます。（ブラウザを閉じたりしたら、消えてしまう。)

セッションの機能がなければ、ページを移動するたびにログインをし続けなければなりません。

セッション実装する為には、ユーザーごとのブラウザに情報する必要があります。

#定義の仕方
セッションを付与するメソッドをどこかに定義しておきます。
下記コードでは、`ユーザーのid`に**「user_id」**という名前のセッションを付与しています。

こうすることで、ユーザーのブラウザ内に暗号化済みのユーザーidを自動で作成し、保存します。
ユーザーidをブラウザ上に保存しておくことで、ユーザー情報を保持することができます。

```ruby:sessions_helper.rb
#セッションを付与するメソッド
  def log_in(user)
    session[:user_id] = user.id
  end
```

下記コードはログイン実装する際のアクションです。
ユーザーのパスワード認証が正しければ、ユーザーに`session`を付与するようにしています。

```ruby:sessions_controller.rb
def create
    user = User.find_by(email: params[:session][:email].downcase)
    if user && user.authenticate(params[:session][:password])
      log_in(user)
      redirect_to user
    else
      flash.now[:danger] = 'Invalid email/password combination'
      render 'new'
    end
  end
```
#セッションの削除方法
付与したsession[:user_id]の値を`nil`にするもしくは削除することで、セッションを削除することができます。

```ruby
#値を「nil」にする
session[:user_id] = nil

または

#値を削除する
session.delete(:user_id)

```

#current_userの定義の仕方
sessionを利用して、現在ログインしているユーザーを返すことができます（いる場合）。

```ruby:sessions_helper.rb
#現在ログインしているユーザーを表す。
def current_user
  if session[:user_id] #user_idというsessionを持っている場合「真」とする
    User.find_by(id: session[:user_id])
  end
end
```

###current_userメソッドの使い方

```ruby:xxx.html.er
#現在ログインしているユーザーの名前を表示する
<%= current_user.name %>
```

```ruby:xxx.html.er
#現在ログインしているユーザーの名前とユーザー情報に飛ぶリンクを表示する。
<%= link_to current_user.name, user_path(current_user) %>
```

#参考文献
rails tutorial 第８章　ログイン、ログアウト
https://railstutorial.jp/chapters/log_in_log_out?version=4.2
Splunkでマルチバリューを整列する（失敗しました）

以前の記事でマルチバリューを`sort`みたく整列できなくて結構大変だったので、作れるんじゃないかと頑張りましたが、無理でした。

でも途中まで書いときます。

2020/1/19
https://github.com/gjanders/SplunkAdmins/blob/master/bin/streamfilter.py
が参考になると。

multivalue fields come through as a list, iterate through the list and run the regex against each entryin the multivalued field

あとは

Multivalue fields are sent as a `;` delim string with each term incased in `$`, and the field name is set to `__mv_fieldname`.The original field name is sent as a `\n` delim string. Also need to  set supports_multivalues in *commands.conf* 

聞いてみるもんです。



#Code

```python:mvsort.py
#!/usr/bin/env python

import sys
from splunklib.searchcommands import dispatch, StreamingCommand, Configuration, Option, validators


@Configuration()
class mvsortCommand(StreamingCommand):
    """ sort multivalue
    """


    def stream(self, records):
        self.logger.debug('mvsortCommand: %s', self)  # logs command line

        for record in records:
            args=self.fieldnames[0]  # 引数のフィールド名
            if isinstance(record[args],(str)):  # フィールドがシングルバリューかの判定
                pass

            else:
                record[args]=sorted(record[args])
            yield record

dispatch(mvsortCommand, sys.argv, sys.stdin, sys.stdout, __name__)
```

うまくいかない・・・・:cry:

#pythonによる検証

[Colaboratory](https://colab.research.google.com/notebooks/welcome.ipynb?hl=ja)で作ってみた。

```python:generator_test.py
# generator テスト
import random

num=[random.randrange(0,20) for i in range(20)]

def orig_gen():
  for i in num:
    yield i

g1=orig_gen()
j=[]

def gen_out():
  try:
    for i in g1:
      j.append(i)
      yield j

  except:
    pass

  finally:
       yield sorted(j)


g2=gen_out()
for i in g2:
  print(i)
```

##結果

```
[5]
[5, 16]
[5, 16, 6]
[5, 16, 6, 19]
[5, 16, 6, 19, 18]
[5, 16, 6, 19, 18, 3]
[5, 16, 6, 19, 18, 3, 16]
[5, 16, 6, 19, 18, 3, 16, 17]
[5, 16, 6, 19, 18, 3, 16, 17, 6]
[5, 16, 6, 19, 18, 3, 16, 17, 6, 8]
[5, 16, 6, 19, 18, 3, 16, 17, 6, 8, 8]
[5, 16, 6, 19, 18, 3, 16, 17, 6, 8, 8, 3]
[5, 16, 6, 19, 18, 3, 16, 17, 6, 8, 8, 3, 12]
[5, 16, 6, 19, 18, 3, 16, 17, 6, 8, 8, 3, 12, 13]
[5, 16, 6, 19, 18, 3, 16, 17, 6, 8, 8, 3, 12, 13, 8]
[5, 16, 6, 19, 18, 3, 16, 17, 6, 8, 8, 3, 12, 13, 8, 7]
[5, 16, 6, 19, 18, 3, 16, 17, 6, 8, 8, 3, 12, 13, 8, 7, 15]
[5, 16, 6, 19, 18, 3, 16, 17, 6, 8, 8, 3, 12, 13, 8, 7, 15, 10]
[5, 16, 6, 19, 18, 3, 16, 17, 6, 8, 8, 3, 12, 13, 8, 7, 15, 10, 1]
[5, 16, 6, 19, 18, 3, 16, 17, 6, 8, 8, 3, 12, 13, 8, 7, 15, 10, 1, 9]
[1, 3, 3, 5, 6, 6, 7, 8, 8, 8, 9, 10, 12, 13, 15, 16, 16, 17, 18, 19]
```
きちんと最後の`sorted（）`が効いてくれている。

#考察

https://docs.splunk.com/DocumentationStatic/PythonSDK/1.6.14/searchcommands.html
の説明をみてもよくわからないので色々と試したところ、

- もともとのイベントは`dict`
- マルチバリューの時は`list`で値がくる。
- `append()`でくっつけるのは十分可能だけど、最後の`sorted`だけが効かない。
- `str`のリストのはずなんだけどな〜
- [pstree](https://github.com/murchisd/splunk_pstree_app)なんかは思いっきりマルチバリューを作っていてすごい。

#まとめ
手詰まりになったので、いったんSplunk>AnswersにあげてPythonの勉強をします。