OmniAICreator/Qiita-1.07M huggingface dataset:
そのまま書くには違和感のあるロジックはクラスに分離しよう〜毎週○曜日に実行されるRakeタスクの実装を例に（Heroku）

## 問題

Herokuでスケジュール実行のために用意されているアドオンHeroku Schedulerでは「10分毎」「1時間毎」「1日毎」のオプションが用意されているものの、「1週間毎」に実行したいときのオプションはないので、週次でタスクを実行したい場合はRails側で実装する必要があります。さて、それでは週次で実行するための判定処理はどこに書くべきでしょうか？

## よくあるコード

こんなときよく見かけるのがパターンAとパターンBのコードですが、双方ともデメリットが大きいです。

### パターンA: Rakeタスク側に判定コードを書く

```ruby
DAY_OF_WEEK = %i[sun mon tue wed thu fri sat].freeze

namespace :awesome_check do
  desc 'Invoke AwesomeChecker'
  task run: :environment do
    if DAY_OF_WEEK[Date.current.wday] == :sat
      AwesomeChecker.call
    end
  end
end
```

シンプルではありますが、Rakeタスクのテストは書きづらいので、このコードの例で言えば本当に土曜日だけに実行されるように担保したい場合に困ります。

【参考】Rakeタスクのテストを書きたい人はこちらの記事が参考になります
[RailsでRakeタスクをシンプルかつ効果的にテストする手法](https://qiita.com/aeroastro/items/c97bd26ce8b8818b6bed)

### パターンB: AwesomeChecker側に判定コードを書く

```ruby
class AwesomeChecker
  # ...（中略）...
  def call
    return false unless DAY_OF_WEEK[Date.current.wday] == :sat
      
    # （処理の中身を書く）
  end
  # ...（中略）...
end
```

「週次実行するビジネスロジック」と「AwesomeCheckerのそもそものビジネスロジック」は目的が異なるので、コードとしていびつです。そもそも、所定の曜日にしか実行できない関数が存在するのは不気味ですよね。

## 解決策: 週次実行を管理するクラスを作る

どちらにロジックを書いても不自然になるのであれば、新しくクラスを作ってロジックを分離するのが策になります。Rakeタスクにこんな感じのコードを書けるとすれば、Rakeタスクにロジックを書かなくても済むし、AwesomeChecker上に週次実行のロジックを盛り込まなくても済みそうです。

```ruby
namespace :awesome_check do
  desc 'Invoke AwesomeChecker'
  task run: :environment do
    # NOTE:
    # Procで実行したいコードを渡しておけば、
    # 即座に実行されてしまうことはありません
    DayOfWeekInvoker.call(:sat, -> { AwesomeChecker.call })
  end
end
```

このような「指定された曜日にだけ第二引数の関数が実行される」クラスの実装はこんな感じになるかと思います。

```ruby
class DayOfWeekInvoker
  DAY_OF_WEEK = %i[sun mon tue wed thu fri sat].freeze

  def self.call(*args)
    new(*args).call
  end

  def initialize(day_of_week, func)
    @day_of_week = day_of_week
    @func = func
    unless valid_day_of_week?
      raise ArgumentError, "無効な引数です: #{day_of_week}"
    end
  end

  def call
    unless DAY_OF_WEEK[Date.current.wday] == @day_of_week
      Rails.logger.info '[DayOfWeekInvoker] Invocation Skipped'
      return
    end
    @func.call
  end

  private

    def valid_day_of_week?
      @day_of_week.in? DAY_OF_WEEK
    end
end
```

Heroku Schedulerのオプションで「日毎」が選択できるため、1日1回だけ実行されるというロジックはHeroku Schedulerにお任せしている実装にはなりますが、1日1回だけ実行されることをRails側で担保したい場合もこのような発想でクラスを分離すればテストも簡単になります。

「何だかロジックが入り組んでテストを書きづらくなったなー」というときにご参考ください。
MacでExif情報からファイル名を変換する

こんにちは。
一眼レフやミラーレスを複数台使って撮影とかしていると、ファイル名順≠時間順とならないことがあると思います。
<img width="362" alt="Screen Shot 2020-01-13 at 12.51.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102801/c9d31395-ca02-72df-992a-e89e0c65f76f.png">
こんな感じで。
ファイル名が時間順のほうがいろいろと便利なので、簡単に変換できるワンライナーをいつも動かしてるのでご紹介します。

## ファイル名の先頭に時間をつける

該当のフォルダまでcdし、

```bash:commandline
 bash $ for i in `ls -1 DSC_*.JPG` ; do ¥
S=`sips -g all $i | grep "creation" | perl -pe 's/^.*\:\s+(20\d\d):(\d\d):(\d\d)\s+(\d\d):(\d\d):(\d\d).*$/img$1_$2_$3_$4_$5_$6_/'` ; ¥
mv $i $S$i ; ¥
done
```

ただsipsというExif情報を見られるコマンドから`creation`を抽出し変換してるだけです。
日付時間の前に`img`をつけてるのはなんとなくです。
いきなりmvしてしまうと不安という方は、まず`echo "mv $i $S$i"`ってやってみたほうがいいとおもいます（自分もだいたいそうですｗ）



## おまけ

「DSC_0123.jpg」みたいなそもそものファイル名がかぶる場合は、きっとカメラ側にprefix(先頭につく文字)を変更する設定があるはずなのでそちらで先に調整してしまったほうが早いです。

もしくはいったん別々のフォルダに入れて上記のコマンドを動かし、あとでまとめるでもいいでしょう。秒までかぶってるとファイル名が衝突してしまいますが、一人で複数台持ち前提ならほぼないでしょう。
OutSystemsのColumn系BlockのAdaptive Pattern対応

OutSystemsUIのAdaptiveフォルダには、Columnで始まるBlockがいくつかあります。
このBlock内に配置したコンテンツは、狭い画面では自動的に表示方法を調整してくれます。
その仕組みを調べてみました。

# 環境
Personal Environment(Version 11.0.606.0)
Service Studio(Version 11.6.21)
OutSystemsUI(Version 2.2.7)

# Adaptive Pattern
OutSystemsのUIにおけるAdaptive Patternは、端末の種類(PC、タブレット、スマートフォン)に応じて表示方法を変えられるBlockです。

以下のように、Input Parameterに、タブレットのときの表示方法、スマートフォンのときの表示方法を指定します。
![qAdaptive1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/2b52b20a-7cc4-29ff-c43a-e67586208643.png)

Static Entity BreakColumnsの値で設定します。

# 端末の判別
OutSystemsUIのClient Acction GetDeviceTypeで、"phone"/"tablet"/"desktop"のいずれかが帰ります。

この値は、bodyタグについたclassから取得しています。

このclassはどこで設定されているかというと、Silk UI(Version 10)のときの資料に記載がありました(下の参考リンク参照)。

ページ初期表示時点でJavaScriptが動いて端末の種類や画面幅を取得し、CookieやSessionに保持されるようです。サーバからHTMLページとしてレンダリングされるときに、取得した値から端末の種類をclassに書き込む仕組み。

# 実行イメージ
Column3 を使って、タブレットならBreakColumns.Middle、スマートフォンなら、BreakColumns.Allを設定します。Column3のそれぞれに、Containerをおいて、各Columnがどこで折り返されているかを確認します。
端末種別のシミュレーションには、Chromeの開発者ツールのdevice toolbarを使っています。

## desktop(PCサイズ)
![qAdaptive2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/410a021f-47a8-8fd1-6939-c67ef1d40806.png)

## table(タブレットサイズ)
![qAdaptive3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/7bbfef40-a1d9-931b-eb3d-a5fe7d33f148.png)

## phone(スマートフォンサイズ)
![qAdaptive4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/328e34b1-0c73-42d5-d717-ed0d29f4606f.png)

## 動作の仕組み
Column3は、実行時に以下のタグとして出力されます。

``` html
<div data-container="" class="columns columns3 gutter-base tablet-break-middle phone-break-all ">
```

TableBehaviorに設定したEntities.BreakColumns.Middleがclass tablet-break-middleに、PhoneBehaviorに設定したEntities.BreakColumns.Allがclass phone-break-allとして出力されます。

OutSystemsUIが提供するCSSの設定で、このclassをつけたColumns Patter内の各列の幅等を指定して折返しを実現しています。

# 参考リンク
古い(バージョン10時のUI Framework Silk UI向け)ですが、
[Columns Responsive Behavior](https://success.outsystems.com/Documentation/SILK_UI_Framework/05_Understanding_Responsive_and_Adaptive#Columns_Responsive_Behavior)
【Androidアプリ】AMD CPU RyzenのPCでエミュレータを使用する方法

## 概要
- 開発環境によっては、Android Virtual Device（AVD）を起動することができません（ex. Windows 10 Home, AMDプロセッサ）
- Andoridアプリを開発する上でAVDを使用できないと、いちいち実機にインストールしたり、.apkを出力して[Nox Player](https://jp.bignox.com/)などのエミュレータで動作確認をしなければならず効率が落ちます
- 当方も最初はこの方法を採っていましたが、デバッグがしづらく途中で我慢ができなくなり、自身の環境でもAVDを使う方法はないか調査しました

-> の結果をまとめたのが本記事です


## 環境
- OS: Microsoft Windows 10 Home
- プロセッサ: AMD64 Family 23 Model 17 Stepping 0 AuthenticAMD ~2000 Mhz
- BIOS: LENOVO 8PCN45WW
- Android Studio 3.4.1

## 手順

### ハイパーバイザープラットホームの有効化

`Windowsの機能の有効化`を開き、`Windowsハイパーバイザープラットフォーム`にチェックを入れます。

![Windows の機能 2020_01_13 11_42_58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230436/ddfe715f-9fc6-e26f-c3df-d59cfe3ab87d.png)



### BIOSの設定変更

- PCを再起動して、BIOSの設定変更画面に入ります（起動方法はメーカーによって様々なので、`機種名 BIOS`などで検索してみてください）
- 仮想化に関する設定を変更します（ex. AMD SVN Technology = Disabled -> Enabled に変更）


### ハイパーバイザーの状態を確認

`Hyper-V の要件`を確認します。

コンソールから`systeminfo`を実行し、下記の状態になっていれば、AMD CPU RyzenのPCでもエミュレータを起動することができます。

```
Hyper-V の要件:         ハイパーバイザーが検出されました。Hyper-V に必要な機能は表示されません。
```

### AVDを起動

- Android Studioの右上のメニューからAVD Manager（右から2つ目）を起動します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230436/2d4c025c-60c9-5e15-47b2-aec6daeafbd8.png)

- 仮想デバイスを作成して、`Launch this AVD in the emulator`で起動します

![Android Virtual Device Manager 2020_01_13 13_24_33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230436/88b75476-0523-f78d-5605-e901432dd583.png)

- このような感じで起動します

![Android Emulator - Nexus_5_API_29_5554 2020_01_13 13_27_35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230436/2cc2d4bf-bfa8-9432-69a0-b2c284f9904f.png)
人工知能は私たちの仕事を乗っ取るのか？

![lego-628569_1920.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566223/17516372-a46b-f1ed-56ff-26ae4b2f38b1.jpeg)

人工知能は、歴史全体を通して人間が採用および適用してきたすべての技術やスキルと同様に、想像できるさまざまな方法で開発および使用できる新しい技術です。 このテクノロジーが私たちの社会にプラスまたはマイナスの影響を与えるかどうかは、政府、企業、コミュニティがその発展と成長をどのように導くことができるか、そしてテクノロジーと人間の調和がとれた共存を促進するためにどのように社会に基盤を築くことができるかにかかっています。

AIが持つ可能性について言えば、この技術は経験のある専門家だけでなく、スキルがあまり高くない労働者にも影響を与える可能性が高いため、多くの試みが行われていることを十分に認識している必要があります。 さまざまなビジネス環境でのパフォーマンスにAIを適用する試みが数多く行われていると確信しています。

もちろん、普通の人が「AIは私たちの仕事を奪う」または「AIは人間が果たしてきた役割に取って代わる」と仮定することは非常に合理的です。一部の研究者および彼らが引用する統計によれば、3〜6人の労働者が1993年から2007年にかけて単一の産業用ロボットを導入して失業しています。実際、企業内でのAIの適用に関する多くの議論は、「特定のタスクに必要な労働力の削減方法」です。（これは概して全般的な現象です。）

![aijob_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566223/4df2e3e2-1f38-3511-9bbb-a5c36ff59823.png)


ただし、「職業」は「完全に代替」されることはなく、新しいテクノロジーの導入によって「変化」されることが指摘されるべきです。 たとえば、ほとんどの人がもう気にすることのないほど馴染みのあるATMは1970年に最初に導入され、90年代を通じてより評判が良くなり普及してきました。現在も積極的に使用されていますが、 窓口係の職業はまだ消えていません。 若い世代はモバイル決済アプリケーションをより快適に感じているに違いないと思います。 とにかく、職業の範囲と内容は、「基本的な金融取引への対応」から「個々のクライアントに合わせたマーケティング/販売活動の実施」に変わりました。

![aijob_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566223/703dc54b-1fd5-27f6-9cdd-3893ce64f1d3.png)


この観点に沿って、AIは単に既存の仕事を取って代わるのではなく、実務の全体的な状況で「特定のタスク」を自動化することにより、特定の従業員が行うパフォーマンスが強化されることを理解することがより重要と思われます。 同時に、その適用に適切な指示を見つけるよう努めます。 これを行うことで、私たち全員が、退屈で価値の低い活動から自由になり、人間だけができることにもっと集中できるようになります。 雇用市場の規模も拡大し、その多様性はこれまで以上に強化され、より多くの雇用が創出されます。

また、多大な労力を費やすことなく、AIと人間が完全に調和して共存する未来を見ることは決して容易ではないことにも注目してください。 私たちが夢見てきたAIの時代の始まりに貢献する少なくとも3つの重要な要素があると確信しています。
まず、「仕事の未来」についての議論の焦点を「未来の仕事」に移すべきです。私たちが産業社会から抜け出し、最終的にデジタル社会に到達したとき、社会システムは長年にわたって変化しました。  AIは、次世代の社会を支配するシステムをどのようにすべきかを決定する任務が課されています。  「仕事」の概念、さらには「労働と生産」の概念が将来どのように変化するかを理解するには、視点とアイデアが必要です。

第二に、中央政府と企業の両方が、労働者とオフィスワーカーの「職業」を保護および保護できる方法でAIの採用を可能にする原則、環境、および戦略を開発する必要があります。 ビジネスでAIを採用するプロセスで尋ねる必要がある質問は、「労働力を削減する方法」ではなく、「人工知能に新しいテクノロジーを採用することで既存の労働力が新しい価値を生み出し、業績に貢献できるようにする方法」です。 加えて、フィールドワーカーの声に注意深く耳を傾け、彼らのニーズや要求を反映できるAIシステムを開発することは非常に重要です。

最後に、教育と学習の機会を設計し、社会のあらゆる世代に提供して、人々が新しいテクノロジーを採用する為にシフトできるようにする必要があります。 人工知能の技術は、無数の点で、過去数十年にわたって私たちが使い慣れてきたテクノロジーとはまったく異なり、社会や企業の全体的な構造を革新的に変える可能性を秘めています。 長期的な視点での新しい時代の適切な教育は、社会のすべてのメンバーがAIがもたらす変化に適応し、より明るい未来とそれが提供するものを享受できる環境の前提条件です。

明るい未来には、もしあれば、値札が付きます。 人類の未来に大きな可能性を秘めている人工知能を最大限に活用する方法と、私たち全員の発展のためにAI内の技術を強化する方法を決定するのは、社会、政府、企業、および個人次第です。
iOS SafariでWebサイトの特定の要素をCSSセレクタで指定して非表示にするアプリ[無料]

iOS Safari で広告など Web サイト上の邪魔な要素を非表示にするアプリ AdFilter の紹介です。なお iOS ではユーザースタイルシート(CSS)は使えないため `display: none` することしかできません。

CSSセレクタチートシート: https://webliker.info/css-selector-cheat-sheet/

# 方法

1. AdFilter をインストール

    [AdFilter - 広告ブロック
https://apps.apple.com/jp/app/adfilter-広告ブロック/id1042682195](https://apps.apple.com/jp/app/adfilter-広告ブロック/id1042682195)

2. 設定 → Safari → コンテンツブロッカー から AdFilter を有効にする
3. AdFilter を開き、下中央の「カスタム」をタップ
4. 右上の＋をタップ
5. タイプ→「要素の非表示」を選択
6. セレクターとターゲットを設定して保存
<img width="375" alt="IMG_8655.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155587/5800767f-0165-e5d0-91f6-8c0bf79003f4.jpeg">

# 参考
有料ですが、Web Cleaner というアプリもあるようです。(2020/01/13現在 ¥120)
こちらは要素を GUI で選択できるため簡単そうです。
https://lifehacking.jp/2017/06/web-cleaner/
😜【Sass】疑似要素使うときは&をちゃんと付ける

## 環境

Laravel 6.5.0
Vue.js

## やりたいこと

::beforeとか::afterとかで任意の要素周辺を修飾できる疑似要素
Sassで使用する場合は必ず「&」を付加しないといけなかった

## やったこと

🔵文言の前に✬が付く

```hoge.sass
.message
  font-weight: bold
  color: #ffffff
  background-color: #ff0000
  &::before
    content: "✬"
    background-color: #ff0000
    color: #000000
```

❌コンパイルは通るが機能しない

```hoge.sass
.message
  font-weight: bold
  color: #ffffff
  background-color: #ff0000
  ::before
    content: "✬"
    background-color: #ff0000
    color: #000000
```
gulpでsassとbabel環境構築（nodeインストールから）

# gulpセットアップ
自分用メモなので、大まかな手順のみ。
作業詳細はリンクの各記事を参照。
環境構築を一から行ったことがない人向け（自分！）

## 作業環境
macOS 10.14.6

## 手順
1. node.jsインストール  
nodeのバージョン管理をするため、下記記事を参照しインストール  
[MacにNode.jsをインストール](https://qiita.com/kyosuke5_20/items/c5f68fc9d89b84c0df09)

2. gulp-sass設定
3. gulp-babel設定
[Babel](https://blog.triana.jp/?p=1338#Babel)
4. Autoprefixer設定
[Autoprefixer](https://blog.triana.jp/?p=1338#Autoprefixer)


## 参照
[絶対つまずかないGulp 4入門（2019年版） インストールとSassを使うまでの手順
](https://ics.media/entry/3290/)
[gulp3→4の変更点に気をつけよう！](https://qiita.com/tatsuo-iriyama/items/08ba4bd621b7fdedcc4e)

## 意味のない感想
自分の投稿見返したら、ほぼ一年前に[npmでwebpack環境構築](https://qiita.com/yamaki_777/items/8569aa40c76cb2735b7b)に手をつけてた、、
けど現在実業務ではgulpで色々ごにょごにょしているのでgulp使い方復習&gulp4の書き方覚えようてことでまずはsassとbabelの設定やってみた。

昨年末はphpとDBの基本だけやったので、Laravel・Vueで開発できる環境構築できればな、、というところ。
手を出しすぎると意味わからなくなるので、少しずつ着実にやっていこう。っていう。
Android 動画再生アプリ開発(ExoPlayer)

#Android Exoplayerの使い方
Exoplayerとは簡単に言うとAndroidで動画再生をするためのAPIをたくさん用意したライブラリです。

通常１から動画プレイヤーを開発しようとすると、動画デコード、音声デコード、ストリーミング、復号化などを全て作らなければなりませんが、Exoplayerでは簡単なAPIですぐに実装できます。

API 16以上のSDKであれば使用できるのでハードウェアにも依存せず使用できます。

**[下記公式URL]**
[ExoPlayer  |  Android デベロッパー  |  Android Developers](https://developer.android.com/guide/topics/media/exoplayer)

##Exoplayer導入
初めにExoplayerライブラリをプロジェクトに追加します。

###google(), jcenter()追加
まず、build.gradleに下記を追加します。

```build.gradle
repositories {
    google()
    jcenter()
}
```

###Exoplayerライブラリ追加
次にExoplayerのライブラリを追加するのですが、Exoplayerはいくつかのライブラリを分けていますが、一括で導入したい場合は下記です。
**※**2020/01/13時点での最新バージョンは2.11.1

```build.gradle
implementation 'com.google.android.exoplayer:exoplayer:2.11.1'
```

特定のライブラリのみを追加したい場合、Exoplayerは5つのライブラリに分かれているので、これを指定してください。
Exoplayer 

- core
    - 動画配信用のコアライブラリ
- dash
    - Dashコンテンツ用ライブラリ
- hls
    - Hlsコンテンツ用ライブラリ
- smoothstreaming
    - smmothstreaming用ライブラリ
- ui
    - UIカスタム用のライブラリ

例えば、coreのみを指定する場合は下記です。
ライブラリを分けることはapkサイズの縮小に繋がります。

```build.gradle
implementation 'com.google.android.exoplayer:exoplayer-core:2.11.1'
```

###Java 8追加
```build.gradle
compileOptions {
  targetCompatibility JavaVersion.VERSION_1_8
}
```

##Exoplayer View追加
layoutファイルに下記を追加します。

```.xml
 <com.google.android.exoplayer2.ui.PlayerView
        android:id="@+id/playerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:surface_type="texture_view">

</com.google.android.exoplayer2.ui.PlayerView>
```

次にjavaファイルに下記を追加します。

```.java
private PlayerView playerView;
private SimpleExoPlayer player;

player = ExoPlayerFactory.newSimpleInstance(this);
player.addListener(this);
playerView = (PlayerView)findViewById(R.id.playerView);

DefaultDataSourceFactory dataSourceFactory = new DefaultDataSourceFactory(this,Util.getUserAgent(this,this.getPackageName()));
ExtractorMediaSource extractorMediaSource = new ExtractorMediaSource.Factory(dataSourceFactory).createMediaSource(Uri.parse(url));

playerView.hideController();
playerView.setControllerAutoShow(false);
playerView.setPlayer(player);
player.prepare(extractorMediaSource);
player.setPlayWhenReady(true);
```

[url]に再生した動画のurlを入れてください。

##おわりに
Exoplayerはカスタムできる幅も実は多く、今回挙げた簡単な動画再生以外にもたくさんありますので、リアルタイムDASHやAES復号、おしゃれなUIなど作りたい場合はコメントなどやTwitterのDMなどでお知らせください。

以上です。
TensorFlowでpng画像をdecordしようとして上手くいかず結局Numpyで解決した話

tensorflowを使って256 px$\times$256 pxのpngデータを

```python
import tensorflow as tf
image = tf.read_file("hoge.png")
image = tf.image.decode_png(image channels=3)
```

で取得したらshapeが(?, ?, 3)になって困ったので結局numpyを使って

```python
import numpy as np
img = np.array(Image.open("hoge.png"))
```

をしたらshapeが(256, 256, 3)で正常に得られました。
めでたしめでたし？
Chromebook向けにツールを作る

## はじめに
Chromebookって便利ですよね？ただ痒いところに手が届かないことも多々あり、解決すべくツールを作ろうと思い立ちました。
## どのアーキテクチャ、フレームワークが向いてる？
Linuxが動いたりAndroidアプリが使えたり、Chrome OSネイティブアプリの存在感が皆無だったりしたのでざっくり纏めてみました。
###[Chrome App](https://developer.chrome.com/apps/about_apps)
- JavaScript向けの[Chrome APIs](https://developer.chrome.com/apps/api_index)を使って、manifestを定義すればChromeアプリが作れる。APIの使い方は[sample](https://github.com/GoogleChrome/chrome-app-samples/tree/master/samples)を見るのがよい。
- Windows、Mac、Linux向けが途絶えたりしてChrome OS向けだけ残った状況。
- [Native Client](https://developer.chrome.com/native-client)という低レイヤー用のSDKもあるようだ。

###[Chrome Extension](https://developer.chrome.com/extensions)
- Chrome Browser内で閉じられる場合はこれ。

###[Progressive Web App](https://developers.chrome.com/apps/migration)
- Chrome AppではなくPWAがメインストリームなのでしょうか。ファイル操作とかのAPIが使えないのでツール開発には向かなそう。

###[Android App](https://developer.android.com/chrome-os)
- Chrome OSをサポートしたAndroidアプリもChrome OSアプリというようだが、さくっと作れるものではない。

### Linux上で動かす
- ツールを動かすためにCrostiniを有効にはしたくない。立ち上がるの遅いし、メモリ食うし。

### [Flutterアプリ](https://developers-jp.googleblog.com/2019/05/flutter-ui.html)
- [Flutter SDK](https://flutter.dev/docs/get-started/install/chromeos)はChromebookもサポートしてるけど、ツールを作るのにここまでしたくない。

### 結論
現状（バージョン: 79）でtabletで動かすケースではChrome Appがベターですかね。
ファイル操作だけ出来ればいいなら[Native File System](https://blog.chromium.org/2019/09/chrome-78-beta-new-houdini-api-native.html)使うのがいいかも。

## ハローワールド
- Chrome browserを開いて、拡張機能のデベロッパーモードを有効にする。
- samplesから参考になりそうなのを見つけて、「パッケージ化されていない拡張機能を読み込む」で開く。
- アプリのアイコンがメニュー登録されているので、実行する。
- デバッグは拡張機能の一覧からアプリの「ビューを検証」のバックグラウンドページ、index.htmlをクリックして[Chrome DevTools](https://developers.google.com/web/tools/chrome-devtools)を開く。
- 修正したら拡張機能の一覧からアプリをリロードしてデバッグする。
【JavaScript】2種類の恐竜画像を任意の数だけ表示させてみる。

###はじめに
会社で使っている言語以外にも、何か身につけたい。

仕事では全く違う言語を使っていることもあって、楽しくないと新しい知識が吸収できなくなっている。
作って楽しい気分になるプログラムを考えてみた。

今回登場のメンバーはステゴディアスとインドミナスレックス。
__ボタンを押すと、この二匹のどれかが、任意の数だけ表示されるプログラムを作ってみた。__

![stedia.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494408/6d5e5008-5264-573b-240e-bd61adb4a1d3.jpeg)
![indominas.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494408/de883dbd-1513-1fc0-cc4b-69cb9afcaa33.jpeg)


###１．今回のポイント

+ __任意の数だけイメージタグを作りたい。__
+ __idはわかりやすいように数字を入れたい。__
+ __乱数(ここで表示する画像数を決定する)__
+ __インドミナスの画像が沢山表示されたら、攻めの姿勢で、ステゴディアスが表示されたならソースの実行確認などを念入りに行って守りを固めるとよいでしょう__


###２．実際のソース

```html:dino_print_random.html
<!DOCTYPE html>
任意の数だけ恐竜を表示<br>
<form name="test">
<input type="button" value="dinosor_print!!" onClick="OnClickmake()"/>
</form>
<div id = "dino"></div>
<body>
<script type="text/javascript">

function OnClickmake(){
	var min=2;
	var max=6;
	//表示する画像の個数
	var num_dino=Math.floor( Math.random() * (max + 1 - min) ) + min;
	//表示する画像の種類
	var type0=Math.floor( Math.random() * (max + 1 - min) ) + min;
	appendImage(num_dino,type0);
}


function appendImage(num1,d_type) {
	if (!document.createElement || !document.getElementById) return;

	alert(num1);
    var str_dino="";
    //１つのイメージタグに設定する内容
    var c_dino="";
    //イメージのid
    var str_id="";
    //４以下ならばステゴディアス
    if(d_type<4){
		img_src="./stedia.jpg";
	//4以上ならインドミナスレックス	
    }else{
    	img_src="./indominas.jpg";
    }
    for(var i=0;i<num1;i++){
    	//イメージのid ダブルコーテーションはエスケープ(\)が必要
    	str_id="\""+"img"+i+"\"";
    	c_dino="<img id="+str_id+ " src = "+img_src+" width=\"360\" height=\"240\"><br><br>";
		str_dino=str_dino+c_dino;
	}
	document.getElementById("dino").innerHTML = str_dino;
	
}
</script>
</body>
</html>

```
###実行結果

上記の2つの画像にそれぞれstedia.jpg,indominas.jpg
と名前を付けて、ソースと同じフォルダにおいてブラウザで実行すると
下記のような画像が表示されます。

![dino_random_image1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494408/ab7c902c-7748-25ec-66be-1ac1879358ba.jpeg)
JavaScript勉強の記録その15: 配列にオブジェクトを格納するデータ構造

#配列とオブジェクトを組み合わせたデータ構造

配列にオブジェクトを格納されてあるようなデータ構造もあります。
以下の例では、pointsという定数に配列が代入してあり、その配列は２つのオブジェクトを持っています。
プロパティーへのアクセスは、　配列名[インデックス番号].キー　と記述することで可能になります。

```index.js
const points = [
  {x: 100, y: 180},
  {x: 120, y: 160},
];

console.log(points[0]);
//=>{x: 100, y: 180}
console.log(points[0].x);
//=>100
```
時短テクニック精度アップ法

# 前述
> 皆さん、あけましておめでとうございます。昨年末は、githubのwiki中心に活動していて、キータ更新が疎かになっておりました。今年は月１，２ペースで更新できたらなと思います。本年も技術メモや効率改善などを書いていきますので、本年もよろしくお願いいたします。

# 背景
> 新年最初の投稿としまして、今年の総括テーマとして、「時短テク」です。
目標を立てるにあたり、昨年は、仕事や家庭において総括して通勤の移動時間も含めて、まだ時間を有効に使えてなかったのかなと感じました。

# 時短テクとは
知っての通り、時間短縮テクニックの略です。
※１日２４時間を分割すると、睡眠で６～８時間、定時で基本８時間を削ると、残りは８～１０時間程度しか残らない。その中で通勤時間を平均１時間とした場合、１０時間満たないのです。

# 目的
> しっかり計画を立てて、残業を減らす。またはなくす方法を考えていき、時間を有効に使えるようにしたい。

# どう実践するのか？
> google先生に絞り込むだけでも以下の絞り込みがある、、、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57249/19dc5a43-88d4-feab-90b1-69c2dd7cbd99.png)

## 仕事編として仕様面等で感じたこと   
### １．コミュニケーションスキル、コミュニケーションロス
> 状況把握をどう報連相するかがポイント:point_up: 
 
### ２．コミュニケーションツールが正しく使われていない
> 現場によっては、メールしか、、とかチャットオンリーで現場ごとに接し方が変わる 
 
### ３．理解期間が短いため、時間外突入してしまう
> これについては仕様の難易度や個人の理解力スキルによるので一概には直接的に関係ないが、たいていリリース日がずらせない点で残業発生したりする。  

### ４．ソース管理ツールが正しく使えてない人までいる

## 実践していきたい５か条のポイント
### １．依頼された作業を１５分～３０分程で細分化
> 細分化して、泥沼しそうな作業があるなら、そこで１度相談してみる。
自分では泥沼する考えしかなくても、分かる人に聞けば、瞬殺に終わる場合もある。

### ２．１の上で、どう相談するか、内容を簡単に細分化してメール
> 口頭だと、言い忘れあったりで時間が無駄になるため。自分用チーム用に
バックアップにもなるため、テキスト化をおすすめ:point_up:

### ３．報告はAM１回、PM１回で少なく、相談は、相手の状況を確認しOKの場合のみ、報告よりも多めにシンプルに、懸案が出たら、分かりすく相談しましょう

### ４．朝出勤したら、WBSの確認を前提に朝会等で今日のゴールを決める。
> 決まったら、チームメイトやリーダーと話し合って、時間内か時間外か、時間外なら、何時までかをあらかじめ決めておく。
> 仕様等が不定で帰る時間が不明なときは、お昼あたりまで待ってみる。それまでは今の作業か、作業がなければ、リーダーに相談。
> 夕方時点で、今日のゴールに届かない場合は、手詰まりとなっている懸案事項を丁寧に相談する⇒その上で残るか明日か決める

### ５．作業イメージは、なるべく早めに相談して先に進める

# 世界の労働時間 国別ランキング
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57249/4414239c-228b-0aac-a831-87a3329d6a5e.png)
[https://data.oecd.org/emp/hours-worked.htm](https://data.oecd.org/emp/hours-worked.htm)

> なぜ「働かない大国」ドイツの社会はまわるのか　住んで分かった日本との大きな違い
[https://news.livedoor.com/article/detail/17656618/](https://news.livedoor.com/article/detail/17656618/)

# さいごに
> 作業に集中かつ報連相を忘れずに正しく伝えて時間を有効にしてエンジニアライフを楽しくしていきましょう！
hp probook 450 & Ubuntu 18.04LTSでWiFiがつながらない時

https://h30434.www3.hp.com/t5/Notebook-Wireless-and-Networking/No-WiFi-option-in-Ubuntu-18-04-in-HP-ProBook-450-G5/m-p/6909187/highlight/true#M158093
このやり方でいけた。

# ネットワークカードのMT7630eが強敵すぎる
これを試したが、不安定。5分に一回WiFiのonとoffをしないと切れる。
https://askubuntu.com/questions/1084991/mediatek-mt7630e-wifi-chipset-unstable-conection

これも試した。ガッだめ！
`iwconfig`
`sudo iwconfig wlp3s0f0 (replace with your indentifier) power off`
http://forum.ubuntu-fr.org/viewtopic.php?id=2029975
JavaScript勉強の記録その14: Object.keys(オブジェクト名)を利用してオブジェクトのプロパティーを操作

#Objet.keys(オブジェクト名)を利用して、オブジェクトのプロパティーを操作

オブジェクトのプロパティーの値を全て取り出したい場合は、forEachは使えません。なぜならforEachは配列に対するメソッドだからです。

代わりにObject.keys(オブジェクト名)というメソッドを使い、オブジェクトのキーを取得し、取得したキーを利用してオブジェクトの値を取り出す方法があります。

まず、以下の例ではObject.keys()の基本的な動きを確認できます。

```index.js
const point = {
  x: 100,
  y: 180,
};

const keys = Object.keys(point);
console.log(keys);
//=>["x", "y"]

keys.forEach(key => console.log(`Key: ${key}`));
//=>Key: x
//=>Key: y
```

Object.keys()を使うことで、キーを取得して配列に格納しているのがわかるかと思います。
この仕組みを利用してループ処理をしてあげれば、オブジェクトの各プロパティーへアクセスすることができます。

```index.js
const point = {
  x: 100,
  y: 180,
};

const keys = Object.keys(point);
console.log(keys);
//=>["x", "y"]

keys.forEach(key => console.log(`Key: ${key}　Value: ${point[key]}`));
//=>Key: x Value: 100
//=>Key: y Value: 180
```
kuromoji を Win10 + Eclipse + Java の環境で動かす (2020年1月版)


さすがはJava製のkuromojiはOSに依存することもなくMavenにも対応しているので、とても導入しやすくて使いやすいです。

本投稿のタイトルにはWin10とEclipseと入れておりますが、kuromojiはどちらにも依存していません。

# Maven

セットアップはたったこれだけ。
モデルデータもダウンロードされます。

```xml
<!-- https://mvnrepository.com/artifact/com.atilika.kuromoji/kuromoji -->
<dependency>
	<groupId>com.atilika.kuromoji</groupId>
	<artifactId>kuromoji</artifactId>
	<version>0.9.0</version>
	<type>pom</type>
</dependency>
<dependency>
	<groupId>com.atilika.kuromoji</groupId>
	<artifactId>kuromoji-ipadic</artifactId>
	<version>0.9.0</version>
</dependency>
```

# Code

サンプルコードそのままです。

```java
// https://www.atilika.com/ja/kuromoji/
package hello.kuromoji;

import com.atilika.kuromoji.ipadic.Token;
import com.atilika.kuromoji.ipadic.Tokenizer;
import java.util.List;

public class KuromojiExample {
	public static void main(String[] args) {
		Tokenizer tokenizer = new Tokenizer();
		List<Token> tokens = tokenizer.tokenize("お寿司が食べたい。カレーも食べたい。");
		for (Token token : tokens) {
			System.out.println(token.getSurface() + "\t" + token.getAllFeatures());
		}
	}
}
```

## 実行結果

```
お	接頭詞,名詞接続,*,*,*,*,お,オ,オ
寿司	名詞,一般,*,*,*,*,寿司,スシ,スシ
が	助詞,格助詞,一般,*,*,*,が,ガ,ガ
食べ	動詞,自立,*,*,一段,連用形,食べる,タベ,タベ
たい	助動詞,*,*,*,特殊・タイ,基本形,たい,タイ,タイ
。	記号,句点,*,*,*,*,。,。,。
カレー	名詞,一般,*,*,*,*,カレー,カレー,カレー
も	助詞,係助詞,*,*,*,*,も,モ,モ
食べ	動詞,自立,*,*,一段,連用形,食べる,タベ,タベ
たい	助動詞,*,*,*,特殊・タイ,基本形,たい,タイ,タイ
。	記号,句点,*,*,*,*,。,。,。
```



# 所感

Kuromoji はとても使いやすいです。

# 参照

## 参考にしたページ

kuromoji | Atilika
https://www.atilika.com/ja/kuromoji/
Markdown記法：改行の検証 <br>タグで改行できるよ

Markdown記法で文章かけるように練習しようと思い、ブログでもMarkdown形式書いていこうと決めました。  
しかし、すぐにあたる壁。  
いい感じに改行できない...；
<br />
というわけでMarkdownの改行について調べました！
<br /><br /><br />

#Markdownの改行方法
##エンターで改行
```:markdown
1行目
↑エンター改行

↑エンター1回分の空改行


↑エンター2回分の空改行


↑エンター3回分の空改行
```
[結果]
>1行目
>↑エンター改行

>↑エンター1回分の空改行


>↑エンター2回分の空改行


>↑エンター3回分の空改行

何回エンターで改行しても、1回分のエンターの改行しか認識しませんね。

##半角スペース2個
```:markdown
1行目  
↑半角スペース2個
***
2行目    
↑半角スペース4個
***
3行目  

↑半角スペース2個＋エンター1回
```
[結果]
>1行目  
↑半角スペース2個
***
2行目    
↑半角スペース4個 
***
3行目  

>↑半角スペース2個＋エンター1回

半角スペースでの改行は2個だけ認識されて、それ以上半角スペースを増やしても認識されませんね。  
また、半角スペース改行とエンター改行を組み合わせても、改行は1行分しか認識されません。
##brタグを使う
```:markdown
1行目<br>
↑br1個<br><br>
↑br2個<br><br><br>
↑br3個<br><br><br><br>
↑br4個
```
[結果]
>1行目<br>
↑br1個<br><br>
↑br2個<br><br><br>
↑br3個<br><br><br><br>
↑br4個

brタグを使えば、複数行で改行が可能ですね！  
便利！

##まとめ  
brタグを使えば、複数改行可能。  
コード的にbrの文字が繰り返されると、少し見にくいような気もします。  
ですので単改行であれば半角スペース2個が良さそうです。
<br>
<> <-これを入れるのが面倒な方は[辞書登録](https://www.atmarkit.co.jp/ait/articles/1806/12/news021.html)しておきましょう。  
僕は読みが「br」でbrタグが出てくるようにしています。

#References
- [はてなブログのマークダウン記法で空白行を入れる](https://kiyoshi.hatenablog.com/entry/2017/12/14/091627)
- [MarkDown記法](https://qiita.com/Blueman81/items/72ca43681d16d44e21ad)
tektonでPrivate Github Repositoryをcloneする

# 目的
tektonのtask-run内でprivateなgithub repositoryを扱います．

### Version
- tekton v0.9

# 事前準備
はじめにtutorialにある[hello world](https://github.com/tektoncd/pipeline/blob/master/docs/tutorial.md)を準備します

```yaml
apiVersion: tekton.dev/v1alpha1
kind: Task
metadata:
  name: echo-hello-world
spec:
  steps:
    - name: echo
      image: ubuntu
      command:
        - echo
      args:
        - "hello world"
---
apiVersion: tekton.dev/v1alpha1
kind: TaskRun
metadata:
  name: echo-hello-world-task-run
spec:
  taskRef:
    name: echo-hello-world
```

# やってみる
今回はSSH Keyを使用してPrivate Github Repositoryをclonseします(参照: [pipeline/auth](https://github.com/tektoncd/pipeline/blob/master/docs/auth.md))．
そのためtaskを書く前にkubernetes上でSecretとService Accountを作成する必要があります．

Secretには，`ssh-privatekey` と `known_hosts` をbase64にしたものをdataとして設定します．
ssh-privatekeyに関しては適宜作成，known_hostに関しては下記コマンドで取得できます

```shell
$ ssh-keyscan github.com | base64
```

作成したbase64の文字列をyamlファイルに保存します．

```yaml
# ref: https://github.com/tektoncd/pipeline/blob/master/docs/auth.md#ssh-authentication-git
apiVersion: v1
kind: Secret
metadata:
  name: ssh-key
  annotations:
    tekton.dev/git-0: github.com # Described below
type: kubernetes.io/ssh-auth
data:
  ssh-privatekey: <base64 encoded>
  known_hosts: <base64 encoded>
```

実際は，[kubesec](https://github.com/shyiko/kubesec)を使用して暗号化しておくのがbetterです．

```yaml
apiVersion: v1
data:
  known_hosts: mTDLhG7c...
  ssh-privatekey: QIg2T...
kind: Secret
metadata:
  annotations:
    tekton.dev/git-0: github.com
  name: github-ssh-key
  namespace: tekton-playground
type: kubernetes.io/ssh-auth
# kubesec:v:3
# kubesec:gcp:projects...
```

これらをapplyします

```shell
$ kubectl apply -f <FILE>
$ kubesec decrypt <FILE>  | kubectl apply -f -  # kubesecを使ってる場合
```

ServiceAccountも作成します

```yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: github-account
secrets:
- name: ssh-key
```

Secret類が用意できたので，TaskRun内で使用していきます．
TaskRun内で使用するために，PipelineResourceの作成，TaskにInputを追加，TaskRunにてInputするResourceの指定を行います．

はじめにPipelineResourceを作成します
今回はSSH Keyを使って認証を行うためgit@から始まるURLを指定する
なおPublicなGithub Repositoryならhttpsから始まるURLでも大丈夫です．

```yaml
apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
  name: private-repository
spec:
  type: git
  params:
  - name: url
    value: git@github.com:<Private Repository>.git
  - name: revision
    value: master
```

次にTaskにInputを追加，TaskRunにてInputするResourceの指定します

```yaml
apiVersion: tekton.dev/v1alpha1
kind: Task
metadata:
  name: echo-hello-world
spec:
  inputs:
    resources:
    - name: repository
      type: git
  steps:
    - name: echo
      image: ubuntu
      command:
        - echo
      args:
        - "hello world"
---
apiVersion: tekton.dev/v1alpha1
kind: TaskRun
metadata:
  name: echo-hello-world-task-run
spec:
  serviceAccountName: github-account
  taskRef:
    name: echo-hello-world
  inputs:
    resources:
    - name: repository
      resourceRef:
        name: private-repository
```

以上で完了です．

```
$ kubectl apply -f <task file>
```
で確認してみてください

# まとめ
tektonでPrivate Github Repositoryをcloneする方法をまとめました．
docx.jsを使って、ブラウザでMS Wordファイルを書き出せるようになるまで

#概要
Wordファイル（.docx）を書き出すためのライブラリ docx.js をブラウザで動かすための手順。
https://docx.js.org/

公式にブラウザでも動くとなっているのですが、ドキュメントのサンプルが基本、node.jsベースになっており、私のスキル不足も相まって意外とハマったので、全手順をメモしておきます。

#ポイント
- node.jsでは、最終的なファイル書き出しは、fsモジュールを使うらしいが、ブラウザでは動かないので、FileSaver.jsを使う


#手順
npmの初期化。対話式で聞かれる設定は適当に設定します。ただし、**ここで名前をdocxとしないこと**。後に名前の競合で進めなくなります。

```
npm init
```

docxのインストール

```
npm install docx --save-dev
```

webpackのインストール

```
npm install webpack webpack-cli --save-dev
```

HTMLの準備
ざっくり以下のような感じで、webpackでこれから書き出す```docx_browser.js```と```FileSaver```をロードし、```generate()```というメソッドをボタンで呼ぶようにする。

```html:index.html
<html>
	<head>
		<meta charset="utf-8">
		<title>docx sample</title>
		<!-- script by webpack -->
		<script src="docx_browser.js"></script>
		<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.8/FileSaver.js"></script>
	</head>
	<body>
		<h1>docx sample</h1>
		<button onclick="generate()">Generate DOCX</button>
	</body>
</html>
```

jsの準備
https://docx.js.org/#/?id=basic-usage
こちらを参考にするが、以下を変更（変更箇所コメントいれています。）

- 1行目の ```import * as fs from "fs";``` は削除
- ファイル書き出し部分をブラウザ用に書き換え
- 全体を```function generate()```で囲み、HTML上から```generate()```呼び出すために、グローバル関数にする命令を追加

```javascript:./src/main.js
//不要コメントアウト
//import * as fs from "fs";
import { Document, Packer, Paragraph, TextRun } from "docx";

//全体をfunctionで囲む
function generate() {
	// Create document
	const doc = new Document();

	// Documents contain sections, you can have multiple sections per document, go here to learn more about sections
	// This simple example will only contain one section
	doc.addSection({
		properties: {},
		children: [
			new Paragraph({
				children: [
					new TextRun("Hello World"),
					new TextRun({
						text: "Foo Bar",
						bold: true,
					}),
					new TextRun({
						text: "\tGithub is the best",
						bold: true,
					}),
				],
			}),
		],
	});

	// Used to export the file into a .docx file
	//ブラウザ動作用に書き換え
	/*
	Packer.toBuffer(doc).then((buffer) => {
			fs.writeFileSync("My Document.docx", buffer);
	});
	*/
	//以下ブラウザ動作用
	Packer.toBlob(doc).then((blob) => {
		saveAs(blob, "output.docx");
		console.log("Document created successfully");
	});

}

//グローバル関数にする
window.generate = generate;

```

webpackでビルドする

```
npx webpack --mode development ./src/main.js --output docx_browser.js
```

以上です。

#実行結果
ブラウザで表示
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24420/1d7214bf-f373-bc19-dfb2-7b3f5f1d41d5.png)

書き出されたWordファイル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24420/8c1f1f13-7fda-cca0-da5d-1ea1892511e0.png)

#動作環境

- IE11は動きません。

#おまけ

いくつか同名の別ライブラリがあり、それを取り扱った日本語記事もあるのですが、ここで紹介したものが唯一メンテナンスされています。
メンテが止まっている別ライブラリ
https://github.com/MrRio/DOCX.js
https://github.com/stephen-hardy/DOCX.js

他に使えそうなライブラリ（まだ試していない）
https://github.com/guigrpa/docx-templates
テンプレートファイルを書き換えるという方法で生成する。
k3s v1.0.0 リリースノート翻訳

毎度、ググっても出てこない小ネタを取り扱っております。
本記事は個人的な見解であり、筆者の所属するいかなる団体にも関係ございません。

この記事は、Rancher Labs社のk3s v1.0.0のリリースノート(原文は以下)を翻訳したものです。

Release v1.0.0 · rancher/k3s
https://github.com/rancher/k3s/releases/tag/v1.0.0

--------

最初の構想から1年以上が経って、K3sがv1.0.0に到達したことを発表できることを誇りに思います。このリリースでは、安定性と品質を重視しながら、引き続き新しい便利な機能を提供しています。

K3sはKubernetesに完全に準拠したディストリビューションで、小さなフットプリントと操作の容易さを提供することに焦点を当てています。K3sは、Kubernetesスタック全体を1つのバイナリにパッケージ化していて、以下の機能が組み込まれています:

* Kubernetes マスターコンポーネント: kube-apiserver, kube-scheduler, kube-controller-manager, and cloud-controller-manager
* Kubernetes ノードコンポーネント: kubelet and kube-proxy
* コンテナランタイムとしてのcontainerd
* クラスターDNSのCoreDNS
* クラスターネットワークのFlannel
* kubectl、crictl、ctrを含んだCLIのユーティリティー
* etcdを置き換える組み込みSQLiteデータベース

Kubernetesスタックのベースの機能を越える以下のような機能のパッケージも同梱しています:

* [Traefik イングレスコントローラー](https://docs.traefik.io/providers/kubernetes-ingress/)
* Traefikによりインプリメントされた[サービスロードバランサー](https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer)
* [独自実装のローカルパスのストレージドライバープロビジョナー](https://github.com/rancher/local-path-provisioner)
* 私たちの新しいKubernetesデータストアインターフェースKINEによりSQLite、DQLite、MySQL、Postgres、etcdといったユースケースに最適なデータストアバックエンドを選択することを可能にします。
* ユースケースに最適なデータストアバックエンド(SQLite、DQLite、MySQL、Postgres、etcdなど)を選択できる独自実装の新しいKubernetesデータストアインターフェイス[KINE](https://github.com/rancher/kine)。
* ヘルムチャートを管理するためのCRDおよびコントローラパラダイムを提供する独自の[Helmコントローラ](https://github.com/rancher/helm-controller)
* helmチャートを管理するためのCRDとコントローラーパラダイムを提供するhelmコントローラー
* IPSecまたはWireguardで暗号化されたネットワーク

これらはすべて、amd64、arm64、およびarmhfアーキテクチャで動作する50MB未満の単一バイナリで提供されます。
Googleで検索結果に戻ったときの「他の人はこちらも検索」を非表示にする方法

Google の検索結果に戻ってきたとき、リンクの下に "他の人はこちらも検索" と表示されてリンクが動いてしまうのを防ぐ方法です。Chrome, Brave, Firefox, Safari に対応しています。ただしモバイル版では制約上不可能なようです。
ちなみに英語版では "People also search for" と表示されるようです。
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155587/3a764b58-6f9f-f69e-6aa5-9f65175b397d.png)

# Chrome / Brave
以下の拡張機能を追加するだけです。
[No Search For - Chrome ウェブストア
https://chrome.google.com/webstore/detail/no-search-for/gfilnngoaebchcnkmppbnijaakeccdjc](https://chrome.google.com/webstore/detail/no-search-for/gfilnngoaebchcnkmppbnijaakeccdjc)

※ プライベートモードでも使用したい場合は拡張機能設定の「詳細」から「シークレットモードでの実行を許可する」のチェックを入れてください。


またはカスタム CSS を追加することもできます。
https://gist.githubusercontent.com/shge/cccac34a618662d0ea7c25a5b0a681ad/raw/2debb136650da023b398ef34ef3a356e93277176/hide_people_also_search_for.user.css

```css
.exp-outline,
.rc > div:nth-child(3) {
    display: none !important;
}
```

# Firefox

まずはカスタム CSS を追加するための拡張機能を追加します。

[Stylus - Firefox (ja) 向け拡張機能を入手
https://addons.mozilla.org/ja/firefox/addon/styl-us/](https://addons.mozilla.org/ja/firefox/addon/styl-us/)

次に下のリンクから `Install style` をクリックするか、以下の CSS をコピーすると追加できます。

https://gist.githubusercontent.com/shge/cccac34a618662d0ea7c25a5b0a681ad/raw/2debb136650da023b398ef34ef3a356e93277176/hide_people_also_search_for.user.css

```css
.exp-outline,
.rc > div:nth-child(3) {
    display: none !important;
}
```

# Safari

以下の内容のファイルを拡張子 `.css` で作成し、Safari メニュー→環境設定→詳細→スタイルシートから選択します。

```style.css
div.srg > div.g > div > .exp-outline,
div.srg > div.g > div > div.rc > div:nth-child(3) {
    display: none !important;
}
```

すべてのウェブサイトに適用されてしまいますがまったく同じclassを使っているところはないと思うのでおそらく大丈夫です。

# iOS
iOS Safari ではコンテンツブロッカーを使用して特定要素を非表示にすることはできますが、モバイル版 Google では "他の人はこちらも検索" の表示と同時にサイトのタイトルの下に表示される説明文が非表示 (`display: none`) になってしまうため、結局リンクは動いてしまいます。
現時点でカスタムCSSを適用することは Safari の制約上不可能なようです。

# Android

以下の記事がヒットしましたが情報が古く、また Android 端末を所持していないため真偽はわかりません。
[Opera Mobileのユーザースタイルシートでサイトの見栄えを変更 特集その4](
http://android-smart.com/2011/08/opera-mobile%E3%81%AE%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%82%B9%E3%82%BF%E3%82%A4%E3%83%AB%E3%82%B7%E3%83%BC%E3%83%88%E3%81%A7%E3%82%B5%E3%82%A4%E3%83%88%E3%81%AE%E8%A6%8B%E6%A0%84%E3%81%88.html)

# 参考
https://keikenchi.com/how-to-hide-search-other-people-also-here
S3にAWS CLIからアップロードすると「Access Denied」が発生した

![s3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178837/cfc94803-17ab-712b-ffe2-0451a9dd199a.png)

#概要
ラズパイで撮影した画像をS3に送る時に、「Access Denied」が発生してS3にアクセスすることができず、解消に手間取ったので備忘録。

#事象
    aws s3 cp test.jpg s3://test/

上記のコマンドでS3へ画像を送ると以下のエラーが発生する。

    upload failed: ./kaitlyn-baker-vZJdYl5JVXY-unsplash.jpg to s3://test/kaitlyn-baker-vZJdYl5JVXY-unsplash.jpg An error occurred (AccessDenied) when calling the PutObject operation: Access Denied

IAMポリシーとか、IAMロールとかいろいろ見たけどどれも問題なさそう。

**ちなみにIAMユーザーに対してS3フルアクセスの権限を与えているので、ポリシーレベルでは問題ないはず。**

#原因
**MFAでの認証が取れていないため、アクセス拒否されていた。**

会社のAWS環境でなく個人のAWS環境で同じようにS3へアップロードしたところ問題なくUPすることができた。唯一の差分といえばIAMユーザーに対しMFAが割り当てられているかどうかぐらいだった。

#解消法

**CLIでMFAの認証を通してから、S3へアップロードしたところ本事象が解消した。**

MFAが有効になっているかどうかは、Identity and Access Management (IAM)の画面で確認することができる。

IAMユーザーの一覧画面でMFA項目が「仮想」になっていたらMFAが有効になっている。
その場合、AWS CLIでaws configureコマンドで設定を行ったあと、一時的なアクセスキーとシークレットキーを払い出し、環境変数に設定する必要がある。

以下のリンク先を参考にすればMFAの認証を行うことができる。
「AWS CLIのみでMFAを有効にする方法」
　http://blog.serverworks.co.jp/tech/2019/08/16/cli-mfa/
　※上記リンクの「6.CLIでのMFA認証方法」から参照してください。

#実行例

例として、「ターミナルを開いてからS3へアップするまでのコマンド」を上げておきます。

###1.AWSへの接続情報を準備

    $ aws configure
      AWS Access Key ID [none]: {アクセスキー}
      AWS Secret Access Key [none]: {シークレットキー}
      Default region name [none]: {リージョン}
      Default output format [none]: {フォーマット形式}

上記のキー設定・取得方法は以下を参照
「AWS CLIのインストールから初期設定メモ」
　https://qiita.com/n0bisuke/items/1ea245318283fa118f4a

###2.環境変数に接続情報を設定

    $ export AWS_ACCESS_KEY_ID= {アクセスキー}
    $ export AWS_SECRET_ACCESS_KEY={シークレットキー}
    $ export AWS_DEFAULT_REGION= {リージョン}
    $ export AWS_DEFAULT_OUTPUT= {フォーマット形式}

ここは１をやっていればやらなくても大丈夫かもしれないが念のため。
たとえばすでに別のAWSアカウントでCLIの接続をしたことがある場合。
環境変数に古い値が設定されていると１で設定した内容よりも環境変数で設定されている内容をAWS側で優先して見てしまうので念のため設定しておくことをお勧めする。

###3.一時情報の取得

    $ aws sts get-session-token  --serial-number {IAMユーザーのユーザーの ARN}  --token-code {MFAの認証コード６桁}

MFAの認証コード６桁については以下を参照
「AWSでMFA(二段階認証)を有効にする方法を超丁寧に説明するよ」
　https://qiita.com/viptakechan/items/6d19aee635b2ab189e47

###4.取得した一時情報を環境変数に設定する
３を実行すると以下のような結果が取得できる

    "Credentials": {
        "SecretAccessKey": "シークレットアクセスキー", 
        "SessionToken": "セッショントークン", 
        "Expiration": "2020-01-13T13:33:35Z", 
        "AccessKeyId": "アクセスキー"
    }

それを環境変数に以下のような形式で設定する。

    export AWS_ACCESS_KEY_ID={アクセスキー}
    export AWS_SECRET_ACCESS_KEY={シークレットアクセスキー}
    export AWS_SESSION_TOKEN={セッショントークン}

###5.S３へアップロードする

    aws s3 cp {ローカル状の画像の配置パス} s3://{バケット名}/

#あとがき
この手順でS3にアップロードできるかと思います。
もしAccess Deniedが発生して、「ポリシーもロールも問題ないんだけどなぁ」って感じであれば、試してみてください！
GAS エラーログを具体的に出力する（コピペOK）


GASでログを出力する時に割といつも面倒なのでフレームワーク化したらここはこうしたい。

```javascript

function execErrorDetails(error) {
  var resultMessage = "message:" + error.message + "\nfileName:" + error.fileName + "\nlineNumber:" + error.lineNumber + "\nstack:" + error.stack
  Logger.log(resultMessage)
  return resultMessage
}
```


```javascript
[20-01-13 11:18:09:430 JST] message:「a」が定義されていません。
fileName:main
lineNumber:45
stack:	at main:45 (append)
	at main:26 (setMonthlyReport)
	at main:2 (jobSetMonthlyReport)
```
Curl の http クライアントの使い方 (Post)

curl で POST を行う方法です。
実行結果は同じです。

1) パラメーター名と値を与える。

```bash。
curl -X POST https://httpbin.org/post -d 'user=jiro' -d 'password=123456'
```

２）JSON　形式で値を与える。

```bash
curl -X POST -H "Content-Type: application/json" \
	-d '{"user":"jiro","password":"123456"}' \
	https://httpbin.org/post
```

３）JSONファイルを使う。


```bash
curl -X POST -H "Content-Type: application/json" \
	-d@in01.json \
	https://httpbin.org/post
```

```json:in01.json
{"user":"jiro","password":"123456"}
```
Laravel FormRequestの５００エラー

正常時
index.blade.php -> Controller@add(add_flag) -> Model@addバリセーフ-> index.blade.php
index.blade.php -> Controller@edit(edit_flag) -> Model@updateバリセーフ -> index.blade.php
バリデーションアウト時
index.blade.php -> Controller@add(add_flag) -> Model@addバリアウト -> index.blade.php
index.blade.php -> Controller@edit(edit_flag) -> Model@updateバリアウト -> **500エラー**
改善例
index.blade.php -> Controller@edit(edit_flag) -> Model@updateバリアウト -> Controller@reEdit -> index.blade.php

index.blade.phpとFormRequestを使いまわして、
追加処理画面と編集画面を兼用した場合の話。

FormRequestを設定して@addと@editの引数のバリデーションしたら、
@editの方だけが500エラーがでて動かないことがありました。
その対処法の一つです。

FormRequestを分けます。
エラーの出なかった@addはそのまま。
エラーの出た@update用をUpdateRequest等とします。

```php:UpdateRequest
public function rules()
{
//@addのものと同じ
}
//以下追加
protected function failedValidation(Validator $validator)
{
    $this->merge(['validated' => 'true']);
    throw new HttpResponseException(
        //編集 -> バリデーションチェックNG -> リダイレクト
        redirect(route('Controller.reEdit'))->withErrors($validator)->withInput()->with('request', $this->request)
    );
}
```
なんてことはありません。
エラーを拾ってバイバス用の@reEditメソッドへ飛ばしているだけです汗

```php:web.php
Route::get('/index', 'Controller@index')->name('Controller.index');
//getメソッドとすることで正常動作
Route::get('/reedit', 'Controller@reEdit')->name('Controller.reEdit');
```

```php:Controller@reEdit
public function reEdit(Request $request) {
    $old_input = $request->session()->get('_old_input');
    //$usersが複数形なのはindex.blade.phpの引数に合わせてます
    //違和感バリバリですみません・・
    $users = new Model;
    //バリデーションアウトなデータを直してもらうために
    $users->id = $old_input['id'];
    $users->name = $old_input['name'];
    $users->tel = $old_input['tel'];
    $is_edit = true;
    return view('Controller.index', compact('is_edit', 'users'));
}
```

以上です。

追加画面と編集画面を分けていればおそらくこんなことにはならない。
コードの好みの問題かなあ。
JavaScript勉強の記録その13: スプレッド構文とレスト構文を使ったオブジェクトの操作

#スプレッド構文を利用したプロパティーの結合

スプレッド構文を利用して、２つのオブジェクトのプロパティーを結合することができます。

```index.js
const otherProps = {
  r: 4,
  color: 'red',
}

const point = {
  x: 100,
  y: 180,
  ...otherProps,
};

console.log(point);
//=>{x: 100, y: 180, r: 4, color: "red"}
```

#レスト構文を利用してプロパティーの値を分割代入する

レスト構文を使って、オブジェクトの分割代入をすることもできます。

```index.js
const otherProps = {
  r: 4,
  color: 'red',
}

const point = {
  x: 100,
  y: 180,
  ...otherProps,
};
const {x, y, ...others} = point;

console.log(x);
//=>100
console.log(y);
//=>180
console.log(others);
//=>{r: 4, color: "red"}
```
#Rails / has_one and has_many association both / without DB foreign key

You can specify both

```rb
class User < ApplicationRecord
  has_one :book
  has_many :books
end
```


If use has one association and user has many books

```
user.book
```

then it  maybe returns newest one "book" instance
but it does not return older other instances

# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/2940








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
#Rails で DBに外部キー制約がない場合 has_one と has_many のアソシエーションを両方指定できそうだ

You can specify both

```rb
class User < ApplicationRecord
  has_one :book
  has_many :books
end
```

userが持つbookが複数ある場合にhas_oneを見ると、最新のbook一個だけが得られた

```rb
user.books.size # 3

user.book # Return latest book instance a user has
```



# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/2941








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
Q6.配列を使用するには？


前回のQ5で行ったことを配列を使用して再現してみるにはどうしたらいいでしょうか？

ちなみに前回の記事はこちら
[Q5.特定の条件に合致するセルの情報を取得するには？][1]
[1]:https://qiita.com/guren111/items/40af20cc74d958603993



さて、前回使ったデータはこちらです。
![Q5-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560479/e24b6007-2195-1971-d458-98a1fafb736c.png)

Q5では、ForEach文を利用して、Rangeの情報を取得して30歳以上の人が
何人いるかをカウントしました。


今回は、同じようなことを配列を利用して実現する方法を考えていきます。
20歳以下の人を調べて、20歳以下だった場合、名前をまとめて、最終的に
20歳以下の人はこちらです。といった具合に20歳以下の人を表示するマクロを作ってみましょう。


### ■配列を利用する
配列を利用するのはとても簡単です。
変数を宣言するのと同じように、

Dim　変数名(要素数) as データ型名

といった記述です。


ここで、注意しておきたいのが、要素数が分かっているかという点です。
今回は、より簡単な要素が分かっている場合について説明します。

要素数があらかじめわかっている場合は、要素数をそのまま宣言時に指定してあげればOKです。
ちなみに、要素数が分かっていない場合は何も記載せず空にして宣言します。


###■回答
では、マクロを見ていきましょうこちらです。

```VB
Sub Q6_Answer()
    Dim Names(6) As Variant
    Dim j As Variant
    Dim i As Range
    Dim massage As String
    Dim index As Integer
    For Each i In Range("C2:C8")
        If i.Value >= 20 And i.Value < 30 Then
            Names(index) = i.Offset(0, -1).Value
            index = index + 1
        End If
    Next i
    
    For Each j In Names
        If Not IsEmpty(j) Then
            massage = massage + j + "さん" + vbLf
        End If
    Next j

    MsgBox "20代の人は" & vbLf & massage & "です。"
    
End Sub
```

###■解説

まず、1行目のDim Names(6) As Variantで、
配列の宣言をしています。
この配列に、20代の人の名前を格納していきます。

今回は、あらかじめ人数が分かっている前提で作成しているので、
このようになります。
ちなみに、7人いるにも関わらずNames(6)としているのは、
配列の要素は0から始まるからです。
この場合、Names(0)からNames(6)までの配列となります。

if文にあるAndは複数の条件に合致したものを判定するのに利用します。
今回は20代以上なので、このように、

If i.Value >= 20 And i.Value < 30 Then

Andを使って複合条件を記述しています。


これで、20代の人をNamesという配列に格納することができました。

ただし、Namesという配列には値が入っている要素とそうでない要素があります。
7人の人全員が20代であるならば、すべて埋まるのですが、そうでない場合は、
空の要素とデータが入っている要素が混在していることになります。

ForEach文を利用して配列の要素ひとつひとつを確認していきます。

If Not IsEmpty(j) Thenという記述で、空でなかった場合という意味になります。
IsEmptyは要素が空かどうかを調べる関数です。空であれば、TRUEを返します。
この記述では、頭にNotを付けているので、TRUEでない場合、
つまり、空でない場合となります。

空でなかった場合に、messageという変数に名前を連結して、格納していき最後に表示させています。


今回はこのように配列を使用する為に、あえてこのようの冗長な記述になっていますが、
同じことを実現するには、後半のForEach文はいらなかったりします。
というかそもそも配列を使う必要も実はあまりなかったりします。

が、あくまで配列を使うには？という観点で見ていただけたらと思います。
(もっといい例があれば、また別の機会に取り扱いたいと思います。)

最後にマクロを実行した結果を載せておきます。


![Q6-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560479/8d64832e-fab9-9070-ffa8-683168204e3c.png)
'Placement new' について実験してみた

# 0. はじめに
Effective C++ 第3版 52項 「プレースメントnewの定義を書いたらプレースメントdeleteも書こう」に関して, 実験を通して理解を深めます.

検証環境はつぎのとおりです.

|構成要素|種類|
|:--:|:--|
|OS|macOS Catalina 10.15.2|
|clang|11.0.3|

また, ここで__プレースメントnew__とは__「size_t 以外に引数を受け取る operator new」__のことです.

# 1. コンストラクタで例外が発生したら, メモリ解放漏れになる
まず, つぎのとおり__'文字列を取るプレースメントnew'__を定義してみます.

```
#include <iostream>

using namespace std;

class A{
public:
    int a;

    A(int a){
        this->a = a;
    }

    ~A(){
        cout << "dctor" << endl;
    }

    // 文字列を取るプレースメントnew
    void* operator new(size_t size, const string& msg) {
        cout << "operator new! " << msg << endl;
        void* p = ::operator new(sizeof(A));
        return p;
    }
};

int main(){
    try{
        A* ap = new("Hello")A(5);
        cout << ap->a << endl;
        
        delete ap;
    }catch(exception& e){
        cout << e.what() << endl;
    }    
}
```

この実行結果は, つぎのとおりになります.

```
operator new! Hello
5
dctor
```
つぎに, コンストラクタで例外を発生させてみます.

```
    A(int a){
        this->a = a;
        throw exception();// 例外発生!!!
    }
```

この実行結果は, つぎのとおりになります.

```
operator new! Hello
std::exception
```

なるほど, 確かにデストラクタは呼ばれていません.
なお, このケースでは呼び出し元(main)で delete することはできません.

# 2. 対応するプレースメントdeleteを定義すれば, メモリを開放できることの確認

つぎのとおり, __プレースメントdelete__を定義してみます.

```
    // プレースメントdeleteが通常のdeleteを隠してしまうので, 通常版も定義しておく
    void operator delete(void* p){
        ::operator delete(p);
    }

    // プレースメントdelete
    void operator delete(void* p, const string& msg){
        cout << "operator delete!" << endl;
        delete static_cast<A*>(p);
    }
```

この実行結果は, つぎのとおりになります.

```
operator new! Hello
operator delete!
dctor
std::exception
```

なるほど, 確かに__「C++ランタイムが対応するプレースメントdeleteを探して実行してくれる」__ということは確認できました. なお, ここで注意したいのは実行するのはプレースメントの __operator delete__であって, __delete演算子__を実行するわけではないので, プレースメントdelete の実装でデストラクタが呼ばれるように保証しないといけないことです.

# 3. 補足
ん？あれ？
自分で「プレースメントdelete の実装でデストラクタが呼ばれるように保証しないといけないことです」とか書いて引っかかりました. それは次のケースでは通常の operator delete が呼ばれますが, その中でデストラクタを呼ぶような実装には当然なっていないからです.

```
#include <iostream>

using namespace std;

class A{
public:
    int a;

    A(int a){
        this->a = a;
        throw exception();
    }

    ~A(){
        cout << "dctor" << endl;
    }
};

int main(){
    try{
        A* ap = new A(5);
        cout << ap->a << endl;
        
        delete ap;
    }catch(exception& e){
        cout << e.what() << endl;
    }    
}
```

この路線で考えると, 「ごく普通のクラス定義のケースでもデストラクタが呼ばれるように毎回 operator delete を再定義しろ」ということになってしまいます. これはさすがにないな〜とおもいました.

最終的に__「コンストラクタの中できちんとお掃除してから, 呼び出し元でキャッチすべき意図的な例外を送出する実装・I/Fがある場合にきちんと動作させる (そのオブジェクト自体を開放する) 方法」__ということだと理解しました. なので, デストラクタは呼ばれなくてもいいと思います.

上のことを逆に解釈すると, 「コンストラクタから送出された例外を無闇にキャッチして続行するとメモリ漏れになる」とも言えると思います.
KubernetesのSecretを対話形式で作成・更新するツールを作った

KubernetesのSecretを作成あるいは更新するとき、base64したり、保存の必要のないYAMLファイルを作成するのが手間だったので簡単な対話型スクリプトを作ってみました。

secret.sh
https://gist.github.com/miyanaga/ec98fc28ab28b9302429f195d2c1ff99

シェルスクリプトは手習いなのでイマイチな部分はご指摘ください。

# 使い方

設定を変更します。

```bash
SECRET="my-secret" # Secret name
SECRETS="SECRET_KEY_BASE DATABASE_URL" # Data names
```

スクリプトを実行すると、各項目の値を聞かれるので入力します。

```bash
./secret.sh
SECRET_KEY_BASE: my-secret-key-base
DATABASE_URL: mysql2:my-mysql/database
```

YAMLの内容を確認されます。

```bash
apiVersion: v1
kind: Secret
metadata:
  name: my-secret
type: Opaque
data:
  # SECRET_KEY_BASE: "" -> "my-secret-key-base"
  SECRET_KEY_BASE: "bXktc2VjcmV0LWtleS1iYXNl"
  # DATABASE_URL: "" -> "mysql2:my-mysql/database"
  DATABASE_URL: "bXlzcWwyOm15LW15c3FsL2RhdGFiYXNl"

Apply with kubectl? (y/N):
```

`y`を入力するとYAMLを`kubectl`に食わせます。

```bash
secret/my-secret created

kubectl get secrets
NAME                            TYPE                                  DATA   AGE
my-secret                       Opaque                                2      10s
```

無事に`my-secret`が作成されました。

入力した値は`.k8s-secret-env`に保存され、次に実行したときデフォルト値として再利用されます。また、総じてヤバい値なので`.gitignore`にも追記されるおせっかい設計。

```bash
./secret.sh

SECRET_KEY_BASE [my-secret-key-base]: # 空でエンターキーを押すと my-secret-key-base を再利用
```

ぜひカスタマイズして活用ください！
#Rails が自動付与した fk_rails_... という名前の外部キーをマイグレーションで削除する

直接指定出来せるっぽい

もっと書き方やり方がありそうだけど

```rb
class RemoveUniqueIndexFromSomeTable < ActiveRecord::Migration[5.2]
  def change
    remove_foreign_key :some_tables, name: "fk_rails_43240587ab"
  end
end
```

```rb
db:migrate

== 20200112003437 RemoveUniqueIndexFromSomeTable: migrating ===============
-- remove_foreign_key(:some_tables, {:name=>"fk_rails_43240587ab"})
   -> 0.0250s
...
```

# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/2939








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->