OmniAICreator/Qiita-1.07M huggingface dataset:
C++BuilderでTSpinEditを右詰め(中央)に表示出来るようにコンポーネント作成

#はじめに
C++Builder(XE以降？)には、エディットボックスとスピンボタンを一体化した、**TSpinEdit**が「Sample」パレットにあります。
![spin.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2466942/15b9ef28-c11c-e74b-dbf7-7195d91586a2.png)

スピンボタンで数値を上下出来るので便利なのですが、左寄せでしか数値の表示が出来ません。**TSpinEdit**を継承した、自作のコンポーネントを作ります。

#コンポーネント作成
エディットボックスに右詰め(中央揃え)を実現するには、Windows APIのgetwindowlongptr() (※旧 getwindowlong)と、setwindowlongptr() (※旧 setwindowlong)を使用する方法がありますが、そのようなAPIを使わずとも、もっと簡単に実現できます。

（１）コンポーネント作成
　下図の様にTSpinEditを継承したコンポーネント作成をします。
　クラス名、パレット名などは任意に設定してください。

![spin2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2466942/8c707226-9194-15d6-e634-4aa8dc699939.png)

（２）コンポーネントユニットにヘッダーファイルに**Alignment**

下のソースコードの様にAlignmentを追加します。

```C++:nsSpinEdit.h
//---------------------------------------------------------------------------

#ifndef nsSpinEditH
#define nsSpinEditH
//---------------------------------------------------------------------------
#include <System.SysUtils.hpp>
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.Samples.Spin.hpp>
#include <Vcl.StdCtrls.hpp>
//---------------------------------------------------------------------------
class PACKAGE TnsSpinEdit : public TSpinEdit
{
private:
protected:
public:
	__fastcall TnsSpinEdit(TComponent* Owner);
__published:
	//↓この１行を追加する↓
	__property Alignment;
};
//---------------------------------------------------------------------------
#endif
```
（３）出来たコンポーネントユニットを自作のパッケージに追加してメイク
　ユニットをパッケージに追加してメイクします。
　また、「インストール」必要な場合があります。

![spin3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2466942/1cab3a48-5cff-c081-79e9-8b2bea4f2e05.png)

これで、パレットが更新され、新しく作成したTSpinEditの改良版で「Alignment」プロパティが使えて、右詰め(中央揃え)が可能になります。

![spin4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2466942/1f080c13-9173-f2ae-7bbf-540af6e54fa0.png)

#終わりに
長々と色々書きましたが、結局の所TSpinEditの親のクラスのTCustomEditのAlignmentがpublicスコープになっていて、プロパティとしてTSpinEditでは見えていない状態だったのを、__publishedに変更して見えるようにしただけなんです。
クラスの継承とかよく見ると、楽に機能強化とかできる場合があると言う事です。
【Android/kotlin】LiveDataについて雰囲気おさらい（自分用メモ）

## はじめに
LiveDataとかLifecycleOwnerとかよく聞くけどいまいちなんなのかが分からないので、めちゃくちゃふんわりまとめていきます。
理解が進み次第追記予定

## LiveDataとは
* データを保持してくれる箱みたいなやつ
* LiveDataと言いつつ、大体MutableLiveDataかObservableFieldを使う
    * MutableLiveData→必要な時のみ監視し、別途LifeCycleOwnerを設定する必要がある
    * ObservableField→常に変更を監視し続ける
* ``` val count = MutableLiveData<Int>("0")```みたいな感じで使う

## MutableLiveDataで必要になってくるLifecycleOwnerとは？
* 大体ActivityやFragmentをLifecycleOwnerに設定する
* ActivityやFragmentのライフサイクルに応じて変更を監視したりしなかったりする
    * ActivityやFragmentがstopした時などは変更を監視する必要がないので効率がいい
* Activity/Fragmentにいる状態で``` binding.lifecycleOwner = this ```とかで設定する
US配列MacでもControl+SpaceでリモートデスクトップのIMEを切り替えたい

# はじめに
先日、念願のMacbook Proを手に入れましてウキウキでセットアップを済ませ、さっそくリモートワーク用の会社端末にリモートデスクトップをしようと思った矢先に問題が発覚しました。
**RDP接続先の端末で日本語入力への切り替えができない！！**
正確に言えばRDP接続先のWindowsで割り当てた「Control + Space」でのIME切り替えが機能しない。
購入したMacbookはUS配列なのですが、入力ソースの切り替えはデフォルトで同じく「Control + Space」がアサインされており、Mac側のショートカットが優先されてしまうので、リモートデスクトップクライアントアプリでキー入力されていない扱いとなっているようでした。
一応そのままでも回避策はあり、WindowsはデフォルトでUS配列キーボードの場合「Alt + \`」でIME切り替えができます。なので、リモートデスクトップであってもMacから「Option + \`」で代用することはできます。
**でもやっぱり「Control + Space」で統一したい！！**
Mac初心者ながら四苦八苦した結果の備忘録となります。

# 方針
私はリモートデスクトップにはMicrosoftのリモートデスクトップクライアントとParallels社のParallel Clientを使っています。
そのため、端的にこの2つのアプリを操作している間、Mac側の「入力ソースの切り替え」ショートカットよりも優先してキー入力をインターセプトし、「Control + Space」→「Option + \`」に変換してキー入力として扱うことができれば、RDP接続中でも同じキー操作で日本語変換を行うことができそうです。

# Karabiner-Elementsで解決できる
Macをほとんど初めて触った私には馴染みありませんでしたが、キー入力（From）をトリガーにして様々なイベント（To）に変換することのできるツールで[Karabiner-Elements](https://karabiner-elements.pqrs.org/)というド定番ソフトウェアがあるそうです（すばらしい）。
詳しい使い方は先人達がQiitaをはじめとして解説してくださっているので、そちらでご確認いただくとして、今回の「Control + Space」問題に関して言えば、「方針」の通り、リモートデスクトップアプリの操作中という条件付きでキー入力の変換ルールが実装できそうです。

# ルール作成 & 適用
ポイントは2点です。

- 同時押しを定義する"modifiers"は"from"には"mandatory" or "option"の区別があるが、"to"には存在せず直記述する
- "conditions"の"type": "frontmost_application_if"にて特定アプリケーション（リモートデスクトップクライアント or Parallel Client）がフロントになっている時だけキー変換を機能させる

細かいルールの記法は[公式ドキュメント](https://karabiner-elements.pqrs.org/docs/json/complex-modifications-manipulator-definition/)を参照ください。
ルールファイルの配置場所と内容だけ記載します。

```bash
$ vim　~/.config/karabiner/assets/complex_modifications/[user_rule].json
```

```json:[user_rule].json
{
  "title": "ユーザ定義の日本語環境向け設定",
  "rules": [
    {
      "description": "Control+Spaceを押したときに、Option+`を送信する（RDC、Parallel Clientがフロントの場合）",
      "manipulators": [
        {
          "type": "basic",
          "from": {
            "key_code": "spacebar",
            "modifiers": {
              "mandatory": [
                "left_control"
              ]
            }
          },
          "to": [
            {
              "key_code": "grave_accent_and_tilde",
              "modifiers": [
                "left_option"
              ]
            }
          ],
          "conditions": [
            {
              "type": "frontmost_application_if",
              "bundle_identifiers": [
                "^com\\.microsoft\\.rdc\\.osx",
                "^com\\.microsoft\\.rdc\\.macos",
                "^com\\.2X\\.Client\\.Mac"
              ]
            }
          ]
        }
      ]
    }
  ]
}
```

ルールの作成後、Karabiner-Elementsを起動し、
Complex modifications > Rules > Add rule > [作成した独自ルール] > Enable
で有効化、
Deviceタブでキー変換を行う対象のキーボードにチェックが入っていることを確認して（入っていなければチェックをつけて）完了です。

# 総評
想定通り、RDP接続時でも「Control + Space」で日本語変換ができるようになりました！
なかなか解決方法に辿り着かず、いろいろ試行錯誤があった上で実現できたので記事にしてみましたが、英字配列のキーボードをお使いの方で「Control + Space」でIME切り替えを行う＋リモートデスクトップを行うという方は案外少ないんだろうか。
ちなみに、Karabiner-Elementsは定番ツールなだけあって、よくあるシチュエーションに対応したユーザ作成ルールが公式で共有されているので、今回はマッチするものは見つかりませんでしたが、ものによってはインポートするだけで問題解決したり効率化したりできそうです。
他にも利用できそうな幅があるのでまた良い使い方が見つかったら記事にしようかと思います。
分報を求めるのはPDCAのCまでの損失が惜しいからです。

# TL;DR
タイトルどおりです。

# この投稿の用途
分報の目的や良さを言語化しました。
分報を周りに求めたい時のフォーマットとしてご利用ください。
また、分報の提案を受けた時、提案者はこんなことを考えているかもしれません。考察にご利用ください。

# 背景
私は普段チームで仕事をしています。

チームは10名前後、ときどき新しいメンバーを迎えてチームをスケールしようとしています。
中にはソフトウェア開発経験を今から積んでいく方もチームに参加されることがあります。

新しく参加されたメンバーがPDCAを回して自分の仕事を改善しようとしていることはよくわかります。

そして、チームを成功させたい私としては、是非、新メンバーである「あなた」には分報をしていただきたい。
その理由を伝えたいという気持ちで、本投稿を記載しています。

# 分報のお願い
月報や日報は馴染みが深いかと思います。それを分で行うのが分報です。
ときに月報や日報は決まった書式、お決まりの文言など、めんどくさいルールが付きますが、それは求めていません。求めているのは、あなたの現状の常なるアウトプットです。
そのときにあなたが取り掛かろうとすること、感じていること、あなたの置かれた状況などをフリーフォーマットでチームの参加するチャット上に吐き出してください。なんでもいいです。読んでわからなければ読んだ人が質問するので、あなたの状況をオンライン化するようにしてほしいのです。
昨今の情勢で、リモートで勤務することも多くなりました。
リモートでオフラインになってしまうと、何しているかわからなくなってしまうのです。
分報としてオンライン状態を維持することで、サポートに入ったり、一緒に困ったりしたいのです。
そのための材料としてあなたの分報をください。

# 分報を求める理由
## チームで仕事をしている。
あなたの実力は信じているが、チームメンバーも今まで頑張って仕事をしてきました。もしかしたらあなたを助けられることがあるかもしれない。
もしかしたら、周りが共有しそこねた情報があるかもしれません。あなたの分報はその情報を掘り起こすチャンスになるかもしれません。
我々はチームとして仕事をしています。あなたはPDCAで改善を続けてくれていますが、Checkまで待っていると一人で仕事をしているのと変わらないのです。できるだけ早めにあなたの仕事にチームの知見を合流させたいのです。合流したてのあなたには、なにがわからないかわからないこともあるかと考えます。そんな状態の共有も十分な価値があります。チームを巻き込むために分報をお願いします。

## 作業が終わってからだと、リカバリーが大変。
私含め、プロジェクトメンバーは一定期間仕事をしてきたので、多少の問題であれば解決することもできるでしょう。
しかしながら時間は取り戻せない。
あなたのDoが終わって、Checkの段階まで来た時、すなわちチームメンバーがそれを確認するときには、致命的な時間が経過している可能性があります。そこからリカバリーしようとすると大変なのです。
できるだけ早く問題に気づくために分報をお願いします。

## あなただけがわかることがある。
その仕事を行っている本人が一番深堀りすることができます。その仕事をしているあなただけに知るチャンスがあった事象があるのです。あなたにとって価値がうすそうな気付きでも、そこにチームの知見が加わると値千金の情報になることがあります。それだけあなたのやっている仕事には価値があるのです。その価値をできるだけ速く刈り取りたいのです。
分報によって、その仕事の価値をアウトプットしてほしいのです。

## 教育目的
分報はあなたの作業の振り返りに使えます。分報を見直すことで、「どれくらい悩み続けてしまったか？」、が発見しやすくなります。「どのタイミングのアクションを変えれば、より良い結果を得ることができそうか？」を検討しやすくなります。
PDCAも回しやすくなると考えます。改善を継続することで、よりよい未来を掴み取れるようになると信じます。
そのためにも分報をお願いします。

## 壁打ち代わり
「壁打ち」という言葉がビジネスであります。
相手からの反応がなかったとしても、言語化、アウトプットすることで自分の考えが整理され、困りごとが解決される、新しい発想にたどり着くなどの効果が期待できます。
自分の考えをまとめるためにも、分報をしてみるのはどうでしょう？

## 承認欲求を満たそうとすることができる。
作業をオンライン化しておいていただきたいのです。私も常にチャットを見れるわけではないのですが、あなたがどういう経緯で現在地までたどり着いたかがわかりやすくなります。リモートでも作業が共有できて安心感があります。
そして、あなたの活動を承認できます。「いいね」マークも付けられますし、コメントもできます。
できるだけ、あなたの琴線を立たけるようなワードを発見しますので、チャンスを下さい。分報ください。

# 分報阻害要因とその解消
分報を求められて、もしかしたらあなたは戸惑っているかもしれません。あなたに分報をさせない阻害要因があるかもしれません。
できるだけそれを取り除くように努力します。以下の工夫を行います。

## 反応がないかもしれない
分報は基本垂れ流しなので、反応がないときもあります。もしかしたらいいタイミングで誰も読んでないこともあると思います。しかしながら保険だと思ってください。分報があるとわかっていて読まなかった（読めなかった）のであれば、読んでない側も責任をシェアできます。
できるだけ追うようにするので、分報をお願いします。

## なんとなく、、、分報しづらい。。。
チームメンバーの心理的安全性の確保はもとより、私が率先してくだらないことをつぶやくことで、できるだけ分報しやすい雰囲気を確保します。
他の人を傷つけないかぎりにおいて、何をチャット上に投稿しても許される雰囲気を作ります。
がんばりますので、分報をお願いします。

# おすすめ分報ワード
「仕様を読んでます。グレートですよこいつはァ」
「あ…ありのまま 今 起こったことを話すぜ！mainブランチのビルドがコケたぜ。。。」
「ドララララララぁ（コード記述中）」
「あァァァんまりだァァアァ（自動テスト失敗）」
・・・適当につぶやいていただければ結構なのです。（ん？もしかして分報のハードルを上げた？）

# 〆
あなたの仕事の仕方はPDCAではないかもしれません。PDR/OODA/STPD/DCAPかもしれません。
が、どれでも一緒です。できるだけ速く、あなたが置かれた境遇を共有したいのです。

分報をお願いします。
RubyにEnumerator#rest みたいなのが欲しい

Ruby の Enumerator で、列挙はひとつずつしかできない。まとめていくつか列挙できるメソッドが欲しい。

こんな感じ。

```ruby:Ruby
class Enumerator
  def rest(n=nil)
    ary = []
    case n
    in nil
      loop { ary << self.next }
    in Integer
      n.times { ary << self.next }
    end
    ary
  end
end


a = [*1..10].to_enum

a.next    #=>1
a.next    #=>2
a.rest(4) #=>[3, 4, 5, 6]
a.next    #=>7
a.rest    #=>[8, 9, 10]
```

ダメですかねえ…。
React チュートリアル　パート10　（fetch）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654025/b24ea190-bd5a-43cc-c67b-6de48efea347.png)

#目標:military_medal:
今日は、**fetch()**を使って前回作成した**json-server (localhost:5000/posts)**のデータをブラウザに表示させ、**追加・削除機能**を実装したいと思います:bangbang:
徐々に、アプリケーションっぽくなってきます:point_up:

#はじめにアプリケーションとjsonサーバーを起動させます。
Vscodeのターミナルを開いて、**"npm start"**を実行してください。新たにターミナルを開いて、**”npm run server"**を実行します。jsonサーバが起動しているかは、localhost:5000/postsをurlに入力していただき、ファイルが表示されれば成功です:bangbang:

今回は、**App.js**と**componentsフォルダにAddPost.js**を作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654025/72d13ce4-2fcc-1d81-321c-a754ff5e6b4f.png)


#App.js

![fetchapp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654025/65b342fa-0646-7418-e677-cb022637ed21.png)

>【18行目】ここのコードがjsonサーバーにデータを取得するメソッドになります。

>【26行目】ここのコードがjsonサーバーにデータを追加するメソッドになります。

>【40行目】ここのコードがjsonサーバーにデータを削除するメソッドになります。

>【57行目】ボタンをクリックすると、handleDelete（）にpostのidを渡す記述になります。これで、idが取得できjsonサーバーにある対象のファイルを削除します。

#AddPost.js

こちらのコードは、簡単に説明すると入力した値をaddPostに格納して、App.jsにオブジェクトとして渡しています。

![fetchappadd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654025/d3319b5e-12da-160c-07b2-e3e2c6a84033.png)

>【12行目】ここでは、titleに入力されているか判定させています。

>【22と23行目】ここでは、ボタンをクリックしたあと、インプットフォームを空白にするためです。

#db.jsonも下記の様に変更してください

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654025/65060d8a-f0cd-5d63-d542-cc119be25298.png)

#ブラウザで確認:fire::fire:

![2022-01-18_23h43_44.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654025/025f97ef-9696-2075-6d7f-7cec4360f5bb.gif)

リアルタイムで、jsonサーバーのデータをブラウザに表示でき、追加削除機能も実装することができました:blush:

#次回:bell:
npm の便利なパッケージを紹介します！

#参考
https://youtu.be/w7ejDZ8SWv8
TypeScriptの型で型の条件分岐ができる？(Conditional Types)

タイトルがよくわからなくなっちゃいました:innocent:
個人の備忘録的に記事にいたします。

# 構文例
以下の構文を例にしてみます。

```typescript
type First<T extends unknown[]> = T extends never[] ? never : T[0]
```

この `First<>` は **T が never[] の場合、never型** になります。

それ以外は、**T[]の最初だけの型** になります。

これは、TypeScript の **Conditional Types** と呼ばれるものです。

# 解説
コードの以下の部分に注目いたします。

```typescript
T extends never[] ? never : T[0]
```

ここでの `T` は Generic で受け取る型になります。

そして、`T extends never[] ?` の部分は、
**T が never[]** を継承しているかどうかの判定になります。

そこから後は `真の場合 : 偽の場合` です。

三項演算子と同様の記法ですね。

# 条件分岐地獄
ちなみに、この条件分岐をつなげていくこともできます。

以下は公式にあった例です。

```typescript
type TypeName<T> = T extends string
  ? "string"
  : T extends number
  ? "number"
  : T extends boolean
  ? "boolean"
  : T extends undefined
  ? "undefined"
  : T extends Function
  ? "function"
  : "object";

type T0 = TypeName<string>; // "string"
type T1 = TypeName<"a">; // "string"
type T2 = TypeName<true>; // "boolean"
type T3 = TypeName<() => void>; // "function"
type T4 = TypeName<string[]>; // "object"
```

おっっふ！！！！

# 一緒によく使われるinferについて
最後は、Conditional Types とよく一緒に使われる、inferについてです。

とても簡単に言うと、「Conditional Types の構文の中で型をキャプチャする機能」です。

以下、構文例です。

```typescript
type Awaited<T extends Promise<unknown>> = T extends Promise<infer R> ? R : never
```

# 解説
上記の解説です。

まず、以下の部分です。

```typescript
T extends Promise<infer R> ?
```

`T extends Promise` なので、T が Promise型であるかどうかの判定になります。

`Promise<infer R>` は 
以下の例を参考にしてみます。

```typescript
type Hoge = Promise<string>
type Foo = Awaited<Hoge> // "string"
```

この場合は、`Promise<string>` の `<string>` の部分を R にキャプチャしています。

そして、Promise型であるため、R を返している、つまり string になります。

# ドキュメント

https://www.typescriptlang.org/docs/handbook/2/conditional-types.html

以上になります。
GASでGoogle Slides のページをテンプレートから自動生成する方法

#はじめに

社内のとある部門にお邪魔した際、多くの人がスプレッドシートからデータを手で拾って、プレゼン資料を独自に量産している様子が散見され、あまりに非効率に見えました。スプレッドシートの情報が更新されたらプレゼン資料も更新しなければならないのだとか。。

こんな非効率なことするぐらいなら自動生成してやろうと色々と調査したときの備忘録。

##やりたいこと

やりたいことをざっくりまとめると以下の３点。

- その１ Google SlidesのプレゼンテーションをGoogle App Scriptで自動生成したい。　　
- その2 スライドのページはテンプレートから自動生成したい。
- その3 スライド内の要素を任意の文字列に置換したい。

それでは早速やってみたいと思います。

##スライドテンプレートを用意する

まずはこんな感じで、新しいプレゼンテーションを作成します。
これは、GASで自動生成する際にフォントサイズや文字の配置といった要素の元となるテンプレートとになります。
![スクリーンショット 2022-01-18 18.44.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171832/46f1a191-fc66-7ecd-00d4-526abdc1d38f.png)
テンプレートが無いと文字列の位置、フォントサイズや色等をいちいちコードで調整する必要があるのでゼロからスライドを生成するよりもテンプレートを作っといたほうが楽です。


##スライドテンプレートに置換用文字列を追加する
さっき作ったスライドの文字列に当たる部分をテンプレートっぽい置換用の文字列にします。

![スクリーンショット 2022-01-18 18.45.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171832/4e14edb2-c462-a6a7-daee-c40d508218ea.png)
できました。

ここでは{{title}}と{{body}}を置換用文字列として追加してみました。
これでスライドのテンプレートは完成です。

テンプレートが出来上がったら、プレゼンテーションのURLを記録しておきます。
![スクリーンショット 2022-01-18 19.06.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171832/0d923f44-fb7d-dd39-4ff7-f59ab5f21ff5.png)
このURLは後でコード内でテンプレートを指定する際に使います。

##要素をGASで置換する
テンプレートの次は、テンプレートからスライドを生成し、文字列を置換するコードを書きます。
さっき記録したテンプレートスライドURLをここで使用します。

```javascript
function myFunction() {
  //生成元となるデザインテンプレートURL
  var templateSlideUrl = 'https://docs.google.com/presentation/d/xxxxxxxxxxxxxxxxx';

  //生成元のスライドテンプレートを開く
  var templateSlidesApp = SlidesApp.openByUrl(templateSlideUrl);

  //生成先のスライド
  var newPresentation = SlidesApp.create('あたらしいスライド');

  //テンプレートの1ページ目からスライドをコピーして自動生成スライドの最終ページに挿入
  var newSlide = newPresentation.appendSlide(templateSlidesApp.getSlides()[0]);

  //文字列置換
  newSlide.replaceAllText('{{title}}','タイトルだよー');
  newSlide.replaceAllText('{{body}}','本文でござる。本文は長いのでござる。');
}
```


##実行結果
実行すると自分のGoogleDriveの最近使ったファイルに「あたらしいスライド」というプレゼンテーションが生成されているはずです。

![スクリーンショット 2022-01-18 23.47.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171832/8cd78dae-35d8-e950-a21d-58e2b4dae172.png)


プレゼンテーションを早速開いてみましょう。

![スクリーンショット 2022-01-18 19.26.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171832/6a57667f-2885-43b1-64df-145d051231be.png)

やったー、うまくいきましたね。
ここまでできれば、スプレッドシートのデータを読み込んで何ページもあるプレゼン資料を自動生成するのは簡単にできそうです。

#おわりに
このように、空のテンプレートからスライドを生成し、置換用文字列を任意の文字列に入れ替えることが簡単にできることがおわかりいただけたかと思います。

ちょっと応用すればQRコードを埋め込んだり、画像を入れ替えることも出来ます。
お試しあれー。
個人的Mac/Windowsショートカット

Macを仕事で使うようになったので、
一旦よく使うショートカットをまとめておく。

# Macショートカット

・ウィンドウ
Fn＋F：ウィンドウ最大・最小
Fn＋バックスペース：デリート
Esc：最大化（フルスクリーン）終了。ポップアップ閉じる
コマンド＋M：ウィンドウ最小化（アニメーションが無い非表示の方が好み）
⭐️コマンド＋H：ウィンドウ非表示
コマンド＋W：ウィンドウ閉じる
⭐️コマンド＋Q：アプリ終了
コマンド＋タブ＋選択アプリでQ：アプリ終了

オプション＋￥：バックスラッシュ（＼）

・メインクリップボード
コマンド＋C：コピー
コマンド＋V（＋オプション）：（Finderでは＋オプションでコピー元削除し）ペースト

・セカンダリクリップボード（メインとは別メモリで管理されるが、切り取りができてコピーはできない）
⭐️コントロール＋K：切り取り
⭐️コントロール＋Y：ペースト
コントロール＋コマンド＋スペース：絵文字パレット

・カーソル移動（＋シフトで選択モード）
コマンド＋←：行頭
コマンド＋→：行末
コマンド＋↑：最上部
コマンド＋↓：最下部
オプション＋←→：単語単位

・高度なカーソル移動
コントロール＋F（orward）：一文字前
コントロール＋B（ack）：一文字後
コントロール＋P（revious）：前の行
コントロール＋N（ext）：次の行
コントロール＋A（head）：行頭
コントロール＋E（nd）：行末

## 高度な削除
コントロール＋D：右一文字
コントロール＋H：左一文字
コントロール＋K：行末まで切り取り

## 矢印
zh：←
zj：↓
zk：↑
⭐️zl：→

## ファイル
対象ファイルをオプション押しながらドラッグ&ドロップ：新規作成
ファイル選択＋スペースでクイックルック
コマンド＋D：コピーの作成
コマンド＋デリート：削除
コマンド＋デリート＋シフト：ゴミ箱中身全削除（[確認ダイアログ毎回出現するが非表示にできる](https://book.mynavi.jp/macfan/detail_summary/id=90701)）



## スクショ
コマンド＋シフト＋3：全画面スクショ
コマンド＋シフト＋4＋スペース：後に選択したウィンドウを撮る（この時＋optionだと影が入らない）
コマンド＋シフト＋4：後にドラッグで選択した範囲を撮る


## ブラウザ
コマンド＋R：Webページの更新
シフト＋更新マーク：スーパーリロード
⭐️コマンド＋クリック：新規タブで開く
コマンド＋シフト＋クリック：新規タブで開き、選択。
コマンド＋オプション＋クリック：新規ウィンドウで開く
コマンド＋オプション＋シフト＋クリック：新規ウィンドウで開き、選択
コマンド＋W：タブを閉じる
コマンド＋シフト＋T：タブ復元
コマンド＋←/→：戻る/進む

## 注意
ツール（IDE等）のショートカットと競合しているとどちらかが使えない。

## コピー用記号
たて	│ ┃
たてひだり	┨ ┥ ┤ ┫
たてみぎ	┣ ┠ ┝ ├
ひだりうえ	┌ ┏
ひだりした	└ ┗
ふとわく	┗┻━┛ ┏┳━┓
ほそわく	└┴─┘ ┌┬─┐
まんなか	┼ ╋ ┿ ╂
みぎうえ	┐ ┓
みぎした	┘ ┛
よこ	─ ━
よこうえ	┻ ┷ ┸ ┴
よこした	┳　┯ ┰ ┬

# Windowsショートカット
win+D：画面に表示してるウィンドウを隠せる
win+L：ロック画面にする
win+E：エクスプローラー開く
win+Pause：スペック確認
win+V：クリップボード履歴表示
win+(↑/↓)：画面最大化/最小化 
win+(←/→)：画面の左/右に分割
win+Shift+S：トリミングスクショ

Esc(エスケープ) 更新取り消し

F1 その画面のヘルプに飛ぶ(ソフトでも)
F3 画面内検索
F5 更新
F6 ひらがなに変換
F11   全画面表示 (表示/解除)
F12 ソースコード表示(exleだと名前付け保存の画面が出る)

こめじるし※を上にする方法
wordなら書式→フォント→上付き
excelならセルの書式→フォント→上付き

入力途中の文字はESC2回押すと全削除

ctrl+F：画面内検索
ctrl+D：削除
ctrl+T：新しいタブを作成
ctrl+W：タブを閉じる
ctrl+T+Shift タブを復元
ctrl+TAB：右のタブに移動
ctrl+TAB+Shift：左のタブに移動
ctrl+ リンクをクリック：新しいページで開く

Ctrl＋shift＋T：消したタブを復活できる(web)

Tab：次の欄に移動
Tab+shift：前の欄に移動
Space：チェックボックスにチェック

Alt+Print Sc：全画面スクショ
win+Shift+S：トリミングスクショ
Alt+ ←/→ ：戻る/進む(※巻き戻しの意味)
Alt+ ↑ ：上(前)のフォルダに戻る

Alt＋Tab：ウィンドまとめて表示(Tabおすごとで選択)

ctrl+N：同じウィンドウを表示(クローム→クローム。エクスプローラ→同ページの)

ctrl+移動(↑/↓)  ,spaceで選択：複数選択コマンド
shift+移動(↑/↓)：範囲選択コマンド

shift+Caps Lock：大文字固定
Home：行の始めへ移動
End：行の終わり
PegeUp：ページ最上部
PegeDn：ページ最下部

shift+Dlete  完全削除(ゴミ箱無)

Win ＋対応する数字キー（【1】〜【0】）
タスクバーから起動できる
(※アプリを並べた左からの順に「1、2、3、4、5、6、7、8、9、0」のキーに対応)


## エクセル編
Alt + Enter 改行
PegeUp：1画面分上へ移動
PegeDn：1画面分下
Alt+ PegeUp：1画面分左
Alt+ PegeDn：1画面分右
(ctrl+down/up でシート移動)

ctrl+ (方向キー)：空白まで移動
ctrl+ ;：今日の日付入力 年/月/日

⭐️ctrl+Y：直前のコマンドまたは動作を繰り返す（macならcon+Y or com+Y）
⭐️ctrl+5：取り消し線（macならcon+5）
⭐️shift+space：行選択
ctrl +space：列選択
⭐️ctrl+ shift + [+/-]：選択した行数分挿入（←半角モード時、macならcomでも可）


## エクスプローラー
Win＋E：エクスプローラーを開く
Ctrl＋N：ウィンドウ複製
Ctrl＋Shift＋N：新フォルダ作成
Alt+D：アドレスバー選択
Alt+P：Excelプレビュー

## マルチモニター
Shit＋Win＋（←/→）：ディスプレイ間ウィンドウ移動（既に同ソフトが開いている場合、新規ウィンドウは同じディスプレイ上に表示されている）

## 番外編
windowsのエクスプローラーやlinuxのファイル更新日時の仕様
孫フォルダ階層を更新しても親の更新日時は変わらず子の更新日時が変わる。
子フォルダにテキストファイル等を新規作成すると親の更新日時が変わる。
フォルダは自分の直下の階層のみを更新対象として管理している。
構成：親フォルダ ー 子フォルダ ー 孫フォルダ
シェルでデータ編集；ワンライナー

grep, sed, awk を使ったデータ編集をするよ。
データを下記の様な data_before から data_after へ変換してみよう！
３ステップだ。
Excel に貼り付けて手動でポチポチ編集だなんて、まっぴらごめんだ。

```:data_before
foods ={
'ラーメン',
'つけ麺',
'僕イケメン'
};

fruits ={
'りんご_150',
'みかん_50',
'ばなな_80'
};

これ以下に別のデータが続く。
```

```:data_after
fruits ={
りんご
みかん
ばなな
};
```
まず、grep を使って取り出したい行を抽出。

```:ステップ１
$ grep -A 4 "fruits" data_before
```
次に、sed を使って不要なシングルクォーテーションとカンマを削除（空白に置き換える）。

```:ステップ２
$ grep -A 4 "fruits" data_before | sed -e "s/'//g" -e "s/,//g"
```
さらに、awk を使ってアンダーバー以降の不要な文字列を削除。

```:ステップ３
$ grep -A 4 "fruits" data_before | sed -e "s/'//g" -e "s/,//g" | awk '{sub("_.*$",""); print $0; }' 
```
これでお望みの結果（data_after）が得られたはずだ。
【Azure】AZ-104合格体験記

# AZ-104の勉強法
◆Azureの経験年数
　0年0ヵ月

◆勉強期間
　2021年6月にAZ-900を取得し、他の資格の勉強をしていたので少しAzureから離れ、
　2021年10月からAZ-104の勉強を開始。2021年11月中旬に合格できたので約1.5ヵ月の
　勉強期間で取得することができました。

◆合格時の点数
　823点で合格でした。

◆資格名称
　AZ-104: Microsoft Azure Administrator

◆AZ-104の試験範囲
　Azure の ID とガバナンスの管理 (15~20%)
　ストレージの実装と管理 (15~20%)
　Azure コンピューティング リソースのデプロイと管理 (20 ~ 25%)
　仮想ネットワークの構成と管理 (25~30%)
　Azure リソースの監視とバックアップ (10~15%)

# 勉強方法①
　MSが用意しているラーニング パスがあるので、まずは範囲の確認と
　ラーニングを実施して大まかな部分を確認しました(日本語が微妙な箇所があり、
　分かりづらい箇所が見受けられます)
　[・MSラーニングパス](https://docs.microsoft.com/ja-jp/learn/certifications/exams/az-104)


# 勉強方法②
　Amazonで下記対策本を購入して3周しました。
　[・合格対策 Microsoft認定試験AZ-104:Microsoft Azure Administratorテキスト＆演習問題](https://www.amazon.co.jp/%E5%90%88%E6%A0%BC%E5%AF%BE%E7%AD%96Microsoft%E8%AA%8D%E5%AE%9A%E8%A9%A6%E9%A8%93AZ-104-Microsoft-Azure-Administrator%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88-%E6%BC%94%E7%BF%92%E5%95%8F%E9%A1%8C/dp/4865943080/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1BH5179D94K87&keywords=AZ-104&qid=1642514543&sprefix=az-104%2Caps%2C167&sr=8-1)

　試験に出る範囲のサービスを試験に必要な範囲で書かれているので
　試験対策としてはとても優秀だと感じました。
　→初版は誤字や設問の回答が間違っていたりしたので、2版以降で修正入るかもしれません。

# 勉強方法③
　Udemyの下記問題集を3周実施、正答率が9割超えた状態で試験に望みました。
　[AZ-104: Microsoft Azure Administrator 模擬問題集](https://www.udemy.com/course/az-104-microsoft-azure-administrator-practice-test-jp/)

# 総評
　上記①～③の勉強を行い、各種サービスはどのようなサービスなのかを理解し、
　問題ケースに合わせたサービスの選択が行えればAZ-104の合格は可能だと思います。
Mathematicaの変数を保存して気楽にカーネルを終了する

# これは何の記事か
Mathematicaではノートブックソフトを終了したりすると、それまで大量の時間をかけて計算した結果が失われてしまって、非常にストレスフルである。かといって、作業をしばらくしないのにノートブックをずっと起動しておくのも気持ち良くない。そこで、この記事では計算結果を外部ファイルとして保存しておき、次に作業をする際にはその外部ファイルを読み込む事で前回の続きから作業できる様にする方法を説明する。

# データの保存方法
まず、あらかじめノートブックが存在するフォルダに```savefiles```というフォルダを作成しておく。それが完了したら、計算結果を保存するファイルパスを定義する。ここでは```hoge.nb```というノートブックで定義された変数などを```hoge_savefile.wl```という名前の外部ファイルに保存する方針を取るので、そのファイルのパスを定義して```savefile```という変数に入れている。別のディレクトリ構造やファイル名で保存したければ右辺を適当に書き換えればいい。

```wl
savefile = 
 FileNameJoin[{NotebookDirectory[], 
   TemplateApply[
    "/savefiles/``_savefile.wl", {FileBaseName[NotebookFileName[]]}]}]
```

あとは、保存したい変数を指定して[```Save```コマンド](https://reference.wolfram.com/language/ref/Save.html.ja?source=footer)を実行すれば上で用意したファイルに定義などが保存される。例えば、現在の[コンテキスト](https://reference.wolfram.com/language/workflow/AutomaticallyUseSeparateContextsForDifferentNotebooks.html.ja?source=footer)に存在する全てのシンボルの設定を保存したい場合であれば、

```wl
Save[savefile, "`*"]
```

を実行すればよい。ノートブック全体を書き出すのは時間がかかるので特定のシンボルに関する設定のみを保存したい時には

```wl
Save[savefile, a]
Save[savefile, {a, b, c}]
```

の様に、直接その変数や変数のリストを指定してあげれば、savefileにその情報が追加される。他の文字列パターンの指定方法は[公式サイト](https://reference.wolfram.com/language/tutorial/InputSyntax.html#6562)にヒントがあるかもしれない。ついでに言っておくと、とある文字列パターンに合致するシンボルのリストやその個数は

```wl
Names["文字列パターン"]
Dimensions[Names["文字列パターン"]]
```

などによって、調べることができる。

# データの読み込み方法
データを読み込む時には以下の様に[```Get```コマンド](https://reference.wolfram.com/language/ref/Get.html)を実行すればよい。

```wl
Get[savefile]
```

もちろん、上記のsavefileはデータの保存方法のところで定義したものと同じものであり、Getをする前に実行しておく必要がある。
JSON形式のログを加工してみる

#JSONのログを加工してみます

下記のようなログを

```json
[
    {
        "hoge": {
        "abc" : "除外される",
        "xyz" : "除外される",
        "jjj" : "残る値"
        },
        "fuga" : "残る値",
        "fuge" : "残る値"

    },
    {
        "hoge": {
        "abc" : "除外される",
        "xyz" : "除外される",
        "yyy" : "残る値2"
        },
        "fuga" : "残る値2",
        "fuge" : "残る値2",
        "fugeex" : "除外される"

    }
]
```


こんな感じで加工しみたいと思います

```json
[
    {
        "fuga": "残る値2",
        "fuge": "残る値2",
        "hoge": {
            "yyy": "残る値2"
        }
    },
    {
        "fuga": "残る値",
        "fuge": "残る値",
        "hoge": {
            "jjj": "残る値"
        }
    }
]

```


加工するためのソース

```elixir
#! /usr/bin/env elixir

Mix.install([{:jason, "~> 1.2"}])

defmodule JFilter do
  def remove(data, path) do
    data
    |> Enum.map(&pop_in(&1, path))
    |> Enum.map(&elem(&1, 1))
  end
end

data =
  File.read!("log.json")
  |> Jason.decode!()
  |> Enum.reverse()
  |> Enum.map(&Map.take(&1, ["hoge", "fuga", "fuge"]))
  |> JFilter.remove(["hoge", "abc"])
  |> JFilter.remove(["hoge", "xyz"])
  |> Jason.encode!()

File.write!("out.json", data)
```

①　File.read!("log.json")でログファイル読み込み
②　Jason.decode!()でjsonをelixirで扱える形式に変換
③　Enum.reverse()配列を逆転
④　Enum.map(&Map.take(&1, ["hoge", "fuga", "fuge"]))　欲しい項目を選択
　　この例だと　hoge、fuga、fugeの３つの項目を選択
⑤ Filter.remove(["hoge", "abc"]) 除外項目を選択
　　この例だと、　hogeの下にあるabcを除外
⑥　Jason.encode!()　Json形式に変換
⑦　File.write!("out.json", data)　ファイル出力


#おまけ

GCPのログを取得コマンド
下記の用にGCPのログを log.jsonに保存して上記のelixirで作ったスクリプトを流すとログ解析が少しは幸せに？なるかも。

```
gcloud logging read 'ログクエリ' --freshness="1m" --format=json  > /log.json
```
Dynamics 365 Finance and Operations ~ Materials Requirements Planning（MRP：資材所要量計画）~

#MRP（Material Requirements Planning System）とは
・狭義では、半製品・部品・材料について、「必要なものを」「必要なときに」「必要なだけ」購買したり製造したりするための計画を行うことを意味する。（恐れずに言えば、D365 FO は MRP としては、これを意味する。）
・広義では、製造物に関する「必要なものを」「必要なときに」「必要なだけ」の計算だけではなく、生産能力計画（設備とか）、人員計画、物流計画を行うことを意味する。⇒「MRP2」や、生産資源計画（Manufacturing Resource Planning）とも言われている。

#MRPの基本
MRPの基本的なフロー。Master Planningは、正味所要量を算出することです。正味所要量 ＝ （総）所要量 - 在庫量
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/4515be4b-6ed7-46cc-7cb7-b775c73c1f08.png)

#Master Plan
Master Plan は「品目」「在庫トランザクションの増減（販売注文、発注、製造オーダーなど）」「手持在庫」「保管分析コード」「カレンダー」などの要素から、計画オーダーを算出。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/70531a04-df9d-e5ee-aa7e-55299f0db22a.png)
プランタイプは、静的と動的の二種類あります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/e953a144-c30c-9c7e-e4dd-40e59249f5f9.png)
実行は手動でもできますが、MRPといえば夜間バッチですよね（笑）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/1e4a6833-598c-d6f7-27f2-0fb93d6018d6.png)


#補充グループ・品目補充
補充グループとは、正味所要量をどう計算するか（期間、Min/Max、タイムフェンス、Postive/Negative）を定義したグループです。そしてそれを品目やサイト/倉庫や法人に対してセットします（二つ以上にセットしている場合はオーバーライドされます）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/ecc5d0fb-4686-0519-e8ce-d82d45b917e7.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/e904020d-4ac9-05af-0522-d0b8d890cb94.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/b4f2080e-0b0d-b426-7135-79b97131c3bb.png)

#カレンダー・日数
品目や実稼働日に合わせて発注・製造・移動のリードタイムを計算してくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/0c6f5bc5-5a32-f393-4f99-cd1b1e38dc3a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/5aef2579-f797-92f4-f4fa-e80c22955f52.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/f05ad7a9-979f-0949-1df3-afc0e83468eb.png)

MRPに限った話ではないですが、配送日数も設定しておきましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/c2e43e52-dbf3-5442-93bb-7f4dd5cab164.png)


#計画オーダーの確定
計画オーダーが正味所要量を計算してくれます。当然、部品表（BOM）で構成されている製品であれば、紐づく部品に対しても計画オーダーが作成されてきます。例えば以下の部品のケースだと、今0個の手持在庫だが、2個はある販売注文に紐づくもの、10個は安全在庫として必要な量、ということで12個の正味所要量となっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/5be86fbd-f476-80db-3e8e-62db22154ba0.png)
計画発注オーダーは売買契約に基づいて作成することもできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/9cd57d52-b340-8ddb-66f8-e11c0299d4f0.png)
Firm（確定）は手動でも行えますが、タイムフェンスによる自動確定することも可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/43c07b83-8407-9d1e-3ea8-1dd8210a4f38.png)
Juliaで日付連番を得る

```julia
julia> using Dates

julia> dr = Date(2021,12,20):Day(1):Date(2022,1,18)
Date("2021-12-20"):Day(1):Date("2022-01-18")

julia> typeof(dr)
StepRange{Date, Day}

julia> collect(dr)
30-element Vector{Date}:
 2021-12-20
 2021-12-21
 2021-12-22
 2021-12-23
 2021-12-24
 2021-12-25
 2021-12-26
 2021-12-27
 2021-12-28
 2021-12-29
 2021-12-30
 2021-12-31
 2022-01-01
 2022-01-02
 2022-01-03
 2022-01-04
 2022-01-05
 2022-01-06
 2022-01-07
 2022-01-08
 2022-01-09
 2022-01-10
 2022-01-11
 2022-01-12
 2022-01-13
 2022-01-14
 2022-01-15
 2022-01-16
 2022-01-17
 2022-01-18

julia> dr = Date(2021,12,20):Week(1):Date(2022,1,18)
Date("2021-12-20"):Week(1):Date("2022-01-17")

julia> collect(dr)
5-element Vector{Date}:
 2021-12-20
 2021-12-27
 2022-01-03
 2022-01-10
 2022-01-17

julia>
```
#Slack アプリ開発：モーダルでのバリデーションについて

![Slack___local_SlaIM___George_Dev.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22294/40275dce-dac1-c32a-8cca-7f9b4b0f66ce.png)

モーダル、使ってますか？
めちゃ使っているのですが、今回はバリデーションについてです。
上記のようなモーダルを作っているのですが、URL欄にはhttpが含まれたものがほしい。ユーザーIDはユニークじゃないとだめなので、重複した場合はエラーを返したいという場合にどうしましょう。というものです。

答えはこちらに書かれています

https://slack.dev/bolt-python/ja-jp/concepts#view_submissions

入力ウィンドウのビューはこんな形で開かれています。

```Python
        client.views_update(
            view_id=body["view"]["id"],
            hash=body["view"]["hash"],
            view={
                "type": "modal",
                # ビューの識別子
                "callback_id": "view_1",
                "title": {"type": "plain_text", "text": text_title},
                "submit": {"type": "plain_text", "text": text_submit},
                "private_metadata": json.dumps(private_metadata),
                "blocks": blocks
            }
        )
```

ビューの識別子に当たる部分で、submitの結果を受けるという形です。

```python
@app.view("view_1")
def handle_submission(ack, body, client, view, logger):
    # `input_c`という block_id に `dreamy_input` を持つ input ブロックがある場合
    hopes_and_dreams = view["state"]["values"]["input_c"]["dreamy_input"]
    user = body["user"]["id"]
    # 入力値を検証
    errors = {}
    if hopes_and_dreams is not None and len(hopes_and_dreams) <= 5:
        errors["input_c"] = "The value must be longer than 5 characters"
    if len(errors) > 0:
        ack(response_action="errors", errors=errors)
        return
```

入力値を検証と書かれた部分バリデーションをかけています。

errors["input_c"]の部分が、blocksのblock_idを指します。
該当するblock_idが存在していた場合、submit自体はキャンセルされて、元のモーダルの入力欄にエラーメッセージを表示することができるという仕組みになっています。

全然気付いてなかった…。便利なので使っていきましょう。

仕様についてはこちらも参照

https://api.slack.com/surfaces/modals/using#displaying_errors


### おまけ
もともとは、submit_disabled属性を使おうとしていましたが、こちらはワークフローのみでしか使えないということでした。
バリデーションが通ってない場合はこんなふうにすれば送信ボタンがアクティブにならないだろうと思っていたんですよね。
それは出来ませんのでご注意ください。

```python
client.views_open(
            trigger_id=body["trigger_id"],
            view={
                "type": "modal",
                # ビューの識別子
                "callback_id": "callback_id",
                "title": {"type": "plain_text", "text": text_title},
                "submit": {"type": "plain_text", "text": text_submit},
                "submit_disabled": True,#←このような設定は出来ない
                "blocks": blocks
            }
        )
```
特定の要素だけのスクリーンショットが欲しいとき

## この記事の概要

日頃スクリーンショットを撮る機会は多いと思います。
そんな中でも「ドロップダウンメニューだけを写したい」のように、特定の要素だけのスクリーンショットが欲しいタイミングはありませんか？

実は各種ブラウザには初めから「特定の要素だけのスクリーンショット」を撮る機能があります。
範囲選択でのスクリーンショットでは、余白が揃えづらい・要素の幅や高さにピッタリと一致した画像は取得しづらいですよね。
ちょっとしたテクニックとして紹介します。

## 準備するもの

以下のブラウザならどれでもOKです。
（他のブラウザでもできそうな気はしますが今回は試していません。）

- Google Chrome
- Firefox
- Safari

## やり方

微妙な差こそありますが、どのブラウザでもほぼやり方は一緒です。
一旦Chromeを用いて説明します。

1. 目的のページを開く
1. 開発者ツールを開く
   - <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/55fd0b29-6754-8ad8-f88a-eaedb65f72a4.png" width="600" alt="">
1. インスペクタなどから撮影したい要素をアクティブにする
   - <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/b846dd2d-820f-88aa-d67b-04f73ad17ea3.png" width="600" alt="">
1. 右クリック > Capture node screenshot
   - <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/3d8bb5df-c434-1186-b5bf-416e58f4493b.png" width="404" alt="">
1. 保存するディレクトリを選んで完了

コンテキストメニューに記されているラベルは以下のようになっています。

| ブラウザ | バージョン | ラベル |
| --- | --- | --- |
| Google Chrome | 97.0.4692.71 | Capture node screenshot |
| Firefox | 96.0.1 | Screenshot node |
| Safari | 14.0.3 | Capture Screenshot |

:::note warn
Safariだけはnodeのスクリーンショットであると明示されていませんが、ちゃんと選んだnodeだけを撮影してくれます。
:::

## 仕上がりの差

当たり前と言えば当たり前ですが、ほとんど違いはありません。
ただしSafariだけは背景色が指定されていない場合は透化した画像として保存します。

背景色が欲しいとき・要らないときがあると思うので覚えておくと便利かもしれません。

| ブラウザ | 撮影したスクリーンショット |
| --- | --- |
| Google Chrome | ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/1b4aeac2-d24a-de58-4bdb-ff99d3d155e5.png) |
| Firefox | ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/37c4c0bd-6a48-2317-058b-974b57a0372a.png) |
| Safari | ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/7eeb9565-6935-ce52-8f38-d58e384cb40d.png) |

## 余談

この記事の内容は本当に些細な小ネタですが、これを知るまで自分はわざわざグラフィックソフトを立ち上げて切り抜く場合すらありました。
（ある程度ちゃんとした資料を作るようなとき、中途半端に他の要素が入っているとノイズになるので、つい……）

知ってからはこのやり方で切り抜いていますが、周りの人に定期的に教えている機能の1つです。
それならいっそ記事にしてしまうか〜という背景でした。
rails 7.0.1 + MySQL/SQLiteの構成だとrails6.0で作成したmigrateファイルの`references`/`belongs_to`定義が動かない

# TL;DR

`MySQL`を使用している`rails`アプリケーションの場合、`rails`バージョンを7.0.1にして、`rails` 6.0で生成したmigrateファイルを使ってdb migrateを行うとエラーが発生します

# 詳細

## 発生するケース

例えば`users`テーブルが存在していて、`users`に紐づく子テーブル`posts`を追加しようとした場合で以下のようなmigrateファイルをrails6.0の作成したとします。

```ruby
class Posts < ActiveRecord::Migration[6.0]
  def change
    create_table :posts do |t|
      t.references :users, foreign_key: true

      t.timestamps
    end
  end
end
```

の後rails7.1にアップグレードを行い`migrate reset`などmigrateを再度実行した場合に以下のエラーが発生します。

```
Column `user_id` on table `posts` does not match column `id` on `users`, which has type `bigint`. To resolve this issue, change the type of the `user_id` column on `posts` to be :bigint. (For example `t.bigint :user_id`).
Original message: Mysql2::Error: Referencing column 'user_id' and referenced column 'id' in foreign key constraint 'fk_rails_b01e4286d5' are incompatible.
/app/db/migrate/posts.rb:3:in `change'
```

## おきている事
`rails g migrate`コマンドでmigrateファイル生成すると`ActiveRecord::Migration[6.0]`の様に`[]`でその時のrailsバージョンに対応するクラスを取得して、そのクラスを継承したクラスを作成します。

```ruby
class Users < ActiveRecord::Migration[6.0]
  def change
  end
end
```

その時のrailsバージョンに対応するクラスを取得する仕組みによって、バージョンの互換性を保つ仕組みがあるのですが、rails7.0.1での対応によって6.0の互換性がなくなってしまった不具合です。

## railsの対応

対応されているPRがマージされているので次期バージョンで解消されると思います。

https://github.com/rails/rails/pull/43295
CCNAの基礎知識その１

##はじめに
この記事では「OSI参照モデル」という、ネットワークで必要とされる機能を７層(レイヤ)に分類した通信の基本的なモデルについてレイヤごとに説明します。


##OSI参照モデル
・物理層(レイヤ１)
データの伝送で使用するケーブルや、コネクタの形状など、ネットワークに関するすべての物理的な仕様を定めています。送信されてきたデータをビットの列に変換後、電気信号に変換して送信します。また、物理層の機能を実装したネットワーキングデバイスとして「ハブ」が挙げられます。  
・データリンク層(レイヤ２)　
ケーブル等で直接接続された同一ネットワーク内でデータを正確に宛先のノードへ転送するために、データの送信元や宛先の識別方法などを定めています。この層ではデータの宛先を示す「MACアドレス(物理アドレス)」が使われています。また、データリンク層の機能を実装したネットワーキングデバイスとして「スイッチ」が挙げられます。  
・ネットワーク層(レイヤ３)
異なるネットワーク間でデータの転送を行うために、「IPアドレス(論理アドレス)」を使うことで、ネットワークをたどって遠くの宛先までデータを届けることができます。また、ネットワーク層の機能を実装したネットワーキングデバイスとして「ルータ」が挙げられます。  
・トランスポート層(レイヤ４)
送信したデータを宛先のコンピュータのアプリケーション(プログラム)に届ける。この層ではデータが確実に届くように、確認や再送をすることで通信の信頼性を確保します。  
・セッション層(レイヤ５)
通信を行うプログラム同士のセッションの確立から終了までを管理します。  
・プレゼンテーション層(レイヤ６)
データの暗号化や圧縮方式の規定をはじめ、文字や画像、動画等のデータ形式を区別するといったこともこの層で行われます。  
・アプリケーション層(レイヤ７)
ユーザ同士のインターフェイスになる層です。この層でルールを決めることで、アプリケーションの目的に応じたサービスを提供します。

##おまけ(TCP/IPモデル)
今回は「OSI参照モデル」について説明しましたが、このモデルは最近ほとんど使用されていません。現在は「TCP/IPモデル」が使用されています。このモデルは、レイヤ１・２が「リンク層(インターフェイス層)」、レイヤ３が「インターネット層」、レイヤ４が「トランスポート層」、レイヤ５・６・７が「アプリケーション層」となっています。階層数や名称は異なりますが、機能はほぼ変わらないので、内容を理解する目的なら「OSI参照モデル」のほうがわかりやすいため「TCP/IPモデル」はおまけとして紹介しました。
ReactとNode.js、AWSで社内システムを構築するまで 2/2

ReactとNode.jsでアプリケーションを作りました。

実際にAWSを用いて環境構築して、動くようにしたので、どのようなネットワークを作ってどのような技術を用いてデプロイしたのかを書いていきます。
※どのようなネットワークを作ったかを重点的に説明します。技術の詳しい説明はまた別の記事で書きます。

①まずネットワークですが、VPCを用いてプライベートサブネットとパブリックサブネットを2つずつ、プライベートサブネットとパブリックサブネットを1つずつペアにして異なるリージョンに配置した。

②インターネットゲートウェイとパブリックサブネットを紐づけた。

③NATゲートウェイを各パブリックサブネットに配置した。

④プライベートサブネットにSSHでアクセスするための踏み台サーバをEC2を用いてパブリックサブネットに配置した。

⑤各プライベートサブネットに1台ずつNodeサーバ用のEC2インスタンスを作成し、踏み台サーバ経由でnginxやpm2等をインストールし、nodeサーバを使える状態にした。

⑥ELBを配置し、各プライベートサブネットに接続するようにした。

⑦RDB(MySQL)をプライベートサブネットに配置し、Nodeサーバと接続できるようにした。

⑧IAMでS3への権限をEC2インスタンスに付与した。

⑨AmazonS3とCloud Frontの静的ホスティング機能を用いてReactアプリケーションをデプロイした。

⑩ReactアプリとNodeサーバが連動してることを確認した。S3のエンドポイントからアクセスできるようになった。

⑪Route53を用いて独自ドメインを取得した。

⑫Route53のDNS設定で、取得したドメインとS3のエンドポイントを紐づけて、ドメイン経由でアプリにアクセスできるようにした。

以上です。
【Unity】Android実機でブレークポイントを置いてデバッグする

Unityで開発しててデバッグ時に、ブレークポイントを置いて処理を追ったり変数の中身を見たい時があったので備忘録的に記事にいたします。

# 環境
- Windows10
- Unity Hub 2.4.5
- Unity 2020.3.25f1
- Android Studio 2020.3.1
- Visual Studio Enterprise 2022

# 1. PCと実機を繋ぐ
実機とPCを繋いでおきます。

Android側の設定は以下の記事をご参照下さい。

https://qiita.com/tak001/items/045e6a0bd86628d59cfe

# 2. Unity側の設定
File > Build Settings > Android (もしくは ctr + shift + B)から
「**Development Build**」 と 「**Script Debugging**」 にチェックを入れます。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399610/c6f9be6a-b410-8740-c20d-06141af14572.png)

設定ができたら、「Build And Run」しておきます。

# 3. Visual Studio側の操作
実機側でアプリが起動していれば、Visual Studioのツールバーから
デバッグ > Unityデバッガーのアタッチ を開きます。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399610/cc482d1b-ec32-4318-a9e4-01ac32c27313.png)

すると「Unityインスタンスの選択」が出てきます。

動作中のポートが選択できるので、 「プロジェクト: AndroidPlayer(USB)、コンピューター: 現在繋いでいる端末名」を選択して「OK」を押します。

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399610/8e18730b-1621-19db-db12-bc898826a04f.png)

するとデバッグモードになり全体的に赤くなります。

![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399610/0bfdf553-bb60-8c89-f4be-54b40cc111f7.png)

# 4. ブレークポイントを置く
この状態になったら、ブレークポイントを置きたいファイルを開いて、ブレークポイントを置けば、その処理になった時に止まります。

その状態で変数の上にマウスオーバーすると、値が確認できたり、
イミディエイトウィンドウで関数を貼り付けて実行したりができます。

![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399610/4bc03728-961a-7912-880a-119c832c0b8f.png)

# うまくいかない時
うまくいかない時は、「Build And Run」からやり直してみましょう。

# Unity上で動かしてスクリプトデバッグする方法
最後に、Unity上でPlayボタンを押した時にも、スクリプトデバッグをしたい時の方法です。

Visual Studio側の「Unityにアタッチ」を押せば同じようにブレークポイントで止めることができます。

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399610/8a19d7f8-c312-5b0a-1eb9-601876815560.png)

以上です。
ご拝読有難うございました。
[Drupal] メールを送信する

## やりたいこと
記事タイプのノードが保存されたら管理者にメールを送る

## やり方

```php
/**
 * Implements hook_ENTITY_TYPE_presave().
 */
function my_module_node_presave(NodeInterface $node) {
  if ($node->bundle() === 'article') {
    $mail_manager = \Drupal::service('plugin.manager.mail');
    $result = $mail_manager->mail(
      'my_module', // このメールに対応するhook_mailを持つモジュールのマシン名.
      'my_module_node_save_mail', // メールを識別するためのキー.
      \Drupal::config('system.site')->get('mail'), // 送信先.
      \Drupal::config('system.site')->get('langcode'), // 言語コード.
      ['nid' => $node->id()] // メールの中で使用する変数等.
    );

    if (!$result) {
      // エラーのログ等.
    }
  }
  
}

/**
 * Implements hook_mail().
 */
function my_module_mail($key, &$message, $params) {
  if ($key === 'my_module_node_save_mail') {
    // $mail_manager->mail()の第5引数で指定した値を$paramから取得できる.
    $nid = $params['nid'];
    
    // 送信元、タイトル、本文などを定義する.
    $message = [
      'from' => \Drupal::config('system.site')->get('mail'), // 送信元.
      'title' => 'ノードが更新されました。', // タイトル.
      'body' => "NID{$nid}のノードが更新されました。", // 本文.
    ];
  }
}
```

必ずhook_mailを経由しないといけない & fromとtoの定義場所がバラバラなのがわかりづらい。[Simple Mail](https://www.drupal.org/project/simple_mail)というモジュールを使うと簡略化できるようです。

```
 simple_mail_send($from, $to, $subject, $body);
```
[Drupal]時間・日付に関するチートシート

※随時増やしていく予定

## 現在の時刻を取得する
###  現在の時刻のタイムスタンプを取得する
```php
\Drupal::time()->getCurrentTime();
```

### リクエスト時刻のタイムスタンプを取得する
```php
\Drupal::time()->getRequestTime();
```

## 日付↔タイムスタンプの変換をする

### タイムスタンプを日付に変換する
```php
use Drupal\Core\Datetime\DrupalDateTime;
$timestamp = '1640995200';
$datetime = DrupalDateTime::createFromTimestamp($timestamp);
$date = $datetime->format('Y/m/d');
```

### 日付をタイムスタンプに変換する

- フォーマットから取得する場合

```php
use Drupal\Core\Datetime\DrupalDateTime;
$date = '2022-01-01';
$datetime = DrupalDateTime::createFromFormat('Y-m-d', $date);
$timestamp = $datetime->getTimestamp();
```
- 配列から取得する場合

```php
use Drupal\Core\Datetime\DrupalDateTime;
$date = [
  'year' => 2022,
  'month' => 1,
  'day' => 1,
];
$datetime = DrupalDateTime::createFromArray($date);
$timestamp = $datetime->getTimestamp();
```

## フィールド値をフォーマットする

### DrupalDatetimeを使う
```php
$timestamp = $node->get('field_my_timestamp')->getString();
$date = DrupalDateTime::createFromTimestamp($timestamp)->format('Y-m-d');
```

### Drupalに登録されているフォーマットを使う
「Drupalに登録されているフォーマット」= `/admin/config/regional/date-time`で登録されているフォーマット

```php
$date = \Drupal::service('date.formatter')->format($timestamp,'my_custom_format');
```

## フィールドに値をセットする
### 日付フィールドに値をセットする
```php
// 日付だけの場合
$node->set('field_date', '2025-12-31');
// 日付+時刻の場合
$node->set('field_datetime', '2025-12-31T23:59:59');
```
### タイムスタンプフィールドに値をセットする
```
$node->set('created', '1760140799');
```
EMRクラスタの作成からポートフォワーディング、Hueへのログイン、データベースおよびテーブルの作成までの手順

EMRクラスタ作成~ポートフォワーディング~Hueにログイン~DB,テーブル作成まで


Glueをメタデータストアとして使うことに注意。glueをメタデータストアとして使わないとクラスタの中にmysqlが立ち上がりそこにメタデータが保存される。emrを閉じてしまうとメタデータから作り直しになってしまう。

```
構成の詳細
リリースラベル:emr-5.24.0
Hadoop ディストリビューション:Amazon 2.8.5
アプリケーション:Hive 2.3.4, Hue 4.4.0, Spark 2.4.2, Tez 0.9.1, Zeppelin 0.8.1, Pig 0.17.0
ログの URI:s3://aws-logs-hoge-ap-northeast/elasticmapreduce/
```

![fadsfdsafdsafdsafdsafdsafdsafdsa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1347377/b3714beb-576b-5c14-d50f-2dbe809006da.png)




クラスタを立ち上げたらマスターノードにsshで通信、キーペアを指定

```
ssh -i C:/path/to/key.pem hadoop@ec2-5...3.ap-northeast-_.compute.amazonaws.com
```

コンソールにログインできなかったがインバウンドトラフィックの編集でssh22番ポートを開けるのを忘れていた。マイIPでインバウンド通信許可。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1347377/506b56c5-4b23-4c67-9eeb-1bdc4dba4f92.png)

しかし、hueに接続できない。調べるとポートフォワーディングが必要とのことなので以下のコマンドでローカルからポートフォワーディングした。
追記：ポートフォワーディングしなくても、マスターノードのセキュリティグループ>インバウンドルールから8888を開ければさっとhueにアクセスできたかもしれない…

```
ssh -i C:/path/to/key.pem -N -L 8157:localhost:8888 hadoop@ec2-5...3.ap-northeast-_.compute.amazonaws.com
```

この後`http://localhost:8157/`にアクセスするとhueに繋がった。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1347377/ed06e842-d041-5893-b686-fd9709ed03f8.png)

あとは特にSQLを実行するのと何ら変わりない。

```
CREATE DATABASE EMRTEST_0118;

-- ## Hiveの実行エンジンを設定する
-- MapReduceで処理
set hive.execution.engine=mr;
-- tezのほうが早いのでtezに設定
set hive.execution.engine=tez;
-- 実行エンジンを確認
set hive.execution.engine;
```
```
CREATE EXTERNAL TABLE emrtest_0118.talking_train_raw (
  ip INT, -- カラムの名前 そのカラムの型
  app INT,
  device INT,
  os INT,
  channel INT,
  click_time STRING,
  attributed_time STRING,
  is_attributed INT
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
LINES TERMINATED BY '\n'
LOCATION 's3://emr-0118/'
TBLPROPERTIES ("skip.header.line.count"="1");
```

とりあえずテーブルの参照まで終わった。Hiveを使ってやることといえば大規模な分散処理、バッチ処理を実行しそれをS3などのデータレイクへのエクスポートすることだろう。

この部分ができれば、実務的にはスケジューラを通してHiveを定期実行する部分を作成したいところ。EMRを定期実行して、○○して…となるとなかなか時間がかかりそう。趣味的にはネットワーク関連の勉強をしてからのほうがいろいろとはかどりそうだが。逆にHiveからエクスポートされた加工済みのデータはただのcsvなのでその処理自体は簡単そう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1347377/f1c7063b-2cfe-800b-5d62-2bd08144acce.png)





参考
https://qiita.com/asdasda/items/a2caf5d771bc81ee3dfa
Arduino IDEでDigisparkへのスケッチ書込みがエラーとなる際の対処方法

##### ※2019/12/28に[Twitterにツイートした内容](https://twitter.com/littlebear_6w6/status/1211155509044101121)をまとめ直した記事になります。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">解決😃✌️<br><br>ArduinoでDigisparkへ書き込むbootloaderモジュールのMicronucleusが古かったぽい！<br><br>↓からソースをクローンしてbuildした！<a href="https://t.co/oB1v0eYXYa">https://t.co/oB1v0eYXYa</a><a href="https://twitter.com/hashtag/%E3%83%8F%E3%83%83%E3%82%AD%E3%83%B3%E3%82%B0%E3%83%A9%E3%83%9C?src=hash&amp;ref_src=twsrc%5Etfw">#ハッキングラボ</a></p>&mdash; LittleBear (@littlebear_6w6) <a href="https://twitter.com/littlebear_6w6/status/1211155509044101121?ref_src=twsrc%5Etfw">December 29, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 事象
Arduino IDEでスケッチをDigisparkへ書込みしたところ、以下のエラーが発生した。
その事象を解決するために試行錯誤した内容をまとめる。
＜環境＞
・Ubuntu
・Arduino IDE 1.8.13


```console:エラー内容
Warning: device with unknown new version of Micronucleus detected Report as 2.2
```

# 原因
Digisparkへ書き込むbootloaderモジュールのMicronucleusが古かった。

# 解消手順
1. Micronucleusの最新ソースを取得して、モジュールを再作成する
1. 作成したモジュールをArduinoのパッケージディレクトリにコピー
1. アクセスルールファイルの差替え

```bash:解消手順
# Micronucleusの最新ソース取得
$ git clone https://github.com/micronucleus/micronucleus.git
$ cd micronucleus/commandline
# usbアプリケーションをプログラミングするためのライブラリをインストール
$ apt install libusb-dev
# コンパイル
$ sudo make
# Arduinoにインストール済みのモジュールの差替え
$ cp micronucleus ~/.arduino15/packages/digistump/tools/micronucleus/2.0a4
# Linuxディストリビューションによりuserspace appsがunknown USB deviceに
# アクセスできないので、アクセスルールを差替え
cp 49-micronucleus.rules /etc/udev/rules.d/
````

# 参考情報
- [Micronucleusリポジトリ](https://github.com/micronucleus/micronucleus)
[RxCocoa]プログラムからテキストを変更した場合, textField.rx.textにイベントが流れない

`textField.text = "hogehoge"`とプログラムから`text`を変更しただけでは`textField.rx.text`にイベントが流れてくれない。

RxCocoaのソースを見ると`.valueChanged`イベントが流れた時に`rx.text`が更新されるようである。そのため、`textField.sendActions(for: .valueChanged)`として、明示的にイベントを流せば良い。

```swift:UIControl+Rx.swift
    /// This is a separate method to better communicate to public consumers that
    /// an `editingEvent` needs to fire for control property to be updated.
    internal func controlPropertyWithDefaultEvents<T>(
        editingEvents: UIControl.Event = [.allEditingEvents, .valueChanged],
        getter: @escaping (Base) -> T,
        setter: @escaping (Base, T) -> Void
        ) -> ControlProperty<T> {
        return controlProperty(
            editingEvents: editingEvents,
            getter: getter,
            setter: setter
        )
    }
```

参考 https://stackoverflow.com/questions/45633173/how-do-you-get-a-signal-every-time-a-uitextfield-text-property-changes-in-rxswif
New Relic でも ctrl-h で backspace したい

# 何が起きたか

[New Relic One](https://docs.newrelic.com/docs/new-relic-one/use-new-relic-one/get-started/introduction-new-relic-one) には謎のキーバインドが張られており、ctrl-h を押すと前のページに戻ってしまう。ctrl-h で backspace したい派としては、クエリの入力欄でミスタイプしてctrl-hで消そうとするたびに前のページに戻ってしまい不便だった。


# 解決策

New Relic がバインドしてくる [`keydown` イベントを `stopPropagation`](https://developer.mozilla.org/ja/docs/Web/API/Event/stopPropagation) しちゃえばいい。

```javascript
document.addEventListener('keydown', (event) => {
    if (event.key === 'h' && event.ctrlKey) event.stopPropagation()
})
```

これを [Tampermonkey](https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo?hl=ja) か [Greasemonkey](https://addons.mozilla.org/ja/firefox/addon/greasemonkey/) で New Relic にアクセスするたびに実行させればいい感じになる。 userscript 版は gist に置いた。

https://gist.github.com/oieioi/940f98826edc0293292702085448a684
Elixir 変数の頭文字　小ネタ

#概要
変数の頭文字の記号の意味のまとめ　　
しばらく触れないでいると忘れてしまいがちなので。

### @(アットマーク)　
定数

```elixir
例：
  @url "https://hogehoge.com/aiueo/sample.xml"
　　　　@user_agent [ {"User-agent", "Elixir foo.boo.001@gmail.com"} ]
  
  def getBody do
　　　　　　　　　response = 
      @url |> HTTPoison.get!(@user_agent)
    response.body
  end
    
```

また、アノテーションとしても利用されている
`@moduledoc`　・・・　モジュールのドキュメント
`@doc`　・・・　関数やマクロのドキュメント

```elixir
例)
defmodule MyApp.Blog do
  @moduledoc """
  The Blog context.
  """
  <<省略>>
  @doc """
  Returns the list of posts.
  ## Examples
      iex> list_posts()
      [%Post{}, ...]
  """
  def list_posts do
    Repo.all(Post)
  end
  <<省略>>
```

### ^(キャレット)
ピン演算子。束縛済みの変数を新たに束縛させたくない場合に使用する。　　
パターンマッチのみで、上書きされない。

```elixir
例 (^無）:
iex(1)> x = 123
123
iex(2)> x = 321
321

例　　(^有):
iex(1)> x = 123
123
iex(2)> ^x = 321
** (MatchError) no match of right hand side value: 321

iex(2)> ^x = 123
123

```

### _（アンダーバー）

使われない変数の頭につける。これを付けないとwarningが出る。

```elixir
例）
  def index(conn, _params) do
    posts = Blog.list_posts()
    render(conn, "index.html", posts: posts)
  end
```
↑を変更し、アンダーバーを消してみると

```elixir
例）
  def index(conn, params) do
    posts = Blog.list_posts()
    render(conn, "index.html", posts: posts)
  end
```
warningが発生する

```
warning: variable "params" is unused (if the variable is not meant to be used, prefix it with an underscore)
  lib/my_app_web/controllers/post_controller.ex:7: MyAppWeb.PostController.index/2
```


以上