OmniAICreator/Qiita-1.07M huggingface dataset:
VMware Horizon Client を簡単に切り替えるショートカットキー

## サマリー
VDIやリモート作業で、VMware Horizon Client for Windows を利用していると他のアプリへの切り替えが結構手間です。

普通はマウスで VMware Horizon Client メニューバーの最小化をクリックして、タスクバーから他のアプリをクリックするでしょう。
これだと2, 3秒くらいかかります。

ショートカットキーを利用することで、簡単に切り替えられます。
また、ノートPCタッチパッドの場合であれば、3本指スワイプ（左右）で一瞬です。

## 環境
* Windows 10
* Lenovo L380 ThinkPad

## ショートカットキー
`Ctrl` + `Alt` で VMware Horizon Client の非アクティブ化した後、 `Alt` + `Tab` でアプリを切り替える。

※残念な点として、この方法でアプリを切り替える場合、切り替え後のアプリが VMware Horizon Client だと、マウスクリックしないとアクティブになりません。
　最後に紹介している3本指スワイプだと、マウスクリックの必要なく VMware Horizon Client がアクティブにできます。

### VMware Horizon Client for Windows ショートカットキー

| ショートカットキー| 動作内容 |
|:--|:--|
| [Ctrl] + [Alt] | VMware Horizon Client の非アクティブ化 |
| [Alt] + o | VMware Horizon Clientのオプションメニューを開く（ [Ctrl] + [Alt] で Client を非アクティブ後） |
| [Alt] + c | パスワードロックの解除など（ [Ctrl ]+ [Alt] で Client を非アクティブ後） |

### Windows 10 ショートカットキー
| ショートカットキー| 動作内容 |
|:--|:--|
| [Alt] + [Tab] | 通常ウィンドウズショートカットキーによるアプリ切り替え |
| [Ctrl] + [Win] + ← →| 仮想デスクトップ切り替えの場合 |

## 3本指スワイプ（Windows10のタッチパッドジェスチャ機能）
ノートPCのタッチパッドの場合、3本指でスワイプ（左右）で、VMware Horizon Client をさくっと切り替えられます。

## 参考ページ
[キーボード ショートカット - VMware Horizon Client 4.5 for Windows ヘルプ](https://docs.vmware.com/jp/VMware-Horizon-Client-for-Windows/4.5/com.vmware.horizon.windows-client-45-help.doc/GUID-8B50FE4F-F7EC-4F15-A892-CC59ABFB0B3E.html)
[Windows 10の新しい「タッチパッドジェスチャー」を使いこなす - ITmedia PC USER](https://www.itmedia.co.jp/pcuser/articles/1508/06/news050.html)
Dockerの存在意義とは何か調べてみた（個人的見解も含みます）

#この記事の目的
技術的にDockerが使えるようになりたくて先日環境構築をして、「この作業いるのだろうか...というか逆にコンテナ消したり作ったりするから通信量ばかになってなくないか...なんか重いし...」とふと疑問が湧いてきたので調べてみました。

#Dockerとは結局何者なのか
非常に軽い仮想環境（バーチャルマシン）です。似たようなものとしてVMware,VirtialBox,bootcampなどがあります。

用途は環境構築(OS)からプロジェクト完成までの変化を記録してくれる、Gitの亜種だと理解するといいそうです。(筆者の感覚だとGitHubの亜種です）

環境構築を多人数で行う時、途中までをpushしておいて、途中から別な人がpullして付け加えていく使い方になります。

`docker pull`は`git pull`と同じで差分だけダウンロードされます。

#Dockerの良さは？
######バージョン管理の容易さと環境の準備の容易さ
ローカルの開発環境から独立し、OSの階層からアップロードされたものだけを使うため、gemのバージョンやOSの統一などを一切気にしなくて良くなります。MojaveとCatarinaという違いどころか、Windowsで同じプロジェクトをやっても大丈夫です。

######コンテナ化のシステムではダントツ軽い
通常コンテナを使う際にはOSを入れなければいけないのですがdockerだとOSにubuntuを使用すればストレージの使用量が123MBで済むためVMwareやbootcampなどと比べた時圧倒的に仮想環境で使用するストレージ容量が小さいです。bootcampでwindowsを快適に使うには50GBは必要です。

######デプロイがわかりやすい
AWSのEC2（Elastic Cloud Container）を使わずdockerで作成し、仮想環境で作ったものをそのままpullすればwebに公開できるのでわかりやすい、らしいです。（未実施なので今後確認します。ただ確かにEC2で作業していた時はコンパイルの問題とアプリケーションの起動の問題で悩まされており、それがDockerfileにRun ~ と書いてあるだけで動くならとても楽だと思います。ちなみに前回はcapistranoという自動デプロイ機能のgemのおかげでなんとか乗り切りました。）

#参考
https://iga-ninja.hatenablog.com/entry/2018/06/28/091412
【GAS】スプレッドシートのオートフィルタのフィルタをGASで操作する（日付によるフィルタ）

# GASでオートフィルタのフィルタリングを操作する
この記事は
`スプレッドシートのオートフィルタのフィルタをGASで操作する`、
という内容についての作業メモです。
2~3行のスクリプトでサクッと出来るかと思いましたが、少し面倒だったので記事にしたいと思います。

# フィルタルール
今回は、日付形式の値が入った列に対し、列の値が空白の行だけ表示するようにフィルタします。

# 手順

スプレッドシートのフィルタリングをGASで操作するには、基本は下記の流れでプログラムを記述します。

1. フィルタルールを作成する
2. フィルタルールを適用する

今回は、日付形式の列をフィルタに使用するので下記のようにします。

1. フィルタする列の値を配列に取得する
2. 日付のフォーマットを変換する
3. フィルタルールを作成する
4. フィルタルールを適用する

# 1.「特定の列が空欄のセルのみを表示」という条件でフィルタする
まずは、答えのコードを示します。

GoogleDriveを開き、GASファイルを新規作成して下記のように記述しました。

```Javascript:GAS
//15列目の対応日列が、空欄の行だけ表示するようにフィルタする。
//スプシには既にオートフィルタが適用されている。

function IncompleteFilter() {

  var spreadsheet = SpreadsheetApp.openById('key');
  var st = spreadsheet.getSheetByName("st_name")
  //コンテナバインドスクリプトにする場合↓
  //var spreadsheet = SpreadsheetApp.getActive();
  //var st = spreadsheet.getActiveSheet();

  var maxrow = st.getLastRow();
  var data = st.getRange(2, 15,  maxrow,1).getValues(); //①

  for(var i = 0; i < data.length; i++) {
    //② 日付の形式を変換する
    if(data[i]!= ""){
      data[i] = Utilities.formatDate( data[i][0], "JST" ,"yyyy/MM/dd" ); 
    }else if(data[i]== ""){
      data[i] = null;
    }
  }

  var criteria = SpreadsheetApp.newFilterCriteria()
   //③フィルタルール作成
  .setHiddenValues(data)
  .build();

   //③フィルタルール適用
  spreadsheet.getActiveSheet().getFilter().setColumnFilterCriteria(15, criteria);
};

```


# 解説
要点だけ説明していきます。

### フィルタルールは表示しない値を設定する
GASでフィルタする場合、`表示しない値を設定する`ようです。
マクロの記録により`.setHiddenValues(data)`というメソッドがあることがわかったので、`.setVisibleValues`もあるだろうと思ったのですが、使ってみたところ、「今は使えないのでsetHiddenに表示しない値を渡せ」というような内容のmsgが表示されました。

そこで、一旦列の値をすべて配列に入れて、その配列から表示する値を抜き取った配列を作り、その配列を.setHiddenValuesに渡しました。


### 日付データが入った配列を、フォーマットを変換する
フィルタに使用する列が日付形式の場合は、
セルには"2020/01/01"という形で文字列で入っている値でも、配列に入れるとDate形式になりました。

例：Mon Apr 27 19:33:33 GMT+09:00 2020

例えば、上記のデータをこのまま.setHiddenValues()の引数に渡しても、「"2020/04/27"」の行はフィルタされません。
お互いの形式が違うのでマッチしない為です。そのため`Utilities.formatDate`を使って日付形式を変換する必要がありました。
PIEと非PIEにおけるアセンブリでのグローバル変数アクセス

グローバル変数を扱うアセンブリを書いているときに、最初よく分からずに非PIEでのコードを書いてしまっていた。
最近のLinuxディストリビューションにインストールされているGCCはデフォルトでPIEとしてリンクしようとするため、非PIEのアセンブリコードはリンクに失敗してしまう。
そのあたりで少し調べたことをメモしておこうと思う。

なお、この記事ではx86-64のアセンブリを対象とし、アセンブリの記法にはIntel記法を使用する。また、検証環境はLinuxベースを前提としている。

# PIEとは

PIEとは、Position Independent Executable（位置独立実行形式）のことで、メモリアクセスが全て相対アドレスにより表現されており、メモリ上のどの位置に配置されても正しく実行できるというもの。
似たような用語でPICというものがあるが、こちらはPosition Independent Code（位置独立コード）のことで、PICで構成された実行形式をPIEと呼ぶ（と思う）。

PICは主に共有ライブラリなどで使用される技術だったが、最近はセキュリティの側面から実行形式にもPICを適用する流れがあるようだ。（[位置独立コードのWikipedia記事](https://ja.wikipedia.org/wiki/位置独立コード)）

# GCCの対応

GCCはもちろんPIEに対応しているが、GCCのビルド時のオプションに--enable-default-pieを付けるとデフォルトでPIEとして実行形式を出力するようになる。
自分の環境（Debian buster）にインストールされているGCCを確認すると、デフォルトPIEでビルドされていることが分かる。

```
$ gcc -v
...
Configured with: ... --enable-default-pie ...
...
```

# 確認用コード

やりたい処理をCで書くとこんな感じになる。整理のためのコードなので特に意味はない。

```c
long g;

int main() {
    g = 1;  
    return g;
}
```

グローバル変数をlongで宣言しているのはアセンブリでレジスタの扱いを64ビットに揃えるためで、Cのコードでみた場合はintで宣言したほうが自然にみえる気もするが、アセンブリ優先で書いてみた。

# 非PIEのアセンブリ

非PIEのアセンブリはこのようになる。

```:global_no_pie.s
    .intel_syntax noprefix

    .bss
g:
    .long 0

    .text
    .globl  main
main:
    push    rbp 
    mov rbp, rsp 
    mov rax, OFFSET FLAT:g # グローバル変数のアドレスを取得
    mov QWORD PTR [rax], 1
    mov rax, QWORD PTR [rax]
    pop rbp
    ret 
```

OFFSET FLAT:gでグローバル変数gのアドレスを取得しているわけだが、これは絶対アドレスでの表現となる。そのため、このコードをPIEとして出力することができず、エラーになってしまう。

```
$ gcc global_no_pie.s -o global_no_pie
/usr/bin/ld: /tmp/ccJR4M58.o: relocation R_X86_64_32S against `.data' can not be used when making a PIE object; recompile with -fPIC
/usr/bin/ld: final link failed: nonrepresentable section on output
collect2: error: ld returned 1 exit status
```

エラーメッセージで「recompile with -fPIC」として出ているが、この場合は-fPICを付けても結果は変わらない。
このメッセージはリンカであるldが出力しているようで、おそらくldはアセンブリが直接渡されたのではなく、（高級言語からアセンブリを出力するという意味での）コンパイル時に-fPICがついていないため、PIEとしてリンクすることのできないアセンブリが出力され、それがldに渡されていると想定しているのだと思う。

特に理由がなければ、下で説明するようなPIEとして出力可能なコードにすべきとは思うが、-no-pieのオプションを付ければ非PIEとしてリンクすることもできる。

```
$ gcc global_no_pie.s -o global_no_pie -no-pie
```

# PIEのアセンブリ

PIEとして出力できるアセンブリはこのようになる。

```:global_pie.s
    .intel_syntax noprefix

    .bss
g:
    .long 0

    .text
    .globl  main
main:
    push    rbp 
    mov rbp, rsp 
    lea rax, QWORD PTR g[rip] # グローバル変数のアドレスを取得
    mov QWORD PTR [rax], 1
    mov rax, QWORD PTR [rax]
    pop rbp
    ret 
```

やりたいことは非PIEと同じでグローバル変数のアドレスを取得したいのだが、ここではleaという命令を用いてripからの相対アドレスを計算している。ripはインストラクションポインタであるため、これから実行される命令がある場所からの相対値でグローバル変数にアクセスしているということになる。

# おまけ

アセンブリについて調べたいとき、GCCが出力するアセンブリを確認することがよくあるが、gccやobjdumpのデフォルトではAT&T記法で出力されたり表示されたりする。Intel記法にするには以下のようにオプションを付ければいい。結構コマンドごとに違って覚えにくいんだよね、、、

```
$ objdump -M intel -d <file>
$ gcc <file> -S -masm=intel
```

gccで出力されるアセンブリでの（初期値なしの）グローバル変数の宣言には.commというディレクティブが使用されるようだ。.bssセクションに変数を確保することを意味するらしい。

```
    .comm   g, 8, 8

# これと同じ
    .bss
g:
    .long 0
```

# まとめ

アセンブリでグローバル変数を扱う際の、PIE対応について整理した。
PIEと非PIEそれぞれでのリンカの処理とかもう少し深く理解したいが、まだまだ勉強不足。
いろんなwebサーバを使ってHelloWorld ～nginx編～その1


#はじめに
今回は前回IISでやった内容のnginx編です。
ちなみに前回のはこちら。

[いろんなwebサーバを使ってHelloWorld ～IIS編～その1](https://qiita.com/roku28632/items/9e7d265dc4cc0b8fa46e)
 
#資材の取得
まず、nginxの資材を手に入れます。
今回はここから取得します。

[nginx.org](http://nginx.org/en/download.html)
 
ダウンロードするのはstable、安定バージョンの「nginx/Windows-1.18.0」です。
ダウンロードできたら解凍して、すきなところに設置します。
<img width="882" alt="1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538462/71dc6d4b-2591-ee21-df84-03959868505b.png">

#nginxの起動
 nginx.exeを実行します。
ん...、一瞬起動したと思ったら何も変化がありません。
おかしいです。
logフォルダをみると、error.logが更新されていました。
logには下記のようにあります。
10013: An attempt was made to access a socket in a way forbidden by its access permissions
ぐぐってみると、どうやら既に使っているポートを利用しようとしているのがまずいようです。
一応何がポートを使っているのか調べてみます。
<img width="735" alt="2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538462/6b42eaf1-cd16-defc-e2bf-0976fe362697.png">


httpデーモンのようです。
あまり、記憶にありませんがとにかく80番ポートは別のサービスが使っていることがわかりましたので、他のポートを使うこととします。

#ポートの指定

IISのときは8080番を使ってましたので、一応8090番を使うことにします。
conf配下にある、nginx.confのポート部分を変更します。
<img width="300" alt="3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538462/412e9a08-9b6b-5f59-c920-495a773f13b4.png">

 
再度nginx.exeを実行します。
<img width="308" alt="4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538462/a94f3829-4957-3c82-c511-9df625ada30e.png">

 
firewallの通信メッセージが表示されたので、プライベートネットワークを指定しておきます。

#アクセス
アクセスしてみます。
<img width="633" alt="5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538462/a189e14f-0ce9-69b6-6fd4-87766ba9e88c.png">


できました。
あとは、オリジナルの画面にするだけです。
 
#他のPCからhtmlへのアクセス
nginx.confにlocaltionという記載があり、パスが書かれています。
デフォルトでは、htmlフォルダがそれにあたります。
index.htmlが既に存在しているので、HelloWorld.htmlを作って格納しました。
HelloWorldは前回と同じく「helloworld html template」と検索したらすぐ出てきたので、それを利用しました。
<img width="308" alt="7.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538462/5e5aa37d-194a-62b4-44e6-230079ceed38.png">

 
別のPCからアクセスしてみます。
<img width="779" alt="8.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538462/5c824825-4805-3716-3f0d-afae7f80796b.png">


できました！
IISの時と同じくタブの文字がバグっていますが、やりたいことができました。
【Docker】基本をざっくりメモ


#Dockerとは、、
サーバ環境をパッケージングできる仕組み。
osのバージョンから使用するライブラリ・ミドルウェアの構成等の実行環境をパッケージングすることで固定する。
そうしてDockerで作成された開発環境は配布しやすく、そのパッケージがあれば、環境を作ったり捨てたり（消したり）が簡単にできる。

#アプリケーション起動・実行までの流れ

1.アプリケーションの環境を Dockerfile ファイルで定義する。このファイルは、どこでも再利用可能。

2.アプリケーションを構成する各サービスを docker-compose.yml ファイルで定義する。そうすることで、独立した環境を一斉に実行できるようにしている。

3.最後に、`docker-compose up` を実行すると、Composeがアプリケーション全体を起動・実行する。


##Dockerfileで行うこと

```ruby:（例）
FROM ruby:2.5.1-stretch

ENV ENTRYKIT_VERSION 0.4.0

WORKDIR /path

RUN apt-get update 
〜（後略）                                                                                                
```
-  **FROM**で元にするOS（ベースイメージ）の指定
-  **ENV**で環境変数の指定（<key> <value>の形式）
-  **WORKDIR**でRUN等の命令実行時の作業場所の明示
-  **RUN apt-get**で必要になるライブラリのインストール

　　などなど、、


##docker-compose.ymlで行うこと

```yaml:(例)
version: "3"
volumes:
  mysql_8_0-data:
  redis-data:
  vendor_bundle_2_5_1:
  vendor_assets_2_7:
  node_modules:
  
services:
  mysql:
    image: mysql:8.0
    environment:
    networks:
      - default
    ports:
      - '33306:3306'
  redis:
    image: redis:alpine
    networks:
      - default
  app_name:
    build:
      context: .
      dockerfile: Dockerfile.dev
    depends_on:
      - mysql
      - redis
    networks:
      - default
    command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails server -b 0.0.0.0
```
-  **version**でdocker-composeの使用バージョンの指定
-  **services**でアプリケーションを動かす為の各要素(railsとmysqlとredisと…)を定義。更にそれぞれの設定をその下に記述。

　
　などなど、、


###docker-compose.ymlの考え方
上述したservicesに記載のある各要素もそれぞれコンテナであり、docker-compose upを行うことで、docker-compose.ymlの内容を元に別々に分かれているコンテナが一つの環境としてまとめられる。

実際のサーバ構築で例えるとすると、rails、mysql、redisがそれぞれ動くサーバを立てる、更にそれぞれがネットワークで繋げるという状況を記述しているイメージ。

#参考
- [Docker Compose 概要](http://docs.docker.jp/compose/overview.html)

##終わりに。
転職の為、未経験の状態からRailsを学習しております。正しい知識を着実に身に着け、実力のあるエンジニアになりたいと考えています。継続して投稿していく中で、その為のインプットも必然的に増え、成長に繋がるかと考えています。
今現在、初心者だからといって言い訳はできないですが、投稿の内容に間違っているところや、付け加えるべきところが多々あるかと思いますので、ご指摘頂けると幸いです。この記事を読んで下さりありがとうございます。
Bootstrapのボタンの色を増やす方法

CDNを使っている方`npm`または`yarn`を利用してください。

# インストール
Bootstrapを[インストール](https://getbootstrap.com/docs/4.4/getting-started/download/)してご利用ください。

```
$ npm install bootstrap
```


# Scss作成

```scss:/scss/style.scss
$qiita: #55c500;

$theme-colors: (
  "qiita": $qiita,
);

@import "../node_modules/bootstrap/scss/bootstrap.scss";
```

コードはこれだけです。
Gulpなどでコンパイルしてください。


# 確認
```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Bootstrap Qiita</title>
<link rel="stylesheet" href="./css/style.css">
</head>
<body>

<button type="button" class="btn btn-primary">Primary</button>
<button type="button" class="btn btn-qiita">Qiita</button>

</body>
</html>
```

これで新たに`btn-qiita`が追加されていることが確認できます。
`badge-qiita`も追加されてたりします。

注意点として、`btn-qiita`分コードが増えるので、容量も増えます。
ほどほどでどうぞ。
逆に削ることも出来るので開発、実行環境とご相談ください。

# 以上
`npm`等でインストールすると、CDNでBootstrapを利用することがなくなるぐらい便利になります。
よっぽどの理由がない限りCDNの利用は避けたほうが吉です。
Custom Search APIでランダムに画像の検索をしてみる

# 概要
Custom Search APIを使って多少ランダムな画像の検索をしてみた。
今回はGoogleAppScriptから呼び出しをする。

## Custom Search APIを利用する上で気にした点
・無料枠の1日あたり100件の検索クエリを使う
・検索結果は10件なので検索の開始位置を変えてみる

## 1.API KeyとCSE ID(検索エンジンID)の取得

以下の記事を参考に取得
https://www.pre-practice.net/2017/12/google-custom-search-api.html

**取得したCSE ID**
- 画像検索はONにする
- 検索するサイト：`www.google.co.jp/imghp?hl=ja&tab=ri&ogbl` (SearchTypeで画像指定をするが念のため)

![CSE_data.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248644/07eb80e7-5519-6989-7f44-92390572273c.jpeg)


## 2.GoogleAppScriptに画像検索処理を実装
・プロジェクトのプロパティにAPI Keyを設定（プロパティ名：`GOOGLE_API_KEY`）
・プロジェクトのプロパティにCSE IDを設定（プロパティ名：`CUSTOM_ID`）
・取得開始位置(startIndex)を指定（ここでは1~10をランダムに設定する）
・取得した値(items)のlinkをランダムに指定（ここではitemsの配列番号をランダムに設定する）

```js

function getImage(){
  // プロジェクトのプロパティからGoogleのAPI KEYを取得
  var apikey = PropertiesService.getScriptProperties().getProperty('GOOGLE_API_KEY');
  var apiUrl = 'https://www.googleapis.com/customsearch/v1/';
  var start = 1 + Math.floor(Math.random() * 10); //取得開始位置を1~10の数値の中のどれかにする
  var query  = '?q='+ encodeURIComponent('検索ワード'); //検索したいワードを指定
  query += '&cx=' + PropertiesService.getScriptProperties().getProperty('CUSTOM_ID'); //CSE ID
  query += '&key='+ apikey;
  query += '&searchType=' + 'image';
  query += '&start=' + start;
  
  apiUrl = apiUrl + query;
  var response = UrlFetchApp.fetch(apiUrl);
  if (response.getResponseCode() !== 200) {
    throw new Error('エラーのため取得できませんでした');
  } else {
    var res =  JSON.parse(response);    
    var rdm = Math.floor( Math.random() * res["items"].length );
    // consoleにURLを表示
    console.log(res["items"][rdm]["link"]);
  }  
}
```

取得するURLはstartIndex番号と取得したitems数のランダムになるはず。
[Shopify] 細かな文言修正

ご指摘いただき、いろいろShopify内の文言を修正。

文言を修正する場合は管理画面、テーマ、テーマ言語を変更するを選択。

今回はチェックアウトを、レジへ進むへ変更。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241909/8329bc5b-6e97-b6ac-1543-5c6187fdecd8.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241909/d14935c3-4680-7d48-89b0-36158e50d2be.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241909/f9db6ed6-070a-6be3-1e2b-2785e1440fd0.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241909/7a0bae3d-5ad5-b010-8ae0-cf98b2450728.png)
Bootstrapのハンバーガーメニューが動作しない (Uncaught TypeError: Cannot convert object to primitive value)

# はじめに
Bootstrapのナビゲーションバーを使用して作成した、ハンバーガーメニューがトグルスイッチをクリックしても動作しませんでした。
はじめ、自分のBootstrapに関するコーディングミスかと思い、調査したのですが、結果2020年4月10日に3.5.0にアップデートされたjqueryが原因でした。

## 環境
- rails  6.0.2.2
- bootstrap 4.4.1
- jquery 3.5.0


## 現象
bootstrapのナビゲーションバーを使用して作成した、ハンバーガメニューがクリックしても動作しない。
ハンバーガーメニューを押下した際、chrome検証ツールのコンソールに、以下のエラーが出力されている。

```console
bootstrap.js:1498 Uncaught TypeError: Cannot convert object to primitive value
    at RegExp.test (<anonymous>)
    at HTMLDivElement.<anonymous> (bootstrap.js:1498)
    at Function.each (jquery.js:325)
    at jQuery.fn.init.each (jquery.js:165)
    at jQuery.fn.init._jQueryInterface [as collapse] (bootstrap.js:1492)
    at HTMLDivElement.<anonymous> (bootstrap.js:1552)
    at Function.each (jquery.js:325)
    at jQuery.fn.init.each (jquery.js:165)
    at HTMLButtonElement.<anonymous> (bootstrap.js:1547)
    at HTMLDocument.dispatch (jquery.js:4670)
(anonymous) @ bootstrap.js:1498
each @ jquery.js:325
each @ jquery.js:165
_jQueryInterface @ bootstrap.js:1492
(anonymous) @ bootstrap.js:1552
each @ jquery.js:325
each @ jquery.js:165
(anonymous) @ bootstrap.js:1547
dispatch @ jquery.js:4670
elemData.handle @ jquery.js:4490
```

## 原因
2020/4/10にアップデートされたjquery 3.5.0に伴い顕在化したbootstrapの不具合（と想定。私もはっきりとは読み取れず）



## 対処方法
### 現状の対処
jqueryを3.5.0から3.4.1にダウングレードする
→ ハンバーガメニューが動作することを確認。

### 将来的な対応
根本的な修正はBootstrap 4.4.2版で適用される模様(すでに[github](https://github.com/twbs/bootstrap/pull/30559/commits/d7a71f3e857a28ca5b055f3e5d28800d9235d57b)上では、修正版がcommit&mergeされていました）


## 参考

[Bootstrap data-toggle for collapse failing · Issue #2147 · LD4P/sinopia_editor](https://github.com/LD4P/sinopia_editor/issues/2147)

[Bootstrap v4.4.1 collapse doesn't work with jQuery v3.5.0 · Issue #30553 · twbs/bootstrap](https://github.com/twbs/bootstrap/issues/30553)

## 追記
2020/5/4にjqueryのv3.5.1が公開され、v3.5.1を使用することで上記不具合は解消されました。
TWITTERとyoutubeのビデオをダウンロード

https://www.reiwarss.com/reiwadl

家にいるうちにreiwarss.com/reiwadl
を使ってTWITTERとyoutubeのビデオをダウンロードして学習せよ.
マニュアル:

1. copy URL .例:
youtube.com/watch?v=gn4nRC…
2. 令和download をクリックする

while fighting with covid-19, try this tool to download the video you like and learn at home .
[Shopify] 登録時に 苗字 名前順にする

デフォルトの登録画面を使うと海外仕様で名前、苗字の順になっているので、日本仕様で苗字名前にしてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241909/2feed4ac-b0fe-22eb-8b36-df25cdd1ace2.png)

場所は `/customers/register.liquid`

確かにみると

```html

<label for="FirstName">{{ 'customer.register.first_name' | t }}</label>
<input type="text" name="customer[first_name]" id="FirstName" {% if form.first_name %}value="{{ form.first_name }}"{% endif %} autofocus>

<label for="LastName">{{ 'customer.register.last_name' | t }}</label>
<input type="text" name="customer[last_name]" id="LastName" {% if form.last_name %}value="{{ form.last_name }}"{% endif %}>
```

となっているので、ここの順番を変更。そして保存。

```html
<label for="LastName">{{ 'customer.register.last_name' | t }}</label>
<input type="text" name="customer[last_name]" id="LastName" {% if form.last_name %}value="{{ form.last_name }}"{% endif %}>

<label for="FirstName">{{ 'customer.register.first_name' | t }}</label>
<input type="text" name="customer[first_name]" id="FirstName" {% if form.first_name %}value="{{ form.first_name }}"{% endif %} autofocus>

```

こんな感じに変更できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241909/f8d2ca9d-981b-82d0-f7d6-5aa69ab97e45.png)
AtCoderでREが出たら(C++er用)

# vectorの要素数多すぎ

```c++
// n = 10^5くらいがありえるとき
vector<int> pp(n);
```
これはメモリ確保できず，REが出ます．しかも気づきにくい...
`vector`である必要がないなら，mainの外で配列にしましょう．

```c++
int pp[200000];
int main() {
    // do something
}
```

# 配列外参照

```c++
int a[4]; // a[0], a[1],...,a[3]からなる配列
a[4] = 1;
```
みたいに，定義されてないa[4]を参照すると実行時エラー．最適化時には未定義動作なので[何が起こるかわからない](https://cpplover.blogspot.com/2014/06/old-new-thing.html)．
なおvectorでそのときのサイズより大きなnで`[n]`とすると，お節介から，n番目以下のところを勝手に0で埋めるという大惨事が起きるので，それはそれで気をつけましょう．

# stringはmain()内に定義
これはTLEの原因になるものなのでちょっと違うのですが，stringの定義はmain()の外はやめたほうがいいです．(詳しくはないですし，環境依存かもしれないですが，長い文字列だとスタックからヒープへのコピーが重い？？)


# 最後に
また失敗したら書き足していこうと思います．
競プロがんばりたい！
「パスワードは次のメールでお送りします」をやめるためのツールを作った

リポジトリは https://github.com/nabetani/mandihe/ 。

mandihe は、**MAN**ual **DI**ffie-**HE**llman から。

# 手順

1. Alice→Bob: 鍵交換支援HTMLを生成するHTMLへのアクセスを提供する。
2. Alice→Bob: 公開鍵を伝える。
3. Bob: 鍵交換支援HTMLと Alice からもらった公開鍵を使って、パスワードとダイジェストを作る。
4. Bob→Alice: ダイジェストとBobの公開鍵を Alice に伝える
5. Alice: Bobからもらった公開鍵で、パスワードとダイジェストを作る。手元で作られたダイジェストと Bobからもらったダイジェストが一致していることを確認する。
6. Ailce→Bob: 一致しているからOKだよ、と伝える。

Alice と Bob の間の通信はすべて平文でOK。盗聴されても問題ない。
盗聴+改竄だと困ると思う。
盗聴+改竄 に耐えるようにするには認証局(のようなもの)がないと無理なんじゃないかと思っているんだけど、どうだろう。

(1) の「鍵交換支援HTMLを生成するHTMLへのアクセスを提供」は、平文で HTML を送ってもいいし、サーバーに置いて URL を伝えてもいい。

# 仕組み

鍵交換をメールなどを通じて行う。

鍵交換の情報の流れは下図の通り:

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6854/fb3a8db5-6d69-041c-bea8-4078a8d96a59.png)

# 「鍵交換支援HTMLを生成するHTML」がある理由

鍵交換支援HTMLは、 `crypto.subtle.generateKey` で鍵ペアを作る。
HTML を表示するたびに鍵ペアを作るようにすると、

> 2.Alice→Bob: 公開鍵を伝える。

と

> 5.Alice: 手元で作られたダイジェストと Bobからもらったダイジェストが一致していることを確認する。

の間に数日空いたりすると運用上面倒なことになる。
面倒を避けるために鍵ペアを記憶したい。
秘密鍵も記憶するので、暗号化したい。
暗号化には鍵が要る。
では、その鍵はどこに保存するか...という問題がある。

そこで

* 鍵は、 `crypto.getRandomValues` で生成。
* 生成した鍵は「鍵交換支援HTML」内の JavaScript のソースコードに埋め込む。

という作戦にした。
これで、 `localStorage` であっても安全に秘密鍵を保管することができる。

情報の流れは下図の通り:

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6854/d4dc15c5-cdc3-0cc6-8821-9f491b53d40e.png)

`index.html` が「鍵交換支援HTMLを生成するHTML」で、 `key-exchange-helper.html` が「鍵交換支援HTML」である。

1. 「鍵交換支援HTMLを生成するHTML」内でパスワードを生成
2. 生成したパスワードを埋め込んだHTMLを「鍵交換支援HTMLを生成するHTML」内で生成
3. 生成したHTMLを Base64 にして、`href` に入れる
4. リンクを右クリック→名前を付けて保存 で、できたての HTML をダウンロード

という流れになる。
パスワードの生成からダウンロードまでの流れに通信が絡まないので傍受できない。

これで、

* localStorage にデータがあればそれを表示
* なければ生成

という処理にすることができる。
これで運用上の面倒がなくなる。

# 動作するブラウザ

手元で調べたところ

* 最新の Firefox
* 最新の Google Chrome
* 最新の Microsoft Edge(Chromium版)

で動作することがわかった。調べたのは macOS版 と Windows版。

一方。

* 最新の Safari on macOS
* 最新の Internet Explorer 11 on Windows

では動作**しない**事がわかった。残念。
非 Chromium の Edge は手元にないので試していない。
AtCoder 生活　36日目

[前回](https://qiita.com/flandrescarlet237/items/e6e552239636833af080)

#36日目
今回は、[AtcoderProblemsのBoot camp for Beginners](https://kenkoooo.com/atcoder/#/training)のEasy問題を1問解き,
ABC164に参加しました。

|問題|難易度|自力で解けた|かかった時間|
|:-:|:-:|:-:|---|---|
|ABC071|B|✕|129分37秒|

![スクリーンショット 2020-04-26 22.48.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/606053/d70c267a-f3c8-693f-694f-af1d8d6e866c.png)

##[ABC098_B](https://atcoder.jp/contests/abc071/tasks/abc071_b)

```c++

#include <bits/stdc++.h>
#define rep(i,n) for(int i = 0;i < (n);i++)
using namespace std;
using ll = long long;
using pii = pair<int,int>;

int main(){
    string s;
    cin >> s;
    bool alp[26];
    rep(i,26){
        alp[i] = false;
    }
    rep(i,s.size()){
        alp[s[i] - 'a'] = true;
    }
    rep(i,26){
        if(!alp[i]){
            cout << char(i + 'a') << endl;
            return 0;
        }
    }
    cout << "None" << endl;
    return 0;
}

```

解くのにかかった時間：129分37秒
感想：アルファベットの調べ方の方法についてかなり迷ってしまった。


#[ABC164](https://atcoder.jp/contests/abc164)

###A

```c++

#include <bits/stdc++.h>
#define rep(i,n) for(int i = 0;i < (n);i++)
using namespace std;
using ll = long long;
using pii = pair<int,int>;

int main(){
    int s,w;
    cin >> s >> w;
    if(s > w) cout << "safe" << endl;
    else cout << "unsafe" << endl;
}

```


###B


```c++

#include <bits/stdc++.h>
#define rep(i,n) for(int i = 0;i < (n);i++)
using namespace std;
using ll = long long;
using pii = pair<int,int>;
using pil = pair<pii,int>;


int main(){
    int a ,b,c,d;
    cin >> a >> b >> c >> d;
    bool ok = true;
    while(ok){
        C -= b;
        if(c <= 0){
            cout << "Yes" << endl;
            return 0;
        }
        a -= d;
        if(a <= 0){
            cout << "No" << endl;
            return 0;
        }
    }
}

```


###C


```c++

#include <bits/stdc++.h>
#define rep(i,n) for(int i = 0;i < (n);i++)
using namespace std;
using ll = long long;
using pii = pair<int,int>;
using pil = pair<pii,int>;


int main(){
    ll n;
    cin >> n;
    vector<string> s(n);
    rep(i,n) cin >> s[i];
    int cnt = 1;
    sort(a.begin(),a.end());
    rep(i,n-1){
        if(s[i] != s[i+1]) cnt++;
    }
    cout << cnt << endl;
}

```

###最後に
ABC164は少し時間に遅れてしまったので今後無いように注意しなければならない。
D問題が、dp問題らしいが今まさに勉強中なので次に見るときには解けるようにしておきたい。
dockerでjupyterlabを開く

```
docker run -it --rm -p 8888:8888 jupyter/datascience-notebook start.sh jupyter lab
```

```
>docker run -p 8888:8888 -v C:\Users\____\:/data --name python_jupyterlab  -it python /bin/bash

#jupyter lab --ip=0.0.0.0 --allow-root
```

# 参考
https://jupyter-docker-stacks.readthedocs.io/en/latest/using/recipes.html#dask-jupyterlab-extension

https://stackoverflow.com/questions/55435949/error-starting-jupyter-inside-docker-container/55436012
Jenkins初回起動時のオフライン状態を解決する

homebrewでJenkinsをインストールし初回起動時にセキュリティのためにパスワード認証を行います．
そのあとにプラグインのインストールなどのセットアップを行いますが，以下のようにオフラインになってしまいました．

<img width="1037" alt="jenkins_offline.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252857/95db58e5-f420-586c-8e06-1e23059a9ef1.png">

# 解決策
`~/.jenkins/hudson.model.UpdateCenter.xml`内のurlをhttpsからhttpへと変更する

```xml

<?xml version='1.1' encoding='UTF-8'?>
<sites>
  <site>
    <id>default</id>
    <url>https://updates.jenkins.io/update-center.json</url>
  </site>
</sites>
```

変更後再起動することでオフライン状態が解決

```sh
brew services restart jenkins
```

もし再起動後にアクセスしても404 NotFoundとなる場合はキャッシュを削除すれば解消される

# 参照
https://stackoverflow.com/questions/42408703/why-does-jenkins-say-this-jenkins-instance-appears-to-be-offline
Ubuntuで外付けHDDを自動マウントする

fstabを用いた内臓HDDのマウントについては、「[Ubuntu 起動時にディスクをマウントする](https://qiita.com/suisuina/items/7b55a640fdd6b299aa46)」および、コメント欄を参照ください。

結果的にはfstabを用いれば課題は解決できたのですが、筆者の試行錯誤の記録としてfstabを使わない方法も以下に残しておきます。

# 課題
ＮＡＳサーバーであるLinux PCの起動時(ログインする前)に、外付けＨＤＤをマウントしたい。
> 注意点
> 外付けＨＤＤがＵＳＢに刺さっていなかったら、マウントせずに起動したい。
> ~~したがって、`fstab`を使えない。~~
> ~~(`fstab`に記述されたＨＤＤがマウントできないとＰＣは起動できない)~~
> ↑コメント欄を参照のこと！

# マウントを実行するシェルスクリプト
外付けＨＤＤが接続されていたらマウントするシェルスクリプト

```bash:mountHdd.sh
 #!/bin/bash
 VERBOSE=false 
 if [ "$VERBOSE" == true ]; then
         set -x
 fi

 # Get Device File of HDD
 DEVICE_FILE=$(blkid --uuid 2FCACECF7887A2E1) 
 if [ -z "$DEVICE_FILE" ]; then
         exit 1
 fi
	
	# Prepare Mount Point 
 MOUNT_POINT="/path/to/mount/point" 
 if [ ! -d $MOUNT_POINT ]; then
         mkdir $MOUNT_POINT
 fi
 # Mount HDD
 mount $DEVICE_FILE $MOUNT_POINT
```

# 起動時に実行されるコマンドrc.localに追記

```bash:rc.local
 #!/bin/sh
 # output log into /tmp
 exec 1>/tmp/rc.local.log 2>&1  # send stdout and stderr from rc.local to a log file
 set -x                         # tell sh to display commands before execution 
 
 RET=0
 
 # mount HDD if connected
 /home/koyama/bin/mountHdd.sh
 RET=$RET && $?
 
 exit $RET
``` 

実行したいシェルスクリプトを作成する（実行権限に注意）

```bash
 # 実行可能なrc.localを作成
 sudo vi /etc/rc.local
 sudo chmod u+x /etc/rc.local

 # systemdがrc.localを実行するための設定をする
 cd /etc/systemd/system
 sudo cp /lib/systemd/system/rc-local.service .
 sudo ln -s ../rc-local.service
```

# 検証
```bash
 sudo systemctl enable rc-local # 起動時に実行されるようにする
 sudo systemctl start rc-local # マウントを実行
 sudo systemctl restart rc-local # マウントを再実行
 sudo systemctl stop rc-local # アンマウントされる（なぜ？？）
```
【Day62】積み上げ日記

##予定
■Udemy（有料教材）
－セクション17,18,19

##完了
■Udemy（有料教材）
－セクション17,18,19

##学習時間
５h

##学習ポイント
■マルチデバイス対応
■cocoapodsインストール
■API
■Alamofire
■スクリーンショット撮影

※別記事でまとめたことを報告

##疑問点
■JSON解析

##参考記事
https://e-to-e.org/articles/ios-alamofire-tutorial
AtCoder Beginner Contest 164 参戦記

# AtCoder Beginner Contest 164 参戦記

## [ABC164A - Sheep and Wolves](https://atcoder.jp/contests/abc164/tasks/abc164_a)

2分半で突破. 書くだけだったけど、コードテストが詰まってて、慌ててローカルでテストしたりして時間がかかった.

```python
S, W = map(int, input().split())

if W >= S:
    print('unsafe')
else:
    print('safe')
```

## [ABC164B - Battle](https://atcoder.jp/contests/abc164/tasks/abc164_b)

2分半で突破. B問題なので、素直にシミュレートしても TLE しないので書くだけですね.

```python
A, B, C, D = map(int, input().split())

while True:
    C -= B
    if C <= 0:
        break
    A -= D
    if A <= 0:
        break

if A > 0:
    print('Yes')
else:
    print('No')
```

## [ABC164C - gacha](https://atcoder.jp/contests/abc164/tasks/abc164_c)

2分半で突破. set で distinct して個数を数えるだけ. C問題にしたって簡単すぎませんかね.

```python
N = int(input())

print(len(set(input() for _ in range(N))))
```

## [ABC164D - Multiple of 2019](https://atcoder.jp/contests/abc164/tasks/abc164_d)

敗退.

追記: [ABC158E - Divisible Substring](https://atcoder.jp/contests/abc158/tasks/abc158_e) を簡単にした問題なので、[AtCoder Beginner Contest 158 参戦記](https://qiita.com/c-yan/items/87f5fd32472a964a996b#abc158e---divisible-substring)を見てください. 復習をサボっていなかったら高パフォ取れてたのに…….

```python
S = input()

S = S[::-1]
result = 0
t = [0] * 2019
m = 1
n = 0
for i in range(len(S)):
    t[n] += 1
    n += int(S[i]) * m
    n %= 2019
    result += t[n]
    m *= 10
    m %= 2019
print(result)
```
googleスプレッドシートで第二引数が任意入力のオリジナル関数をつくる（Google Apps Script）

スプレッドシートで支払関係の表を埋めているときに、「消費税の計算めんどくさ…」となることはありませんか？
私はあります。

通常であれば、セルに`=A1*1.1`とか書いてフィルハンドルを引っ張って一気に適用させるとかすればよいのですが。
税抜きだけでなく税込みの金額が混じっていてたら、そうもいきません。
さらに今は軽減税率という厄介なものもあり、消費税率が一定じゃなかったりします。

そんなわけで、数字の入力が面倒なのでスプレッドシートに消費税を足したり抜いたりするオリジナル関数を組み込んでみました。

ノンプログラマーである私がGASの門を叩いたのはここからだったので、同じように「何か関数でラクしたいわー」というノンプログラマー向けに汎用的なタイトルにしました。
計算式を変えればいろいろできるので、試してみてください。

#仕様

- 消費税を乗せる関数（taxon()）と消費税を抜く関数（taxout()）の2種類どちらも使えるようにする
- 税率を任意で変えられる
- デフォルトの消費税率は10％。変更したい場合のみ8％などに変更できる

#こうなる

##税込み価格にする関数

`taxon()`の中に消費税10％を追加したい数値を入れれば、消費税込みの数値を返します。
![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621062/c152e53c-a6de-c2fd-7251-7bb35ba2f473.png)

第二引数に任意の税率（ここでは8％）を入れれば、その税率込みの数値を返します。
![03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621062/973e4ca9-53d1-64fc-3a9c-199465ff9383.png)

##税抜き価格にする関数

`taxout()`の中に消費税10％を抜きたい数値を入れれば、消費税抜きの数値を返します。
![04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621062/fd5f0aad-acc7-c710-2d9a-8d607ff8c1dc.png)


第二引数に任意の税率（ここでは8％）を入れれば、その税率抜きの数値を返します。
![05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621062/38ec38dc-28c7-5b2a-50ad-372a428c6f20.png)




#つくりかた

ノンプログラマーが最初に作った際には、いろいろ理解するのに苦労したので、一応解説しておきます。


##①関数を組み込みたいスプレッドシートを開く

どのシートでも大丈夫です。
※ただし、当該のシートでしか動作しません。excelとして落としたい場合などは注意


##②スクリプトエディタを開く
スプレッドシートのメニュー　ツール＞スクリプトエディタ　から開きます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621062/82fef967-c384-a7b3-3f03-c7fdfc7bae74.png" width=75%>

エディタが開いたら、ファイル名を付けましょう。

##③スクリプトを書く
最初から```function myFunction() {}```と入っていますが、これは削除して以下のとおり記入します。

```javascript

const standard_tax_rate = 10; //デフォルトの消費税率

// 税込価格を出す関数
function taxon(price, tax_rate) {
  if(!tax_rate){
    tax_rate = standard_tax_rate;
  }
  return price * (1 + tax_rate / 100);
}

// 税抜き価格を出す関数 
function taxout(tax_include_price, tax_rate) {
  if(!tax_rate){
    tax_rate = standard_tax_rate;
  }
  return tax_include_price / (1 + tax_rate / 100);
}
```

##④保存する
フロッピーマークを押せば保存されます。

以上です。
これでスプレッドシート側で関数が使えるようになっています。

要は、ここで定義した関数が、そのままスプレッドシートで使えちゃうというわけです。

#スクリプトの説明

こちらもノンプログラマー向けに一応解説しておきます。

##関数と第一引数・第二引数を定義する
まず、function　に続く部分で新たな関数を定義します。
続くかっこの中で、関数に入れる引数を定義します。

##任意の計算式の結果が返るようにする
`return`の後ろに記載した計算式の結果が関数の結果として返ることになります。
taxonの場合は税率を乗算して、taxoutの場合は税率を除算します。



##第二引数を入れない場合はデフォルトの数字が入るようにする

今回は、「第二引数に何も入れなければ基本の消費税の10％にするけど、8％など他の税率にしたいときはできるようにする」としたいので、デフォルトの引数を設定する必要があります。

スマートなやり方かはわかりませんが、こんな風に解決しています。

```javascript
  if(!tax_rate){
    tax_rate = standard_tax_rate;
  }
```

第二引数tax_rateが`!tax_rate`のとき、つまり何も入ってなかった場合に`tax_rate`は、予め設定しておいた `standard_tax_rate`（10％）を適用する、ということです。

以上です。いろいろ応用すれば、よく使う計算などの手間がかなり省けるのではないかと思います。
ただ、以下のようになるので、少し注意が必要です。

- このシート上でしか動作しない
- 計算時にセル上に「Loading...」と出て、数字が表示されるまで少し読み込み時間がある
AtCoder(ABC)164にPythonで挑戦！A~C問題

#はじめに
AtCoder ABC164にPythonで挑戦しました！
Ratedとしては２回目の挑戦です。
A〜Cまで解けました。
D問題はTLEでした。


#A問題
sがwより大きければsafe、その他の時はunsafeを出力すれば終わりです

```Python3:A.py
s, w = map(int, input().split())
if s > w:
    print("safe")
else:
    print("unsafe")

```

#B問題
無限ループで、aまたはcが０以下になるまで回しましょう
高橋くんが先攻なので、両方とも負になってしまう回は、高橋くんの勝ちなので先にflg1を処理するようにコードを書きましょう


```Python3:B.py
a, b, c, d = map(int, input().split())
flg1 = False
flg2 = False
while True:
    c -= b
    a -= d
    if c <= 0:
        flg1 = True
    if a <= 0:
        flg2 = True

    if flg1:
        print("Yes")
        exit()
    if flg2:
        print("No")
        exit()

```

#C問題
set()に直すことにより、重複を省くことができます。重複を除いた個数が答えです。

```Python3:C.py
n = int(input())
s = [str(input()) for _ in range(n)]
print(len(set(s)))
```

#D問題
二重ループになっているので計算量が大きくなりすぎましたね
このコードではTLEになります。

```Python3:D.py
s = input()
keta = len(s)
ans = 0
mul = []

for i in range(100):
    if "0" in str(2019 * i):
        pass
    else:
        mul.append(str(2019 * i))

for i in range(len(mul)):
    for j in range(0, keta + 1 - len(str(mul[i]))):
        if s[j : j + len(mul[i])] == mul[i]:
            ans += 1


print(ans)

```

#まとめ
今回は2回目の挑戦でした
A問題はどうせ解けただろうと思っていたのですが、まさかのunsafeとsafeを反対にしてしまっていることに気づかずにB,Cと解いてしまっていたので、かなりパフォーマンスが落ちてしまいました。
次からは気をつけたいと思います
【Git】Gitの基本操作と基本コマンド

Gitの仕組みとコマンドについて改めて基礎を復習したのでまとめておきます。

#Gitの特徴
Gitの特徴は以下になります。

- データをスナップショットとして管理する
- コミットでバージョンを記録する

この二つができることで何が便利かと言いますと、

- 差分で保存しないので開発スピードが上がる
- スナップショットで記録しているのでバージョンをそのまま以前の状態に戻すことができる

というところです。

私が以前参加したプロジェクトはものすごくレガシーな環境だったため、バージョン管理ツールも非常に古く差分をいちいち確認しなければいけないタイプだったのですが、それだと非常に進捗が遅くなり効率が悪いです。
それに対してGitは、上に挙げたような理由からそういった従来の管理ツールの欠点を解消した形で誕生し、現在はほとんどの開発に利用されているわけですね。

#Gitの操作の流れ
##自分の変更の場合
1. ローカルでファイルの変更
2. ローカルリポジトリにスナップショットを記録
3. GitHubにアップロードする

```
git init
```

###ローカルリポジトリ
ローカルリポジトリはファイル変更などを記録しておく場所のことです。

##他人の変更を取り込む場合
1. GitHubから記録を取得する
2. 取得したGitHubの記録をワークツリーに反映する

```
git clone リポジトリ名
```

##ローカルを詳しく見る
ローカル環境については以下三つを押さえておく。

1. ワークツリー
2. ステージ
3. リポジトリ

###ワークツリー
ファイルを変更する場所。
ここで開発作業を行う。

###ステージ
コミット（スナップショットを記録）する変更を準備する場所。
一旦ここに変更を追加する。

```
git add ファイル名
```

記録しておきたい変更分のみ追加しておく。

###リポジトリ
スナップショットを記録する。
ステージの追加が完了したら最後にコミットをして変更を記録する。

```
git commit
```

##変更状況を確認
```
git status
```

##変更差分を確認
git add する前の変更差分を確認。

```
git diff
```

git add した後の変更差分を確認。

```
git diff --staged
```

##変更履歴を確認
コミットの履歴を確認できる。

```
git log
```

##削除の記録をする
ファイルごと削除する場合。

```
git rm ファイル名
```

ディレクトリごと削除する場合。

```
git rm -r ディレクトリ名
```

ファイルを残したいとき。

```
git rm --cached ファイル名
```

##移動の記録する
```
git mv 旧ファイル 新ファイル
```

#GitHubにアップする
GitHubにリモートリポジトリを登録。

```
git remote add origin
```

ローカルリポジトリにコミットしたものをGitHubに送信する。

```
git push -u origin master
```
初回に-uオプションをつけておくと次回以降記載がpushのみで良いので楽になる。

##コマンドにエイリアスをつける
コマンドにエイリアスをつけとくことでコマンド入力が楽になる。

例：commitコマンドにcoというエイリアスを付与する。

```
git config alias.co commit
```

パソコン全体の設定を変えたい場合。

```
git config --global alias.co commit
```

##バージョン管理したくないファイル
.gitignoreファイルに管理したくないファイルを指定する。

```.gitignore
#コメント

#ファイル指定
index.html

#ディレクトリ以下を指定
dir/
```

##変更の取り消し
色々取り消し方法。
###ファイルの変更を取り消す
```
git checkout --ファイル名（またはディレクトリ名）
```

全変更を取り消す場合。

```
git checkout -- .
```

###ステージした変更を取り消す
```
git reset HEAD ファイル名（またはディレクトリ名）
```

全変更を取り消す場合。

```
git reset HEAD .
```

###直前のコマンドをやり直す
```
git commit --amend
```
※チーム開発で混乱してしまうため、リモートリポジトリにpushをしたコミットを修正してはいけない。

#まとめ
ひとまずここでいったん終了いたします。
まだ使うコマンドはたくさんあるので、後ほどまた別記事で書いていく予定です。
そちらもぜひ読んでいただければと思います。

ではでは。
【Day61】積み上げ日記

##予定
■Udemy（有料教材）
－セクション14,15,16

##完了
■Udemy（有料教材）
-セクション１４、１５、１６

##学習時間
４h

##学習ポイント
■カメラ実装するコードを書いたら、プライバシー設定をする！（プライバシー設定＝アクセス許可の吹き出し）
－ 『Privacy - Photo Library Usage~』を作る。
－ 『Privacy - Camera Usage Des~』を作る。
■シェアするための機能


##疑問点
■textfield, textview の違い
UITextField：キーボードによる入力可能
UITextView：キーボードによる入力可能（複数行可）
文字列で列名を指定してmutate ＆ aesを文字列で指定して繰り返しggplot

両方できる。そうrlangならね

rlangを調べているうちにこれらを行う方法を見つけたのでメモ。
困っている人がいたら役に立つかも？

今回は主に以下のページを参考にさせていただきました：

- [Tidy evaluation with rlang : : CHEAT SHEET](https://github.com/rstudio/cheatsheets/blob/master/tidyeval.pdf)
- [雰囲気で理解するtidy evaluation(1): tidy evaluationの導入](https://qiita.com/uri/items/6d5f285280387dff0caa)
- [rlang Reference](https://rlang.r-lib.org/reference/index.html)

rlangについてはまだ勉強中で「動くけど原理をうまく説明できない」ため説明がほぼないです。ごめんなさい。めちゃくちゃ便利だけど説明が難しい。。。

仕組みが気になる方は上記ページや「R　非標準評価」で引っかかるページ等を参照していただければと思います。

コードを試す際にはtidyverseが必要なので`library(tidyverse)`をしてください。

# 文字列で列名を指定してmutate
例えば、「あるデータフレームに対して、数値が入った列の値を正規化し、因子が入った列の値を文字列にする」という作業をfor文で行いたいとします（実際は`mutate_if`でやる方が簡単です）。
何も考えずにコードを書くと以下のようになります。`colnames`で取得した列名（文字列）ごとに処理を行う心づもりです。

```うまくいかない.R
test <- iris
for (col in colnames(test)){
    target <- test %>% pull(col)

    if (is.numeric(target)){
        test <- test %>% mutate(col = scale(col))
    } else if (is.factor(target)){
        test <- test %>% mutate(col = as.character(col))
    }
}
```

しかしこのコードは思うように動きません。
これは`mutate`に対しては列名を引用符なしの状態で与える必要があることに起因します。つまり、`mutate(iris, Species = as.character(Species))`とはできても、`mutate(iris, "Species" = as.character("Species"))`とはできないことが原因です。

### 解決策
以下のようにコードを書き換えるとうまくいきます。

```うまくいく.R
test <- iris
for (col in colnames(test)){
    target <- test %>% pull(col)

    colsym <- rlang::sym(col)

    if (is.numeric(target)){
        test <- test %>% mutate(!!col := scale(!!colsym))
    } else if (is.factor(target)){
        test <- test %>% mutate(!!col := as.character(!!colsym))
    }
}
```

ポイントは`mutate`内で
①左辺に`!!`をつけて`=`を`:=`に変える
②右辺の列名を指定する変数は`rlang::sym`で処理した後、`!!`をつけて指定する
ことです。
こうすることによって変数を引用符のない列名として解釈させることができるようになります。



# aesを文字列で指定して繰り返しggplot
例えば、「あるデータフレームをもとに、x軸はそのままでy軸を変えながら複数の図をggplotする」という作業をfor文で行いたいとします。
何も考えずにコードを書くと以下のようになります。こちらでも`colnames`で取得した列名（文字列）ごとに処理を行う心づもりです。

```うまくいかない.R
for (y in colnames(iris)) {
    g <- ggplot(data = iris) + geom_boxplot(aes(x = Species, y = y))
    x11(); plot(g)
}
```

しかしmutateの場合と同様うまくいきません。これは`aes(x = Species, y = Sepal.Length)`を`aes(x = Species, y = "Sepal.Length")`と書くことができないことに起因します。

### 解決例
aes内に文字列を使いたいだけであれば、[文字列として変数に格納されている列名をggplotのaes()に入れたい](https://qiita.com/daifuku_mochi2/items/619a7c243dc23dba0c1b)という記事の解決法が参考になります。
しかし列名を変数で指定してfor文で実行しようとするとrlangを使ったひと工夫が必要です。


以下のようにコードを書き換えるとうまくいきます。

```うまくいく.R
for (y in colnames(iris)) {
    ys <- rlang::sym(y)

    g <- ggplot(data = iris) + geom_boxplot(aes(x = Species, y = !!ys))
    x11(); plot(g)
}
```

ポイントは列名が格納された変数を`rlang::sym`で処理した後、`aes`内で`!!`をつけて指定することです。。mutateの②と同じです。
こうすることによって変数を引用符のない列名として解釈させることができます。

---
これらの問題の根底にあるのは、「関数が実行されるときRが引数をどのように解釈するのか」という普段あまり意識しない問題です。
この問題はdplyrを組み込んだ関数を作ろうとするときなどに非常に重要になるそうです。
vue-cliでsocket.ioを使う方法(socket.io-client)

#はじめに
　基本的なことだからなのか書いている人があまりいなくて入れるのに少し困ったので書きました。

#1. socket.io-clientをインストール
```
$ npm install socket.io-client
```

#2. socket.ioを使いたいコンポーネントに以下を記述
```
~
</template>

<script>
import io from 'socket.io-client';  //追加

export default {
    name: 'name',
    data: function(){
        return {
            socket : io('localhost:4000')  //生成
        }
    },
}
```

#おわりに
思いのほか簡単でした!

##参考
https://qiita.com/dq-jiyoung-lee/items/76e368d88750f5a619d7
Discord GoLive+カメラでZoom勉強会っぽい運用をする手順

# 対象

* 今までコミュニティをDiscord上で運営してきて、できればZoom等に乗り換えたくないコミュニティ管理者
* 少人数で開催する方で、レイテンシーの低い環境で、双方向のイベントを開催したいイベント管理者
* Discordの運用もちょっと気になるイベント管理者

# 背景

DiscordでGoLiveとカメラを複数人で同時利用できるようになりました。
DiscordでもZoom上の勉強会と同じ運用ができるよううになったので、オンライン勉強会準備資料として配布用に手順をまとめます。

↓イメージ画像(Discord上で、一つの画面だけを拡大表示することもできます 後述)
![イメージ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/249644/4160181a-de6b-e071-d918-040fb2920214.png)

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ときには面と向かったコミュニケーションがあったっていいはず。<br><br>本日より、 5%のサーバーでサーバービデオにアクセスできるようになり、およそ1週間でデスクトップの100%に実装される予定です。<br><br>お待ちいただく間、こちらのサーバービデオに関するガイドをご覧ください：<a href="https://t.co/18pLVNqMlh">https://t.co/18pLVNqMlh</a> <a href="https://t.co/eYyIipD694">pic.twitter.com/eYyIipD694</a></p>&mdash; Discord Japan (@discord_jp) <a href="https://twitter.com/discord_jp/status/1249884426294587393?ref_src=twsrc%5Etfw">April 14, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# おすすめ利用方法(上限25人)

## 推奨環境

ディスプレイ2枚以上 または 大型ディスプレイ
Discordデスクトップアプリケーション 

## 手順

### 配信者(イベント管理者)側

1.ボイスチャンネルに入って、画面左下のScreenボタンを押し、GoLive設定画面を開きます

![screen.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/249644/9bdc26e1-2af7-7e50-e4c7-ce339f8f973c.png)

2.GoLiveの画面タブから、共有したいスクリーンを選択してGoLiveを開始します

アプリケーションウィンドウ単体の指定もできますが、アプリケーション(例: Unity Editor)によっては、うまく配信できないことがあるので、事前確認できていない場合は、スクリーンごと共有するのをお勧めします。

![golive.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/249644/b780c529-1a9d-7bff-584f-c43b164aab12.png)

3.下図のように、配信画面がポップアウトするので、配信画像をダブルクリックします。

![共有画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/249644/d3f2c8c1-edb0-cb66-b79d-e14444f95c73.png)

4.配信画面が拡大されるたら、画面右下のポップアウトボタンをクリックします。

画面をポップアウトしない状態で、他のウィンドウを触ると、配信画面のプレビューが止まって、確認しづらくなります。
ポップアウトするとこの問題を解決できます。
最前面に表示できるので、他の人の配信を見ながら、操作するのも簡単です。
![ポップアウト.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/249644/039d1d63-bed7-9e28-7a91-15e09c3c5125.png)

5.見たい画面をクリックして、拡大表示します。

あとはお好みで、ウィンドウサイズを変更したり、カメラをオンにしたりしてください。![拡大表示.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/249644/e3bdc356-ab89-9fab-6b57-d7fd2e5acf09.png)

### 参加者側

1.同じサーバー配信に参加します

![参加.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/249644/614c5a11-2936-f6a7-f68a-97a0cd257e05.png)

2.配信者(イベント管理者)側手順4の画像と同じような画面が表示されるので、配信者(イベント管理者)側手順4.5.を読んで、調整します。

![参加者側.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/249644/0b90e901-2e27-af3c-48b2-75f339779ee0.png)

3.自分の画面を共有する場合は、配信者(イベント管理者)側手順1.2.に沿って画面共有を行います。

# 最後に

設定は以上になります。
修正等ございましたら、編集リクエストをお願いします。
PythonでABC164のA~D問題を解きたかった

### はじめに
A~Cの三完でした。

### A問題
[問題](https://atcoder.jp/contests/abc164/tasks/abc164_a)

**考えたこと**
はい

```python
s, w = map(int,input().split())

if w >= s:
    print('unsafe')
else:
    print('safe')
```

### B問題
[問題]()

**考えたこと**
互いの体力を攻撃力で割って大小を考えるだけですが、同じ値の時の処理を書き忘れて1WA。とても痛い

```python
import math
a, b, c, d = map(int,input().split())

x = math.ceil(a/d)
y = math.ceil(c/b)

if x == y:
    print('Yes')
elif x > y:
    print('Yes')
else:
    print('No')
```

### C問題
[問題](https://atcoder.jp/contests/abc164/tasks/abc164_a)

**考えたこと**
setにいれてlenするだけ。簡単。なんでこっちがCなんだ。

```python
n = int(input())
s = [input() for _ in range(n)]

s = set(s)
print(len(s))
```

### D問題
[問題](https://atcoder.jp/contests/abc164/tasks/abc164_d)

わかりません

### まとめ
CとDの間に大きい壁があったので、Bの1WAが響いた。くやしい。ではまた、おやすみなさい。
bootstrap-selectの選択済み項目をJavaScriptで変更する際の注意点

bootstrap-selectプラグインを使ってドロップダウンリストを作成した場合は、JavaScriptで `$("ドロップダウンリスト").val("変更したい値")` で値を変更しただけでは表示が変更されない。
bootstrap-selectプラグインを使う場合は値のセットとは別に表示の変更を書く必要がある。

標準のドロップダウンリストは以下のようにすれば `selected` が変更され、表示も変更される。

```html:html
<select name="vegetable" class="selectpicker">
   <option value="carrot">にんじん</option>
   <option value="onion" selected>たまねぎ</option>
   <option value="potato">じゃがいも</option>
   <option value="broccoli">ブロッコリー</option>
</select>
```

```javascript:javascript
$("select[name=vegetable]").val("potato");
$(".selectpicker").selectpicker("render");
```

`refresh` でも表示の変更は可能だが、こちらはoption要素の追加・削除など、もっと高度な変更に使用するもののようだ。 [※参考サイト](https://developer.snapappointments.com/bootstrap-select/methods/)


```javascript
$(".selectpicker").selectpicker("refresh");
```
[draft] how to run wordPress on azure

<img width="950" alt="Screen Shot 2020-04-26 at 7.58.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431287/e18f5507-1c0e-7d47-1425-4a7ca2d4e343.png">

<img width="1422" alt="Screen Shot 2020-04-26 at 7.59.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431287/73c6e0b8-844e-9bd3-a27f-b57ad0be69c8.png">

<img width="884" alt="Screen Shot 2020-04-26 at 7.59.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431287/c32e5aef-438d-8bcb-7113-f986ee09259b.png">

<img width="561" alt="Screen Shot 2020-04-26 at 8.00.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431287/c4a2c659-5a18-3863-ba89-790698397d9b.png">

<img width="1234" alt="Screen Shot 2020-04-26 at 8.01.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431287/0bd8a4c0-8601-01fe-f1d3-03257eeddd15.png">

<img width="740" alt="Screen Shot 2020-04-26 at 8.01.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431287/3254ddde-53a5-5bee-1ce2-bd7584d64e2a.png">

<img width="612" alt="Screen Shot 2020-04-26 at 8.02.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431287/418b3920-30d9-a76e-abee-09ee2b15c251.png">

<img width="713" alt="Screen Shot 2020-04-26 at 8.02.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431287/3f95ce39-0a4a-6fda-2425-bc0c5e9122e0.png">

<img width="781" alt="Screen Shot 2020-04-26 at 8.03.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431287/04ecc793-a6b6-c5f6-499a-3f89958e0dc0.png">

<img width="1048" alt="Screen Shot 2020-04-26 at 9.03.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431287/6ad0e837-f182-fa35-add0-cfb801beb90f.png">

<img width="577" alt="Screen Shot 2020-04-26 at 16.56.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431287/7f5efa11-8844-3fd0-7021-e963abb583f2.png">

<img width="584" alt="Screen Shot 2020-04-26 at 22.14.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431287/b5d0622d-8aa5-f313-8031-77557272c633.png">

<img width="1439" alt="Screen Shot 2020-04-26 at 22.15.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431287/4a7c1ee6-5e65-085d-2d94-2e462d95aba5.png">

<img width="1433" alt="Screen Shot 2020-04-26 at 22.16.52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431287/07b305f9-7945-fd16-bb36-ad0152d3fa3e.png">
rails開発でハマったto_modelのエラー

　railsでフリマアプリをチーム開発してる時、あまり見かけないエラーに遭遇したので、具体的な原因はよくわかっていませんが、残しておきます。
　rubyバージョン  :2.5.1
　railsバージョン :5.2.4.2
　データベース 　 :mysql
#エラーが発生したコード
```ruby:_product.html.haml
 =image_tag product.images.first.images
```
productモデルとimageモデルが一対多の関係で結びついており、productモデルには***accepts_nested_attributes_for :images***が書かれています。
#エラー画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520754/b04f2478-8313-4960-a914-e5b42799e244.png)

to_modelという記述はどこにもしていませんし、to_xmlというxml形式で出力させる形式のメソッドをどう使えばいいのかわかりません。

#解決したコード
```ruby:_product.html.haml
  = image_tag product.images.first.images.url
```

　このエラーの"to_model”の意味は調べてみたもののよくわかっていませんが、データの呼び出しに失敗しているエラー（このオブジェクトにはこんなメソッドは存在しないよという意味のエラー）だと思うので呼び出し方を変えたらうまくいきました。
　あまり中身のない記事ですが、参考になれば幸いです。
vscode-pc-viewer

## 概要
点群データ(現在ply,pcdファイルのみ)を開くのにいちいちMeshLabもしくはvisualizerプログラムを開くのが面倒になったので、vscodeから直接中身の確認が可能な拡張機能[vscode-pc-viewer](https://marketplace.visualstudio.com/items?itemName=obarads.vscode-pc-viewer)を作成しました。

この手の拡張機能はすでに存在してそうだったのですが、ぱっと見で点群用はなかったので自作しました(検索ワードに引っかかった各拡張機能の説明文を少し読んだりした程度なのでもっとあるかもしれませんが)。
これに関連する拡張機能は[3D Viwer for VSCode](https://marketplace.visualstudio.com/items?itemName=slevesque.vscode-3dviewer)ぐらいしかありませんでした。

下の図は、頂点とそのRGB値を載せたplyファイルを表示させたものです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/250293/7a818afc-aaef-da17-4a38-d3a48f85e53a.png)


## プログラム
作成したプログラムは[github](https://github.com/Obarads)に上がってます。プログラムの中身は[tomoki1207さんのvscode-pdf](https://qiita.com/tomoki1207/items/8e7ade9b7bf6dd362f08)をベースとして作成しました。
ファイルのロード、表示は[three.js](https://threejs.org/)を参考に作成しており、自分で書いた部分は少ないです。

## 気になった点
- プログラムの項の@tomoki1207のリンク先にも述べられているように、一瞬ファイルの中身がそのまま映るという現象に対して、[onCustomEditor](https://code.visualstudio.com/api/extension-guides/custom-editors)を使うことでその現象がなくなりました(少なくとも自分の環境では)。ただこの方法を用いた場合、バイナリデータとして保存されているpcdファイルなどが読み取れなくなります(開けないと警告メッセージが出る)。そのため、結局@tomoki1207さんの実装をベースとした方を採用しました。
- 現在の実装ならバイナリファイルも開くことができますが、開くたびに「Do you want to open it anyway?」を押さなくてはいけません(下図)。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/250293/2671b6f5-ff2f-85f2-0a28-d0a33c0703c8.png)

- 開けるデータであるにもかかわらず、たまに画面が緑色のままになるという現象があります(原因不明)。一応、そのファイルを開き直せばちゃんと表示されます(連続で緑になることもあり)。

## あとがき
点群の位置まで視点を移動させる機能とか、点のサイズを変える機能とかあれば便利だと思いました~~が実装が面倒~~。
maven repogitory をgitlabのpagesで作成する。

# そもそもmavenリポジトリとは？
ビルド済みjarファイルのライブラリを配布するハブ空港みたいなもの。

今回はmavenセンターやjcenterなどの国際線空港を使わずに、gitlab pagesを使って自宅にヘリポートを作る試みです。

サーバーが自由に使えるならnexusなどを立ち上げればいいので、色々事情があって、gitlabプロジェクト単体でサポートしたい試みです。

mavenリポジトリの仕様はただの静的なwebページであることが最大のポイントです。実際に`maven deploy`せずに手動でnexusに登録することもできます。この仕組を再現する。つまり、mavenに頼らず、全てCIで管理する。

# 作ったもの
https://gitlab.com/akihirof0005/hello
で自動生成するリポジトリの
https://akihirof0005.gitlab.io/hello/
のURLです。

#　やっていること
```
## 
dir=`pwd`
mkdir -p ./public/org

## latest version
sed -i -e 's/<version>.*replace-->$/<version>latest<\/version>/' pom.xml
mvn -Dmaven.repo.local=./repo/ clean install
mv ./repo/org/sample ./public/org

## javadoc
mvn javadoc:javadoc
mv ./target/site/apidocs ./public/

## releases version
json=`curl "https://gitlab.com/api/v4/projects/17557723/releases?private_token=$CI_DEPLOY_PASSWORD"`
len=$(echo $json | jq length)
for i in $( seq 0 $(($len - 1)) ); do
  version=$(echo $json | jq -r .[$i].name)
  link=$(echo $json | jq -r .[$i].assets.links)
  len2=$(echo $link | jq length)
  mkdir "$dir/public/org/sample/hello/$version"
  cd "$dir/public/org/sample/hello/$version"
  for k in $( seq 0 $(($len2 - 1)) ); do
    curl $(echo $link | jq -r .[$k].url) -o  $(echo $link | jq -r .[$k].name)
  done
done

## create index.html
cd "$dir/public"
curl "https://gist.githubusercontent.com/andyferra/2554919/raw/10ce87fe71b23216e3075d5648b8b9e56f7758e1/github.css" -o ./github.css
pandoc -s ../README.md -t html5 -c github.css -o ./index.html
echo "<html><body><h1>Directory listing:</h1>" >> ./index.html
find ./org/sample/hello/ -exec echo "<a href='{}'>{}</a><br/>" \; >> ./index.html
echo "</body></html>" >> ./index.html

```

#　使ってみる
こちらから、gradleで検証した。

# お願い
mavenリポジトリの仕様に詳しい方などいらしたら詳しいツッコミをお待ちしています。