OmniAICreator/Qiita-1.07M huggingface dataset:
TypeScript: ビルド対象から除外するファイルを指定する方法

# 概要
アプリケーションを開発していると、単体テストなどアプリケーション以外のコードを書くことがあると思います。

アプリケーションコードとそれ以外のコードを分けて扱う仕組みは言語やフレームワークによってサポートされていることが多いと思いますが、TypeScriptでも同様の仕組みが用意されています。

この記事ではTypeScriptで書かれたコードをビルドするときに、ビルド対象から除外するファイルを指定する方法を紹介します。

# 環境
```
$npx tsc -v
Version 4.5.4
```

# 課題
以下のような構成のプロジェクトで、
`__tests__`配下をビルド対象から除外する場合について考えてみようと思います。

```
├── dist
├── src
│   ├── __tests__
│   │   └── index.test.ts
│   └── index.ts
└── tsconfig.json

```
コンパイラの設定は仮に以下のようにしておきます。
`src`配下のコードをビルドして、結果を`dist`配下に出力します。

```json:tsconfig.json
{
    "compilerOptions": {
        "target": "es2016",
        "module": "commonjs",
        "rootDir": "./src",
        "sourceMap": true,
        "outDir": "./dist",
        "esModuleInterop": true,
        "forceConsistentCasingInFileNames": true,
        "strict": true,
        "skipLibCheck": true
    },
}
```
この状態でビルドすると以下のように`__tests__`配下もコンパイルされます。
デフォルトでは全ての.tsファイルがビルドの対象になります。

```
├── dist
│   ├── __tests__
│   │   ├── index.test.js
│   │   └── index.test.js.map
│   ├── index.js
│   └── index.js.map
├── src
├── __tests__
│   │   └── index.test.ts
│   └── index.ts
└── tsconfig.json

```

# 解決策
コンパイラの設定(tsconfig.json)に以下を追加します。

```
{
    "compilerOptions": {
        "target": "es2016",
        "module": "commonjs",
        "rootDir": "./src",
        "sourceMap": true,
        "outDir": "./dist",
        "esModuleInterop": true,
        "forceConsistentCasingInFileNames": true,
        "strict": true,
        "skipLibCheck": true
    },
    "exclude": ["src/**/__tests__/*"] <- これを足す
}
```
ビルド結果は以下のようになります。

```
├── dist
│   ├── index.js
│   └── index.js.map
├── src
├── __tests__
│   │   └── index.test.ts
│   └── index.ts
└── tsconfig.json

```

`__tests__`配下が出力されなくなりました。

# 留意事項
`exclude`を指定する場合には以下の点に留意する必要があります。

1. __ビルド対象から外したファイルを編集する場合__
VSCodeの場合は、プロジェクト内の他のモジュールをインポートしようとしたときに、自動インポートや入力補完が動作しなくなるようです。
インポートできないわけではありませんが、全て手動で入力する必要があります。

2. __ビルド対象のファイルからビルド対象外のファイルをインポートする場合__
ビルド対象外だったファイルもビルドされます。
【Tips】IntersectionObserver API(交差監視API)

## いつ使う
- Twitterのような無限スクロール（遅延読み込み）
- 広告費用を計算するための広告が表示されたかどうかのレポート
- ユーザーが対象を見るかによって、タスクやアニメーションの実行分岐

 様々な場面で「要素の交差を検出する実装」は必要とされます。
ポピュラーな実装方法としては、scrollイベントで画面の高さやスクロール後の位置を取得する
方法が考えられますが、如何せんスクロールの度に発火するので負荷が大きいです。
本稿ではscrollイベントは使わず別の手法を取り上げます。
（scrollイベントの最適化に関しては、下記リンクが参考になると思います）
https://qiita.com/hiro0218/items/7ac41f58891d96951fa1
https://qiita.com/damele0n/items/f4050649de023a948178

## IntersectionObserver API
交差監視APIという意味で、監視対象とする要素の交差によりイベントが発火します。
scrollイベントを使った手法とは違い、ビューポートサイズの変更による影響を受けず、
さらにスクロールの都度実行されるということもないのでパフォーマンス向上が期待できます。
[googleトレンド](https://trends.google.co.jp/trends/explore?date=today%205-y&q=intersection%20observer%20api,scroll%20js)を見る限りまだまだマイナーみたいですが、知っておいて損はないと思います！

## 基本的な使い方

```javascript:js
$(function () {
   var boxes = document.querySelectorAll('.targets'); // 監視対象とする要素
   var boxesArray = Array.prototype.slice.call(boxes, 0); // Arrayのメソッドを借りて配列化
   var options = {
      root: null, // 交差監視をする範囲。nullの場合ビューポートとなる。
      rootMargin: '10px', // 上記の範囲を拡大縮小指定する。
      threshold: 0, // 発火条件となる要素の交差割合を閾値(0~1)で指定。
   };

   //　コンストラクタ。各ターゲット要素の監視、イベントの発火を担う。
   var observer = new IntersectionObserver(doWhenIntersect, options);
   boxesArray.forEach(function (box) {
      observer.observe(box);
   });

   //　イベント発火時の処理を指定。
   function doWhenIntersect(entries) {
      var entriesArray = Array.prototype.slice.call(entries, 0);
      entriesArray.forEach(function (entry) {
         if (entry.isIntersecting) {
            console.log(entry + 'が交差しました！');
         }
      });
   }
});
```



## 注意点
現状IE11はIntersectionObserverに対応していませんので、別途polyfillを読み込ませる必要があります。

```javascript
if (!('IntersectionObserver' in window)) {
    appendScript("https://polyfill.io/v3/polyfill.min.js?features=IntersectionObserver");
}
```
Power Automate: Search Query の使いどころ

# 背景

[複数のメールの取得 (V3)](https://docs.microsoft.com/ja-jp/connectors/office365/#%E8%A4%87%E6%95%B0%E3%81%AE%E3%83%A1%E3%83%BC%E3%83%AB%E3%81%AE%E5%8F%96%E5%BE%97-(v3)) では、Search Query が使えるようになってます。
これは、Rest-API での Search Query Parameter を利用する機能なんですが、[複数のメールの取得 (V3)](https://docs.microsoft.com/ja-jp/connectors/office365/#%E8%A4%87%E6%95%B0%E3%81%AE%E3%83%A1%E3%83%BC%E3%83%AB%E3%81%AE%E5%8F%96%E5%BE%97-(v3)) コネクタ自体にも色々機能がついてて、どんな要望のときに使う必要があるのかすぐにわからなかったので調べた記録

Search Query Parameter は以下

https://docs.microsoft.com/en-us/graph/search-query-parameter

https://docs.microsoft.com/ja-jp/connectors/office365/#%E8%A4%87%E6%95%B0%E3%81%AE%E3%83%A1%E3%83%BC%E3%83%AB%E3%81%AE%E5%8F%96%E5%BE%97-(v3)

# 結論
以下のような検索操作をしたいときに使えそうですね。

- BCC
- 参加者（From/TO/CC/BCC)
- 受領者（TO/CC/BCC)
- 送信／受信　日付
- 本文（Body）
- 種類<br><code>contacts, docs, email, faxes, im, journals, meetings, notes, posts, rssfeeds, tasks, or voicemail.</code>
- 大きさ：Byte Size 
- From/Subject/Body へ同時に<br><code>メッセージで検索を行うときに、特定のメッセージ プロパティを指定せずに値のみを指定した場合、検索は **既定の検索プロパティである from、subject、body に基づいて** 行われます。</code>

:::note info
Filter や、Select Query なんかとも並行指定出来るので今後追加される？
:::

:::note info
Default だと未読メッセージに対しての検索なので、既読検索の際は設定変更必要
:::
![2021-12-21_13h49_22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1645569/66adb5bf-72f2-f3d3-d4e4-472f4d8082dd.png)

# 利用例
## AND 検索
```text:bodyの利用例(AND)
body:('情報' '本日')
```

## AND 検索にみえて、スペースで区切った後が、Body → 既定のプロパティ(From/Subject/Body) に緩んでしまう例
```text:bodyの利用例
body:'本日' '情報'
```

## OR 検索
```text:bodyの利用例(OR)
body:('情報' '本日') OR body:'明日'
```

:::note info
Double Quote → Single Quote に注意
:::

詳細は以下で。

https://docs.microsoft.com/ja-jp/sharepoint/dev/general-development/keyword-query-language-kql-syntax-reference

# 比較記録
更新早いだろうから、ざっくり比較
![2021-12-21_13h43_45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1645569/40171076-ea32-15d2-62bb-beedfa78fb5d.png)

# keyword

when to use search query of mail connector in power automate
Nuxtでビルド時に環境変数をセットする

# はじめに
基本的には`.env`ファイル等使うかと思いますが、この記事ではビルド時にセットする方法になります。

# 実装
Nuxtでは環境変数の頭に`NUXT_ENV`を付与する必要があります。
https://nuxtjs.org/docs/configuration-glossary/configuration-env/#automatic-injection-of-environment-variables

下記はStorybookのビルドの時だけセットするという例になります。

```package.json
...
"scripts": {
  "storybook": "set NUXT_ENV_IS_STORYBOOK=true && yarn nuxt storybook"
}
...
```
```nuxt.config.js
...
process.env.NUXT_ENV_IS_STORYBOOK // true
...
```

# おわりに
備忘録的な内容なので薄いですが、何かあればコメントいただけると幸いです。
転職に悩んでいるナースへ


仕事先に悩んでいるナースの仲間たちに多くの有益な情報を届けるためのサイトをご案内いたします。ぜひ参考にしてみてください。
転職したいナースへ「看護師FIREのすすめ」をテーマに情報発信しています。
※看護師FIRE＝早期退職し、不労所得だけで自由きままに暮らすナース

「看護師IREのすすめ」　https://kangoshi-work.com
2021年の振り返り

こちらはノンプロ研アドベントカレンダー21日目になります。

https://adventar.org/calendars/6746

毎年アドベントカレンダーで振り返りをさせてもらっています。

- [2019年の振り返り](https://qiita.com/plumfield56/items/f1b2cd9b301d8d8fed6b)
- [2020年の振り返り](https://qiita.com/plumfield56/items/b3608f22348a0ffe0cba)

今年もアドベントカレンダーで振り返りをしたいと思います。


## 今年新しくチャレンジした技術
毎年振り返ると今年は色々なことを触ったなーって思いますが、
今年も雑多に色々触ってました。

ここら辺は触ったレベルで業務に使えるレベルまでは達していないので、
もう少し本腰を据えて勉強したいなと思っています。

```:GCP関連
GAE, GCE, Cloud Functions
```

```:アプリケーション関係
Flask, FAST API, Streamlit, Vue.js
```

```:その他
Docker, Heroku, Git/GitHub
```

```:その他プログラミング関係
OOP, デザインパターン、UML
```

## 今年の変化

### OOPにチャレンジ

OOPやドメイン駆動設計はノンプロ研内でバズワード的に盛り上がって
引っ張られるように勉強したけど辛かった。

抽象的な設計概念から入って具体的なコードに落とし込もうとしたのが間違いでした。
書籍をいくつか買って読んだけど全然身になっていない。
具体的なコードから入っていった方がよかった。

業務でもともと使っていた450行あった巨大クラスをちゃんと切り出して、
180行ぐらいのクラスにできたのはよかった。

それでも大きいとは思うけど、SOLIDの単一責任の原則的には良いと思うんだけどどうなんだろ？

### Google Colaboratory(Colab)からVSCodeでの開発へ変更

前々からColabでの開発からは脱却したいと思っていましたが、
そもそもPythonを社内で使えていないという状況をやっと打破できました。

そのおかげでモジュールで切り分けができてコードの整理がかなり進みました。

ただ、営業にPythonを手動で実行してもらうのはまだColabで実行。
VSCodeで作成したコードをGitHubへアップロードして
必用に応じてColabで実行するという運用になりました。

散らばっていたコードがいフォルダに集約できている点もよき！


## 今年学んだこと

色々手は出したけどちゃんとスキルとして身に付いた感じがするものは少ないな。
Pythonの基礎力が上がって言語化できるようになったとかクラスや理解が高まって
実務で活用できるようになった点は大きい。

業務ではPandasばっかり使っていて、
Pandasにおけるエラー処理とかにはだいぶ慣れてきた感じがします。


## ノンプロ研での活用

1年での活動概要は下記の通りです。

![2021-12-21_20h40_04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/428239/9c280dae-ebed-ed5b-1eb5-435c30939768.png)

お金をもらって教えるという経験は想像以上に自分のためになりました。
受ける側の立場だとだいたい知っていると流して聞いていたないようでも、
しっかりと相手がわかりやすい言葉で伝えようとすると言葉選びに困りました。
そして知っていると思っていたけど、言語化できていないことにも目を向けられて
知識の差分アップデートできたのも大きかったです。


## 来年やりたいこと

会社で自社システムを作成することになっていて、
内製化するのにすべての知識を吸収しようと思っています。

そのために

- インフラ
- AWSでの環境構築
- Vue.js
- SQL
は必須になってくるので勉強をしていきます。

システム化が進んでDBがちゃんと使えるようになったら、
機械学習やDeep Learningの領域の勉強にもチャレンジしていきたいと思っています。
jsにてユーザーエージェントを判別する方法。PCでのみ表示などが可能

##まず初めに

こういう時ってないですか？

「レスポンシブだけど、なぜかブレイクポイントを作ってもipadだけ表示されてまう」
「そもそもipadとかiphone,androidやったら表示したくないねんけど」
「なんなんもう。。。」

上記みたいな時って、僕はありました。
masx-widthでブレイクポイント作ってもうまくいかない時

### jsで判定して、あとからstyleを追加しよう

とりあえずコード

```js
<script>
const isIPad = /iPad|Macintosh|iPhone|iPod|Android/i.test(navigator.userAgent)
&& 'ontouchend' in document

var pc_only = document.getElementById("pc_only");
if(isIPad){
  pc_only.style.setProperty("display", "none");
}
</script>
```

pcのみで表示させたい要素に"pc_only"のIDを付与してあげます。

HTMLが全部読み込まれたあとじゃないとダメなので、そこは注意しましょう。


では、良いPHPライフを！！
ICU4Jでカタカナをヘボン式ローマ字に変換する

```groovy:build.gradle
implementation 'com.ibm.icu:icu4j:70.1'
```

```java
import com.ibm.icu.text.Transliterator;

public class KatakanaToHepburn{
  public static void main(String[] args) {
    Transliterator latin = Transliterator.getInstance("Katakana-Latin");
    Transliterator hepburn = Transliterator.getInstance("Katakana-Latin/BGN");

    System.out.println(latin.transform("トウキョウ"));
    System.out.println(hepburn.transform("トウキョウ"));

    System.out.println(latin.transform("シンバシ"));
    System.out.println(hepburn.transform("シンバシ"));

    System.out.println(latin.transform("ッア"));
    System.out.println(hepburn.transform("ッア"));
  }
}

```

詳細は [BGN/PCGNラテン文字表記法(wikipedia)](https://ja.wikipedia.org/wiki/BGN/PCGN%E3%83%A9%E3%83%86%E3%83%B3%E6%96%87%E5%AD%97%E8%A1%A8%E8%A8%98%E6%B3%95) にある。日本語ではBGNがヘボン式ローマ字を指す、という理解でとりあえずはOKと思われる。


実行結果は以下の通り。

```
toukyou
tōkyō
shinbashi
shimbashi
~tsua
ッa
```

上記の通り「トウキョウ」などは長音符号つき文字になるのでそこは必要に応じて変換が必要。また、ヘボン式として変換出来ないカタカナはそのままになる点にも注意が必要。
Carbonの「CarbonPeriod」を使ってみたよ。

## まず初めにCarbon とは

phpで日付処理を行う時にとっても便利なのがCarbonです。
今日の日付や指定した日付など、支持してあげれば欲しい日にちを持ってきてくれます。

### 使えるようになるまで（インストール）
```
 composer require nesbot/carbon
```

```
//Laravelなら、利用したいファイルでuseしよう
use Carbon\Carbon;
```

## 基本的な利用法
	
```php
$date = new Carbon();
$date = Carbon::now(); // 現在時刻
```

とまぁ、こんな感じで便利に利用できるのがCarbonさんです。
今回は、Carbonさんを利用して以下のような配列を作ってみようと思います。

```
現在 2021年12月14日
array:49 [▼
  0 => "2019年12月"
  1 => "2020年01月"
  2 => "2020年02月"
  3 => "2020年03月"
  4 => "2020年04月"
  5 => "2020年05月"
......
  44 => "2023年08月"
  45 => "2023年09月"
  46 => "2023年10月"
  47 => "2023年11月"
  48 => "2023年12月"
```

こんな感じで、現在の月から24ヶ月過去と未来（合計48ヶ月分）の配列ですね。

## とりあえずコード


```php
$dt_past = Carbon::now()->subMonths(24)->format('Y-m-d');
$dt_future = Carbon::now()->addMonths(24)->format('Y-m-d');
$periods = CarbonPeriod::create($dt_past, "1 month" , $dt_future);
$reversed_period = array_reverse($period->toArray());　//未来から過去にする場合

foreach($periods as $key => $value){
$selects[] = $value->format('Y年m月');
}
```

過去は「subMonths()」と指定します。引数にはどれぐらい遡りたいかを記載します。

```php
Carbon::now()->subMonths(24)->format('Y-m-d');
```

未来は「addMonths()」と指定します。引数にはどれぐらい未来かを記載します。

```php
Carbon::now()->addMonths(24)->format('Y-m-d');
```

CarbonPeriodを利用して、foreach である期間中の反復処理を行います。
第1引数と第3引数で期間を指定　第2引数には取得する幅を指定します。（2 daysなら2日ごとに取得）


```php
$periods = CarbonPeriod::create($dt_past, "1 month" , $dt_future);
```

## CarbonPeriod とは

CarbonPeriod は Carbon のライブラリに含まれている期間を表わすクラスで、これを使うと foreach である期間中の反復処理をするときにとても便利です。PHP 標準にある DatePeriod の Carbon 版です。 

### おまけ

Carbonは過去から未来に向けて処理を行います。
もし未来から過去の配列を取得したい場合は「array_reverse」を利用しましょ！

```php
$reversed_period = array_reverse($period->toArray());　//未来から過去にする場合
```


今日はこんな感じで！
良いPHPライフを！！
Laravel5.5にて、Authのログイン後にアクセス元にリダイレクトする処置

さっと書きます。
今回実装したいのは、 ログインが必要なページにアクセスした際ログイン画面にリダイレクト ↓ ログイン ↓ アクセスした元のURLにリダイレクトされる
といった簡単な内容です。

すぐ答えです。以下です。
Laravel 5.5の場合、LoginController.phpを更新するだけで次のコードが機能しました

```php
public function showLoginForm()
{
    session(['link' => url()->previous()]);
    return view('auth.login');
}


protected function authenticated(Request $request, $user)
{
    return redirect(session('link'));
}
```

セッションに残して、それにリダイレクトさせる簡単なコードで実装できました。
参考文献 https://www.it-mure.jp.net/ja/php/laravel-5%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3%E5%BE%8C%E3%80%81%E5%89%8D%E3%81%AE%E3%83%9A%E3%83%BC%E3%82%B8%E3%81%AB%E3%83%AA%E3%83%80%E3%82%A4%E3%83%AC%E3%82%AF%E3%83%88/1052037127/amp/
上記には多数のバージョンがあるので、見てみてくださいねん。
以上
ICU4Jで利用可能なID一覧を取得する

ICU4J https://unicode-org.github.io/icu/userguide/icu4j/ の ```Transliterator.getInstance("id")``` で指定可能なIDの一覧を取得する。

```groovy:build.gradle
implementation 'com.ibm.icu:icu4j:70.1'
```

```java
import java.util.Enumeration;

import com.ibm.icu.text.Transliterator;

public class PrintAvailableIDs {
  public static void main(String[] args) {
    Enumeration<String> ids = Transliterator.getAvailableIDs();
    while (ids.hasMoreElements()) {
      System.out.println(ids.nextElement());
    }
  }
}
RPAとVBAって相性良いよね！と言うお話し

**【なぜ書こうと思ったの？】**

全くの未経験からRPAの世界に飛び込み3年超、こんな身近にある便利ツールとRPAを組み合わせて使えるのは本当に便利だし、VBAは敷居がそんなに高くないから導入しやすいし、何よりRPA自体の安定化稼働も図れるので一石二鳥では？と、RPA3年生は思った次第です。



**【業務側にいたからこそ分かる。Excelは便利な相棒】**
業務側が使用する頻度が高いのは「Excel」です。
現在もExcelで各種の管理や報告・集計等をまとめている所が多い筈です。

定型フォーマットの指定のセルに、数字や文字をを入力する。
入力した数値を計算して集計する。
関数を使う、ピボットテーブルを使う。
シートを分けて、文字色やフォントや罫線を変えるなどetc。

総務事務時代、本当に些細な事でもExcelを使ってました。
報告書等はWordで作成する事もありますが、大体はExcelです。
ないと仕事になりません、事務系職の大事な相棒。


**【RPAとVBAの相性は抜群】**
RPAは、言わずもがな「定型業務を自動化」する事に優れています。
コマンド・アクション・ノード等と言った、既に用意されている「箱」へ、RPAの土台の「言語」に渡す「変数等」を設定し、処理が実行されます(と言う浅めな認識で生きてます)


一見、何でもできそうに見えますが、工夫しないと難しい部分もあり、実際には万能ではありません。
大事なことなので、再度…


**RPAは万能ではありません。
苦手な分野もあります。**

全てをRPAだけで終わらせる事は、少々危ういという実感を得ました。
そんな時に「VBA」が活躍しています。
決して難しい事はしていません。
**「RPAとVBA」を使い分けて、最終的にRPAが処理を失敗せずに実行できるようにする為に「互いの得意な部分」を担ってもらっています。**

**◆VBAにお願いする作業
　　　～主にExcelやファイルの加工～**

・空白や不要な行列を削除する
・フィルタで、必要なデータのみに整える
・セルの罫線や文字・セル色を設定する
・項目・担当者・取引先ごとにシート分けする
・重複を削除する、並べ替えをする
・項目名の設定、抽出結果の入力行や列の挿入

他色々な小さい細かい事

RPAでのショートカットキーを使用した操作と言った、ちょっとした工夫や調整が必要な部分は、断然VBAのほうが速いし安定感があります。
表から指定条件でデータを抜き出す、条件によって文字や数値等を入力するといった「配列」の操作も、やはりVBAが速かったです。
(RPAで魅せる処理を組むのは好き、大好き)



**【RPAとVBAのエラー・例外処理】**
「VBAの属人化」というお話を耳にして思う事。

や、私はそんな難しい処理は組んでないんで、大丈夫っす！(まだまだ組めないよ！)
しかし、ある程度のエラー・例外処理は入れてます。

「フォルダ存在してないかも」
「指定データがないかも」
「そもそもファイルないかも」
「まさかのフォーマット変更かも」
「毎回項目数が変わってるかも」

想定するエラー・例外条件をコードの中に組み込んで「VBAのエラー表示が出ない」ようにしておいて、あとはRPA側の処理で補ったりしています。本当に使い分け。




**◆最後に…◆**
**二つのツールを使い分けて、よりRPAの成功率が上がれば、使う側も作る側もHappyになるよね！というお話でした。**
Mattermost 403 エラー



# Go 言語で Mattermost BOT を作成する

Mattermost と Go 言語で Bot を作ろうとして、リクエストを投げると 403 エラーが出力された。

# ソースコード

```golang
package main

import (
	"fmt"
	"net/http"
	"net/http/httputil"
	"bytes"
	"os"
	"encoding/json"
)

type BODY struct {
	channel_id string
	message string
}

func HTTPPost(mes string) {

	requestBody := &BODY{
		channel_id: "1ngefhpjojyabd9fc7n8twt3xh",
		message: "hello",
	}

	//リクエストbodyをjson.Marshal関数を使って作成する
	jsonString, err := json.Marshal(requestBody)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	endpoint := "http://192.168.202.129:80/api/v4/posts"
	req, err := http.NewRequest("POST", endpoint, bytes.NewBuffer(jsonString))

	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	//ヘッダーを付与
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization","Bearer jmkk43ic3ib3tenmhycbfj7jre")
    req.Header.Set("channel_id", "1ngefhpjojyabd9fc7n8twt3xh")
	req.Header.Set("message", "hello")

	//リクエストの内容確認
	dump, _ := httputil.DumpRequestOut(req, true)
	fmt.Printf("%s", dump)

	//リクエストを送信
	client := new(http.Client)
	resp,err := client.Do(req)

	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	defer resp.Body.Close()

	dumpResp, _ := httputil.DumpResponse(resp, true)
	fmt.Printf("%s", dumpResp)
}


//slashコマンドを受け付ける
func slash(w http.ResponseWriter,r *http.Request) {
	text := r.FormValue("text")
	//fmt.Fprintf(w,"hello %v",text)

	//http postする
	HTTPPost(text)
}

func main() {
	http.HandleFunc("/slash",slash)
	http.ListenAndServe(":8090",nil)
}
```

# 出力

```
POST /api/v4/posts HTTP/1.1
Host: 192.168.202.129:80
User-Agent: Go-http-client/1.1
Content-Length: 2
Authorization: Bearer jmkk43ic3ib3tenmhycbfj7jre
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip

{}HTTP/1.1 403 Forbidden
Content-Length: 237
Connection: keep-alive
Content-Type: application/json
Date: Tue, 21 Dec 2021 10:39:41 GMT
Server: nginx
Vary: Accept-Encoding
X-Ratelimit-Limit: 101
X-Ratelimit-Remaining: 98
X-Ratelimit-Reset: 1
X-Request-Id: 5mxe4u7aupd4db89wpbd3wxiae
X-Version-Id: 5.36.0.5.36.0.673343c915db87d44c29a4c208aeb200.false

```

# 問題点

403 エラーなので認証がうまく通ってなさそうだった。
Header は問題なさそうだったので、チャンネル ID などの情報が載っている BODY に問題がありそう。

```golang
	requestBody := &BODY{
		channel_id: "1ngefhpjojyabd9fc7n8twt3xh",
		message: "hello",
	}

	//リクエストbodyをjson.Marshal関数を使って作成する
	jsonString, err := json.Marshal(requestBody)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
```

ここを、構造体を使わずにごり押しでやる。

```
	jsonStr := `{"channel_id":"` + "1ngefhpjojyabd9fc7n8twt3xh" + `","message":"` + mes + `"}`

	endpoint := "http://192.168.202.129:80/api/v4/posts"
	req, err := http.NewRequest(
		"POST",
		endpoint,
		bytes.NewBuffer([]byte(jsonStr)),
		)
```

そしたらできた。
SwiftでHTMLのaタグみたいなページ内リンク(ジャンプ)を実装してみる

htmlであれば、ページ内リンクはすごく簡単ですが、Swiftではどうなのでしょうか。

それをやってみたいと思います。

<h1>コード</h1>

まずは全体コードから

```php

import UIKit

class ViewController: UIViewController {
    
    @IBOutlet weak var myScrollView: UIScrollView!
    @IBOutlet weak var enableTapTextView: UITextView! //メインのTextView
    @IBOutlet weak var forScrollLabel: UILabel! //スクロール先
    
    override func viewDidLoad() {
        super.viewDidLoad()

        //基本設定
        enableTapTextView.delegate = self
        enableTapTextView.isEditable = false

        //TextView内の文字をタップ可能にする
        let attributeString = NSMutableAttributedString(string: enableTapTextView.text)
        attributeString.addAttribute(.link, value: "myLink", range: NSString(string: enableTapTextView.text).range(of: "記事コンテンツ①"))//valueは任意の値

        //リンク色を青から黒に変える
        enableTapTextView.linkTextAttributes = [.foregroundColor:UIColor.black]

        //下線を引く
        enableTapTextView.linkTextAttributes = [.underlineStyle:NSUnderlineStyle.single.rawValue]

        //最後に追加する
        enableTapTextView.attributedText = attributeString

    }    
}

extension ViewController : UITextViewDelegate{
    func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {
        
        let urlString = URL.absoluteString
        
        if urlString == "myLink"{ //href属性
            //記事内リンクスクロール(アニメーション付き)
            UIView.animate(withDuration: 0.5) {

                self.myScrollView.contentOffset = CGPoint(x: 0, y: self.forScrollLabel.frame.origin.y)
                
            }
        }
        return false
    }
}

```

では、何をやってるのか簡単に説明します。

(ちなみに、スクロールビューは各自で用意をお願いいたします。)

まずは、TextViewをカスタムできるようにするため、NSMutableStringに入れます。

次に、その種類や値、適用させる範囲などをaddAttributeに設定していきます。リンク化させたいので.link、適用範囲はここでは”記事コンテンツ①”としています。自由に設定してください。
ちなみに「value」は、HTMLでいうところのaタグ(アンカータグ)の中の「id属性」になります。こちらも自由です。

そして後は、見やすいように線を引いたりしてます。

最後は、リンクの遷移先を設定しています。

```php

extension ViewController : UITextViewDelegate{
    func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {
        
        let urlString = URL.absoluteString
        
        if urlString == "myLink"{ //href属性
            //スクロールさせる(アニメーション付き)
            UIView.animate(withDuration: 0.5) {

                self.myScrollView.contentOffset = CGPoint(x: 0, y: self.forScrollLabel.frame.origin.y)
                
            }
        }
        return false
    }
}
```

このTextViewのメソッドは、いわばURLの指定先を受け取る場所です。

ここではページ内に遷移したいので、上記のようにしてます。
もし例えば、外部ページに飛びたい場合は、SFSafariViewControllerなどで対応すると良いと思います。

あと、遷移先オブジェクト(ここではforScrollLabel)のoriginYを指定することで、良い感じにタイトルがページの一番上部にぴたっとつくようになります。

<h1>最後に</h1>

お疲れ様でした。

自分はまだSwiftを勉強し始めて1年経過したほどの初心者なので、間違ってるところを多々あるかもしれませんので、その時はぜひ指摘をお願いいたします。

では！
JavaGold一夜漬けチャレンジ

## この記事について
**JavaGold取りたいな…でも試験、明日なんだよな…**
一夜漬けでも取れるのかな…って人が不安になって調べたりすること、あると思います。
私がそうでした:sweat_drops:
申込日は自分で決められるのに…24時間前までなら試験日時の変更可能なのに…

**そうです。予約日時の変更が間に合うかもしれません！**
Java Programmer IIの試験日時変更は、予約した試験日時の24時間前までできますよ。
もしまだ間に合う方は予約日時を変更し、気合を入れて勉強してから受けた方が安心でしょう。

この記事はもう間に合わない、あるいはOracle2回目受講無料キャンペーンなどでとりあえず受ける！
そんな方に向けて書きます。
しかしながら、当然落ちても補償はできませんので…。。

**なに？再受講無料キャンペーンを知らない？**
ついでに記載します。

## 再受講無料キャンペーンについて
毎年、Oracleはオラクル認定資格試験の再受講無料キャンペーンをしています。[^1]

12月から始まり翌年5月いっぱい。
くわしくは[検索](https://www.google.com/search?q=oracle%E8%A9%A6%E9%A8%93+%E5%86%8D%E5%8F%97%E9%A8%93%E7%84%A1%E6%96%99%E3%82%AD%E3%83%A3%E3%83%B3%E3%83%9A%E3%83%BC%E3%83%B3&rlz=1C1QABZ_jaJP890JP891&sxsrf=AOaemvKWYww5PLSK8MKh2HvQty_TEDR6mQ%3A1638890019463&ei=I3qvYdvIG62n2roP4danKA&ved=0ahUKEwib5r2L_dH0AhWtk1YBHWHrCQUQ4dUDCA4&uact=5&oq=oracle%E8%A9%A6%E9%A8%93+%E5%86%8D%E5%8F%97%E9%A8%93%E7%84%A1%E6%96%99%E3%82%AD%E3%83%A3%E3%83%B3%E3%83%9A%E3%83%BC%E3%83%B3&gs_lcp=Cgdnd3Mtd2l6EAMyBQgAEM0COgoIIxCuAhCwAxAnOgYIABAEEB46CQghEAoQoAEQKjoHCCEQChCgAToGCCEQChAqOgQIIRAKSgQIQRgBSgQIRhgAUMQEWMwlYMEoaAFwAHgAgAF8iAGcE5IBBDE3LjiYAQCgAQHIAQHAAQE&sclient=gws-wiz)！

とりあえず一度受けて試験の感覚をつかみたい人にはうってつけです。

## 受験時のレベル感
資格取得時、業務でJavaを書くこと1年ちょっと。
情報系出身ではない、新卒二年目くらいのレベル感です。
SE8で追加されたStream APIもラムダ式も、LocalDateも日頃使います。
しかし普段使わないような機能はさっぱり…こんな機能あったんだ…
と問題を解きながら知る感じでした。。

## 試験準備編
用意するもの：黒本
黒本のおまけ問題のPDFもDLしておきましょう。かなり重要です。

これだけです。
なんといっても試験直前ですから。
他をする余裕なんてありません！

とはいえJavaSilverと違って黒本そのまんまというわけではありません。
あれは本当にそのまんまでしたから…
とはいえ、問われていることは黒本から大きくは外れません。
黒本に書いてあることを理解できれば合格できます。

## 対策編
・StreamAPI
・JDBC
この二つが大きいです。
11章の総仕上げ問題とおまけのPDF（どちらも模擬試験）を満点取れるくらい身に着ければ固いと思います。
満点取れるくらい、というのはただ答えを暗記するのではなく、解説まで読み込むということです。

特にプレーンなJDBCを扱う機会など今はほとんどないのではないかと思います。
模擬試験だけでなくしっかりと確認しておくべきでしょう。

そのうえで不安な範囲があれば前の章で学習するとよいでしょう。
Silverでも黒本を使った方はわかると思いますが、模擬試験以外の各章の問題はレベル感が違います。
本当によくわかっていない範囲の学習、という形になると思います。

きっと読み切る方は切羽詰まっているでしょうが、頑張ってください！

[^1]: 一部対象外があります！要確認
iOSのシステムサウンド



#まとめた

システムサウンドを聞けるサンプル作りました

必要でしたら使ってください

https://github.com/SNQ-0/iOS-SystemSounds

![SystemSoundGIF.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/08026d7e-d968-af89-4a98-cc608d207615.gif)

こんな感じです
押したらシステムサウンドが聴けます

#参考
https://iphonedev.wiki/index.php/AudioServices
【Python】Discord Botにページネーションを実装する【pycord】

# 0. 使用ライブラリ「pycord」について

当記事はDiscord APIのPythonラッパー「[discord.py](https://github.com/Rapptz/discord.py)」の後継ライブラリ、「[pycord](https://github.com/Pycord-Development/pycord)」の新機能「ページネーション」についての解説記事です。discord.pyの開発終了については [こちら](https://gist.github.com/Rapptz/4a2f62751b9600a31a0d3c78100287f1) から、pycordの導入方法・解説は以下の記事からご覧ください。

https://qiita.com/melonade/items/25c038e8e4e6800aa639

# 1. ページネーションとは

一般にいうページネーションとは「ページ分け」のことで、WEBサイトやドキュメントなどの長い文章を、似たデザインの複数のページに分割して掲載することをいいます。
当記事では、Python製のDiscord Botでページネーションを実装していきます。

# 2. ページネーションの実装

pycordの拡張「discord.ext.pages」を使用していきます

https://github.com/Pycord-Development/pycord/tree/master/discord/ext/pages

## 2.0. コードの基本形

```python:discordbot.py
import discord

bot = discord.Bot()

# ここにコードを記述

bot.run('DISCORD_BOT_TOKEN')
```

`'DISCORD_BOT_TOKEN'` には、自分のBOTのTOKENを入れてください。

## 2.1. 最も簡単なページネーションの実装

```diff_python:discordbot.py
import discord
+ from discord.ext import pages

bot = discord.Bot()

# ここにコードを記述

bot.run('DISCORD_BOT_TOKEN')
```
まず、pycordのページネーション拡張をimportします。

ここからは `#ここにコードを記述` に記述をしていきます。

```python:discordbot.py
@bot.slash_command()
async def test_pages(ctx):
    await ctx.defer()
    test_pages = ['Page-One', 'Page-Two', 'Page-Three', 'Page-Four', 'Page-Five']
    paginator = pages.Paginator(pages=test_pages)
    await paginator.send(ctx)
```

`pages.Paginator` の `pages` には文字列か `discord.Embed` の配列を入れます。
配列の中身がそのままページとして反映されます。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2273214/0b17f000-3d9a-e466-4253-8bebff288410.png)

とても簡単にページネーションを実装することができました。
ボタンをクリックすることで実際にページを推移することが可能です。

## 2.2. ページネーションの応用

### show_disabled

```python
pages.Paginator(show_disabled=False)
```

無効なボタンを非表示にします。

### show_indicator

```python
pages.Paginator(show_indicator=False)
```

インジケータ( `1/5` のような表示) を非表示にします。

### author_check

```python
pages.Paginator(author_check=False)
```

ページネーションのボタン操作をコマンドの入力者以外にも許可します。

### custom_view

```python
pages.Paginator(custom_view=discord.ui.View)
```

ページネーションのViewをカスタムします。
(新たにボタンやセレクトなどのUIを追加できます)

## 2.3. ページネーションのカスタム

```python:discordbot.py
paginator.customize_button('next', button_label='next', button_style=discord.ButtonStyle.grey)
paginator.customize_button('prev', button_label='prev', button_style=discord.ButtonStyle.grey)
paginator.customize_button('first', button_label='first', button_style=discord.ButtonStyle.grey)
paginator.customize_button('last', button_label='last', button_style=discord.ButtonStyle.grey)
```

![cus.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2273214/479242ae-ce8e-e1aa-6188-d0923df2e73a.png)

ページネーションのUI (デザイン) を変更することができました。

# 3. おわりに

今回はDiscord Botにページネーションを実装する方法について解説しました。
何かありましたらコメント等で指摘して頂けると助かります。

# 4. 参考

- [ページネーション 【pagination】 ページネート / パジネーション](https://e-words.jp/w/ページネーション.html)
- [Pycord-Development/pycord/blob/master/examples/views/paginator.py - github](https://github.com/Pycord-Development/pycord/blob/master/examples/views/paginator.py)
[ServiceNow]ブラウザの別タブで画面を表示する

今回は私が最近知った小技について書きます。
1年半SNOWを触ってきましたが、今頃こんなことを知って恥ずかしい・・・

#ブラウザの別タブで画面を表示する
ServiceNowを触っていて（開発していて）、別タブでXXテーブルの情報を見たくなることとかないでしょうか？
その場合に役立つ小技について執筆します。

##動作環境
- インスタンスVersion：Rome
- ブラウザ：Google Chrome

##操作方法
例えば開発しているとシステムプロパティ一覧が見たくなることがありますよね。
その時はフィルターナビゲータに「sys_properties.list」と入力し、Enterキーを押すと、
![小技１.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/fd2bf5bc-78d4-49aa-1c61-1c81da4bb29b.png)

システムプロパティ一覧が同じタブに表示されます。
![小技2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/ac88d13d-919a-ad88-6c1c-aa4b5f7ccb32.png)

ただ別タブで開きたい時もありますよね。
そんな時はフィルターナビゲータに「sys_properties.**LIST**」と入力して検索すると、
![小技3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/ce84fe18-a883-15f8-5da3-893a5fc02413.png)


別タブで簡単に開けます。
**基本".（ドット）"より右を大文字にして検索すると別タブで開けます。**
![小技4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/e67f3501-93d8-dc79-4df5-118387c6074b.png)
logrotate の世代や圧縮を後から設定する

少し前に新規でインストールしたサーバのログを、あまり考えずに「残す世代多め」「圧縮はしない」という設定で使い始めていました。
運用し始めてから /var/log の容量が気になり始めたので、世代を短くして、圧縮をかける設定にしました。
設定変更したあとに rotate されるタイミングで、自動的に「世代を短くしたぶんの過去ログは消えるのか」「圧縮されていなかった過去ログは圧縮されるのか」が気になったので検証してみました。

## 試した環境

```
# cat /etc/redhat-release
CentOS Linux release 7.9.2009 (Core)
# rpm -q logrotate
logrotate-3.8.6-19.el7.x86_64
```

## 元の設定

「過去ログは15世代」「圧縮しない」という設定になっています。

```text:/etc/logrotate.d/httpd
rotate 15
```

その結果、このようなログになっています。

```
access_log
access_log-20210905
access_log-20210912
access_log-20210919
access_log-20210926
access_log-20211003
access_log-20211010
access_log-20211017
access_log-20211024
access_log-20211031
access_log-20211107
access_log-20211114
access_log-20211121
access_log-20211128
access_log-20211205
access_log-20211212
```

## 新しい設定

「過去ログは10世代」「圧縮する」「けど、一番新しい過去ログは圧縮しない」という設定に変更しました。

```text:/etc/logrotate.d/httpd
rotate 10
compress
delaycompress
```

つまり、こうなってほしいです。

```
access_log
access_log-20211017.gz
access_log-20211024.gz
access_log-20211031.gz
access_log-20211107.gz
access_log-20211114.gz
access_log-20211121.gz
access_log-20211128.gz
access_log-20211205.gz
access_log-20211212.gz
access_log-20211219
```

## rotate された結果

```
access_log
access_log-20211017.gz
access_log-20211024.gz
access_log-20211031.gz
access_log-20211107.gz
access_log-20211114.gz
access_log-20211121.gz
access_log-20211128.gz
access_log-20211205.gz
access_log-20211212.gz
access_log-20211219
```

はい、理想どおりです。

* 圧縮されていなかった過去ログはすべて圧縮される（今回 gz になる access_log-20211212 以外も圧縮される）
* 残す世代数より古い過去ログはすべて削除される（今回押し出される 20211010 だけでなく、もっと古いログも削除される）
* いまのログファイルが過去ログ（非圧縮）になる

すべてが行われました。
GitHub Actionsを使ってGitHub Discussionsの通知をSlackで受け取る

この記事は[岩手県立大学とか、岩手の人たち Advent Calendar 2021](https://qiita.com/advent-calendar/2021/ipu)の 8 日目の記事です！

https://qiita.com/advent-calendar/2021/ipu

## はじめに

現在、GitHub の Slack App では GitHub Discussions で Discussion やコメントが作成されたときの通知に対応していません。

そこで、GitHub Actions を使って、

- Discussion の作成
- Discussion へのコメントの作成

を Slack に通知するまでを記事としてまとめます。

## Slack で Webhook の設定

Slack の Webhook の URL を用意しておきます。

以下の記事が参考になります。

https://qiita.com/vmmhypervisor/items/18c99624a84df8b31008

## GitHub Actions の設定

通知を受け取りたい GitHub Discussions のあるリポジトリに GitHub Actions の workflow を設定します。

workflow は以下のようになります。
（`jq`を使う例がいくつかありましたが、一番シンプルなものにしました。）

```yml:.github/workflows/discussions-notice.yml
on:
  discussion:
    types: [created]
  discussion_comment:
    types: [created]
jobs:
  discussion_created:
    runs-on: ubuntu-latest
    if: github.event.discussion && !github.event.comment
    steps:
      - run: |
          curl -X POST -d '{ "text": "Created discussion: ${{ github.event.discussion.html_url }}" }' ${{ secrets.SLACK_WEBHOOK_URL }}
  discussion_commented:
    runs-on: ubuntu-latest
    if: github.event.discussion && github.event.comment
    steps:
      - run: |
          curl -X POST -d '{ "text": "Created discussion comment: ${{ github.event.comment.html_url }}" }' ${{ secrets.SLACK_WEBHOOK_URL }}
```

あとは、リポジトリの`Settings > Secrets`で取得した Webhook の URL を`SLACK_WEBHOOK_URL`として登録してあげれば完了です。

## 解説

```yml
on:
  discussion:
    types: [created]
  discussion_comment:
    types: [created]
```

workflow を実行する event で、

- `discussion`
  - Discussion のイベント
- `discussion_comment`
  - Discussion へのコメントのイベント

です。

また、event には type があり、作成（`created`）、編集（`edited`）などの type ごとに event を発火させることができます。

https://docs.github.com/ja/actions/learn-github-actions/events-that-trigger-workflows

```yml
  discussion_created:
    runs-on: ubuntu-latest
    if: github.event.discussion && !github.event.comment

    省略...

  discussion_commented:
    runs-on: ubuntu-latest
    if: github.event.discussion && github.event.comment
```

各 job についている`if`では、Discussion が作成されたのか、Discussion へのコメントが作成されたのかを判定しています。

`github.event.discussion`は対象となった Discussion のオブジェクトが含まれているため、コメントをした際でも`github.event.discussion`にはオブジェクトが入っています。
また、Discussion へのコメントをした際には、`github.event.comment`にコメントの情報が入っています。そのため、`github.event.comment`の中身を確認し、Discussion か Discussion へのコメント化を判定しています。

実際に何が入っているかは以下のようにすると確認できます。

```yml
check_github_event_discussion:
  runs-on: ubuntu-latest
  steps:
    - run: echo "${{ toJSON(github.event.discussion) }}"
```

https://docs.github.com/ja/actions/learn-github-actions/contexts

## 動作テスト

試しに Discussion を作成してみると、、、

無事に Slack 通知が来ました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352836/d82546cc-391a-b7c9-6ec5-181a46587841.png)

## 最後に

GitHub の Slack App で対応してほしい、、

## 追記

### 2022/01/25

https://github.com/integrations/slack/issues/1026#issuecomment-994277107

GitHub の Slack App で Discussions が一部サポートされたみたいです。
Discussion コメントはまだなので、今後に期待ですね。
IBMCloud VPCのPrivateDNSでトラブルが起きた時のTips

* IBMCloud VPCにてPrivateDNS障害がおきたときに、ケースを起票する際に確認しておく項目について記載する。（サポートとの調整をスムーズに進めるためのTips）

VPCにてPrivateDNSの名前解決がうまくいかない場合、以下の情報を確認のうえでケース作成する。
　(ケース作成時によく聞かれる項目)


 1. VPC Id
 2. Dig result
 3. DNS Server ip address

項番3について、たとえばVPCサーバがCentOSなどであれば、/etc/resolv.confは以下のnameserverアドレスを確認する。
以下の例では、PublicのDNSアドレスを利用していることがわかる。(PrivateDNSを利用している場合は161.26.0.7/161.26.0.7が表示されるはず)

```
[root@fisher-centos ~]# cat /etc/resolv.conf
# Generated by NetworkManager
nameserver 161.26.0.10
nameserver 161.26.0.11
```

参考ドキュメント:
[DNS ServicesとVPCの併用](https://cloud.ibm.com/docs/vpc?topic=vpc-about-dns-srvcs&locale=ja)
[サポートケース起票方法](https://cloud.ibm.com/docs/get-support?topic=get-support-open-case&locale=ja)
Vagrantで立ち上げたUbuntu20.04が「SSH auth method: private key」で止まる問題の対処

Ubuntu Box「ubuntu/focal64」を`vagrant up`で起動しようとしても、`SSH auth method: private key`でタイムアウトしてしまう。

```shell-session
❯ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'ubuntu/focal64'...
==> default: Matching MAC address for NAT networking...
==> default: Checking if box 'ubuntu/focal64' version '20211026.0.0' is up to date...
==> default: Setting the name of the VM: **********************************
==> default: Fixed port collision for 22 => 2222. Now on port 2200.
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
    default: Adapter 2: hostonly
==> default: Forwarding ports...
    default: 22 (guest) => 2200 (host) (adapter 1)
==> default: Running 'pre-boot' VM customizations...
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2200
    default: SSH username: vagrant
    default: SSH auth method: private key      # ここでタイムアウトしている
Timed out while waiting for the machine to boot. This means that
Vagrant was unable to communicate with the guest machine within
the configured ("config.vm.boot_timeout" value) time period.

If you look above, you should be able to see the error(s) that
Vagrant had when attempting to connect to the machine. These errors
are usually good hints as to what may be wrong.

If you're using a custom box, make sure that networking is properly
working and you're able to connect to the machine. It is a common
problem that networking isn't setup properly in these boxes.
Verify that authentication configurations are also setup properly,
as well.

If the box appears to be booting properly, you may want to increase
the timeout ("config.vm.boot_timeout") value.
```

該当箇所でネットの情報を見ると、`vb.customize ["modifyvm", :id, "--cableconnected1", "on"]` を設定すると治ったみたいな情報が出てくるが、実際にやっても変わらず。

Vagrant のissueを覗くと[同じような事象のissue](https://github.com/hashicorp/vagrant/issues/11890)があった。
Vagrantfileに以下の設定を行う事ですんなり`vagrant up`することができた。

```ruby
  config.vm.provider "virtualbox" do |vb|
    vb.customize ["modifyvm", :id, "--uart1", "0x3F8", "4"]
    vb.customize ["modifyvm", :id, "--uartmode1", "file", File::NULL]
  end
```
statコマンド について

## 勉強前イメージ

ちょっと便利なコマンドを知ったのでまとめておきたかった

## 調査

### statコマンド

statコマンドはファイルやファイルシステムの情報を表示するコマンドです。
結構全般的なことが色々見えるので便利です。

`stat [filename]` で使用します。

```
stat a.txt 
```

```
[root@localhost ~]# stat a.txt 
  File: `a.txt'
  Size: 45824           Blocks: 96         IO Block: 4096   通常ファイル
Device: fd00h/64768d    Inode: 8990909     Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Context: unconfined_u:object_r:admin_home_t:s0
Access: 2021-12-19 14:15:37.619502835 +0900
Modify: 2021-12-19 14:15:18.098621998 +0900
Change: 2021-12-19 14:15:18.100624037 +0900
 Birth: -
```

ファイル名はもちろん、最終アクセス時間、変更時間など確認することが出来ます。
Birthはファイルの作成日のようですが、なぜか今見れていないです。

### ちなみに

modifyとchangeの違いは以下になります。

- modify : 修正した時間
- change : ステータス変更時間

なので、権限を変更するだけだとmodifyは変わりませんが、changeは変更になります。


```
[root@localhost ~]# stat a.txt 
  File: `a.txt'
  Size: 45824           Blocks: 96         IO Block: 4096   通常ファイル
Device: fd00h/64768d    Inode: 8990909     Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Context: unconfined_u:object_r:admin_home_t:s0
Access: 2021-12-19 14:15:37.619502835 +0900
Modify: 2021-12-19 14:15:18.098621998 +0900
Change: 2021-12-19 14:15:18.100624037 +0900
 Birth: -
```

```
chmod 655 a.txt 
```

```
[root@localhost ~]# stat a.txt 
  File: `a.txt'
  Size: 45824           Blocks: 96         IO Block: 4096   通常ファイル
Device: fd00h/64768d    Inode: 8990909     Links: 1
Access: (0655/-rw-r-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
Context: unconfined_u:object_r:admin_home_t:s0
Access: 2021-12-19 14:15:37.619502835 +0900
Modify: 2021-12-19 14:15:18.098621998 +0900
Change: 2021-12-19 16:05:41.929449775 +0900
 Birth: -
```

上記のように、権限の変更ではchangeだけが変更されています。

## 勉強後イメージ

ファイルについて大体見えるのでいつ変更されたか見たいときとかは結構便利な気がする

## 参考

-[stat - ファイルまたはファイルシステムの情報を確認](https://linuxcommand.net/stat/)
会社のプロジェクト毎に用意しているCLIツールについて語る

## CLI ツールを導入した理由

目標は **エンジニアがどのプロジェクトに入っても，同じ操作体験で開発できる** こと

導入する前の問題は

- プロジェクト毎に作業の詳細が異なる
- 長い README を元に作業するものの再現性がない
- メンバ毎の秘伝のメモ帳が発展するが共有はされない

---

## 導入の経緯

- CLI ツールを作っているチームがいると聞く 👍
- Rust で作ろうと息巻く 😤
- ShellSpript で書く方針に変更 🤔
- ルーチンをひたすらコマンド化 🔥
- 昔作られた CLI ツールをプロジェクト内で発見 🤭
- 邪魔だったのでプロジェクトから削除 😗
- 他プロジェクトに展開 🔥
- CLI ツールを簡単に導入できるテンプレート作成 🎊
- 高機能化に対応するため Python で部分的な機能を書き始めた 🔥（← 今ここ）

---

## 何ができるか

プロジェクト用のコマンドを書くとまずいので，テンプレートから参照

```text
$ uvcli
UniqueVision でプロジェクト開発を便利にするためのCLIツールの雛形

Commands:
  General:
    welcome                     初めて開発する人向けの情報
    init[ialize] [OPTIONS]      初期化する
    cd [DIRECTORY]              プロジェクト内のディレクトリに移動する
    edit [FILE]...              エディタでプロジェクトを開く

  Containers:
    build                       ビルドする
    start                       開始する
    stop                        終了する
    process|ps [-s]             起動しているDockerサービス一覧を表示する
    exec[ute] SERVICE COMMAND   SERVICE_NAMEのコンテナで、COMMANDを実行する
    shell SERVICE               対象のコンテナにシェルではいる。
    restart SERVICE             特定のサービスを再起動する
    log [-f] [SERVICE]          ログを出力する
    url SERVICE                 指定したサービスへアクセスするURLを出力する

```

---

## ディレクトリ構成

プロジェクト用のコマンドを書くとまずいので，テンプレートから参照

```text
.
├── bin
│  └── uvcli
│
├── cli
│  ├── commands
│  │  ├── welcome.sh
│  │  └── ...
│  │
│  ├── completion
│  │  └── uvcli_cmdcomp.toml
│  │
│  ├── README.md
│  └── uvcli.sh
│
├── docker-compose.yml
└── README.md
```

---

## 実際の操作体験

### インストール

```sh
git clone $YOUR_PROJECT
uvcli init
echo 'eval $(uvcli init -)' >> ~/.bash_profile
```

### 開発

```sh
# 開発開始
uvcli build
uvcli start

# 開発終了
uvcli stop
```

### デプロイ

```sh
uvcli $REALM deploy
```

いや〜簡単ですね

---

## 補完機能

CLI を使うなら，補完機能は必須だと思っている

いいツールが見つからなかったので簡単に補完機能を用意できるツール [cmdcomp](https://hub.docker.com/r/uvdockerhub/cmdcomp) を新規に設計

[toml](https://toml.io/) ファイルを書くことで補完機能の書き方を知らない人でも容易に補完機能を追加することができる！

```toml
[cmdcomp]
version = "0.1.0"

[app]
name = "uvcli"

[root.subcommands.welcome]

[root.subcommands.initialize]
alias = "init"
options = ["-"]
```

---

## なぜ ShellScript で作ったのか？

実行速度，安全性，機能性，全てにわたって Rust が凌駕するでしょう...（当然）

しかし，Rust をどれだけの人が読み書きできるだろうか？ 5 年後にも同じことが言えるだろうか？

ShellScript を採用した理由は **みんなが書けて， 5 年後もそう** だからだ（だよね 😉 ）

---

## 高機能化について

高度な機能（あいまい検索，設定ファイルを元にした複雑な処理）が欲しい！

Python で複雑な機能を処理し ShellScript 内で呼ぶことにした

なぜ Rust で書かなかったのか？...clap v3 が正式リリースされてないからかな？

---

## 最後に

- みんなも CLI ツールを作ろう 🤩
- Shell Script は寿命が長いよ 😉
- Shell Script には限度があるよ 😉
- tcsh，fish には塩対応 🤫
ログ解析の強い味方、EmEditor Free(V21.3)の紹介

# 追記
Free版の制限を見落としていました。申し訳ございません。

> Free版は、ご家庭または学校で個人としてのみお使いいただけます。会社、政府、その他の組織で利用することはできません。

本記事で紹介している機能を利用するには有償版(PRO)の購入が必要となります。無償版を利用可能と誤解を与えてしまい申し訳ございませんでした。


# 本文

EmEditorの巨大ファイルサポート機能が、無償版で利用可能になっていました。

https://jp.emeditor.com/text-editor-features/history/new-in-version-21-3/

> Free版で巨大ファイルをサポートしました (従来は、Professional版でのみサポートしていました)。

数年前、数百MB～数GBといった巨大なログファイルを開くのにEmEditorにお世話になっていたのですが、その後巨大ファイルは有償版のみでのサポートとなり、無償版では利用できなくなっていました。
それが、バージョン21.3で無償版で利用可能に復活しました。

EmEditorの巨大ファイルサポート機能は強力です。
例えば、手元で1.6GBのCSVをEmEditor Freeで開いてみたところ、開いた瞬間にデータが表示され、スクロールの操作もスムーズに可能で普通に閲覧できます。ファイル起動直後、ステータスバーではファイル起動の進捗のパーセンテージが表示されますが、5秒程度で100%になり起動完了しました。

どういうアルゴリズムでこうできるのか、他のエディタではありえない高速さで巨大なログを開くことができます。

数百MB以上あるログファイルを開くのは、Windowsでは特に大変で、僕の場合はそういったログを開くとき、一旦適当なLinuxサーバにログを転送して、headやtailなどファイルの行数を指定して開くことができるコマンドを駆使してログを分割してから、ページャで開いています。

でかいファイルでファイル全体を開く、という操作は、他のエディタやLinuxのページャでも鬼門かと思っています。
これが、EmEditorだと何も考えずにDrag/Dropするだけです。

ちなみに1.6GBのファイルを開いたとき、EmEditorではコミットサイズ189MB, ワーキングセット208MB, ピークワーキングセット1.2GBでした。
なので、ファイル起動時の一時点ではファイルの大きさに伴ってメモリを消費するものの、ファイルサイズよりもメモリ消費は小さく、さらに、起動後はメモリ消費はファイルサイズの8分の1程度となっている、ということとなります。

ちなみにサクラエディタで同じファイルを開くと、開く間フリーズするのと、PC自体もプチフリ状態になり、開いている途中～開いた後の状態で、コミットサイズ3.6GB, ワーキングセット2.8GB, ピークワーキングセット3GBでした。また、開くのに3分くらいかかりました(開いた後は、普通にスクロールして見れるようになりました)。※サクラエディタは巨大ファイルを開くのはつらいものの、普段利用では便利に使っています

インストール方法について、基本的にはホームページから、今すぐダウンロードをクリック後、インストーラを叩いて、途中の選択肢で「このアプリをEmEditor Freeとして使用」をクリックするだけです。

EmEditorの機能開発やパフォーマンス高速化は活発で、v21.3のChange Logs的なものを見ると色々パフォーマンスが高速されているようです
https://jp.emeditor.com/text-editor-features/history/new-in-version-21-3/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620712/9f36790f-5ff3-8b2c-318e-a51fe5ad4424.png)

有償版(PROFESSIONAL)、最新の無償版(V21.3)、過去の無償版(v16)の機能の違いはここで確認可能です
https://jp.emeditor.com/text-editor-features/history/emeditor-free/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620712/7ddff1a1-84eb-fd23-0508-db611e050e89.png)

この記事では巨大ファイルのサポートが無償版で提供された、という点でEmEditorを紹介したのですが、EmEditorは高機能なエディタです。ぜひ試していただくことをお勧めします。

https://jp.emeditor.com/
VSCodeで#ifdefブロックの中がグレーアウトされる問題の解決法

# 環境
macOS

# 解決法
1. メニューバーの Code > 基本設定 > 設定
1. 右上の「設定(JSON)を開く」アイコンをクリック
1. 以下の設定を追加する

```
"C_Cpp.dimInactiveRegions": false
```

参考: https://github.com/microsoft/vscode-cpptools/issues/1707
ペライチは本当に心理的安全性が高いのか

# はじめに
この記事は[ペライチアドベントカレンダー](https://qiita.com/advent-calendar/2021/peraichi)の21日目の記事です。

はじめまして、ペライチでサーバーサイドエンジニアをしている木村です。
ペライチには2021年4月に入社しまして、早いもので8ヶ月が過ぎました。
コロナ禍での転職には一抹の不安があったものの、実際に入社してみると割とすんなりと馴染むことができたように思います。

[CTO香月さんの記事](https://qiita.com/katsukii/items/a37b0afc9cc37d512ecb)では
>リモートワーク下でもチームでの生産性と心理的安全性を高めることに重きを置いた文化となっています。

との記述がありますが、これもフルリモート下でもすんなり馴染むことができた一因ではないでしょうか。
この記事では実際にペライチにおける心理的安全性が本当に高いのかどうか、入社してからを振り返りながらできるだけ忖度少なめに解説してみます。

# ペライチの心理的安全性は本当に高いの？
心理的安全性を提唱したエドモンソン教授による、組織の心理的安全性を測る7つの質問に答える形で見ていきましょう。

### ①チームの中でミスをすると、よく非難される（If you make a mistake on this team, it is often held against you.）
入社して8ヶ月、幸いまだ大きなミスはしていない（はず）です。
もちろん、他の人がミスによって非難されているところも見たことがないです。

やらかしたな〜と思ったことといえば、自分のタスク消化が間に合わずにスクラムのスプリントゴールが達成できなかったときでしょうか。
このときにも特に非難などはされず、その後の振り返りでは同じ失敗を繰り返さないよう他メンバーから意見をもらえたりしました。
ちなみに、所属するチームではスクラムイベント後に毎回YWT（やったこと・わかったこと・次にやること）で振り返りを実施しています。

### ②チームのメンバーは、課題や難しい問題を指摘し合える（Members of this team are able to bring up problems and tough issues.）
打ち合わせやslackで指摘しあえていると思います。
それによってより良いものをつくろうとする文化がペライチの気に入っているところです。

あまり関係ないかもですが、コードレビューもとても活発（過去に勤めた会社比）で、指摘を多くもらえてうれしいです。

### ③チームのメンバーは、自分と異なることを理由に他者を拒絶することがある（People on this team sometimes reject others for being different.）
過去に勤めたことのある会社だと、雇用形態の違いでコミュニケーションのとりかたに差を感じることもありましたが、業務委託の方も多く所属しているペライチではそれを感じたことがないです。
ここは入社してみて良いなと思った点のかなり上位ですね〜（設問の意図とずれてるような気もしますが）

### ④チームに対して、リスクが考えられるアクションを取っても安心感がある（It is safe to take a risk on this team.）
難しいことにチャレンジできる環境で、それによって考えられるリスクは許容してもらえそうです。
ちょうど今進めているプロジェクトでは、サーバーサイドエンジニアがフロントエンド（Vue.js）の実装にチャレンジさせてもらっているところです。
慣れていないことから遅延が発生する可能性が高かったですが、適切にフォローもしてもらえて安心して進めることができています。

### ⑤チームの他のメンバーに助けを求めることは難しい（It is difficult to ask other members of this team for help.）
ペライチではメンバー持ち回りで問い合わせ対応を担当しているのですが、よく知らない箇所だと調査に時間がかかってしまうため詳しい人に質問している場面をよく見かけます。
自分も[ペライチ決済](https://peraichi.com/landing_pages/view/peraichi-payment01)まわりのドメイン知識に乏しいためよく助けを求めており、快く対応いただけて助かっています。

### ⑥チームのメンバーは誰も、他人の仕事を意図的におとしめるような行動をしない（No one on this team would deliberately act in a way that undermines my efforts.）
これはもちろん見たことがないですね〜
そんな人がいたら8ヶ月も働ける自信がないです・・・

### ⑦現在のチームで業務を進める際、自分のスキルが発揮されていると感じる（Working with members of this team, my unique skills and talents are valued and utilized.）
SaaS型のプロダクトを提供している会社は初めてではないため、入社前にはそのノウハウをうまいこと活かすことができるのではないかと考えていました。
しかしながら、勘所などは共通しているところが多いものの、充分に活かしきれていないような気もしています。

使用していたフレームワークは異なりますが、PHP歴は長いので開発においてはスキルを発揮できていそうです。
ペライチのソフトウェア品質を向上するための施策（テスト整備の旗振りなど）を任せていただいており、やりがいと共にほどよいプレッシャーもあります。

# さいごに
ペライチの心理的安全性は本当に高そうだと思っていただけたでしょうか。
また、少しでもペライチ開発チームの雰囲気的なところが伝われば幸いです。

本当は技術的なネタを書きたかったのですが、なぜか担当の日を勘違いしていてサクッと書ける内容に切り替えさせていただきました。
技術ネタはよく温めた後に公開していければと思います。
GraphQLのライブラリ「strawberry」でページネーションを定義する

2021.12.21現在、strawberryのPaginationはcoming soonになっていました。
https://strawberry.rocks/docs/guides/pagination

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105394/e6b250c7-e53f-a500-63f7-1058da7e5999.png)


現在実装に向けた取り組みが行われています。
https://github.com/strawberry-graphql/strawberry/pull/1345


暫定ですがPaginationの定義はこう書くことができます。

```python
from typing import List, Generic, TypeVar

import strawberry


T = TypeVar("T")


@strawberry.type
class Edge(Generic[T]):
    node: T

@strawberry.type
class Connection(Generic[T]):
    edges: List[Edge[T]]
    nodes: List[T]


@strawberry.type
class Bar:
    id: int
    name: str


@strawberry.type
class Foo:
    bar: Connection[Bar]
```


正式リリースが待ち遠しいです。
JSでのイベントUtil作成

#1.ソース

```EventEmitter.js
export class EventEmitter {
    constructor() {
        this.registry = {};
    }

    on(name, listener) {
        this.registry[name] = this.registry[name] || [];
        this.registry[name].push(listener);
        return this;
    }

    once(name, listener) {
        const doOnce = function () {
            listener.apply(null, arguments);
            this.removeListener(name, doOnce);
        }.bind(this);
        this.on(name, doOnce);
        return this;
    }

    emit(name) {
        const args = Array.prototype.slice.call(arguments, 1);
        const listeners = this.registry[name];
        let count = 0;

        if (listeners) {
            listeners.forEach((listener) => {
                count += 1;
                listener.apply(null, args);
            });
        }
        return count > 0;
    }

    removeListener(name, listener) {
        const listeners = this.registry[name];
        if (listeners) {
            for (let i = 0, len = listeners.length; i < len; i += 1) {
                if (listeners[i] === listener) {
                    listeners.splice(i, 1);
                    return this;
                }
            }
        }
        return this;
    }
}
```
GlueにS3ファイルを読み込みと書き込み



https://qiita.com/nemutas/items/c3346a866fa7fe6f7d60
フォルダに保存したcsvデータを、S3バケットにアップロードする

import boto3
filepath = '/tmp/data.csv'
baket_name = 'release-comics'
savepath = 'data.csv'

s3 = boto3.resource('s3')
s3.meta.client.upload_file(filepath, baket_name, savepath)

------------------------------
https://qiita.com/asunaro/items/99472b492af387d97b70
import pandas as pd
import boto3
from io import StringIO

s3 = boto3.client('s3')
obj = s3.get_object(Bucket='バケット名', Key='ファイル名.csv')
body = obj['Body']
csv_string = body.read().decode('utf-8')
df = pd.read_csv(StringIO(csv_string))


----------------------------------
https://qiita.com/skokado/items/57d8f32bb88f4629f2d6
 s3 = boto3.client('s3', region_name = 'ap-northeast-1')
        response = s3.put_object(
            Body = io.BufferedReader(uploaded_file).read(),
            Bucket = s3_bucket,
            Key = f'{s3_dir}/{uploaded_file.filename}'
        )

-----------------------------------------------------

https://qiita.com/smiler5617/items/2edaaf9f6ffdef85a809
response = s3.list_objects_v2(Bucket=bucket, Prefix=prefix)
ランダムシードアベレージ

ランダムシードアベレージについて参考になる記事をメモ書き（自分用）

Numerai で Random Seed Average


https://zenn.dev/kunigaku/articles/914efe9855ad2d8f487b

Kaggle TalkingData Fraud Detection コンペの解法まとめ(応用編)
https://blog.recruit.co.jp/rco/kaggle_talkingdata_advanced/


機械学習におけるランダムシードの研究

https://qiita.com/si1242/items/d2f9195c08826d87d6ad
ASTERIA Warpのフローデザイナーの表示を自分好みにカスタマイズする

ASTERIA Warpのフローデザイナーの画面は複数の編集操作用ペインが配置されています。
ディスプレイが小さいノートPCなどで作業をするとそれらの表示が隠れてしまうことがよくあります。
今回はフローデザイナーの画面配置をカスタマイズすることでそれを解決していきます。

以下のリンクを参考にしました。
[フローサービスマニュアル](https://help.asteria.com/documentation/warp/ja/2112/flow/designer/index_guide.html)
「フローデザイナー→デザイナーのカスタマイズ」

上記リンクには今回カスタマイズするフローデザイナーの画面の構成や名称が説明されているので、事前に見ていただくと理解が深まると思います。

### 初期化方法

今回のカスタマイズによる変更は以下の方法で初期化できます。
うまくいかなかった場合は元に戻しましょう。

フローデザイナー画面の「ツールメニュー→表示→レイアウトを初期状態に戻す」をクリックする。

### ペインを移動する
画面の下側を占拠するメッセージペインを左下に移動します。

![messagePain.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2370877/26f61b94-05db-7bc9-4f11-70ac1deabf4e.gif)

ペインを右クリックして表示されるメニューから「タイトルバーを表示」をクリックすると、
メッセージペインがつまめるようになるのでそのままドラッグ＆ドロップで画面左下に移動させます。
右下のスペースが増えたおかげで右側のインスペクタ、ストリームペインが見えやすくなりました。

### ペインを表示、非表示にする。

ペインの表示、非表示を切り替えることで、
画面右側のインスペクタとストリームペインの表示を広くしてみます。

![painOnOff.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2370877/bb60a660-1c74-03ef-1d45-ce571756378f.gif)

画面上部にあるツールバーを右クリックして表示されるメニューから「ペインツールバー」をクリックします。
ペインツールバーにあるアイコンを押すと、画面右側のペインの表示を切り替えられました。


### おまけ（ワークスペースの視認性を上げる）
変更前
![workspaceBefore.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2370877/513cc97b-1fd5-0519-6124-2e4cd2b793e2.png)

変更後
![workspaceAfter.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2370877/25c19089-bfc0-c881-0561-3998bba547f7.png)

ワークスペースの視認性を上げるために以下の設定をします。

- グリッド線を非表示にする
- フローの説明、コンポーネントの説明のデフォルト表示を変更する

「ツールメニュー→ツール→環境設定」を選択します。
環境設定画面の「表示/編集→共通→グリッドを表示する」のチェックボックスにあるチェックを外します。
また、環境設定画面の「表示/編集→説明の初期設定」でお好みのフォント、背景色を設定します。

![settingWindow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2370877/36332ec8-9040-f2d6-cc39-2e85b11937bb.png)

### 最後に
ASTERIA Warpのフローデザイナーでは他にもいろいろな設定方法があるようなので少しずつ調節していきたいですね。