OmniAICreator/Qiita-1.07M huggingface dataset:
ReferenceError: exports is not defined の解決メモ

## 概要

（フロントエンドではない）Typescriptをローカルで触りたく...
Hello Worldができて次にfetchを使いたかっただけなのに、異常にハマってしまったためメモ。

初めて投稿するため、もし問題などあればご指摘いただけると幸いです。

## 環境

Mac OS Monterey 12.2.1
tsc（typescript） v4.3.4

## 出たエラー（実行時エラー）

```
$ node dist/index.js
file:///Users/myuser/~~~~~/dist/index.js:2
Object.defineProperty(exports, "__esModule", { value: true });
                      ^

ReferenceError: exports is not defined
```

## 解決方法

tsconfig.json から `"module":"commonjs",`を削除
のみ。

参考：[teratail > typescriptを使用して、Import exportしたいです。](https://teratail.com/questions/129706)

どうしてそれでいいのか、`"module":"commonjs",`が必要な場合はどうしたらいいのか...は、まだ分かりません。
いつか理解できる時が来たら追記したいと思っています。

## 実行したかったプログラム、tsconfig.json

- src/index.ts

```
import fetch from "node-fetch";

const hello: string = 'Hello, world!'
console.log(hello)

async function getData(url = '') {
    const response = await fetch(url, {
        method: 'GET', // *GET, POST, PUT, DELETE, etc.
        headers: {
　　　　　　　　　　　　　　　　（〜省略〜）
        },
    })
    return response.json(); // JSON のレスポンスをネイティブの JavaScript オブジェクトに解釈
}

// JSONの取得
getData('https://（〜あるAPIを呼び出したかった〜）')
  .then(data => {
    console.log(data); // `data.json()` の呼び出しで解釈された JSON データ
}); 
```

プログラムの参考というか引用元：[mdn web docs > Fetch の使用#リクエストオプションの適用](https://developer.mozilla.org/ja/docs/Web/API/Fetch_API/Using_Fetch#%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E9%81%A9%E7%94%A8)

- tsconfig.json

```
{
  "compilerOptions": {
    "target": "es2020",
    "module": "commonjs", // ★★★ ここを消したら動いた ★★★
    "lib": ["es2020"],
    "sourceMap": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "moduleResolution": "node",
    "baseUrl": "src",
    "esModuleInterop": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["dist", "node_modules"],
  "compileOnSave": false
}
```

tsconfigの参考というか引用元：[サバイバルTypeScript > tsconfig.jsonを設定する](https://typescriptbook.jp/reference/tsconfig/tsconfig.json-settings#%E3%83%90%E3%83%83%E3%82%AF%E3%82%A8%E3%83%B3%E3%83%89%E3%81%AE%E5%A0%B4%E5%90%88)
gulp-libsquoosh を使って webp/png/jpeg から複数のフォーマットに変換出力する

gulp で画像最適化するのに `gulp-imagemin`、`imagemin-pngquant`、`imagemin-mozjpeg`、`gulp-webp` を使ってたんですが、下記の理由から `Squoosh` に乗り換えることにしました。

- ひとつのツールにまとめたい
- 将来的に他のフォーマットに対応しやすそう
- webのツールを使って他のメンバーとパラメーター値を共有しやすい

3つ目はこちらのサイトです。

https://squoosh.app/

パラメーター名の大文字小文字とか微妙な違いはありますが、ソースコードから探し出せます。

https://github.com/GoogleChromeLabs/squoosh/blob/dev/libsquoosh/src/codecs.ts#L284


# 複数のフォーマットに出力したい

webp がほぼ全てのブラウザでサポートされるようになり、png + webp という感じに二種類用意することが増えてきました。

今回紹介する `gulp-libsquoosh` を使うと複数フォーマットの出力が簡単にできるのも大きなポイントです。

下記のサイトを参考にさせていただきました。

https://publishing-project.rivendellweb.net/using-gulp-libsquoosh-to-replace-imagemin/


# gulpfile.js

```js:gulpfile.js
const path = require('path');
const gulp = require('gulp');
const squoosh = require('gulp-libsquoosh');

gulp.task('image', () => {
  return gulp
  .src('src/image/*.{png,jpg,avif}')
  .pipe(
    squoosh((args) => {
      // 拡張子を抽出
      const extname = path.extname(args.path);

      // png、jpg 以外（ここでは avif）用のデフォルト設定
      let options = {
        encodeOptions: squoosh.DefaultEncodeOptions[extname],
      };

      // png形式は png、webp の両方を出力する
      if (extname === '.png') {
        options = {
          encodeOptions: {
            oxipng: {
              quality: 80,
            },
            webp: {
              // ロスレス指定
              // 画像によっては lossless:false して quality 指定のほうが良いかも
              lossless: true,
            },
          },
        };
      }
      // jpeg形式は jpg、webp の両方を出力する
      if (extname === '.jpg') {
        options = {
          encodeOptions: {
            mozjpeg: {
              quality: 90,
            },
            webp: {
              quality: 80,
            },
          },
        };
      }
      // それ以外はデフォルト設定のまま
      return options;
    }),
  )
  .pipe(gulp.dest('src/image/optimize'));
});

```
【TypeScript】スプレッド構文を用いた配列のRESTパラメーターを関数の引数に渡す方法


```tsx
const arr1:number[] = [1,2];
const summaryFunc = (num1:number, num2:number) => num1 + num2;
summaryFunc(...arrr1);//エラー！
```

### A spread argument must either have a tuple type or be passed to a rest parameter.ts(2556)

> スプレッド引数は、タプル型を持つか、RESTパラメーターに渡される必要があります
> 

[こちら](https://cumsum.wordpress.com/2021/08/28/typescript-a-spread-argument-must-either-have-a-tuple-type-or-be-passed-to-a-rest-parameter/)の記事が超わかりやすかったので、参考にさせていただきました(というかほぼほぼ日訳です)

# エラーの原因

1. 呼び出し元の関数の引数の型が`number`で固定されているから
2. 関数の引数がRESTパラメーターを許容しないから。

# 解決策

### 1. 配列の中身の型を明示してあげる(tupleとして宣言する)

```tsx
const arr1:[number, number] = [1,2];
const summaryFunc = (num1:number, num2:number) => num1 + num2;
summaryFunc(...arr1);//3
```

### 2. 配列を読み取り専用にしてあげる

```tsx
const arr1= [1,2] as const;
const summaryFunc = (num1,num2) => num1 + num2;
summaryFunc(...arr1);//3
```

readonlyにしているので、元の配列を追加したりすることはできなくなります。

```tsx
arr1.push(3);//Property 'push' does not exist on type 'readonly [1, 2]'.ts(2339)
```

### 3. 関数にRESTパラメーターを受け取れるようにする

```tsx
const arr1 = [1,2];
const summaryFunc =(...nums:number[]) => nums[0] + nums[1];
summaryFunc(...arr1);//3
```

これだったら配列の変更も効きますね。
ただし、関数の引数は`number[]`のみ受け付けるようになるため、`number`型を扱いたい場合は条件分岐させてあげないといけなさそうです。ただ、オプショナルパラメータでnull許容しているので実務ではあまり推奨されないんでしょうか・・・
この点、良い方法をお持ちでしたらぜひご教授お願いします！！
```typescript
const summaryFunc =( num1?:number, num2?:number, ...nums:number[]) => {
   if (num1 && num2){
     return num1 + num2;
   }else {
     const copiedNums = [ ...nums];
     return copiedNums[0] + copiedNums[1];
   }
}

const arr1 = [1,2]
summaryFunc(...arr1);//3
```

### ちなみに：JSだとどうなるか

```jsx
const arr1 = [1,2]
const summaryFunc = (num1,num2) => num1 + num2;
summaryFunc(...arr1);//3
```

普通にいけます。。。



TypeScriptには入門したばかりですが、今後も学習を続けていきます。


本投稿で紹介した内容よりも、もっと良い方法、ご指摘あれば、ぜひぜひコメントお願いいたします。

# 参考
https://cumsum.wordpress.com/2021/08/28/typescript-a-spread-argument-must-either-have-a-tuple-type-or-be-passed-to-a-rest-parameter/
vistaでphotoshop その10

# 概要

vistaでphotoshopやってみる。
キャンバス作って、jpg読んで、範囲指定で赤、書いて、pngで出力やってみる。

# 写真

![test9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/0dc1c2ba-3f71-9568-d331-cc4c698dbeff.png)

# サンプルコード

```
preferences.rulerUnits = Units.PIXELS;
var docObj = app.documents.add(640, 480);
var fileObj = new File("/Users/ore/eki.jpg");
open(fileObj);
activeDocument.selection.selectAll();
activeDocument.activeLayer.copy();
activeDocument.close(SaveOptions.DONOTSAVECHANGES);
docObj.paste();

var myColor = new SolidColor();
myColor.rgb.red = myColor.rgb.green = myColor.rgb.blue = 0;
myColor.rgb.red = 255;
var x = 100;
var y = 100;
var selReg = [[x, y], [x + 100, y], [x + 100, y + 100], [x, y + 100], [x, y]];
activeDocument.selection.select(selReg);
activeDocument.selection.fill(myColor, ColorBlendMode.NORMAL, 100, false);


var pngOpt = new ExportOptionsSaveForWeb();
pngOpt.format = SaveDocumentType.PNG;
pngOpt.optimized = true;
pngOpt.interlaced = false;
pngOpt.PNG8 = false;
var filePath = new File("/Users/ore/test9.png");
activeDocument.exportDocument(filePath, ExportType.SAVEFORWEB, pngOpt);
alert("ok");



```

以上。
Ubuntu18.04でWifiがunmanagedになった

Ethernetの設定をしている際にWifiを検知できなくなったため，そのときの解決方法を書きます．

余談ですが，その他の方法（ISOをCDROMにMountしてAdditional driverを入れる等）は全てうまく行きませんでした．
参考にしたのは「[Unmanaged network icon - Network management disabled](https://askubuntu.com/questions/2901/unmanaged-network-icon-network-manangement-disabled)」です．

```shell
$ sudo emacs /etc/NetworkManager/nm-system-settings.conf
# managed=falseをmanaged=trueに変更する

# 編集終了後にRebootする
$ reboot
```
[Kotlin]エラー:Type 'State<List<User>?>' has no method 'getValue(Nothing?, KProperty<*>)' and thus it cannot serve as a delegate

# 本文
KotlinのJetpackComposeで
```kotlin
var openDialog by remember { mutableStateOf(false) }
```
以下のエラーが表示された時は
![スクリーンショット 2022-03-02 16.25.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/966189e4-a121-a18a-2839-839358c38db2.png)
エラーメッセージの通り、getValueが定義されていないのでimportすれば解決します。一緒にsetValueもやっておいたほうが良さそうです。
![スクリーンショット 2022-03-02 16.25.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/e7ca71b3-a5c1-ab21-a154-3d5bad74adb1.png)

# 補足
理由はわかりませんがAndroidStudioが自動で勧めてはくれないようです。

[参考にしたstack overflow](https://stackoverflow.com/questions/63875411/type-statelistuser-has-no-method-getvaluenothing-kproperty-and-t)
未経験からインフラエンジニアを目指して①

## はじめに
ずっと憧れていたにも関わらず、勇気が出ずタイミングとチャンスを伺い続ける日々でしたが
この度、自分を奮い立たせてチャレンジすべく、一歩を踏み出した次第です。

先人の方々と肩を並べる事が出来た時、ここを見返し「こんな時もあった」と感慨に耽ったり
「(書き始めた頃と比べて)今はここまで成長できたぞ」と自信に繋げられるよう、僭越ながら四苦八苦の足跡を記していきたいと思います。
## 取り組み内容(当面の目標)
- ネットワークについての知識を会得し、理解を深める
- 頭で覚えただけでなく、きちんと専門用語を用いて説明出来るようになる
- 資格取得(CCNA)する

**<font color="Red">資格取得はスタートライン！実際の作業で滞りなく行えるようになる！！</font>**
## 今回行った学習
**1. ネットワークの基礎知識**
LANとWAN、インターネットの違いやLAN通信の種類、2進数と16進数、OSI参照モデルの概要を学習しました。
「用語は知っているけど、正しく説明してと言われると出来ない」部分が多かったですが
ふわっと覚えていた知識を定着させていく作業なので、非常に有意義で楽しいです。
・・・が、OSI参照モデルの概要は、お恥ずかしながら「？」が頭に飛び交ってました。。。
ですが、こんなすぐ挫ける訳にはいかないので、一つ一つネット検索を駆使しながら
「あぁこういう事を言っていたのか」とどうにか頭に理解する事が出来ました。

**2. 物理層とデータリンク層**
物理層は「機械とそれをつなぐケーブルの事」というのは文字通りなので
「ここはわかるぞ！！」と自信満々でしたが、学習を進めると自分の甘さをすぐに反省。
ケーブルや端子の種類、各名称も「用語は知ってはいるけど説明は･･･」な点が次々出てきて
ここでもネット検索を駆使しあちこち見て、また調べてとやって「なるほど！！」とようやく理解出来ました。

データリンク層もこれまで同様に用語は知っているけれども、という事柄が多かったです。
が、これまでの勤務先でも｢スイッチイングハブを増設(or交換)しますね｣であったり
｢デュプレックスの設定が｣と情報システム担当が話しており、その時は｢？｣な状態でしたが、今回の学習で理解が出来始めた事で｢あの時話していたのはこれか！｣と少し理解できた事に
思わず飛び上がりそうな程喜んでしまいました。
・・・喜んでいる場合ではないです、もっと学習しないとダメです、頑張ります。

**3. ネットワーク層**
今まで行ってきた学習項目ではどうにか手応えが少しあるかなと、かなり小さくはあるものの自信の光があったのですが、この項目は調べても｢？｣、わからないから更に調べてみても｢？｣な状態で、どうにか理解に至るまで時間が掛かりました。

もちろん、IPアドレスについては｢ネットワーク上の住所のようなもの｣であったり
｢なぜ192.168・・・なのか｣というのもIPアドレスは32ビットで、その2進法を8ビットごとにコロンで分割、それを10進法にしてあるんだよというのも、どこかで得た情報として既に知っている内容でしたが、私が理解に相当な時間を要したのは｢サブネット関連｣の所です。

色々調べて知恵熱が出そうなくらい考えた現時点では｢ネットワーク部とホスト部の境目をずらして一つだったネットワークを分割させる為の仕組み｣という事は、どうにか理解出来ました。
ただし｢理解したつもり｣な不安が拭えてないので、まだまだ反復学習が必要です。
(他の項目も完璧じゃないので、当然反復しないとです)

DHCPやNAT、NAPTについては意外にもすんなり理解出来ました。自分でも驚いています。
よくよく考えてみれば、カスタマーサポート担当時代に｢DHCPの設定自動ですか？｣であったり｢pingで疎通確認しましょう｣と案内していた事もあり、その関連で覚えていたようです。

**4. ルーティングについて**
ここは現在学習途中です。
ルーティングとは何か、RIPとOSPFはどんな内容、というのをあちこち検索しつつ覚えている所です。
<br>
**明日以降も進捗報告していけたらと思います。**
【GA4】WEB/アプリで同一プロジェクトのGAを使用する場合の懸念点

# 0. 概要

運営サービスのアクセス解析にはGoogle Analytics(以下GA)を使うのが一般的かと思いますが、GAは出来ることが多いがゆえに、使いこなすのにある程度の学習が必要だったり、自身のサービスに固有のユースケースにどう対応すれば良いのか分からず困る場合が多々あるかと思います。

同一サービスをWEBとネイティブアプリの両プラットフォームで運営していてGAを使う場合、各々のプラットフォームのアクセス解析をしたいという場合もあれば、両プラットフォームを合算した値を解析したいという場合もあると思います。後者の要件を実現するにはWEBとネイティブアプリで同一プロジェクトのGAを使用する必要がありますが（GAのデータをBigQueryにエクスポートして独自に解析を行う場合は別ですが…）、その場合前者の要件も満たすことが出来るのか、また他に気づけていない懸念はないか…ということが分からず困ったので、その際に行った調査の結果をこちらの記事でまとめたいと思います。

# 1. 結論

- 「各々のプラットフォームのアクセス解析をしたい」
- 「両プラットフォームを合算した値を解析したい」

上記の要件を両方満たすことは可能でした。

ディメンションの「プラットフォーム」という値で、「WEB/Android/iOS」を選択することが出来るようになっており、各々のプラットフォームでの値、合算値を各々閲覧できるようになっています。

![スクリーンショット 2022-03-02 16.01.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264889/3664af9b-fc11-3003-271c-54125f71b031.png)

![スクリーンショット 2022-03-02 16.01.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264889/3956184c-b929-d279-d512-21f70c6fc1ec.png)

# 2. 懸念点

上記で「可能」と書きましたが懸念点はあります。

GA4のカスタムディメンションやコンバージョン等には設定数に上限が設けられているので、例えばアプリ側で計測したいカスタムディメンション、ウェブ側で計測したいカスタムディメンションがそれぞれ数十個ずつあるような場合には、GA4でレポーティング可能な上限数に達してしまう可能性があります。制限値については[こちら]([https://support.google.com/analytics/answer/11202874?hl=ja](https://support.google.com/analytics/answer/11202874?hl=ja))に詳細の記載があります。360化することで上限を一定緩和することは可能なのですが、それ以上の緩和は例えGoogle社にお願いをしたとしても緩和不可になっているので要注意です。
ちなみにですが、カスタムディメンションは25件まで、コンバージョンは30個までという制限になっています。

こちらの制限を許容できない場合は、WEBとネイティブアプリでプロジェクトを分け、合算値を見たい場合はBigQueryにエクスポートして集計するといった流れになるかと思います。
ダミーデータを作るときに使うGem "Faker"は、東方Projectにも対応している

クスっとしたのでシェア
ドラゴンボールとかワンピースがあるのはわかるけど……

https://github.com/faker-ruby/faker/blob/master/doc/games/touhou.md

```ruby
# Random Touhou game
Faker::Games::Touhou.game #=> "Mountain of Faith"

# Random Touhou character
Faker::Games::Touhou.character #=> "Sanae Kochiya"

# Random Touhou location
Faker::Games::Touhou.location #=> "Moriya Shrine"

# Random Touhou item
Faker::Games::Touhou.spell_card #=> 'Esoterica "Gray Thaumaturgy"'

# Random Touhou song
Faker::Games::Touhou.song #=> "Faith Is for the Transient People"
```

これでテスト用データを東方キャラに統一することも可能！
JavaScriptの学習

# 今日もJavaの学習...かと思ったら
入社2日目、初日に比べて少し気楽になり今日もJavaの学習をする...のかと思いきや
何とJavaScriptを用いた案件のチャンスが舞い降りました、その為Javaではなくほぼ手付かずだったJavaScriptの学習を急遽始める事に。
そんな訳で学習内容としましては

1 午前中はJavaScriptの基礎的な構文の学習、とは言ってもJavaと類似してる部分も多数あったのでサクサク進む。
内容として前日同様演算子やfor文if文等。

2 午後からは主にJavaScriptに関する調べもの、DOM操作とは?HTMLとは?CSSとは?簡単に纏めたつもりが予想以上に没頭してしまい、無駄に掘り下げた感が出ましたがJavaScriptに関する知識が深まったのと職場の上司のサポートもあり有意義な学習になったと思いました。
明日から更に調べものと学習量が増えるかと思いますが一つ一つ確実に前進したいと思います。
いよいよ入社

# 入社初日の研修
緊張と不安に押しつぶされそうになりながらも初日の研修が始まりました...。
これから自分はやっていけるのだろうか...それともついていけなくて諦めるのだろうか...。
そんな思いを胸に終えた初日の肝心の学習内容は

1 午前中はJavaの基礎の演算子やif文、for文と言ったJavaどころかプログラムの基礎的な部分を改めて復習しましたが自分の中ではどうも苦手意識のあるfor文if文を遂に克服出来た実感を得られたのが一番の収穫でした。

2 午後からはJavaSilverの資格取得の学習、JavaSilverSE11という書籍を30ページ程を読み進めて思ったのが自分の中では身についたと思っても言語化して落とし込む事が出来ていないのが丸わかりでした...。
基礎的なことですらもまだまだ身につくのは先かもしれません...。

こんな感じで1日を終えました、明日からはもっと上手くやれたらなぁ...と思い学習に励みたいと思います。
40 代おっさんPythonでExcel操作をしてみる

## 本記事ついて

本記事は プログラミング初学者の私が学習していく中でわからない単語や概要をなるべくわかりやすい様にまとめたものです。
もし誤りなどありましたらコメントにてお知らせいただけるとありがたいです。

## 参考資料

<https://www.udemy.com/course/python-kaizen/learn/lecture/26849736#overview>

## 環境

以前はCloud9を使用していましたが、今回はExcelのため変えることにしました
Windows 10
Jupyter Notebook
そのため構文に少し違いがあります。
気を付けてください

## Excel操作

### Excel操作するライブラリをインストール

```python
!pip install openpyxl
```

普通はPandas使用するみたいですが、書式が固定されるため、今回はこちらを使用します。

### Excelファイルを読み込む

```python
import openpyxl
wb = openpyxl.load_workbook("出社在宅集計表_人事部.xlsx")
```

特にエラーが出ていなければ大丈夫です。

補足
openpyxl.load_workbook("~", data_only=True)と第二引数を追加すると、Excel内で関数が使われている場合にも、その計算結果だけを読み込むことができる。

#### Excelファイルのシート情報を読み込む

```python
ws = wb["4月"]
```

＊全角４にするなどするとエラーが出るので注意

#### セルの値を取ってくる

```python
ws.cell(row=2, column=2).value
```

cell（セル）の
row（行）
column（列を指定）

#### セルの値を書き込む

```python
ws.cell(row=5, column=5).value=1000
```

こちらをしても元のExcelファイルには影響していない（jupyter上にあるファイルを操作しただけ）

```python
wb.save("test.xlsx")
```

test.xlsxにしたのは元の出社在宅集計表_人事部.xlsx上書きをしないため
上書きを試してみましたが、注意文も出ずに変わりました。元の文章に戻す必要が出た場合はやり方があるかもしれませんが注意

拡張子はxlsxでしたがxlsmの場合もあり、xlsmはマクロ使用しているものになるみたいです。
サイトシール ってなに？

## 勉強前イメージ

SSLのwebページにつけるバナー的なやつだと思ってるけど、
そもそもつけて何の意味あるのかな

## 調査

### サイトシール とは

信用できる認証機関の認証を受けている証明となるもので、
「このサイトは本当に安全なの？」と確認したい時に使用されます。
また、サイトシールをクリックすることでサイトのプロフィール(コモンネーム等)が見れ、安全性を確認することが出来ます。

会社によって、呼び方は違うようですが
総称してサイトシールと呼ばれることが多いようです

## 勉強後イメージ

SSLの暗号化通信してるよ！安全だよ！ってことを言いたい画像ってことかな。
あと動的に作ってるところも有るみたい。

## 参考

- [サイトシールについて](https://jp.globalsign.com/ssl/guide/siteseal.html)
- [サイトシールとは](https://valuessl.net/support/help/siteseal.php)
github のssh のキー設定

# なんでメモりたいのか
- github のssh設定していたら、何度作り直しても通らなかった！
- キーの作り方は公式見たほうがいいので[こちら](https://docs.github.com/ja/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent)


# なんで通らなかったのか
ファイル名を変更していたから！！

# 設定

キー作成

```
ssh-keygen -t ed25519 -C "your_email@example.com"
```

`~/.ssh/config` のファイルを作成し、以下を追加。
ファイル名は、自分のファイル名に変更する。

```~/.ssh/config
Host github github.com
  HostName github.com
  IdentityFile ~/.ssh/id_github
  User git
```

# 接続確認

```
ssh -T git@github.com
```

「Hi snowdog! You've successfully authenticated, but GitHub does not provide shell access.」って言われたらOK

# 終わり
設定終わってからこれに気付いたので、メモしとくよ・・
Open VPN ConnectアプリからDNSエラーでAmazon VPNに繋がらない

iOS / Android 版の [Open VPN Connect](https://openvpn.net/client/) アプリを使って Amazon Client VPN に接続しようとしたのですが

```
Transport Error: DNS resolve error on 'cvpn-endpoint-0102bc4c2eEXAMPLE.clientvpn.us-west-2.amazonaws.com' 
```

ってな具合でエラーが出て繋がりません。iOS / Android どっちも。なぜ？

# 原因

[Amazonの公式ヘルプ](https://docs.aws.amazon.com/vpn/latest/clientvpn-admin/troubleshooting.html#resolve-host-name) によると、VPN構成ファイルの中に remote-random-hostname というプロパティがあって、これを解釈できないVPNアプリだと接続できないそうです。

```client.ovpn
client
dev tun
proto udp
remote cvpn-endpoint-0102bc4c2eEXAMPLE.clientvpn.us-west-2.amazonaws.com
remote-random-hostname # ← ココ
...
```

# 解決法

remote-random-hostname というのは、DNSキャッシュ回避目的で、接続先ホストの先頭にランダムで文字列を付けるというオプションなので、解決法としては、remote-random-hostname の行を消して、remote の接続先ホスト名の頭に自分でなんかランダム文字列を付けてやれば良いです。

- これを cvpn-endpoint-0102bc4c2eEXAMPLE.clientvpn.us-west-2.amazonaws.com
- こうする `asdfa`.cvpn-endpoint-0102bc4c2eEXAMPLE.clientvpn.us-west-2.amazonaws.com

`asdfa` の部分がランダムな文字列ですね。

このように変更したVPN構成ファイルを改めて読み込むことで、 Open VPN アプリから無事接続できるようになりました。

もちろんDNSキャッシュ回避の仕組みは機能しなくなるので、名前解決がうまく行かなくなったら暫く待つか、またランダムホスト名を変えた　ovpn ファイルを作れば OK と思います。

# おわりに

Open VPNアプリのトラブルシューティングが証明書周りの話が主体で、DNS名前解決周りの話がググってもなかなか見つからなかったので書きました。

記事をここまで書いた後で、改めてググったら大変良いブログ記事が[ありました](https://dev.classmethod.jp/articles/aws-client-vpn-with-android/)。
Gitのコミット数取得

たまにメンバーがアウトプット出してるか上長に提出を求められるので備忘。

調査したいブランチに切り替えた後、.gitファイルの配置されてるディレクトリに移動してから以下を実行（日付は取得したい範囲を指定する）
>git shortlog -ns --since="2021-10-01" --until="2022-01-18"1-18" ---all
AWS認定資格をまとめてみた

## AWS認定試験一覧をまとめてみました。
(参考：https://aws.amazon.com/jp/certification/exams/?nc2=sb_ce_exm)

はじめに私自身もAWS認定資格を全て取得しています。
以下を参考に是非、AWS認定の受験を検討してはいかがでしょうか。
![全資格.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1493529/1fc27d37-bd10-ee92-1522-6a35d894788a.png)

## AWS試験一覧

| 試験名 | 受験コード | 受験料 | 難易度 |
|:-:|:-:|:-:|:-:|
| AWS 認定 クラウドプラクティショナー | CLF-C01  | 11,000  |低  |
| AWS 認定 ソリューションアーキテクト - アソシエイト  | SAA-C02  | 15,000  |中  |
| AWS 認定 SysOps アドミニストレーター – アソシエイト  | SOA-C01  | 15,000  |中  |
| AWS 認定 デベロッパー – アソシエイト  | DVA-C01  | 15,000  |中  |
| AWS 認定 ソリューションアーキテクト － プロフェッショナル  | SAP-C01  | 30,000  |高 |
| AWS 認定 DevOps エンジニア - プロフェッショナル  | DOP-C01  | 30,000  |高 |
| AWS 認定 高度なネットワーキング – 専門知識  | ANS-C00  | 30,000  |高 |
| AWS 認定 データアナリティクス – 専門知識  | DAS-C01  | 30,000  |高 |
| AWS 認定 セキュリティ – 専門知識  | SCS-C01  | 30,000  |高 |
| AWS 認定 機械学習 – 専門知識  | MLS-C01  | 30,000  |高 |
| AWS 認定 データベース – 専門知識  | DBS-C01  | 30,000  |高 |

AWS 認定 データベース – 専門知識は2021年に廃止されています。
AWS試験は定期的にUpdateされており、廃止や新規ででてきますが、現時点では以上のような資格があります。（全11資格）

## AWS資格のメリット

* 社内にアピールできる（外部からも認められる）
* 昇進、昇給のチャンスになる
* 最新の技術を学ぶことができる

## AWS資格のデメリット

* 受験料が高い（落ちた時の負担が大きい）

AWS試験は今後、広く普及していくと思われます。
IT技術者の一般的な資格といえば、情報処理試験ですが、AWS、Azure、Google Cloudといったクラウドの知識は今後は必要になってきます。

周りがまだ学習していない時に先を越して学習していきましょう。
Python/RubyのGILはC-Extension実行中は遷移しない

## Python

https://github.com/cielavenir/pybind11_playground/blob/master/sleeptest.py

```
sleep start
hello # main-thread's hello can be executed during time.sleep(3)
sleep end
sleep start
sleep end
hello # pybind11_playground.toyclass().sleep(3) blocks executing main-thread's hello
```

## Ruby

https://github.com/cielavenir/rice_playground/blob/master/sleeptest.rb

```
sleep start
hello # main-thread's hello can be executed during sleep(3)
hello
hello
hello
hello
sleep end
sleep start
hello # took 3 secs to show the first hello; RicePlayground::ToyClass.new.sleep(3) blocks execution
sleep end
hello
hello
hello
hello
```

## 結論

表題のとおりです。これが意味するところは、 **Python/Ruby側にexportされていないC-Ext内だけで完結しているコードに関しては、競合状態は考慮する必要がないということです。**

(たとえばvectorを0からsize()-1まで走査する場合にsizeが変わる可能性があるとか、そういう話)

C-Extはまだまだ難しいなぁ^^;;;
【PowerCMS】カンマ区切りに入力した記事をループで出力

## はじめに
**PowerCMS**
記事IDをカンマ区切りで入力し、その記事を一覧に出力する方法。

## 入力フィールド
出力させたい記事のIDをカンマ区切りで入力。
![qiita_powercms_img.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1104075/06134ee0-73fc-30a8-a217-fd71992e0bca.png)
**記事IDとは？**
記事IDは6ケタの数字から成り、URLから確認することができます。
（※ちなみにブログIDは4ケタの数字）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1104075/3fa70bb5-df8e-274a-4811-336adab67a63.png)
上の添付画像だと、記事IDは「155975」になります。


## コード
入力されたIDを持つ記事を一覧に表示させます。
```
<ul class="article-list"> 

<MTIfExtFieldType type="text" label="記事ID">
　<$MTExtFieldText label="記事ID" setvar="article_ids"$>
</MTIfExtFieldType> 

<mt:splitvars text="$article_ids"> 
　<MTEntries id="$value"> 
    <li class="article-item"> 
      <a href="<$MTEntryPermalink$>"> 
      　<p class="title"><$MTEntryTitle$></p>
      </a> 
    </li> 
　</MTEntries> 
</mt:splitvars>

</ul> 
```

## タグの説明
```
<MTIfExtFieldType type="text" label="記事ID">
　<$MTExtFieldText label="記事ID" setvar="article_ids"$>
</MTIfExtFieldType> 
```
入力欄「記事ID」に入力された値を、変数「artcle_ids」に代入する。


```
<mt:splitvars text="$article_ids"> 
```
**MTSplitVars**：text モディファイアで指定した文字列（記事ID）を、delimiter モディファイアで指定した文字列（:（コロン）など）で分割し、変数 valueにセットしてループ出力を行う。
ただしdelimiter モディファイアの初期値はカンマ区切りなので、今回は指定しない。
（入力フィールドでカンマ区切りにIDを入植しているため）

textモディファイアには文字列ではなく変数を入れることができる。
今回は「$article_ids」としました。

```
<MTEntries id="$value"> 
```
splitvarsで分割された値（記事ID）が変数valueにセットされる。

**MTEntries**：ブログの記事の一覧のためのブロックタグ。
モディファイアを指定することで、記事の**並び替え**や**特定の記事**だけを表示させることが可能。

idモディファイアに記事IDを入力すると、該当記事が出力される。
今回はループされているため、「id」に155246、155965、155972、155973、155974が順番に入る。



## 注意点
```
<mt:splitvars text="$related_ids">
```
★ textモディファイアに変数を代入する場合、変数名の前に「$」をつける。
**★ 変数名にハイフン（-）は使用できないので注意！**
　OK：article_ids
　NG：artcle-ids

## 参考サイト
[MTSplitVars | PowerCMS](https://www.powercms.jp/products/document/template-tags/splitvars.html)
[MTEntries | PowerCMS](https://www.powercms.jp/products/document/template-tags/entries.html)
【Xcode】the working copy has conflicting, uncommitted changes エラー

Xcodeでブランチ切り替えようとしたら以下のエラーが出た。
しかし、git statusを叩くと問題なさそう。

ってのに遭遇した。どうやったら直ったかを参考までに書いとこうかなと！

![Screen Shot 2022-03-02 at 15.02.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426420/922ce64a-9a9c-1419-1ba7-77e10a463b5c.png)

![Screen Shot 2022-03-02 at 17.23.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426420/d7632967-51e4-5d04-d1f6-323f8e1b0b2d.png)

## やったこと

コマンドでgit checkout ~~~でブランチ切り替える

再度Xcodeで作業してみるとエラーでなくなった

以上！！

ちなみに、強制pullしたり、PC再起動したりしてもエラーは消えなかった
Vimium使ってchromeをvim化する

chromeをvimのように操作する拡張機能があるというので使ってみた

### インストール
**Vimnium**
https://chrome.google.com/webstore/detail/vimium/dbepggeogbaibhgnhhndojpepiihcmeb

これで拡張機能が使えるようになった。
ただこれだとちょっと使いにくいのでキーマップを設定する↓

### キーマップのカスタム
Vimniumが使える状態で「?」をクリック
![スクリーンショット 2022-03-02 17.03.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1477477/5ffddcf3-9a56-93d8-7737-1ac062dcc38d.png)
モーダルが表示されたら右上の「Options」を選択


![スクリーンショット 2022-03-02 17.05.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1477477/b4ec1b87-caff-edb4-1605-166332503373.png)

「Custom key mappings」のところに好きなキーマップを入力する
「Save Changes」をクリックしないと保存されないので注意！



僕は普段よく使う操作だけをマッピングしている

```
# Insert your preferred key mappings here.

# 一旦全てのマッピングを解除
unmapAll

# ヘルプを開く
map ? showHelp
# 左タブに移動
map gr previousTab
# 右タブに移動
map gt nextTab
# 一番下までスクロール
map G scrollToBottom
# 一番上までスクロール
map gg scrollToTop
# 下にスクロール
map j scrollDown
# 上にスクロール
map k scrollUp
# 左にスクロール
map h scrollLeft
# 右にスクロール
map l scrollRight
# 前のページに戻る
map H Go back in history
# 次ページに進む
map L Go forward in history

```
Hibernate3によるupdate時にStaleObjectStateExceptionが発生するようになった原因

# 事象
コードは何も変えていないのに
hibernate3 で insert してから update すると突然下記のエラーが発生するようになりました。
```
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)
```
環境は下記のいずれの組み合わせでも発生。
Java6, Java8
MySQL 5.5, MySQL 5.6, MySQL 5.7

そんな古い Version を使うなよ。という突っ込みはさておき原因を調べてみました。

# 原因
数年ぶりに MySQL Connector/J を最新に上げたことにより発生するようになっていました。

エラーになる流れとしては

1. hibernate3 で insert をする。
このとき、Java ではミリ秒を保持し、DB ではミリ秒は四捨五入される。

2. その後、同じ entity で update する。
Java ではミリ秒を保持しており、update 時にミリ秒も評価するので楽観ロックエラーになる。


どの version からエラーになるのか調べると
MySQL Connector/J 5.1.23 からエラーになるようです。
Release Notes を見てみました。

https://dev.mysql.com/doc/relnotes/connector-j/5.1/en/news-5-1-23.html

この変更が影響してそうな気がします
> The nativeSQL() method would always truncate fractional seconds rather than preserving the fractional part in the output string. Now Connector/J checks the server version: it preserves the fractional part for MySQL 5.6.4 and greater, and truncates the fractional part for older versions. (Bug #14748459, Bug #60598)

日本語訳
> nativeSQL() メソッドは、出力文字列の端数部分を保存するのではなく、常に端数秒を切り捨てていました。現在 Connector/J はサーバ バージョンをチェックし、MySQL 5.6.4 以降では端数部分を保存し、それ以前のバージョンでは端数部分を切り捨てます。

MySQL Connector/J 5.1.22 以前だと update 時にはミリ秒以下を評価の対象にしていなかったためエラーにならなかったと思われます。（nativeSQL()が何かはよくわかってません・・）

ただ、謎なのは動作環境によってエラーになったりならなかったりしていて、 MySQL やサーバの version や設定の違いが関係しているのかもしれませんが、時間と気力の制約上これ以上の深追いはやめておきます。。
Webの勉強はじめてみた その34 〜設計手順と認証のテスト〜

N予備校「プログラミング入門Webアプリ」を受講しています。
今回は第4章16,17節です。

## 設計手順

ユースケース

1. ユースケースの想定
2. サービス名とプロジェクト名
3. サービスの内容
4. 要件定義
5. 要件に上がった用語の定義。用語・変数などで利用する英単語や意味の定義
6. データモデリング。エンティティのリレーションを考える。
---
インターフェース

7. URL設計。ページの構成。
8. ページのURLを考える。メソッド(POSTやGET)とページの内容。
9. APIのURLを考える。メソッド、処理内容、利用方法(HTML,AJAX)。
---
モジュール

10. モジュールの設計。フレームワークを利用するか。
11. `router`モジュールを考える。`routes/`にどういうファイルが必要か。
12. データベースをどこでどう管理するか。  
  
:::note
出来上がったデータモデルで基本要件を満たすか、
要件漏れや根本的な仕組みに問題がないかをチェックする。
:::  

ある程度フワッとしててもいい？  

### ユースケース
実際にシステムがユーザーに利用されるやりとりのこと

### 機能要件
必要な機能、基本的な要件

### 非機能要件
機能に付随する性能、セキュリティに関する要件など

### MVC (Model, View, Control)
:::note
リクエストのルーティングを行う処理をコントロールする部分、
エンティティのモデリングや振る舞いと永続化などの処理をする部分、
表示内容の形式を定義する部分を分割する構造のこと
:::

## アカウント認証が必要なテスト
```
yarn add supertest@3.1.0 --dev
yarn add passport-stub@1.1.1 --dev
```

`supertest`
テスト内でExpressのサーバーを起動することなく`Router`の挙動をテストできる。

`passport-stub`
`passport`の認証が邪魔になるときに、その挙動をコントロールできる。

```javascript:test.js
const request = require('supertest');
const app = require('../app');
const passportStub = require('passport-stub');

describe('/login', () => {
  beforeAll(() => {
    passportStub.install(app);
    passportStub.login({username: 'testuser'});
  });
  afterAll(() => {
    passportStub.logout();
    passportStub.uninstall(app);
  });
  test('ログインのためのリンクが含まれる', () =>{
    return request(app)
      .get('/login')
      .expect('Content-Type', 'text/html; charset=utf-8')
      .expect(/<a href="\/auth\/github"/)      
      .expect(200);
  });  
  test('ログイン時はユーザー名が表示される', () =>{
    return request(app)
      .get('/login')
      .expect(/testuser/)
      .expect(200)
  });
});
```

`request(app).get('/login')`
`/login`への`GET`リクエストを作成する。

`beforeAll`
全ての処理の前に実行する。

`afterAll`
最後に実行する。

## まとめ
本格的にWebサービスを作っていってるんですが、なんとか理解しながら進めていってます。設計の手順は一通りではないと思いますが、自分で作っていく時に参考になるのかなと。
これさえあれば（私が）安心、Gitのコマンド覚書

# Git Pushまでの流れ 

ワークツリー　`git add`　
↓
ステージ　`git commit`
↓
リポジトリ　`git push`　

# master ブランチとは
根幹となる幹。ブランチが最終的に合流する主流。

# ブランチとは
主流から分岐する枝。
編集用。後で主流に合流させる。（`merge` or `rebase`)

# マージとは
主流と合流させること。変更点を取り込むこと。
競合することをコンフリクトという。

# コンフリクトとは
修正が競合しているので修正が必要な状態。
コンフリクト部分がコメントで示されるので削除するなどして対応する。
リモートリポジトリとローカルリポジトリで同一ファイルの変更履歴が異なっていると起こる。

# HEADとは
今自分がいるブランチのこと。ポインタ。

# git checkout -b （ブランチ名）
ブランチを作る。

# git checkout (ブランチ名）
ブランチを変更する。

# git log
ログを表示する。

# git log -p （ファイル名）
ファイルの変更差分を表示する。

# git rm （ファイル名）
ファイルを削除する。

# git rm --cashed （ファイル名）
ローカルリポジトリのファイルだけ削除する。
パスワードが載っているファイルを送りたくない場合などに使う。

# rebaseとは
mergeと似ている。ただし履歴が一本道になる。
mergeは分岐したまま。

# git reset HEAD(　)
ステージの変更を取り消す。
ファイル名、ディレクトリ、全てのそれぞれを指定できる。（全て：「.」）
```
git reset HEAD .
```

# git commit --ammend
直前のコミットを今のステージの状態で上書きする。
変更をやりなおす。
pushしたコミットはやり直してはいけない。
他の人の履歴と食い違ってエラーになる、らしい。

# git diff
`git add`する前に変更したファイルを確認する。
`ステージとワークツリーの変更分`を確認する。

# git diff --staged
`git add`した後に変更したファイルを確認する。
`ステージとローカルリポジトリの変更分`を確認する。

# git mv （旧ファイル）（新ファイル）
旧ファイルをrmして新ファイルをステージにaddする。
以下と同じ挙動。
```
mv （旧ファイル）（新ファイル）
git rm （旧ファイル）
git add (新ファイル）
```
複数のAWS認定アカウントを統合する


* * *
### こんな人にオススメの記事です
* 複数のAWS認定アカウントをマージしたい人
* 会社が変わってメールアドレスを変更したい人
* メールアドレスが単純に変更になった人
* * *

結論からいうとAWS認定アカウントを統合する方法は、AWSサポートから
リクエストを送る必要があります。
手順を以下に紹介します。

①. 下記URLからAWSの認定チームへ問い合わせを行います。
https://aws.amazon.com/jp/contact-us/aws-training/

個人情報を記載の上、
問い合わせの本文は英語にて問い合わせした方がよいです。
簡単な英語でよりので翻訳機能を使って送ってしまいましょう。
（私も他のサイトを参考に以下のように送りました。）
![認定アカウント.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1493529/50bfb1e0-baed-0645-69bc-9bb97ab7262d.png)

```
I want to migrate my AWS certificate.
Since I used to be an APN partner, I used to log in from the APN portal. The APN account is <APNのアカウント番号>. 
The login address is <旧アカウントのログインアドレス>.
```
→私の場合は6時間程で返信がきました。
 アメリカの方が担当しているのか返信は日本時間の夜中でした。

②. 確認依頼メールが届くので回答する

文面は人によって違いますが、以下のような返信が届きました。
アカウントをマージするけど、問題ない？問題なければマージします。
とのことなので、問題なしと回答しました。

AWSサポートからの回答
```
Thank you for providing your email addresses. To proceed with the merge we must ensure proper account validation.

Please review the information below and then respond with your confirmation. We'll proceed with the account merge after we receive your confirmation.

Account #1

- Login email: 旧アカウントのログインアドレス

- Training notification email: 旧アカウントのログインアドレス

- Certification notification email: 旧アカウントのログインアドレス

Account #2

- Login email: 新アカウントのログインアドレス

- Training notification email: 新アカウントのログインアドレス

- Certification notification email: 新アカウントのログインアドレス

I will be merging the above accounts into Account #2. Once I complete the merge, your account details will become:

```

それに対する返信
```
﻿Hello

Thank you for reply.

I checked your reply. This is No problem
Please proceed with the merge process.
```

3. マージされたのを待つ

返信後、数時間待つと「アカウントマージしたよ」との連絡がきました。
連絡後がきた後、実際に自分でログインしたマージできていれば、手続き完了です。

英語でやり取りするのが若干苦労しますが、片言の英語でもしっかり対応していくので
Google翻訳とかを使っていきましょう。

参考になれば幸いです。
rust trait

```rust
#![allow(unused)]
fn main() {
  #[derive(Copy, Clone)]
  struct Person {
    name: String,
    age: u8,
  }

  #[derive(Copy, Clone)]
  enum Direction {
    Up,
    Down,
    Left,
    Right,
  }
}
```

Person类型和Direction类型就都实现了Copy Trait和Clone Trait，具备了这两个Trait的功能：所有权转移时是可拷贝的、可克隆的。

```rust
trait Speaks {
    fn speak(&self);
    fn noise(&self) -> &str;
}

trait Animal {
    fn animal_type(&self) -> &str;
}

struct Dog {}

impl Animal for Dog {
    fn animal_type(&self) -> &str {
        "dog"
    }
}

impl Speaks for Dog {
    fn speak(&self) {
        println!("The dog said {}", self.noise());
    }

    fn noise(&self) -> &str {
        "woof"
    }
}

fn main() {
    let dog = Dog {};
    dog.speak();
}

```

---

ref:

https://rust-book.junmajinlong.com/ch11/02_more_about_trait.html

https://kaisery.github.io/trpl-zh-cn/ch10-02-traits.html

https://riptutorial.com/rust/example/22917/inheritance-with-traits
iOSショートカットを使ってシフト管理アプリ「シフトボード」の予定をGoogleカレンダーに自動で同期させる

<h1>概要</h1>
※この記事は、シフトなどの予定はシフトボードで管理していて、日常的な予定はGoogleカレンダーで管理している人向けの記事です。

<br><br>シフトボードとは、リクルートが提供するシフト管理に特化したアプリで、iOS版、Android版がありそれぞれで使うことができます。<br>Android版に関しては使ったことがないのでここでは触れません。
<br>シフトボードは、Googleカレンダーと連携出来ないですが、iOS標準カレンダーとは連携ができます。<br>なので、GoogleカレンダーのiCloudのシフトボードにチェックを入れて表示すれば、自分のiPhoneからのみシフトボードの予定をGoogleカレンダーから確認できます。
<br>しかし、これだとPC版Googleカレンダーやカレンダーを共有している他の人からはシフトボードの予定が確認できないので若干不便です。
<br>今回作成したiOSショートカットを使うことで、PC版Googleカレンダーやカレンダーを共有している他の人からでもシフトボードの予定を確認できるようになります。
<br>そうすることで面倒なシフトの追加、削除、編集はシフトボードで行い、予定の確認はGoogleカレンダーで、というような完全な使い分けが実現できます。


<h1>実際の動き</h1>
環境：iOS15.3.1<br>
端末：iPhone12 Pro

<br>埋め込み方が分からなかったので外部リンク<br><a href="https://imgur.com/ggRiJJa">https://imgur.com/ggRiJJa</a>

<br>オートメーションのバナーが少し気になるのと、Googleカレンダーに反映されるまで若干ラグがありますが、予定の追加処理はバックグラウンドでもちゃんと動いてくれるので許容範囲内かと思います。


<h1>処理の流れ</h1>
以下の処理をシフトボードが閉じられるたびに実行させることで常に最新のシフトボードの予定をGoogleカレンダーに同期させます。

<br>1. シフトボードからGoogleカレンダーに同期する予定の範囲は現在の日にちから30日間で設定。
<br>2. 前回のショートカット実行でGoogleカレンダーに追加された予定を全て削除する。
<br>3. シフトボードの予定を任意のGoogleアカウントでGoogleカレンダーに追加する。

![画像1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1893891/9b5d7bbd-3309-bf29-fddd-5ccbadd782fa.png)
<br>追加する予定のメモ欄に「シフトボードから追加」と入れておくことで、ショートカットで追加された予定であることを分かるようにしておきます。そうすることで2.の処理で元からGoogleカレンダーに入力されている予定が削除されないようにしています。
<br>イベントを追加の通知は現状「なし」が選択肢に存在しないので、通知しないという設定はできません。手作業でiOS標準カレンダーで予定を追加するときの通知には「なし」の選択肢が存在しているので、そのうちショートカットの方にも「なし」の選択肢が追加されるかもしれません。


<h1>前提</h1>
iOS標準カレンダーとGoogleカレンダーを連携する。
<br><a href="https://support.google.com/calendar/answer/99358?hl=ja&co=GENIE.Platform%3DiOS">https://support.google.com/calendar/answer/99358?hl=ja&co=GENIE.Platform%3DiOS</a>

<br>iOS標準カレンダーとシフトボードを連携する。
<a href="https://help.shiftboard.jp/s/article/000012358">https://help.shiftboard.jp/s/article/000012358</a>


<h1>設定</h1>
1. 下記のリンクからショートカットをダウンロードします。

https://www.icloud.com/shortcuts/e9567ef1faf7446abd9fe9fb9f89c8cf

<br>2. ダウンロードしたショートカットを開き、<a href="#処理の流れ">処理の流れ</a>にある画像のとおり「自分のGoogleアカウントを選択」の二箇所を自分のGoogleアカウントに変更します。
<br>3. ショートカットのオートメーションから「シフトボードが閉じられたとき」でオートメーションを作成して、「行う」はショートカット実行でダウンロードしたショートカットを設定します。
![画像4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1893891/a86b6db7-9314-e897-937e-e379c6f787cf.png)
<br>ここまで出来たらショートカットを実行させ、シフトボードの予定がGoogleカレンダーに同期されるようになっていることを確認します。

<h1>イベントの削除確認を出さないようにする設定</h1>
この設定を行うにはショートカットを実行して、イベントの削除確認を1回は出しておく必要があります。

<br><br>1. 設定>ショートカット>詳細の「確認なしに削除することを許可」をオンにします。
![画像2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1893891/e04f4b1a-a742-bd77-8f59-bf19bb292656.png)
<br>2. ショートカットを長押しで詳細を開き、プライバシーのカレンダーイベントを「確認なしで削除」に設定します。
![画像3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1893891/0ccf071e-dc97-fcc6-0715-49b9b985f2de.png)
<br>以上の設定でイベントの削除確認は出なくなります。


<h1>所感</h1>
シフトボードに限らず、iOS標準カレンダーと連携できるが、Googleカレンダーとは連携できない予定管理アプリをGoogleカレンダーと連携したい場合には便利なショートカットだと思います。

<br>参考文献：https://curiouslead.com/?p=672
【mocha】特定のテストを実行・スキップさせる方法

JavaScriptのテストフレームワーク**mocha**において、特定のテストを実行・スキップさせる方法をメモしておく。一部のテストのみを実行したい場合に利用できる。

# only():特定のテストだけを実行
``only()``を``describe``または``it``にチェーンさせることで、特定のテストだけを実行することができる。
【参考：[https://mochajs.org/#exclusive-tests](https://mochajs.org/#exclusive-tests)】

```javascript
// describeの場合
describe.only("test", () => {
    // テスト内容（この中のテストのみが実行される）
});

// itの場合
it.only("test", () => {
    // テスト内容（このテストのみが実行される）
});
```
このように``only()``で指定してテストを実行すると、``only()``で指定されたテストの結果だけが表示される。

# skip():特定のテストをスキップ
``skip()``を``only()``と同様に``describe``または``it``にチェーンさせることで、特定のテストだけをスキップすることができる。
【参考：[https://mochajs.org/#inclusive-tests](https://mochajs.org/#inclusive-tests)】

```javascript
// describeの場合
describe.skip("test", () => {
    // テスト内容（この中のテストがスキップされる）
});

// itの場合
it.skip("test", () => {
    // テスト内容（このテストのみがスキップされる）
});
```

このように``skip()``で特定のテストをスキップさせた場合の実行結果は、以下のようになる。
(test1～test3の中のtest1をスキップした場合)

```
test
    - test1
    ✔ test2
    ✔ test3

  2 passing (26ms)
  1 pending
```
スキップされたテスト数が``pending``(保留中)として表示される。
【MT7】特定のページだけ処理を適用させる

## はじめに
**MovableType**
特定のページにだけこの記述を入れたい！というときに使用。

## コード
```
<mt:setvarblock name="pageurl"><$mt:CanonicalURL$></mt:setvarblock> 

<mt:if name="pageurl" like="hogehoge.html"> 
   CVタグなどの記述
</mt:if>
```

## MTタグの説明
**setvarblock** : このブロックタグで囲んだ内容を値にした変数を設定します。
ここでは現在のページのURLを変数「pageurl」に設定しています。

**mt:CanonicalURL**：現在のぺージの URL を出力します。
「pageurl」が「hogehoge.html」の場合に適用させたい処理を記述しています。

## 参考サイト

[MTSetVarBlock | MovableType テンプレートタグリファレンス](https://www.movabletype.jp/documentation/appendices/tags/setvarblock.html)

[MTCanonicalURL | MovableType テンプレートタグリファレンス](https://www.movabletype.jp/documentation/appendices/tags/canonicalurl.html)
replaceメソッドのgオプションについて（JavaScript）

# replaceメソッド
先ほどpaizaをやっていたらreplaceメソッドでつまづいたので、記録として残しておきたい。

## そもそもreplaceってなんだっけ、、
→**任意の文字列を別の文字列に置き換えることができる**

```
let str = 'マンチェスターユナイテッド　　<　マンチェスターシティ';
str.replace('<', '>');
結果: マンチェスターユナイテッド　　>　マンチェスターシティ
```

## gオプションとは？
**置換したい文字列を指定した時、その文字が複数含まれている場合に、その全てを置換させることができる。**

```
let team = '私はマンチェスターシティが優勝すると思う、Clもマンチェスターシティが優勝するね';
team.replace('/マンチェスターシティ/g, 'ユナイテッド');
結果:　'私はユナイテッド　が優勝すると思う、Clもユナイテッド　が優勝するね'
```
## 最後に
たったのこれだけだが、記録として残しておくことの大事さを今になって知った。これからはたくさん残していきたい。

読んでくださってありがとうございました。
AtCoderで入茶出来たので現状を振り返る

初めまして、koroshoと申します。

2021/12よりAtCoderを始め、2022/2/5のABC238で無事入茶する事が出来たので、2022/3現在のAtCoderへの取り組み方などについて振り返っていこうと思います。
![2022y03m02d_111651029.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348205/53e97b1b-24da-4837-ccc4-2d640d4384b8.png)

# はじめに
### 自己紹介
25歳のエンジニア志望の無職です。
一応ITの専門を出ていますが、いわゆる強いエンジニアとは程遠い存在です。
普段は個人でプログラミング学習やWebフレームワークを触ったりして過ごしています。
触った言語は習熟度が高い順にJava、Python3、Rubyなど。

# バックグラウンド
* プログラミング自体は個人で2年以上経験あり
* 競技プログラミングはAtCoderが初めて
* PaizaスキルチェックだとJavaでAランク、PythonでBランクの問題が解ける程度
* 一応FE、APの資格は所持

# なぜ始めたか
転職活動で志望していた企業さんで社内でAtCoderをする文化があると耳にしたため。
そもそもAtCoderの事は昔友人から紹介されて知っていたのですが、その時はそれ程興味が無くいずれやろうと思ったままになっていました…
最初にレートについて色々調べた結果、最低限色が付いてないと何も保証出来ないということでまず茶コーダーを目指していました。

# 使用言語、環境等
言語はPython3(Pypy3)で参加しています。
当初選んだ理由は人気がある言語だから身につけたいとかそんな理由でした。

現在は以下のような長所・短所がある言語だと考えています。

長所：直感的に書ける所、便利な標準ライブラリが充実している所。
短所：動作自体がそこまで早くはないので競プロだと不利。D問題などでよく使われる平衡二分木（C++における`std::set`）が標準ライブラリに無い。

コーディング環境ですが、現在はコードテストページにベタ書きでコードを書いて提出しています。（明らかに非効率なのでおすすめしません）
この方法は不自由かつ事故が多いのでいずれVSCodeなどに移行する予定です。

# 取り組み方
まず最初に、決め事として参加できるコンテストには全て参加する方針を立てて取り組み始めました。

初参加のABCでは90分かけてA、B問題の2完という悔しい結果でした。
なので私の場合はA、B問題を安定して正解できるようにした後にアルゴリズムに取り組む事に決めました。
A、B問題を解く為に必要なのは場数だと思うので、過去問を解いて入出力や配列やfor文等に慣れていくのがいいと思います。
（過去問を解く際には[AtCoder Problems](https://kenkoooo.com/atcoder/#/table/)を使うのがおすすめです。）
また、同時進行でAtCoder ProblemsのTrainingのEasy問題を埋めていました。

A、B問題が安定した後は本格的にアルゴリズムの勉強を始め、C問題の過去問を解きながら[競プロ典型](https://atcoder.jp/contests/typical90/tasks)（～★3）などを解き始めたりしていました。
これ以降は所謂アルゴリズムを「知らないと解けない」問題が増えていたので、30分から1時間考えて解けなかった場合は解説を見てACするようにしていました。
「知らないので解けない」から「知ってて解けない」、その次は「知ってて解ける」へとシフトしていくのが狙いなので、解答例を丸コピはせず、最低限考えながら写経するのがいいと思います。

私の場合はC問題が安定してきたぐらいの頃に入茶することが出来ました。

現在はD問題の壁にぶち当たって、モチベーション維持も課題になってきたため、毎日過去問を解いたり、TrainingのMedium問題を数問解くなど長く続ける事を目的とした学習に切り替えています。
積極的なステップアップを図るのであればAtCoder Problemsを使ってリコメンド問題や難易度が自分のレートと同色から一つ上の色の問題を解くなどもいいかなと思います。

# レートへの意識
レートは他の方との比較材料ではありますが、自分と他人のレートを比較して落ち込むのはものすごく無意味です。

AtCoderには少ない参加回数で凄まじい速度でレートを上げる方が一定数存在しており、順位表を見ると特に顕著です。
そういった方は元々競プロ経験があったりする方が多数なので、それらを見て自分の成長速度に自信を無くすのはやめた方がいいです。自分なりに着実にステップアップしましょう。

# 各コンテストについて
### ABC(AtCoder Beginner Contest)
主戦場です。
このコンテストの問題を解き進められるようになる事が殆どのユーザーの目標だと思います。

### ARC(AtCoder Regular Contest)
ABCより発展的な難易度のコンテストです。
ABCと比較すると頻繁に配点が変わり、それに伴って難易度も激しく変化します。
また、必要な知識もABCとは違い数学的考察力がより重視されている印象です。

個人的に一定のスキルレベル（緑コーダー以上？）に達するまでARCにrated参加するのはおすすめしません。
A問題が解けるか解けないかによるperfの差が大きすぎる為です。
ギャンブル感覚で挑むのもありだと思いますが、私は実力をちゃんと身につけたいならunratedで落ち着いて参加するのがいいと考えています。

# 今後の目標
順当に緑コーダーに、できれば今年中に水コーダーまでたどり着ければと考えています。
ですが現在、D問題の壁にぶち当たった事によりモチベ管理という新たな問題にも直面しているので、とにかく長く続けていくことを念頭に精進したいと思います。

# 最後に
長文でしたが最後までお読み頂きありがとうございました。
私と同じような競プロ初心者の方の成長材料の一つにでも加えていただければ幸いです。
Nuxt.jsとRailsでゲストログイン機能を作る

## 概要
今回ポートフォリオを作成した際に実装したゲストログイン機能を紹介したいと思います。

## 実装した経緯
転職活動でポートフォリオを見てもらう際に、ゲストログイン機能があったほうがいいと考え実装しました。
ポートフォリオを見てもらう際に、ログインしないと各機能が使えない仕様では閲覧する採用者の方の負担が増えてしまいます。
その結果せっかく作成したポートフォリオを見てもらえないなんてことも起こる可能性があります。
なので　**ログインしなくても使用できるアプリーケーション設計**、もしくは**簡単にログインできる機能**を付ける必要があると思い実装しました。

## 環境
|/|バーション|
|:--:|:--:|
|ruby|3.0.3|
|rails|6.1.4|
|nuxt|2.15.8|
|vuetify|2.6.1|

## 前提
今回はフロントエンドをNuxt.js、バックエンドのAPIとしてRailsを使用したSPA開発を前提としています。

## ゲストログインの方式
ゲストログイン機能を実装する場合、下記の２種類の方法があります（初心者の私が思いつく限り）。
1. **あらかじめゲストユーザーを作成し、その情報でログイン**
→ この方法は簡単に実装できるが、複数のユーザーにログインさせるのは難しい。

2. **ゲストユーザーをその都度作成し、ログイン**
→ この方法だと都度ユーザーを作成するので、複数のユーザーにゲストログインさせることができる。

今回は2つ目の方式を採用します。

## Rails側の処理
Rails側は全部で３つのステップがあります。

### step 1 ゲストユーザー作成用のコントローラーを作成
下記コマンドを実行してコントローラーを作成します。

```
rails g controller guests
```
すると**app/controllers/guests_controller.rb**が生成されます。

### step 2 生成されたコントローラーにアクションを追加
コントローラーに`create`アクションを追加していきます。

```app/controllers/guests_controller.rb
class GuestsController < ApplicationController
  def create
    random_value = SecureRandom.hex(1) # ランダムな2文字の文字列を生成
    random_pass = SecureRandom.hex(4) # ランダムな8文字の文字列を生成
    user_params = {
      name: "guest_#{random_value}",
      email: "guest_#{random_value}@guest.com",
      password: "#{random_pass}",
      password_confirmation: "#{random_pass}"
    }
    user = User.create!(user_params)
    render json: { email: user.email, password: user.password } # フロント側でログインに必要な値だけ送る
  end
end
```
※ 今回2種類のランダムな文字列を生成していますが、バリデーションによって文字数は決めてください。

### step 3 ルーティングの設定

```app/config/routes.rb
Rails.application.routes.draw do
  resources :guests, only: [:create]
end
```

## Nuxt.js側の処理
### step 1 @nuxtjs/axiosの導入
下記コマンドでaxiosをインストールします。

```
yarn add @nuxtjs/axios
```
その後各コンポーネントファイルに設定するのが面倒なので一括して設定します。
_*nuxt.config.js*_

```nuxt.config.js
export default {
// 省略
  modules: ['@nuxtjs/axios']
// 省略
}
```
これでコンポーネントファイルでaxiosが使えるようになります。

### step 2 コンポーネントファイルでRails側へ通信させる
※ templateはゲストログインのためのリンクのみ記載します。form等は各自実装してください。

```pages/signin.vue
<template>
  <v-btn
    text
    plain
    class="text-decoration-underline"
    @click="guestSignIn"
  >
    ゲストとしてログイン
  </v-btn>
</template>

<script>
export default {
  methods: {
    async guestSignIn () {
      await this.$axios.post('/guests')
        .then((res) => {
          this.$auth.loginWith('local', { data: res.data }) // @nuxtjs/authを使用してログイン処理をしている
        })
    }
  }
}
</script>
```
上記の例ではログイン処理にauthモジュールを使用していますが、ログイン処理は各々自由で大丈夫です。

## まとめ
以上の手順でゲストを作成してログインすることができます。
しかし、一つ問題があります。
それは、データベースにゲストログインで作成されたユーザーデータがゲストログインごとに増えてしまいます。
このままではデータベースを圧迫しかねないので削除させる処理が必要です。
次回はゲストでログイン後にログアウトした場合、そのゲストアカウントを削除する機能の実装方法を説明します。

まだまだ未熟なのでコード的に不備がありましたら指摘してください。
[初学者向け]Fontawesomeが表示できない時の解決策

## 概要
初学者の私が経験した、Fontawesomeが表示できない時の解決策を3パターン紹介します。
この記事は、「なんだ、そんなことか」となる内容ですが、右も左も分からない当時の私にとっては、とても大きな壁に見えたので、共有します。

## 目次（結論）
**＜パターン1＞**
・閲覧しているバージョンが違う。

**＜パターン2＞**
・有料アイコンを導入しようとしている。

**＜パターン3＞**
・CSSの記述漏れ。

## 開発環境
・Cloud9
・Ruby
・Ruby on Rails
・使用gem: font-awesome-sass,'~> 5.15.1'

## ＜パターン1＞閲覧しているバージョンが違う。
##### 説明
「閲覧しているバージョン」とは、Fontawesomeの[公式サイト](https://fontawesome.com/v5/search)で実際に検索しているバージョンのこと。
検索しているバージョンと、使用しているgemが異なる場合、アイコンのクラス名が違い、正しく表示されなくなります。
```html:バージョンによるHTML記述の違い
(例)
・Ver.6の場合: <i class="fa-solid fa-user"></i>
・Ver.5.15.4の場合: <i class="fas fa-user"></i>
```
使用しているgem内容が次の場合、後述する検索バーのように、バージョンを「5.15.4」で選択してください。
```rb:Gemfile
gem 'font-awesome-sass', '~> 5.15.1'
```

##### バージョン指定方法
下記画像のように、Fontawesomeの[公式サイト](https://fontawesome.com/v5/search)を開くと、検索バーにバージョンが記載されています。
赤枠部分の▼をクリックして、使用しているバージョンに合わせてください。
(下記画像は、イメージです。)
![Fontawesome検索バー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2509797/a3146c8f-2b61-db51-134a-f3337b5c1045.png)


## ＜パターン2＞有料アイコンを導入しようとしている。
##### 説明
Fontawesomeは、一部に有料プランのアイコンが含まれます。
そのため、検索する時に無料プランでの絞り込みをしないと、誤って有料プランのアイコンを選択しており、導入できていないという事が起こります。
**アイコンをクリック後のボタン内に、下記画像の赤枠の表記が出るときは、有料プラン**のため、注意しましょう。
(下記画像は、イメージです。)
![Fontawesome有料プラン.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2509797/8ebdcf81-181b-7e53-822d-7284b5a137c9.png)

##### 事前に防ぐ方法
公式サイト画面の左側に「Free」と書かれた部分をクリックして、無料プラン内からアイコンを選ぶようにすると、防ぎやすいです。

## ＜パターン3＞CSSの記述漏れ。
##### 説明
font-awesome-sassは、CSSファイルへの読み込みが必要です。
gemをインストールした後、`app/assets/stylesheets/application.css.scss`内に、下記の記述をしないと使用できないため、要注意です。
```scss:app/assets/stylesheets/application.css.scss
@import "font-awesome-sprockets";
@import "font-awesome";
```
※上記のような、インストールのみでは使用できないgemは他にもあります。
RubyGemの[公式サイト](https://rubygems.org/)から、gem名で検索をかけて、公式GitHub内の記述を参考にして、使用するようにすると、抜け落ちが減ります。

## まとめ
振り返ると、「え～！こんなことか～」と思うミスでも、初学者には、大きい壁に見えるFontawesomeの表示できない問題を、今回はまとめてみました。
その他にも、追加する内容を思い出したら、更新する予定です。
他にもこんなのあるよと、皆さんからの情報もお待ちしております。
Update an architecture for integration of AEM and IDS

<!-- Update an archtecture for integration of AEM and IDS -->

![Slide2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486518/f8dbcde8-512f-5f36-6a3b-6b1784fd4c0d.jpeg)

[以前の投稿](https://qiita.com/o2346/items/d02d22dcb5fdf6ae77ce) で示した設計をアップデートしました。一応実装済みで形にはなっていますので（非公開ですが）、少し振り返りたいと思います
冒頭の画像がそのものです。大きな変更点としては

* エントリーポイントを AEM に移行（Workflow から起動）
* XML の生成は AEM のカスタムファンクションで実行する

こんなところです

これにより、UI は Workflow で完結でき、 ビジネスロジックの側面が強い CF-> xml 生成は AEM 、組版に関わる処理は中間処理+ IDS という分かりやすい棲み分けで見通しが少し改善しています

[以前の投稿](https://qiita.com/o2346/items/d02d22dcb5fdf6ae77ce) で示した基本的な考え方まで変わっているわけではありません。逆にこの基本方針のままで実装を進めたことでその有効性が確認できた、とも言えるのではないかと考えております。すなわち、 「AEM と IDS を疎にするとともに、中間に据えた汎用言語に処理を寄せて ExtendScript は低依存にする」という点です
実は今回の開発中、 IDS のバージョンを 16.4 -> 17.0 へアップグレードしているのですが、これにより生じた対応の大半はテンプレートのアップデートでした。もし AEM と IDS が密でさらに ExtendScript への依存度が高かった場合、テンプレートだけでは済まず、それ以上に工数が増大してしまうなどの弊害が出ていた可能性はあるかと思います
とはいえテンプレート(template.indd)も XML 流し込みを想定した特別仕様だったので、そのアップデートも楽ではなかったのですが、それでも当初方針で狙った通り設計上の利点が活かされたとは言えるかと考えているところです

逆に、 AEM のほうがアップデートしたときにも疎結合である点は有利に働くのではないかと推測しています。その際に改修する必要性が出る可能性のある領域は中間処理(当ケースの場合 Node.js) に留まるはずであり、 ExtendScript までもを改修しなくてもよいはずだからです

## XML Documentation for AEM

[このような機能があります](https://www.adobe.com/jp/products/xml-documentation-for-experience-manager.html)
この機能と上記の連携機構も相性がいいかもしれませんね。 XML のオーサリングはこの機能を使い、組版データとして出力したい時などがユースケースとして考えられます
InDesign にインポートさせる時は InDesign の仕様に則った様式である必要はあり、変換の必要はあろうかと思いますが、そこは自動化できるケースも少なくないでしょう。 上記にならって AEM で WF ->  XML to XML というふうにすれば、中間処理以降の仕組みはほぼ同じでいけるかもしれません
そのようなことを想定した場合、中間処理と IDS(ExtendScript) が特定のビジネス事情に特化していないよう汎用的に設計できていれば移植工数の削減、あるいはそのまま使いませる事も期待でき、好ましいかと思います
【Docker・Laravel】シンボリックリンクしたのに画像が表示されない。パスも合っているのに。

### エラー内容
以下のように、 __画像が表示されない__ というエラーが発生していました。
![スクリーンショット 2022-03-02 15.31.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2525372/24a00c2c-c8da-58ef-09f0-fa9494a1881e.png)

laravelでの画像アップロード機能は、こちらの記事を参考にしていました。

https://note.com/laravelstudy/n/n038bd68f53a7

全てやり方通りに行ったのにも関わらずに、謎の表示されないエラー。
正直、6時間くらいはエラーにハマっていました。

### 試したこと
大体、「Laravel 画像　表示されない」などで検索すると
解決方法として出てくるのが

①シンボリックリンクができていない
②画像がDBに保存されていない
③画像のパスが間違っている

この３つでした。

:::note alert
この３つは全てクリアできているのにも関わらず、エラーが出る。
:::


そんな方にオススメしたいのが、今回紹介する方法です。

Dockerをお使いですか？
---
もし、あなたがDockerを使用していて、上記の3つをクリアしていた場合
おそらく、あなたを助けることができると思います。

なぜなら、大きなミスをしている可能性が高いからです。

どんなミスかというと
シンボリックリンク、つまり画像をブラウザと繋げる指示が上手くできていないのです。

「いやいや、ちゃんとやったし」と思うかもしれません。
僕も思いました。

__しかし、”Docker”という存在が重要だったのです。__
通常、XAMPなどを利用している場合、ローカルのフォルダ上で
シンボリックリンクを行えばいいのですが

:::note info
Dockerの場合は、コンテナ内に入り込み
そこでシンボリックリンクを実行する必要があります。
:::

詳しくは、下の記事を参考にしてみてください。
`↓解決方法`

https://skill-upupup-future.com/?p=502

`↓Dockerの操作方法`

https://qiita.com/tsuboyataiki/items/90dbe94553d3dea39b19

解決できました
---
![スクリーンショット 2022-03-02 15.51.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2525372/42771779-000d-f4ce-596a-056d922bfc9d.png)

嬉しいので、犬の散歩に行ってきたいと思います。

この一件で感じたこと
---
エラーを検索して、解決法を実行しても解決しないこともそこそこある。

その時の、原因って意外と確立されている気がする。

:::note info
・バージョン違いによるエラー
・Dockerなどのサーバー違いによるエラー
:::

こんな感じで、エラー解決記事を載せている人や
作成記事の人との**環境違い**によるエラーがほとんどである。

どう解決していくか
---
今回の件で思ったことは2つです。
#### 1つ目
自分で検索する際は、環境違いによるエラーがあることを第2に考えることを意識する。

これだけで、無駄な時間はかなり減るだろう。

#### ２つ目
こういうくだらない？ミスって無くせると僕は思っています。
例えば、Docker使っている人用の検索サイトを作るとか
Laravel8の人用のキュレーションメディアを作るとか。

なんか、今のエンジニア情報共有サイトは
色々、混じりすぎていて、初心者にとってはかなり気難しい状態である。

情報が少なかった時代は、それでも良かったのだが
そろそろエンジニア界隈もキュレーションの時代に入るだろう。

しかし、自分はキュレーションを行いたいとは思わない。
正直、誰でもできる内容である。

なので、僕は僕のやり方でやってみたいと思う。
具体的には、やはり**真似る**ことが成長促進には欠かせないと僕は思う。

しかし、UdemyにしろYouTubeにしろ
真似る教材が少なすぎる。

数人はやっていても、網羅なんてできそうにもない。
なので、せっかくインターネットでデジダル情報が無限に動いてくれるのだから
僕はたくさんの人が、楽しくコーディングができるように

教育動画を作成していきたいと思います。
まずは、こういった記事で理解して
それを動画にしていきます。
Stylelint の autofix (自動修正) が動かなかったときの対処

## はじめに

とあるプロジェクトで他人の書いた scss ファイルを引き継ぎました

プロパティの順番がバラバラで読みにくかった （ display が最後の方にあったり ） ので、
`stylelint --fix` で自動修正し、一気にプロパティを並べ変えようと考えました

stylelint-config-recess-order は css のプロパティの順序について、
一定の規則に則っているかチェックします

https://github.com/stormwarning/stylelint-config-recess-order

これを `.stylelintrc.yml` で extend し、 `--fix` で自動修正すれば、
自動的にいい感じの並びになってくれます

直近の他プロジェクトでもうまく動いていたので簡単にいくかと思いきや、、、

```bash
$ npx stylelint "src/**/*.scss" --fix

src/scss/components/_footer.scss
  3:3  ✖  Expected "height" to come before "margin-top"        order/properties-order
  4:3  ✖  Expected "display" to come before "height"           order/properties-order
  7:3  ✖  Expected "font-size" to come before "border-radius"  order/properties-order 
...
```

エラーが出るだけで、なぜか修正されませんでした

これの対処法を備忘録として残します

## 実行環境

OS: macOS Monterey 12.2.1
Node.js: 16.13.2
Stylelint: 14.5.3

## 原因

他のプロジェクトでは、 Node.js のバージョンも Stylelint のバージョンも同じで自動修正しているのに、
なぜかこのプロジェクトではうまく動かない、、、

パッケージをインストールし直したりしてもダメ、、、

うまく動いているプロジェクトから node_modules をディレクトリーごとコピーしてきてもダメ

色々試した結果、 scss 上のコメント `/* stylelint-disable-next-line */` を全て消すと動くことが判明しました

上記のコメントは次の行だけ Stylelint でチェックしないようにするものです

まさか、これでファイル全ての自動修正が無効化されるとは、、、

`stylelint fix disable-next-line` でググると、 Stylelint の公式 Issue が見つかりました

https://github.com/stylelint/stylelint/issues/2643#issuecomment-586622917

> Since 13.2.0 stylelint no longer attempts to autofix sources which contain /* stylelint-disable */ comments, making the autofix feature safer to use.

Stylelint 13.2.0 から stylelint-disable のコメントを含むソースを自動修正しなくなったため、安全に自動修正できます、とのこと

...

...

...

いや、気付くわけないし、、、

せめて実行結果に `このファイルは disable を含むコメントがあったため自動修正をスキップしました` とか出して欲しい、、、

何はともあれ、原因は前任者があちこちに残していたコメントたちでした

- `/* stylelint-disable-next-line */`
- `/* stylelint-disable-line */`

本来、これらの Linter に目隠しするためのコメントは最小限、どうしてもの時だけ使うものです

https://qiita.com/RyoWakabayashi/items/8c3d026a481474c9bcf4

https://qiita.com/RyoWakabayashi/items/e9ba35b060f29976a9d5

これをやたらと使われていたため、ほとんどのファイルで自動修正が動かなかったというわけです

## おわりに

コメントがあるときに autofix が動かない件は公式のリリースノートにも書いてはありますが、
やはり実行時にスキップした理由を明示して欲しいですね

https://stylelint.io/changelog/#1320

自分がツールを作るときには肝に銘じます

あと、 Linter を無効化せずにキレイに書きましょう