OmniAICreator/Qiita-1.07M huggingface dataset:
駆け出しエンジニアがLaravelを理解するために意識したこと

## はじめに

実務で **PHP, Laravel** を使用することになり、**最低限の理解(土台つくる)をする**上でやったこと・意識したことをまとめました。実務未経験の方や転職して間もないという方向けの記事になっております。

もちろん実務に入ってまだ約1ヶ月半なのでまだまだわからないことばかりですが、今まで学習してきた Ruby, Rails と違うけど大丈夫かなという不安はなくなってきましたので記事にまとめさせていただきました。

これから転職を考えている人もいるかと思います。個人の見解ですが、そのときに言語を特定のものに絞らなくても良いんじゃないかなあと思いましたので、迷われている方や実務で別の言語を触れるのか不安と思っている方の参考になったら幸いです。

## 実務にはいって

最初は今まで学習してきたものとの違いがあり、自分にできるかなあと思うこともありました。ただそれは振り返ってみれば、**これからやっていけるかなあとか不安などから視野が狭くなっていた**のが原因なのかなと思います。細かく具体的に見ていくとどの言語も別のものになってしまうと思いますが、少し**抽象度を上げて考えるとこの部分は似ているなとか少し違うけどこれぐらいの差**か、となったりします。

要はプログラミングをするということなのであまり大差はないはずです。（今までRuby, PHP, Pythonを扱っただけなので他の言語で全然違う意見があったらすみません。。）

**「誰のどんな悩みを解決」**するのか考え**「成し遂げたいこと」**、**「実装したいこと」**がありそれを**「どのように実現」**していくか、それを **言語化** して実装していくというフローは一緒です。

とはいえ全く一緒ということはないので抵抗は少しありましたし、それを埋めるためにググる時間があるかもしれませんが、それも**慣れ**なのかなと思います。簡単な例を出すと **PHP** だと変数名の前に `$` をつけますが、 **Ruby** だと付けないみたいな感じです。まだ癖が抜けなくて `$` を抜かしてしまうことがありますが、そのときはエラーが吐かれるのでデバッグをすれば解決です。

## 大事だと思ったこと

- ブログ記事はたくさんありますが、補助程度に使用すること
- チュートリアルに沿って要点を抑える
- とにかく実践あるのみ、わからないことがあればとことん調べる
- 公式ドキュメントを読む、英語から逃げない

### チュートリアル

丁寧にインストールするところからサンプルコードから体系的に学習することができます。開発の流れだったりメインの機能だったりが書かれているのでとても取り組みやすいです。

### 公式ドキュメント

公式ドキュメントの大切さは実務に入り身にしみて実感しました。今までも大切だということは理解していたのですが、記事をメインに公式ドキュメントを補助という使い方になっていた気がします。公式ドキュメントにしっかり書いてあるのに、色々な記事を彷徨ってしまう、、これ本当に**時間の無駄**ですよね。

ドキュメントをしっかり読むのには時間がかかります。だったらブログ記事を読んでサクッとデバッグしてけばいいじゃん！って思うかもしれません。それで解決できるならまだ良いですが、解決できなかったりブログに書いてあることが間違いだった場合にまた違う挙動が起きたりしてしまうなんてことになるかもしれません。

はじめは時間をかけてしまうかもしれませんが、しっかりと着実に理解していくほうが後々効いてくると思います。どこに重要なことが書いてあるんだろうとかそういったことも数をこなして慣れていったり、基本英語で書いてあることが多いけどわからないことは翻訳しながら読むようにしています。(少しずつ英語から読み取れるようになった気がします。)

いろいろ書きましたが言いたいことは、**公式ドキュメントを読むことでエラー解決のスピードや実装のスピードが格段に上がった**と思います。

エラーが起きたときにググり偶然同じエラーが起きた人がたまたまブログ記事などでまとめてくれていればラッキーですが、同じようなエラーが起きていないときはすぐに解決することができなくなってしまいます。

ブログ記事などは本当にわかりやすくまとめてくれていますが、あくまで補助的にしようするほうが良いと思います。とはいえ、公式ドキュメントやマニュアルでわからなかったり難しい表現を使ったりしていることも少なくないのでそういったところはブログ記事を参考にさせていただいております。


## ディレクトリ構造や役割を知る、慣れる

どのファイルで何をしているのか、どのような役割をもっているのか知ることは重要だと思います。エラーの原因なども特定しやすいですし、何より流れが追えてくるのでプログラミングの楽しさも増してきます。

わかりやすく全体像をまとめてくださっている記事がありましたので[こちら](https://qiita.com/Tsutou/items/80717884aee96fa804eb)に載せておきます。


## Ruby、Railsとの違い・共通点を考える

新しい言語だからと **「1から学ぶ」** と時間をものすごく浪費してしまう気がします。今まで学習してきたものがあるのであればそれと照らし合わせてこの言語だったらこういうふうにするんだよなあとか考えながらやると定着が早まると思います。また、このような学習の仕方をしていれば今後別の言語を扱ったときも同じようにスムーズに扱うことができるのではと思いました。

## まとめ

- 言語で選ぶのではなく「プログラミングとは」と少し抽象度を上げることによって見え方が変わる
- チュートリアルは体系的にまとまっていて初学者でも取り組みやすい
- 公式ドキュメントを読むことは実力をつけるプログラミングをしていく上では必須となる
- ブログ記事はたくさんありわかりやすくまとめてくれているが、最終的にはその情報があっているのか判断できるように一時ソースを読む


## おわりに

少し駆け足になってしまいましたが、実務未経験から転職して間もないという方向けに記事を書かせていただきました。ただ経験をいくら積んでも大事な点というのは変わらないと思います。より良い考え方や方法をアップデートなどしていけたらしていきます(別記事で違う視点からまとめる可能性も)。


## 参考文献

- [PHP マニュアル](https://www.php.net/manual/ja/index.php)
- [PHP チュートリアル](https://www.php.net/manual/ja/tutorial.php)
- [クイックスタート](https://readouble.com/laravel/4.2/ja/quick.html)
- [Laravelのディレクトリ構造と、お役立ちTips](https://qiita.com/Tsutou/items/80717884aee96fa804eb)
- [Laravel ソース](https://github.com/laravel/laravel)
- [Laravel Contribution Guide](https://laravel.com/docs/8.x/contributions)
【ICMPv6】チェックサム計算


```c:.c
/* https://alpha-netzilla.blogspot.com/2011/08/network.html */
/* Version + HeaderLength + ServiceType : 0x4500    */
/* TotalLength                  : 0x003C            */
/* Identifier                   : 0xF228            */
/* Flag + FragmentOffset        : 0x0000            */
/* TTL + Protocol               : 0x8001            */
/* CheckSum                     : 0xC140 → 0x0000   */
/* SourceIP                     : 0xC0A8            */
/*                                0x0303            */
/* DestIP                       : 0xC0A8            */
/*                                0x0304            */

/* icmpv6 checksum    */
/* Source Address     */
/* Destination Addres */
/* IpV6 Packet Length */
/* zero               */
/* Next Header = 0x3A */

#include <stdio.h>
#include <string.h>

typedef unsigned char  u_int8_t;
typedef unsigned char  u_char;
typedef unsigned short u_int16_t;
typedef unsigned long  u_int32_t;

u_int16_t checksum(u_char *data, int len);

int main( void )
{
    u_int16_t  checksum_gen = 0x0000;
    u_int16_t  checksum_ret = 0x0000;
    u_int16_t  data[] = {
        0x4500, 0x003C,
        0xF228, 0x0000,
        0x8001, checksum_gen,
        0xC0A8, 0x0303,
        0xC0A8, 0x0304,
    };
    
    /* checksum generate */
    checksum_gen = checksum((u_char*)&data[0], sizeof(data));
    
    /* checksum check */
    data[5] = checksum_gen;
    checksum_ret = checksum((u_char*)&data[0], sizeof(data));

    printf("checksum_len = %d\n", sizeof(data));
    printf("checksum_gen = 0x%04X\n", checksum_gen);
    printf("checksum_ret = 0x%04X\n", checksum_ret);
}

u_int16_t checksum(u_char *data, int len)
{
  register u_int32_t sum;
  register u_int16_t *ptr;
  register int       c;

  sum = 0;
  ptr = (u_int16_t *)data;

  for ( c = len; c > 1; c -= 2 )
  {
    sum += (*ptr);
    // sumは32bitなので0x80000000(2進数にしたら最上位bitが1)を超えると
    // 次の足し合わせ時に桁あふれする恐れがある。
    // よってこの段階でオーバーフロー分を加算しておく。
    if ( sum & 0x80000000 )
    {
      sum = (sum & 0xFFFF) + (sum >> 16);
    }
    ptr++;
  }

  if (c == 1)
  {
    u_int16_t val;
    val = 0;
    // 16bitの変数に8bitの値を前方に詰める。
    memcpy(&val, ptr, sizeof(u_int8_t));
    sum += val;
  }

  while (sum >> 16)
  {
    sum = (sum & 0xFFFF) + (sum >> 16);
  }
  // この結果が0または0xFFFFであればよい。
  return(~sum);
}
```

>参考(引用)
https://alpha-netzilla.blogspot.com/2011/08/network.html
RSpecデータリクエストを削減してテスト実行時間を削減した話

# はじめに
私はエンジニアインターンで主にサーバーサイドの開発を担当させていただいています。

機能実装の際はRSpecでテストケースを書いてから実装していて、コミットする前に全体のテストを通してバグを見つけているのですが
### 実行時間が長い！

ということで、RSpecのリファクタリングを行いテストの実行時間を削減して見ましたので、一部紹介したいと思います。

# 1. 従来のRSpecでのデータリクエスト状況
現状、RSpecでは以下のように、```let```を使用してデータの作成を行っています。

```ruby:
require 'spec_helper'

describe User do
  let!(:user) { FactoryBot.create(:user) }

  it 'anything' do
    # userのテスト
  end

  it 'anything' do
    # userのテスト
  end

  it 'anything' do
    # userのテスト
  end
end
```

これではexampleが3回行われる度に```User```モデルが作成されてしまう。
これをどうにか1回のレコード作成に留められないか...



# 2. gem "test-prof"の導入
そこで```test-prof```を導入します。

```ruby:Gemfile
gem "test-prof"
```

```
bundle install
```

## 変更後テストケース

```ruby
require 'spec_helper'

describe User do
  let_it_be(:user) { FactoryBot.create(:user) }

  it 'anything' do
    # userのテスト
  end

  it 'anything' do
    # userのテスト
  end

  it 'anything' do
    # userのテスト
  end
end
```

このようにtest-profは```let_it_be```というヘルパーメソッドを提供してくれるgemになります。

そうするとRailsのトランザクションテスト機能を利用してレコードを最初に1回だけ作成して、テストが終了したら該当データを削除してくれるようになります。

# 3. ベンチマーク
変更したテストファイル数は全体の3割ほどですが、約1分のテスト実行時間の削減に繋がりました。


### let_it_be使用前

![スクリーンショット 2021-03-12 18.12.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515679/9c96893d-6e26-f729-a6bf-ceaa0d549033.png)

### let_it_be使用後

![スクリーンショット 2021-03-12 18.46.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515679/dfc61543-a292-ab47-4685-e209e362919b.png)


# おわりに
画期的にテストの実行時間を削減できた訳ではありませんが、長期的に見て効果のある対処法なのではないかと思います。

# 参考
https://techracho.bpsinc.jp/hachi8833/2018_05_16/55546
BuefyからPrimeVueに移行

vueが3.0になり、そろそろ移行しようかなーと思ってやってみると、普段使っていたBuefyが3.0に未対応のようです。
開発者の方々？はPrimeVueで忙しい的なことを書いていたので移行を検討。
vue3.0に対応しているし、Buefyで使っていたコントロールはほぼ網羅している。
vue3でamCharts4を使いたい→使えた

そもそも、まず「使えるかどうか知りたかった」んですがggっても出てこなかったのでメモです。
vue3でamChart4、使えました。（少なくとも表示はできました。）

公式を元に
https://www.amcharts.com/docs/v4/getting-started/integrations/using-vue-js/
`beforeDestroy`を`beforeUnmount`に変更したら表示までは少なくともいけました。

```vuejs
<template>
  <div class="hello" ref="chartdiv">
  </div>
</template>

<script>
import * as am4core from "@amcharts/amcharts4/core";
import * as am4charts from "@amcharts/amcharts4/charts";
import am4themes_animated from "@amcharts/amcharts4/themes/animated";

am4core.useTheme(am4themes_animated);


export default {
  name: 'HelloWorld',
  mounted() {
    let chart = am4core.create(this.$refs.chartdiv, am4charts.XYChart);

    chart.paddingRight = 20;

    let data = [];
    let visits = 10;
    for (let i = 1; i < 366; i++) {
      visits += Math.round((Math.random() < 0.5 ? 1 : -1) * Math.random() * 10);
      data.push({ date: new Date(2018, 0, i), name: "name" + i, value: visits });
    }

    chart.data = data;

    let dateAxis = chart.xAxes.push(new am4charts.DateAxis());
    dateAxis.renderer.grid.template.location = 0;

    let valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
    valueAxis.tooltip.disabled = true;
    valueAxis.renderer.minWidth = 35;

    let series = chart.series.push(new am4charts.LineSeries());
    series.dataFields.dateX = "date";
    series.dataFields.valueY = "value";

    series.tooltipText = "{valueY.value}";
    chart.cursor = new am4charts.XYCursor();

    let scrollbarX = new am4charts.XYChartScrollbar();
    scrollbarX.series.push(series);
    chart.scrollbarX = scrollbarX;

    this.chart = chart;
  },
  // ここが公式ではbeforeDestroy
  beforeUnmount() {
    if (this.chart) {
      this.chart.dispose();
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.hello {
  width: 100%;
  height: 500px;
}
</style>
```

使えそうです。よかった。

追記：
amCharts4の月を数字にしたい＆日本語化（vue3）
https://qiita.com/AyakoKataoka/items/31382d7c283d753afd39
AtCoder自分用まとめ013(ARC004A The longest distance)

#概要
自分のために、AtCoderで身に付けた内容・コードをまとめておく。

#内容
https://atcoder.jp/contests/arc004/tasks/arc004_1
>平面上に N 個の点があり、それぞれ 0 から N−1 までの番号が付けられており、それぞれの点について x 座標と y 座標が与えられています。
その N 点のうち 2 点を選び結んで得られる線分のうち、最も長くなる線分の長さを求めてください。 

```:入力形式
N
x0 y0
x1 y1
...
xN-1 yN-1
```

##C++
```cpp
#include <bits/stdc++.h>
using namespace std;
int main() {
  int N;
  cin>>N;
  vector<double> X(N), Y(N);
  for (int i=0;i<N; i++) {
    cin>>X[i]>>Y[i];
  }

  double d,max_distance = 0.;
  for (int i=0; i<N; i++) {
    for (int j=0; j<i; j++) {
       d = sqrt((X[i]-X[j])*(X[i]-X[j])
               +(Y[i]-Y[j])*(Y[i]-Y[j]));
       if (d > max_distance)
         max_distance = d;
    }
  }
  cout<<max_distance<<endl;
}
```

#参考にさせていただいた頁
- https://atcoder.jp/contests/arc004/tasks/arc004_1
- https://qiita.com/drken/items/e77685614f3c6bf86f44

#感想
単純なforでの全探索の例でした。
「リーダブルコード」の要約・まとめ

**「リーダブルコード」** ~より良いコードを書くためのシンプルで実践的なテクニック~
を読んだので、簡単に要点だけをまとめてみました。
最短最速で要点を抑えたい人には最適です。

全４章で構成されている

- 表面上の改善
- ループとロジックの単純化
- コードの再構成
- 選抜テーマ

とりあえず１章の要点をまとめます。今後2~4章を追記します。

# 表面上の改善
理解しやすいコードを書くためのコツが以下の6セクションに渡って説明されている。


## セクション１ (優れたコード)
コードは他の人が**最短**で理解できるものが良い。
簡潔なものより、複数行に渡って書かれているものが良い場合もある。

全ては「読みやすさ」重視。

## セクション２ (命名)
名前を見ただけで情報を読み取れることが大事。

- get,stop,sizeなどよりも、もっと具体的なwordを用いるべき。
- retVal,value,resultなどの意味のない単語は避けるべき。ただし、その単語の登場する行数(スコープ)が短ければOK。
- 単語補完機能を使ってみるべし。
- 省略形は共通認識のものだけ。stringをstrやButtonのbtnなどはOKだが、他の勝手な省略は避ける。

## セクション３ (命名での誤解)

他の意味と間違われることはないか確認することが重要。
最善の名前とは誤解されない名前のこと。

- filterなどは誤解を招く。selectなのか、excludeなのか。
- 限界値を決めるときは、max,minを使用。
- bool値はis,has,shouldなどをつけて、true,falseをわかりやすくする。否定形はやめて肯定形にしないと、意味がややこしくなる。

## セクション４ (コードの美しさ)

プログラマの仕事の多くはコードを読む時間。
美しいコードの方がいいに決まっている。
重要なのは「一貫性」と「意味のある整形」

- 変な改行を修正。(IDEのコード補完機能使うとうまくいかないことが多いけど、これは仕方ないのかな。)
- 縦の整列を意識する。
- コードをどんな順番で並べても良い時でも、意味のある順番に並べる。重要度、アルファベット順など。
- 宣言をブロックに分ける(コメントなどで役割を区切る)
- 長いコードのまとまりは段落分けする。（これも要約コメントで区切っていくと見やすい）

## セクション５ (コメントを書く・書かない、コメント内容)

コメントの役割は、書き手の意図を読み手に伝えること。

**コメントを書かないケース**

- コードからすぐにわかることをコメントに書かない。
- ひどい名前を捕捉するためのコメントなら、名前自体を変えるべき。

**コメントを書くケース**

- 自分の考えをコメントする。
- コードの欠陥にコメントをつける。
- 定数にコメントをつける。定数の値を決めた時の頭の中を記録しておくと良い。
- ハマりそうな罠はコメントで告知。
- 読み手が驚きそうなところにはコメントを残す。
- ファイルやクラスには全体像へのコメントを残す。

## セクション６　（コメントする際のTips）
少ない領域に多くの情報を詰める。

- 代名詞を避ける。
- 関数の動作は正確に記述。
- 説明しにくい、伝わりづらいものは実例を交えて説明。
- 多くの意味が詰められた言葉を用いることで簡潔に書く。


# ループとロジックの単純化

## 制御フローを読みやすく
**・条件式の引数の並び順**

```dart

if(10 >= length)
```
よりも

```dart

if(length <= 10)
```
の方が読みやすい。

読みやすくするためには、
左側・・・調査対象(変化するもの)
右側・・・比較対象（あまり変化しない。安定なもの。）
にすると良い。

**・if/elseのブロックの並び順**

```dart

if(a == b){
...
} else{
...
}
```

```dart

if(a != b){
...
} else{
...
}
```

上記の２例では１つめが良い。
これも以下のように優劣が決まっている。

- 条件は否定系より肯定系を使う
- 単純な条件を先に書く
- 関心を引く、目立つ条件は先に書く

これらの条件が重なった場合は自分で判断する。

**・三項演算子**

基本的にはif/elseを使う。
(条件) ? a : b　を使うのは、簡潔にわかりやすく書ける場合のみ。
ActiveModelに対してエラーメッセージ日本語化 ja.yml書き方

投稿記事にタグ付けをするため、1つのフォーム送信で複数のモデルを更新できるというFormオブジェクトを使用しました。

```ruby:app/models/posts_tag.rb
class PostsTag
  include ActiveModel::Model
  attr_accessor :title,:text,:answer,:user_id,:image, :name

  with_options presence: true do
    validates :title
    validates :text
    validates :name
  end

  def save
    post = Post.create(title: title,text: text,answer: answer,user_id: user_id,image: image)
    tag = Tag.where(name: name).first_or_initialize
    tag.save
    
    PostTagRelation.create(post_id: post.id, tag_id: tag.id)
  end
end
```

そして投稿時にエラーが発生した際に日本語でエラーメッセージが表示されるようにja.ymlを作成したのですが、英語から日本語に変換してくれませんでした。><
↓はダメだった書き方です。

```ruby:config/locales/ja.yml
ja:
 activerecord:
   attributes:
     user:
       nickname: ニックネーム
     post:
       title: 投稿タイトル
       text: 投稿内容
       image: 画像
       name: タグ名
```

そこから下記のように修正したところ日本語に変換してくれました！

```ruby:config/locales/ja.yml
ja:
 activerecord:
   attributes:
     user:
       nickname: ニックネーム
 activemodel:
  attributes:
   posts_tag:
       title: 投稿タイトル
       text: 投稿内容
       image: 画像
       name: タグ名
       
```
activerecordとactivemodelの違いも分かっていないプログラミング初学者ですが、
とても良い経験となりました。

おわり
JavaScript　円弧の書き方

JavaScriptで円を描く方法を実際の行為に置き換えながら説明してみました。
ほぼこれの内容です。

https://developer.mozilla.org/ja/docs/Web/API/Canvas_API/Tutorial/Drawing_shapes

# 画用紙の準備 
##canvas要素

canvas要素は、JavaScriptという名の鉛筆で、図形などを描くための画用紙のようなイメージです。widthとheightとそれぞれ幅と高さを指定します。
後でJavaScriptで要素を取得するためにidを指定します。

```html
   <canvas id="canvas" width="150" height="200"></canvas>
```

##getContext
canvas要素をidで取得し、`getContext`メソッドで書きたい図形が２次元だということを指定します。変数ctxに代入してそれに対して様々なメソッドで円を書いていきます。
※３次元もできるっぽいですが、まだ勉強してません。

https://developer.mozilla.org/ja/docs/Web/API/Canvas_API/Tutorial/Basic_usage

```javascript
   var canvas = document.getElementById("canvas");
   var ctx = canvas.getContext("2d");
```

# 鉛筆をもつ
##beginPath
beginPathで鉛筆を持ちます。

```javascript
   ctx.beginPath();
```
#書きたい円を想像する
##arcメソッド
書きたい円を想像してその設計図をarcメソッドに書いていきます。

```JavaScript
   ctx.arc(75,75,20,0,(Math.PI/180)*90,true)
```
`arc(x軸,y軸,半径,弧が開始する角度,弧が終了する角度,弧の向き)`に従って、値を入れていきます。
###x軸,y軸
作成したcanvas要素の左上を原点とし、描きたい円弧の中心をどこにするかを指定する。
width=150,height150のcanvas要素を作成した場あり、`x=75,y=75`とするとcanvas要素の中心に、円弧の中心を指定できます。

###半径
作成したい円の半径を指定します。そのままですね。
###弧が開始する角度,弧が終了する角度
円の中心を通り水平に線を引いたときの右側の円との接点を0°、円の中心を通り垂直に線を引いたときの下側の円との接点を90°として値を設定します。下記例です。(中心が雑ですみません。)

開始する角度に0、終了する角度に90を指定した場合
![スクリーンショット 2021-03-21 20.29.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603163/3b0ca2de-4d42-27c7-07f7-ac16f2d06fb2.png)

開始する角度に90,終了する角度に270を指定した場合
![スクリーンショット 2021-03-21 20.39.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603163/2ba8b85e-adc5-6405-5ce2-b326d1104345.png)

ここでいう角度は、多くの人が想像するであろう60°とか45°とかいう度数法ではなく、弧度法(ラジアン)で指定します。弧度法(ラジアン)のことを知らなくても、`(Math.PI/180)*degrees`の`degrees`に度数法の数字を指定すれば良いです。終了する角度に90を指定したい場合は`(Math.PI/180)*90`のように。
ちなみに、ラジアン知らなかったのですが下記サイトで理解できました。

https://kenyu-life.com/2019/01/09/rad/

###弧の向き
時計回りか、反時計回りかです。真偽値で示します。falseが時計回り、trueが反時計周りで、指定しない場合はfalseとみなされ時計回りに弧が描かれます。

#円弧を描く
strokeメソッドを使って円弧を書きます。ちなみにfillメソッドだと、指定した開始角度と終了角度を結んだ線と円弧で囲まれた部分が黒く塗りつぶされます。

```JavaScript
   ctx.stroke()
```

#完成型コード

```JavaScript
   var canvas = document.getElementById("canvas");
      if (canvas.getContext) {
        var ctx = canvas.getContext("2d");
        ctx.beginPath();
        ctx.arc(250,250,100,(Math.PI/180)*90,(Math.PI/180)*270);
        ctx.stroke();        
      }
```
ブラウザによってはgetContextメソッドが使用できない場合があるらしく、if文いれています。


###おわりに
需要あるかどうかわかりませんが、誰かの役に立てば幸いです。
QuickNode で ethreum アーカイブノードにアクセスするメモ($9/month で 10 回/月まで)

Python web3 で Uniswap の流動性ペアの残高を取得するメモ(最新ブロックのみ)
https://qiita.com/syoyo/items/d4db214903bd0105247c

過去ブロックの残高見たいようです.

https://www.quiknode.io/

$9/month プランで 10 回/month までクエリできました(Free Archive Call = 128 ブロック前のデータにアクセス).

Matic など L2 ノード(ただこちらは過去履歴にはアクセスできないっぽい), BSC なども対応しています.

2021/03/21 時点で, 128 blocks 以上前の 2021/01/05 の Uniswap WETH/USDT 残高にアクセスしてみます.
 
```py
import json

from web3 import Web3,HTTPProvider

web3 = Web3(HTTPProvider('https://cold-solitary-resonance.quiknode.pro/xxxx/'))
blockNumber=web3.eth.blockNumber
print(blockNumber)


addr_weth_usdt = '0x0d4a11d5EEaaC28EC3F61d100daF4d40471f1852' # Uniswap WETH/USDT pair

abi_weth_usdt = json.loads(open('abi.json').read())
contract = web3.eth.contract(address=addr_weth_usdt, abi=abi_weth_usdt)
print("decimals", contract.functions.decimals().call())
print("totalSupply", contract.functions.totalSupply().call())
print("token0 addr", contract.functions.token0().call())
print("token1 addr", contract.functions.token1().call())

block_no=11592051  # Jan-05-2021 03:29:53 AM +UTC
print("reserves(token0, token1, blocktime): ", contract.functions.getReserves().call(block_identifier=block_no))
```

```
456195507074386999986802
12081912
decimals 18
totalSupply 2258295820883597461
token0 addr 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
token1 addr 0xdAC17F958D2ee523a2206206994597C13D831ec7
reserves(token0, token1, blocktime):  [81586037830394576150231, 85811089218896, 1609817339]
```

Voila!

## 課題

Scale プラン(`$299 / month`)でも, アーカイブノードへのアクセスは 300 / month までです.

`$250/month` の archive node アドオン契約すれば各プランでのコール最大(`$9` プランだと 300k /month)で呼べるようですが... ちょっとお高いですよね.

税金計算のためにスポットで使うにはいいかもですが(チェックしたいのが少なければ etherscan で手動取得でもいいかもですが), 常時アーカイブノードにアクセスしたいのであれば自前で建てたほうが安上がりかもしれません.
Gopher君のかるた大会


## 概要

問題文が消失したため不詳だが、 https://github.com/cielavenir/codeiq_solutions/blob/master/00misc/comb/comb_test.go なるテストコードがpassすれば良い。

つまり、

```
func main(){
	strs := []string{"A", "B", "C", "D", "E"}
	for i := range comb.CombinationGenerator(5,2){
		var actual []string
		i.Index(strs,&actual)
		fmt.Printf("%v\n", actual)
	}
}
```

なるmainに対し、

```
[A B]
[A C]
[A D]
[A E]
[B C]
[B D]
[B E]
[C D]
[C E]
[D E]
```

なる出力をすれば良い。

本問に関して、 https://qiita.com/cielavenir/items/d82515b7d12ab25afa56 にて、「Goの型システムは死ぬほど理解に苦しむ、と思った。」と述べた。だが、これを克服できる可能性が生まれた。

## 条件

- comb.CombinationGeneratorが組み合わせを表すオブジェクトを組み合わせ数分返すこと
- 当該オブジェクトがIndexメソッドを持つこと

である。 **「組み合わせを表すオブジェクト」の型は規定されていない** というのが肝要である。

## Go2

Go2にて、ジェネリクスが導入されることとなった。メソッドに対してはジェネリクスを扱えないので、オブジェクトの側に型を導入するしかない。
てなわけで https://github.com/cielavenir/codeiq_solutions/blob/master/00misc/comb/tyama_codeiq181_generics.go のようになった。
**8年越し** に解くことができた。

## 余談1

C++でこういうコードが合法らしい。初めて知った。

```
#include <iostream>
template<typename T>
void P(int x){std::cout<<x<<std::endl;}
int main(){P<char>(3.0);}
```

## 余談2

[unique_permutation](https://qiita.com/cielavenir/items/74f8d547437154c14e72)の方が実用的にはましだと思います。
PyaudioをWindowsのPython仮想環境にインストールする

**Windows10で仮想環境にPyaudioをインストールする際に少し手間取ったので、成功した方法をメモ**


#環境
Windows10 Home
pip 21.0.1

#手順
### ①適当な.pyを作り以下のコードをコピペして実行
  - pipのバージョンによって、1行目が異なるので注意
  - `pip get_supported `などで検索

```Python
from pip._internal.utils.compatibility_tags import get_supported
print(get_supported())
```

- リストに表示されるcp〇〇が後で必要になるため覚えておく
   - 画像ではcp32 ~ cp38
   
        ![pip_cap.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/884788/04628076-62d0-db27-2559-976f2d340ce5.png)


### ②このサイト (https://www.lfd.uci.edu/~gohlke/pythonlibs/#pyaudio) から、先ほどのcpの値と自分のPCのビット数に応じたものをダウンロード
- 今回は、*PyAudio‑0.2.11‑cp38‑cp38‑win_amd64.whl*をダウンロード

### ③仮想環境をアクティブにするため、コマンドプロンプトを開いて以下のコマンドを打つ
- pathは仮想環境のパスを入力

```
path\venv\Script\activate

例:C:\Users\****\PycharmProjects\〇〇\venv\Scripts\activate
```

### ④先ほどダウンロードした.whlファイルをpipを用いてインストールするため、引き続きコマンドプロンプトで以下のコマンドを打つ

```
pip install path\Pyaudio-0.2.11-cp-38-cp38-win_amd64.whl

例:pip install C:\Users\****\Downloads\Pyaudio-0.2.11-cp-38-cp38-win_amd64.whl
```

- 以下のような出力が出れば成功

```
Processing path\pyaudio-0.2.11-cp38-cp38-win_amd64.whl
Installing collected packages: PyAudio
Successfully installed PyAudio-0.2.11
```

***
ビルド順を保つためにincludeをソートしたなくない人へ

ビルド順を固定したいため、include をソートしたなくない場合もあるかと思います。
そのための設定です。

# 要約
これをいれればOK。

```
SortIncludes: false
```

# 設定方法
1. ctrl + , で設定を開く
2. 検索窓で clang_format_style で検索
3. こんな感じで設定する
![2021-03-15_10h02_43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506075/aaaf28e2-b2b8-36cd-1ff1-a6698dfc5468.png)

# 参考
* 解決に至るための [StackOverflow](https://stackoverflow.com/questions/64392293/c-clang-formatter-how-to-avoid-rearranging-sorting-include-blocks-at-all)
* むしろ並べ替えたいときの [IncludeBlocks](https://bcain-llvm.readthedocs.io/projects/clang/en/latest/ClangFormatStyleOptions/) オプション
ssh ポートフォワーディングで複数ポートを転送したいメモ

## 背景

複数ポート(e.g. 8000~8010) のポートアクセスが必要なサービスをポートフォワーディングで対応したい.

## 方法

ワイルドカード指定とかはできずに, 一つづつ指定が必要でした.

https://stackoverflow.com/questions/29936948/ssh-l-forward-multiple-ports/29937009

個数がすくなければ `-L` を複数指定, 多ければ `~/.ssh/config` に記載, フレキシブルにしたいのであれば shell がよいでしょうか.

## TODO

* [ ] リバースポートフォワーディングでいけるか試す(ルータの NAT 設定せずに複数ポート使うサービスを外部からアクセスできるように)
Bashのように波括弧({},ブレース,brace)のパターン展開

# 波括弧の展開ライブラリの紹介

Bashで波括弧の展開にお世話になった人はいないだろうか。
Pythonのライブラリに同じことができるライブラリがあったので紹介する

深いパス等指定が面倒なパスがあったとき、例えばこのファイルを退避しようとすると普通は下記のように書く

```bash
mv a/b/c/d/e/f/g/hoge.txt a/b/c/d/e/f/g/hoge_bak.txt
```

これをBashの波括弧の展開を使うと次のように書ける

```bash
mv a/b/c/d/e/f/g/hoge{,_bak}.txt
```

また、ワイルドカード(```*```)やクエッション(```?```)だと余計なモノが含まれる場合、いちいち列挙しなければならない。

例えば、下記ファイルがあったときにa1,a2,b0のファイルだけ指定したいときに

```bash
file-a0.txt file-a1.txt file-a2.txt file-b0.txt file-b1.txt file-b2.txt
```
次のようにネストして書くこともできる。

```bash
echo file-{a{0,1},b0}.txt
file-a0.txt file-a1.txt file-b0.txt
```


それをpythonでできるようにしたライブラリが [bracex](https://pypi.org/project/bracex/) 
ニッチな用途かもしれないが、使えると手間が少し減るかもしれない。
なお、もっと詳しい説明が[こっち](https://facelessuser.github.io/bracex/)に書いてある。

```python
>>> bracex.expand("file-{a{0,1},b0}.txt")
['file-a0.txt', 'file-a1.txt', 'file-b0.txt']
```

glob でもできればいいのにとは思うけど、globはマッチするモノを返すから混ぜるとよくないかな。。。
シンプルで使いやすいJSONフォーマットツールを作ってみた

# はじめに

こんにちは、システム開発チーム「presto」です。
開発業務（プログラミング中）に「こんなツール、あんなツールが身近なところにあったらいいなぁ」と思ったことはありませんか？

ここではそんなツールをVuetifyを使って作ってみたので紹介させてください。

# JSONフォーマットツール

今回紹介させていただくのは、[JSONフォーマットツール](https://web-tools.presto-service.com/json-formatter)です。

画面は以下の通りです。

![JSONフォーマットツール](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1227155/499b0ae7-49e2-6b73-9536-cb7f60ae25a4.png "JSONフォーマットツール")

# 使い方

使い方は以下の通りです。
1. 画面上部のテキストエリアにJSON文字列を入力する
2. （任意）フォーマットのインデント数を指定する
3. 結果確認

## 1. 画面上部のテキストエリアにJSON文字列を入力する

![JSONフォーマットツール_手順1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1227155/70b7b845-8a0c-e6c5-ab5f-34455468043f.png "JSONフォーマットツール_手順1")

例として、以下を入力します。

```json
{"number":12345,"result":true}
```

![JSONフォーマットツール_手順1_入力内容](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1227155/af2bbd89-c74a-b893-b671-c6c629e725eb.png "JSONフォーマットツール_手順1_入力内容")

## 2. （任意）フォーマットのインデント数を指定する

デフォルトのインデント数は「4」となっています。

![JSONフォーマットツール_手順2_インデント数指定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1227155/27525cca-91e7-18f8-ff61-d69928e5a429.png "JSONフォーマットツール_手順2_インデント数指定")

## 3. 結果確認

以下のような値が表示されます。

```json
{
    "number": 12345,
    "result": true
}
```

![JSONフォーマットツール_手順3_フォーマット結果](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1227155/38815b57-2761-f8f8-c18e-62ca13c918b8.png "JSONフォーマットツール_手順3_フォーマット結果")


インデント数を「0」と指定すると、整形後のJSON文字列がMinifyされます。

```json
{"number":12345,"result":true}
```

![JSONフォーマットツール_手順3_インデント数指定_Minify](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1227155/9f067de1-af0c-78b1-7ab4-82f3f926a78d.png "JSONフォーマットツール_手順3_インデント数指定_Minify")

### JSONフォーマットできない文字列を入力した場合

JSONフォーマットできない文字列を入力した場合、SyntaxErrorが表示されます。

```
SyntaxError: Unexpected token d in JSON at position 6
```

![JSONフォーマットツール_SyntaxError](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1227155/737e85a3-a34b-f677-57bf-b538991d03fa.png "JSONフォーマットツール_SyntaxError")


# まとめ

今回は、[JSONフォーマットツール](https://web-tools.presto-service.com/json-formatter)の紹介をさせていただきました。

他にも、私達が作った[presto web tools](https://web-tools.presto-service.com/)の紹介もしていますので、良ければ合わせてご覧ください。

https://qiita.com/presto/items/cd5f4cd6e3f364025606

https://qiita.com/presto/items/62e962c1f50572f8d399

https://qiita.com/presto/items/2d79f8208f78685ff990

https://qiita.com/presto/items/21a6713a108da35075c0

https://qiita.com/presto/items/e8e1d6fa5b07306937d9

https://qiita.com/presto/items/8dfa800eb8d3008686b1

今後もよろしくお願いします。
ありがとうございましたー！
【JavaScript】配列を分割して配列を生成する

#はじめに
配列の要素を任意の個数で分割したいと思ったときに、既に記事にしていた方がいました。
ナレッジ共有に感謝しかありません。ありがとうございます。
本記事の最後に出典としてURLを貼っておきます。
この記事の目的として自分の知識の整理のための記事のため、もっと詳細な説明を知りたい場合は、出典元の記事を参照していただければと思います。


#配列を任意の個数の配列に分割する関数
以下が配列を任意の個数の配列に分割する関数になります。
何をやっているかを説明していきます。

```ts
const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

const sliceByNumber = (array, number) => {
  // 元の配列(今回で言うと変数arrayを指します)を基に、分割して生成する配列の個数を取得する処理です。
  // 今回は元の配列の要素数が10個、分割して生成する配列は2つの要素を持つことを期待しています。
  // 上記のことから今回は、元の配列から5つの配列に分割されることになります。
  const length = Math.ceil(array.length / number);

  // new Arrayの引数に上記で取得した配列の個数を渡します。これで配列の中に5つの配列が生成されます。
  // 5つの配列分だけループ処理(mapメソッド)をします。map処理の中でsliceメソッドを使用して、元の配列から新しい配列を作成して返却します。
  // sliceメソッドの中では、要素数2つの配列を生成します。
  // fillメソッドはインデックスのキーを生成するために使用しています。もし使用しない場合はmapメソッドはindexがないため、mapメソッドが機能しません。
  return new Array(length)
    .fill()
    .map((_, i) => array.slice(i * number, (i + 1) * number));
};

console.log(sliceByNumber(array, 2));
// [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ], [ 7, 8 ], [ 9, 10 ] ]
```

#終わりに
今回参考にさせて頂いた記事では、詳細な説明までありとても参考になりました。
改めてありがとうございます。
僕も他の人のナレッジ共有できるように詳細で分かりやすい記事を書いていきたいと思います。


#参考サイト
http://yucatio.hatenablog.com/entry/2019/12/10/222311

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/map

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/fill

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/slice
CodePipelineでpush順にデプロイしたい

CodePipelineでデプロイすることに取り組んできましたが、リリースがたまると不都合が発生してきたので、その課題と回避策をまとめてみます。

## 現在の流れ
Commit -> Build -> マニュアル承認 -> Deploy

* CodePipelineは、main(master)ブランチをトリガーに動く
* CodeBuildでDockerイメージを作って、latestタグを付与している
* CodeBuildまで成功したら、マニュアル承認でデプロイを制御する
* CodeDeployで実行するスクリプトはlatestのイメージを使っている

## 課題：ブランチが複数回更新されると、更新順通りの最新(latest)がデプロイできない
* 1回目の更新で動くCodePipelineでデプロイのマニュアル承認前に、2回目のブランチ更新が来ると
* 2回目の更新に連動して、CodeBuildが動くので、latestイメージが更新される(**ここが問題**)
* この状態で、1回目のマニュアル承認すると、latestがデプロイされるので、1回目の更新に関するデプロイができない

## 回避策
Commit -> マニュアル承認 -> Build -> Deploy

* CodeCommitの次に承認を入れ[インバウンド実行](https://docs.aws.amazon.com/ja_jp/codepipeline/latest/userguide/concepts-how-it-works.html#how-it-works-inbound-executions)を利用して、CodeBuildをシーケンシャルにさせることでlatestを保護し順番通りのデプロイを可能にする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1219565/93c23b15-d5d6-afdb-a92a-0d26533db726.png)

## 考察
そもそも、「デプロイスクリプト、方針、設計がよろしくない」部分もありますが、運用に入るとすぐに変更できない都合もあり、回避策の一つとして参考になれば幸いです
gitlab-ceのレポジトリをAWS CodeCommitにミラーする

自前で管理している[gitlab-ce](https://www.gitlab.jp/install/)のレポジトリを、AWS CodeCommitにミラーリングした時の流れをまとめてみました。

今までは、EC2上にgitlab-runnerを走らせてCI/CDを頑張ってきましたが、主のプラットフォームをAWSに移していってるし、CI/CDはAWS側に寄せて行こうと思い、まずはレポジトリミラーリングから始めてみた。

1. 受け側を作る(AWS CodeCommit)
2. ミラーリング用IAM設定を行う(AWS)
3. 送る側を設定する(gitlab-ce)

## AWS CodeCommitの受け側を作る
[AWS CodeCommit](https://ap-northeast-1.console.aws.amazon.com/codesuite/codecommit/start)を開いて、「レポジトリを作成」を行います

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1219565/b8c7edfe-1d28-c678-cec2-483005e0ec46.png)

* レポジトリ名は仮に「codecommit001」で作ると、以下のレポジトリURLが発行されるので、これをメモします(後で使います)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1219565/e449a6c6-9319-524f-8a61-3db0ee09ac8c.png)

## ミラーリング用IAM設定を行う

### IAMポリシーの作成
* サービスは、CodeCommitを選択
* アクションは、GitPullとGitPushのみでOK

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1219565/353d1e72-3021-8e4a-20cf-b6c231c70631.png)

* ARNの編集で先ほど作成したcodecommitのレポジトリを指定します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1219565/151de1d4-829f-0edd-255b-f5129812ef4c.png)

### IAMユーザーの作成
* ミラーリングに使うIAMユーザーを作成し、先ほどのポリシーを割り当てます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1219565/a22cc039-553f-05f4-9840-5b1c1dfdb426.png)

* 作成後に、IAMユーザーの認証情報タブで以下の認証情報を生成します（HTTPSでの認証の場合は、「HTTPS Git認証情報の作成」）
* ここで生成された、ユーザー名、パスワードを後で利用します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1219565/7fea6b7c-7964-09bf-519e-9a5a0d04cbd0.png)


## 送る側を設定する
* gitlab-ceのミラーしたいプロジェクトの、「設定 > レポジトリ」を開き、以下のように、ミラー先のCodeCommitの情報を入力し、「レポジトリのミラー」を実行

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1219565/caaa19af-ac11-1763-d137-3050eb614ee6.png)

## 反映確認
しばらくすると、以下のようにgitlab-ceのレポジトリがミラーされていることが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1219565/ce249196-e639-4fb2-8767-56422e6b5216.png)


## この後は
ここまでできると、gitlab-ceのレポジトリの更新がCodeCommitにミラーされるので、CodePipelineで、CodeCommit/CodeBuild/CodeDeploy等によるCI/CDもできるようになりますね
Linux 基本的なコマンド群


##ls
ファイルやディレクトリの参照

**ls [オプション][ファイル]**

-a  全て出力
-l　long形式で出力
-t　最終更新時間によって、ソートして出力
-r　逆順にソートして出力


##cp
ファイルのコピー

 **[オプション] コピー元 コピー先**


-i 処理を行うときに確認する。
-r　ディレクトリをコピーする。
-p　元のファイルの情報を保存する。

##mv
ファイルの移動

**mv　移動元ファイル　移動先ファイル**

-i　処理するときに確認する
-f　強制的に処理実行

##rm
削除

**rm　ファイル名**

-i　処理するとき確認
-f　強制的に実行
-r　ディレクトリを対象にする

##pwd
現在のディレクトリの表示

**pwd**

##cd
ディレクトリの変更

**cd [ディレクトリ名]**

##mkdir
ディレクトリの作成

**mkdir ディレクトリ名**

-p　指定されたディレクトリの上位ディレクトリも作成する。

##rmdir
ディレクトリの削除

**rmdir ディレクトリ名**

-p 指定した階層までのディレクトリを一括で削除

##ディレクトリの種類
###(.)
カレントディレクトリ、現在のディレクトリ
###(..)
親ディレクトリ、１段層上のディレクトリのこと
###(~)
ホームディレクトリ、ユーザの作業開始位置となるディレクトリ
###(/)
ルートディレクトリ、ディレクトリ階層の最上位階層を示す

##cat
ファイル内容の表示

**cat ファイル名**

**-n　行番号を付加して表示する**

##find
ファイルの検索

**find　パス -name ファイル名**

##which
コマンドのパス表示

**which　コマンド名**
自分のタグを取得するスクリプト<EC2編>

CodeDeployは、CodeBuildの様に環境変数がPipelineから指定できないので、AppSpecFileの中でデプロイ内容をタグの値に応じて制御したいような場合に有効活用できるかも知れません

1. EC2インスタンス自身のメタ情報のインスタンスIDを取得する
1. インスタンスIDを指定して、特定のタグの値を取得する

例えば、「TagNoNamae」の値を取得したい場合、以下の操作で取得できる

```shell:コマンド例
AWS_REGION=ap-northeast-1
MYINSTANCEID=`curl -s http://169.254.169.254/latest/meta-data/instance-id`
VALUE=`aws ec2 describe-tags --region $AWS_REGION --filter "{\"Name\":\"resource-id\",\"Values\": [\"$MYINSTANCEID\"]}" --query 'Tags[?Key==\`TagNoNamae\`][Value]' --output text`
echo $VALUE
```

※「TagNoNamae」の部分を変更することで他のタグの値が取得できます
RailsでとにかくDBをリセットしたい場合（メモ）

migrationファイル内を変更している時、いろいろやりすぎて一度DB関連をすべてリセットしたい時のコマンド

```bash
rails db:migrate:reset
```


このコマンドを実行することでデータベースを作り直すことができる。

（流れ・動き）

①データベースを削除

②データベース作成

③マイグレーション実行

この流れで実行されている。
AtCoder自分用まとめ011(ABC196E Filters)

#概要
自分のために、AtCoderで身に付けた内容・コードをまとめておく。

#内容
https://atcoder.jp/contests/abc196/tasks/abc196_e
>整数列 $A=(a_1,a_2,…,a_N),T=(t_1,t_2,…,t_N),X=(x_1,x_2,…,x_Q)$ が与えられます。
N 個の関数 $f_1(x),f_2(x),…,f_N(x)$を、
$f_i(x)={x+ai(ti=1), max(x,ai)(ti=2), min(x,ai)(t_i=3)}$
と定義します。
$i=1,2,…,Q$のそれぞれについて、 $f_N(…f_2(f_1(xi))…)$ を求めてください。

```:入力形式
N
a1 t1
a2 t2
.
.
.
aN tN
Q
x1 x2 ... xQ
```

##C
編集中

##C++
```cpp
#include<iostream>
using namespace std;
using ll = long long;
int main() {
  ll n, q;
  cin>>n;
  ll s=0;
  const ll INF = 1ll<<60;
  ll l = -INF, r = INF;
  for (int i=0; i<n; ++i){
    ll a, t;
    cin>>a>>t;
    if (t==1) {
      s += a;
      l += a;
      r += a;
    }
    else if (t == 2) {
      l = max(l, a);
      r = max(r, a);
    }
    else {
      l = min(l, a);
      r = min(r, a);
    }
  }
  cin>>q;
  for (int i=0; i<q; ++i) {
    ll x;
    cin>>x;
    ll ans = x+s;
    if (ans < l) ans = l;
    if (ans > r) ans = r;
    cout<<ans<<endl;
  }
}
```

##Python3
```python
N = int(input())
low = -1 << 60
high = 1 << 60
add = 0
for i in range(N):
    A, T = map(int, input().split())
    if T == 1:
        low += A
        high += A
        add += A
    elif T == 2:
        if low < A:
            low = A
        if high < A:
            high = A
    else:
        if low > A:
            low = A
        if high > A:
            high = A
input()
for x in map(int, input().split()):
    print(min(high, max(low, x + add)))
```

##Haskell
編集中

##Racket
編集中

##Vim
編集中

#参考にさせていただいたページ
- https://atcoder.jp/contests/abc196/tasks/abc196_e
- https://atcoder.jp/contests/abc196/editorial/948
- https://www.youtube.com/watch?v=3W_dK_pNOc4

#感想
もう少し慣れたら書き直したい。。
SEOメモ（備忘録）

会社でSEOの研修を受けたので、重要だと思ったポイントをアウトプットがてらまとめたいと思います。

# SEOとは
SEOとは、Search Engine Optimizationの略で日本語で検索エンジンの最適化です。
ここでいう検索エンジンとはほぼGoogleといって問題ありません。
ユーザーにとって有益なコンテンツを提供し、適正に検索エンジンにページ内容を理解・評価されるように技術的にWebページに最適化することのことでGoogleなどの検索結果の上位に表示されることでサイトへの流入を上げていこうというものです。
SEOで上位をとればそれだけ多くの人にサイトを見てもらえることになるので今のWeb業界ではSEOに力を入れるのは至極当然のことになっています。


## クローラー
クローラーとは、インターネット上に存在するWebサイトなどあらゆる情報を取得し、自動的に検索データベースを作成する巡回プログラムのことです。SEOで上位を取るにはこのクローラーに自社のサイトが認識される必要があります。
クローラーが収集した情報を分析し検索データベースに保存することをインデックスといい、クローラーが情報を収集することを単にクローリングといいます。

#### クローリングの対象
クローラーとサーバーとの通信手段は「HTTP/HTTPSプロトコル」なので、HTTP/HTTPSで取得できる情報は、すべてクローリングの対象となります。
具体的には
- テキストファイル
- CSSファイル
- JavaScriptファイル
- 画像
- PDF
などがあります。

#### クローラビリティ
クローラビリティとは、クローラーがインターネット上のリンクを辿ってWebサイトを検出する時の、Webサイトの認識のされやすさのことでクローラビリティを向上させるには主に以下の方法があります。
- Googleにクロールリクエストをする
- XMLサイトマップを送信、更新する
- 内部リンクを設定する
- パンくずリストを設定する
- URLを正規化する
- URLの階層を浅くする
- リクエストに対して正しいHTTPステータスコードを返す



本記事は以下サイトを参考にさせて頂きました。

https://web-kanji.com/posts/crawlability#h-11
GCEへのSSH接続元IPを絞りつつ、Cloud IAPでSSHする

# TL/DR;
- [GCEちょい技 – Cloud IAP TCP Forwarding で踏み台サーバ要らずなメンテナンス](https://www.apps-gcp.com/gce-casual-knowhow-03/#Cloud_IAP)から抜粋。
    - ほぼ自分向けのメモ。
- IAPのAPIを有効化。
- VPC FirewallでIAPからのSSHを許可、拠点のIPを許可、それ以外は拒否。
- Cloud IAP便利だけど、`--tunnel-through-iap`って呪文が覚えれられない。(TAB補完効かない？)
    - iapって関数を.bashrcで切ってあげればどうにかなりそう。

## Cloud IAP APIの状態確認。
- Cloud IAP APIが有効になっている確認する。

```
gcloud services list --filter=NAME:iap
```

- 無効になっていた場合の出力。

```
$ gcloud services list --filter=NAME:iap
Listed 0 items.
```

## Cloud IAPを有効化する。
```
   gcloud services enable iap.googleapis.com
```

# IAPからのSSHをVPC Firewallで許可してあげる。
```
gcloud compute firewall-rules create allow-iap-forwarding-ssh   --network=<VPC名>   --allow=tcp:22   --source-ranges=35.235.240.0/20
```

- 別のVPC FirewallルールでインスタンスへのSSHは絞っている前提。

# IAP経由での接続確認
- GCPのコンソールでSSH-->gcloudコマンドを表示で表示されたコマンドの最後に`--tunnel-through-iap`をつけてあげればOK

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36284/164f4143-510a-9632-ded3-0c181aa2e4ac.png)


```
gcloud beta compute ssh --zone "<インスタンスのゾーン>" "<インスタンス名>" --project "<プロジェクト名>" --tunnel-through-iap
```

# `--tunnel-through-iap`って呪文が覚えれられない。
## 手元の端末のbashrcで以下のように関数定義
```
## for gce
function iap() {
  command gcloud compute ssh $1 --tunnel-through-iap
}
```
- zoneとプロジェクトの引数は省略。
    - だって、gcloudコマンド使うときは対象のプロジェクトにアカウント切り替えるから。

## 実行例
```
$ iap hoge
No zone specified. Using zone [asia-northeast1-b] for instance: [hoge].
Last login: Sun Mar 21 10:38:38 2021 from 35.235.240.242
[XXXXXXXXX@hoge ~]$
```
改めてpure javaでHello World

#はじめに
今やどこの開発現場でも何かしらのフレームワーク・ビルドツールを使うのが主流になっているかと思います。が、javacとかいうコマンドを使ってコンパイルする方法、みなさん覚えていますか？（私は覚えておりませんでした）
先日ふと「研修で習ったjavacコマンドってどうやって使うんだっけ？」と思い復習しましたので記録しておきます。


# 基本の流れ

1. javaファイルを作成
2. コンパイル
3. 実行

# さっそくHello World

## javaファイルを作成

Main.javaというファイルを作成しました。
標準出力するだけの簡単な内容です。
![スクリーンショット 2021-03-21 19.16.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395809/9714487f-d49c-b45a-8194-8c9895369296.png)


## コンパイル

先ほど作成したMain.javaをコンパイルします。

コンパイルとは、ソースコードの内容をコンピューターが実行できる形式に変換することです。
Javaにおいてはクラスファイル（バイナリコードのファイル）に変換することを指します。

```実行コマンド.
javac ソースファイル名.java
```

```今回はこんな感じ.
javac src/main/Main.java
```

そうすると、同じディレクトリに.classファイルが作成されます

```
$ ls src/main/
Main.class      Main.java
```


## 実行

コンパイルしたプログラムをコンピューターに解釈させ、動作させます。

```実行コマンド.
java クラス名
```

```今回はこんな感じ.
java src/main/Main

# 実行結果
Hello World
```
【GAS】③Classroomのコース情報を変更

# 目次
1. [【GAS】①Classroomのコース一覧を取得する](https://qiita.com/oktaSI/items/223515dcc8214175c726)
2. [【GAS】②Classroomのコースを新規作成](https://qiita.com/oktaSI/items/38e7fc3bb897de93fdb4)
3. [【GAS】③Classroomのコース情報を変更](https://qiita.com/oktaSI/items/9c8bd51b4eed1989d080)（このページ）

# コース情報の取得

ここではすでに作成済みコースのコース情報をGASで変更する方法を説明します。まず[コース一覧の取得](https://qiita.com/oktaSI/items/223515dcc8214175c726#classroomの一覧を取得)方法に従って変更したいコースのcourseIDを調べ、getメソッドで変更したいコースを取得します。getメソッドはコース情報をオブジェクト形式で返します。

```javascript
/**
 * Retrieves course by id. 
 */
function getCourse() {
  const courseId = '123456';
  try {
    const course = Classroom.Courses.get(courseId);
    Logger.log('Course "%s" found. ', course.name);
  } catch (err) {
    Logger.log('Course with id "%s" not found', courseId);
  }
}
```
取得したコース(course）の名前を調べたい場合にはcourse.name、取得したコースの教師グループメールアドレスを調べたい場合には、course.teacherGroupEmailなどと「取得したコース.コース情報」で指定する。コース情報として指定できるプロパティは[Resource:courses](https://developers.google.com/classroom/reference/rest/v1/courses#resource:-course)を参照のこと。

# コース情報の変更

以下のコース情報は必要に応じて何時でも変更することが可能です。

- name（コース名）
- section（セクション）
- descriptionHeading（説明のヘッダー、どこに表示されるのか不明）
- description（説明）
- room（部屋）
- courseState（コース状態）

コース情報の変更にはCoursesクラスのupdateメソッド（[courses.update](https://developers.google.com/classroom/reference/rest/v1/courses/update)）を使います。コース情報を変更するには、次の例のように変更したいコース情報を、オブジェクトのプロパティを変更する要領で修正し、それを反映させる方法を取ります。

```javascript
/**
 * Updates the section and room of Google Classroom. 
 */
function courseUpdate() {
  const courseId = '123456';
  let course = Classroom.Courses.get(courseId);
  course.section = 'Period 3';
  course.room = '302';
  course = Classroom.Courses.update(course, courseId);
  Logger.log('Course "%s" updated.', course.name);
}
```
このように説明すると、コース情報の一つであるcourseIdも変更できそうに思えますが、courseIdの変更はできない仕様になっています。

同じくCoursesクラスのpatchメソッド（[courses.patch](https://developers.google.com/classroom/reference/rest/v1/courses/patch)）でもコース情報の変更はできるのですが、次の例をみれば分かるように引数の指定方法がやや煩雑です。なぜコース情報を変更する方法としてupdateメソッドとpatchメソッドが用意されているのか、よく分かりません。

```javascript
/**
 * Updates the section and room of Google Classroom. 
 */
function coursePatch() {
  const course_id = '123456';
  let course = {
    'section': 'Period 3',
    'room': '302'
  };
  const mask = { 
    updateMask: 'section,room' 
  };
  course = Classroom.Courses.patch(body=course, id=course_id, updateMask=mask);
  Logger.log('Course "%s" updated.', course.name);
}
```

次回は、コースを削除する方法についてまとめます。
Linux概要

#Linux概要

###カーネル
オペレーションシステムの中核となる部分で、ハードウェアと直接的にやり取りするなど中心的な機能を持つ部分。

###ユーザランド
OSが動作するのに必要な、カーネル以外の部分のこと。ファイルシステムやファイル操作コマンド、シェルなどの基本的なソフトウェア群を指す。

![スクリーンショット 2021-03-21 19.25.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1096361/b93ab192-a658-9a7f-b2da-228be6005661.png)


###使用方法
基本的にコマンドで操作。コマンドはユーザランドで動作する。

###シェル
コマンド＝命令
対話型のコマンド入力環境があり、シェルに入力されたコマンドを理解し、実行する。

###シェルスクリプト
「コマンド入力自動化」、コマンド実行を自動化することが可能。作成したシェルスクリプトをサーバーの起動時に実行したりできる。

###パッケージ
パッケージはLinuxに対して追加機能を提供するもの。

###パッケージマネージャ
応用ソフトウェアの導入には、複数の応用ソフトウェアやこの動作を補足するライブラリが必要な場合がある。依存するプログラムがさらに別のプログラムを依存しているとなると、それらが正しい場所に正しい順序でインストールしなければならない。
　そこでパッケージを簡単にインストールしたり、アップデートするパッケージマネージャというものが標準で用意されている。
AtCoder自分用まとめ010(ABC196D Hanjo)

#概要
自分のために、AtCoderで身に付けた内容・コードをまとめておく。

#内容
https://atcoder.jp/contests/abc196/tasks/abc196_d
>縦 H メートル、横 W メートルの長方形の部屋があります。
この部屋に 2 メートル × 1 メートルの区別できない畳 (長方形のタイル) A 枚と、1 メートル × 1 メートルの区別できない半畳 (正方形のタイル) B 枚を敷き詰めます。 2 メートル × 1 メートルの畳は縦長にも横長にも使うことができます。
敷き詰める方法は何通りあるでしょうか？
なお、2A+B=HW であることが保証されます。 また、回転や反転を行うことで初めて一致するような敷き詰め方は区別します。

```:入力形式
H W A B
```

##C
編集中

##C++
```cpp
#include<iostream>
using namespace std;
using ll = long long;

int h, w;
bool used[16][16];

ll dfs(int i, int j, int a, int b) {
  if (a < 0 || b < 0) return 0;
  if (j==w) j=0, ++i;
  if (i==h) return 1;
  if (used[i][j]) return dfs(i, j+1, a, b);
  ll res = 0;
  used[i][j] = true;
  res += dfs(i, j+1, a, b-1);
  if (j+1<w && !used[i][j+1]){
    used[i][j+1]=true;
    res += dfs(i, j+1, a-1, b);
    used[i][j+1]=false;
  }
  if (i+1<h && !used[i+1][j]){
    used[i+1][j]=true;
    res += dfs(i, j+1, a-1, b);
    used[i+1][j]=false;
  }
  used[i][j]=false;
  return res;
}
int main() {
  int a,b;
  cin>>h>>w>>a>>b;
  cout<<dfs(0,0,a,b)<<endl;
}
```
##C++\<bits/stdc++.h\>
```cpp
#include<bits/stdc++.h>
using namespace std;
using ll = long long;

int h, w;
bool used[16][16];

ll dfs(int i, int j, int a, int b) {
  if (a < 0 || b < 0) return 0;
  if (j==w) j=0, ++i;
  if (i==h) return 1;
  if (used[i][j]) return dfs(i, j+1, a, b);
  ll res = 0;
  used[i][j] = true;
  res += dfs(i, j+1, a, b-1);
  if (j+1<w && !used[i][j+1]){
    used[i][j+1]=true;
    res += dfs(i, j+1, a-1, b);
    used[i][j+1]=false;
  }
  if (i+1<h && !used[i+1][j]){
    used[i+1][j]=true;
    res += dfs(i, j+1, a-1, b);
    used[i+1][j]=false;
  }
  used[i][j]=false;
  return res;
}
int main() {
  int a,b;
  cin>>h>>w>>a>>b;
  cout<<dfs(0,0,a,b)<<endl;
}
```
##Python3
```python
H, W, A, B = map(int, input().split())
used = [[False for i in range(16)]
         for j in range(16)]

def dfs(i, j, a, b):
  if a < 0 or b < 0:
    return 0
  if j==W:
    j = 0
    i += 1
  if i==H:
    return 1
  if used[i][j]:
    return dfs(i, j+1, a, b)

  res = 0
  used[i][j] = True
  res += dfs(i, j+1, a, b-1);
  if j+1<W and not used[i][j+1]:
    used[i][j+1] = True
    res += dfs(i, j+1, a-1, b)
    used[i][j+1] = False
  if i+1<H and not used[i+1][j]:
    used[i+1][j] = True;
    res += dfs(i, j+1, a-1, b)
    used[i+1][j] = False
  used[i][j]=False
  return res

print(dfs(0,0,A,B))
```

##Haskell
編集中

##Racket
編集中

##Vim
編集中


#参考にさせていただいたページ
- https://atcoder.jp/contests/abc196/tasks/abc196_d
- https://www.youtube.com/watch?v=3W_dK_pNOc4

#感想
もう少し慣れたら書き直したい。。
bit探索まだ勉強中。
Python + OpenCVで顔写真のトリミング

今年も春がやってくる。生徒の顔写真をトリミングしなければいけない。
パソコンが勝手にやってくれないかなと思いつつ、色々と検索して、やってみたら出来たので、備忘録的に書いてみようと思う。

環境はWindows10です。使うのは'Python'なのですが、名前を聞いたことあるぐらいの知識。'OpenCV'ってのを使って、顔認識させられるらしいという事が分かった。

そこで、環境の準備から。

まず、[OpenCV](https://opencv.org/releases/)をダウンロードします。
![op1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226981/fca6a08d-7c3a-ba22-11d3-375e28cd0582.jpeg)

ここからWindows版のOpenCVを入手できます。ダウンロードしたアーカイブをダブルクリックすると、自動で解凍してくれますので、解凍された'opencv'フォルダを、Cドライブの直下に移動します。

そして、環境変数をいじって、pathを通します。
![op2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226981/a169b3b7-98e4-03ed-f93b-1e266093de91.jpeg)
具体的には、コントロールパネル＞システムとセキュリティ＞システム＞システムの詳細設定＞環境変数＞path＞新規
で、'C:\opencv\build\x64\vc15\bin'を追加しておきます。

次に、[Visual Studio](https://visualstudio.microsoft.com/ja/downloads/) のインストールを行いました。

もちろん、無料のやつね。

Pythonを扱えるように、インストールします。
![vs.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226981/2a1ede05-e4b6-20f5-b2a3-caf9d6733edd.jpeg)

インストールしたら、Pythonアプリケーションを適当な名前で作成します。
![vs2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226981/72755d1e-8e0a-2385-2f31-dedd9e33a4ed.jpeg)

作成したら、Pythonパッケージの管理で、OpenCV環境を扱えるようにします。
![vs3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226981/4a824d28-4fd2-9fd2-6571-178268a95fad.jpeg)
検索で、opencvと入れると、候補にopencv-python(バージョン番号)が現れると思うので、それを入れます。

これで、準備はOKです。

では、コードを書いていきます。

     #リソースのインポート
     import cv2
     import glob
     import os

     #trimフォルダの作成
     os.makedirs('trim', exist_ok=True)

     #カスケード型分類器に使用する分類器のデータ（xmlファイル）を読み込み
     HAAR_FILE = "C:\opencv\sources\data\haarcascades\haarcascade_frontalface_alt.xml"
     cascade = cv2.CascadeClassifier(HAAR_FILE)

     #ファイルリストの取得
     files = glob.glob("*.jpg")
     for file in files:

         #取得したファイル名の表示
         print(file)

         #画像ファイルの読み込み
         img = cv2.imread(file)

         #グレースケールに変換
         img2 = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)

         #カスケード型分類器を使用して画像ファイルから顔部分を検出する
         face = cascade.detectMultiScale(img2,scaleFactor=1.07,minNeighbors=7,minSize=(300,300))

         #顔部分を切り取り、リサイズする。
         for x,y,w,h in face:

             #横幅のエリアを1.6倍にし、縦幅のエリアを2.23倍にすることで、4：3の比率でカット
             face_cut = img[y-int(h*0.6):y+int(h*1.53), x-int(w*0.3):x+int(w*1.3)]

             #カットした画像を450*600のサイズにする。
             resize_img = cv2.resize(face_cut , dsize=(450, 600))

         #画像の出力
         cv2.imwrite('trim\\' + file , resize_img )

これで、このソースと同じフォルダにある複数のjpgファイルから顔部分だけ4:3の比率でトリミングして、450*600にリサイズして、trimという名前のサブフォルダを作成して、同じ名前で保存するという作業をしてくれるようになりました。

実行は、Pythonソースファイルを作業するフォルダにコピーして
![py1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226981/35159400-0a25-f56d-6041-b39c48d47460.jpeg)
ダブルクリックで実行できました。

参考になったページはたくさんあったのですが、自分が記事を書くとは思っていなかったので、追えませんでした…。

私と同じ仕事をしている方の助けになれば幸いです。
M1macとDocker。

## まえがき

前提として、M1Macとは、AppleSiliconを搭載したArm64アーキテクチャCPUのPCである。

つまり、基本的にamd64/x86_64系アーキテクチャのバイナリは読めないし、M1Macでコンパイルしてうまくいったプログラムを配布しても、M1Mac以外では動かないと言ったことが当然起こる。

そこら辺はまぁ、コンパイラとかのオプションで同じソースから別のバイナリを作成すれば問題ない。結構簡単な話ではある。

だが、話は変わってDockerだったらどうだろうか？DockerはZembutsu氏の[こちら](https://qiita.com/zembutsu/items/24558f9d0d254e33088f#3-hello-world-%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8%E3%82%92%E8%A9%B3%E3%81%97%E3%81%8F%E8%AA%BF%E3%81%B9%E3%82%8B)の資料をみるとこう書かれている。

> （なお、CPU amd64/x86_64 用にコンパイルしたバイナリは実行できますが、他の CPU アーキテクチャ向けのバイナリは amd64/x86_64 上では実行できません。例えば Raspberry Pi は ARM というアーキテクチャですので、この hello バイナリは Raspberry Pi でそのまま動きません。バイナリとして実行できない以上、仮に Docker イメージに入れたとしても、この次のセクションで説明する Docker コンテナとして実行はできません。Docker はハードウェアのエミュレーションを行いませんし、ハードウェアを仮想化するような技術でもありません。）

なるほど、やはり動かないと言うことらしい。

なら、実際動かしてみてどうなるか実験してみようじゃないか。

## M1MacにDockerDesktopをインストール

M1MacにDockerDesktopをインストールするには、[こちら](https://docs.docker.com/docker-for-mac/apple-m1/)のリンクを踏んでダウンロードする必要がある。

さらに、Rosetta2もインストールしなければならないため、以下のコマンドをShellに叩く

```{sh:Rosetta2 install}
softwareupdate --install-rosetta
```
すると、しっかりインストールされ、動くようになる。

## 実際に試す。

以下を試してみた。

```{sh:docker run}
docker run -it python:3.9-alpine python
```
すると、
![スクリーンショット 2021-03-21 17.32.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182970/a72b0462-8b0a-e663-bd89-5a6e358d7e4b.png)
なんだ、しっかり動作するじゃないか。
なぜだろう。

...実は単純な話でARMアーキテクチャ用にビルドされたものがDockerHubにちゃんと上がっているのだ。

実際にDockerHubで調べてみた。

![スクリーンショット 2021-03-21 17.48.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182970/7c39f448-ddcb-3c5c-6eec-7e5fdb542518.png)

なるほど、結構そもそも対応してるのね。と言う結論に。

## M1macでビルドしたものをPushしても動かない？

M1Macでビルドしたものはどうなるのだろう。

そりゃまぁPullの時点でアーキテクチャが選択された上で層を重ねていくのだから、
いくらFROM python:3.9-alpineと指定した時点でARMイメージが決定するので、それに層を足してPushしてもリモートのLinuxサーバでは動かすことはできない可能性が高い。(まだ試したことはないが)

## これに対する解決策

### JenkinsやGoogleCloudBuildとかに任せる

リモートにJenkinsのビルドサーバを建てて、そこからBuildすると言う形がいいかと思われる。
そうすれば、リモートで主に使用されているamd64/x86_64 archの対応ができるので、それで回避すると言う手がある。
普通に考えたらこれでいい気がする。というかそもそもローカルでビルドなんかしたくない。

### buildxコマンドを使用する

コンパイラと同様、アーキテクチャ別にbuildしてくれる機能をもつコマンドが実際に実装されているとのこと。
それがbuildxコマンド。詳細はこちら。

[Docker Buildx](https://matsuand.github.io/docs.docker.jp.onthefly/buildx/working-with-buildx/)

## あとがき

ちなみに、ラズパイとかの関係もあって、正味ARMアーキテクチャなど、さまざまなデバイスで動くようにもう基盤がある程度整っていて、Macが突然M1になったからと言って全然未対応な感じではなかった。なので、M1Macを買ってDockerとかどうしよう...みたいに考えている方でも、安心して欲しい。

あと、基本Rosetta2がなんとかしてくれるし、ここで重い動作させるわけでもないんだし、M1Macだからと言う理由で何か不都合が起こることは、正味このDockerPushが直でできないくらいなものだった。あとはなんとかなる基盤が今の時代全て揃っているので、M1macでも開発環境上、何も問題ないと言える。

やはりコード化と言う原理は最強だった...我々はコードだけを扱えばいいので、下のレイヤーは最悪気にしなくていい。そんな基盤ができている現代社会に感謝したい。
【実験】Dockerを使用してGitLabを構築してみる part2

前回に引き続き、Dockerを使ったGitLabについて触れていきます。
今回はあまり大したことはしません。
次回の前準備のような事を書き残しています。

#Dockerコンテナ化したGitLabの操作
まず、GitLabコンテナの起動状態を確認します。
以下コマンド実行後、GitLabのコンテナイメージが存在していれば起動されています。

```
sudo docker ps -a #dockerコンテナイメージが「Up」になっていれば起動している
※以降、sudo省略
docker start <dockerコンテナのNAME> #起動していない場合
docker ps
```

次にGitLabの各サービスの起動状態を確認します。
大抵コンテナを起動していればrunになっていると思いますが、次の項目で設定変更を実施するので一旦停止させておきます。

```
docker exec -it gitlab gitlab-ctl status
docker exec -it gitlab gitlab-ctl stop #起動している場合
docker exec -it gitlab gitlab-ctl status
```

上記コマンドや前回実施した```docker exec -it gitlab gitlab-ctl reconfigure```コマンド等、通常のGitLabのコマンドの前に```docker exec -it gitlab```を加える事で通常のGitLabと同じコマンドを実行することが可能です。

直接GitLabを操作するには以下のコマンドでコンテナにアクセスします。
コンテナにアクセス後は通常のGitLabと同様```docker exec～```なしでGitLabのコマンドを使用できます。

```
docker exec -it <dockerコンテナのNAME> /bin/bash
```

コンテナから抜けるには```exit```で切断します。

#GitLabの設定変更
コンテナ化したGitLabで設定変更を実施する場合、以下のコマンドを実行します。
実行するとnanoエディタが起動されますので、変更したい設定値を修正します。

```
docker exec -it gitlab editor /etc/gitlab/gitlab.rb
```

#GitLab関連データのディレクトリ
GitLabに関連するディレクトリは```/srv/gitlab/```ディレクトリに収められていますので、nfsサーバーへデータを格納したい時等はこちらの中を参照します。
例として設定ファイルを直接編集する場合、以下に格納されています。

```
/srv/gitlab/config/gitlab.rb
```

設定変更が完了したら、reconfigと起動を実施します。
直接GitLabコンテナにログインしている場合は```docker exec -it gitlab```の部分は不要です。

```
docker exec -it gitlab gitlab-ctl reconfigure
docker exec -it gitlab gitlab-ctl status
docker exec -it gitlab gitlab-ctl start
docker exec -it gitlab gitlab-ctl status
```

少々短いですが、今回は以上です。
次回は既存のGitLabのデータを引き継ぎまたは共有を試します。