Jason.decode!の紹介

こんにちは！
プログラミング未経験文系出身、Elixirの国に迷い込んだ？！見習いアルケミストのaliceと申します。
今回はJason.decode!/2を使ってみて学んだことをまとめます。

# 目的
Jason.decode!/2の使いどころ、導入方法の紹介。

## 実行環境
Windows 11 ＋ WSL2 ＋ Ubuntu 22.04
Elixir v1.17.0
Erlang v27.0

# 今回やりたいこと
[前回の記事](https://qiita.com/Alicesky2127/items/786c10e573d3f47a8fae)で取得した、Qiitaの記事一覧に対して"Elixir"で検索をかけたときの結果を見やすくしたい。

# Jason導入までの経緯
```diff_elixir:lib/get_qiita_articles.ex
   def index do
     "https://qiita.com/api/v2/items?query=elixir"
     |> HTTPoison.get!()
+    |> Map.get(:body)
   end
```

この関数の実行結果は下記の通りですが、一行が長すぎて目で読むにはしんどいです。
そこで、Jasonを使用してデータを整形します。
```diff_elixir:iex
"[{\"rendered_body\":\"\\u003ch1 data-sourcepos=\\\"7:1-7:14\\\"\\u003e\\n\\u003cspan id=\\\"はじめに\\\" class=\\\"fragment\\\"\\u003e\\u003c/span\\u003e\\u003ca href=\\\"#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB\\\"\\u003e\\u003ci class=\\\"fa fa-link\\\"\\u003e\\u003c/i\\u003e\\u003c/a\\u003eはじめに\\u003c/h1\\u003e\\n\\u003cp data-sourcepos=\\\"10:1-10:480\\\"\\u003eV4L2 のストリーミングI/O(V4L2_MEMORY_MMAP) はV4L2 ストリーミング I/O の方式の一つで、V4L2 ドライバ内(カーネル内)で確保した V4L2 バッファを mmap 機構を使ってユーザー空間にマッピングすることで、ユーザープログラムが V4L2 バッファにアクセスできるようにします。V4L2バッファをユーザー空間から直接アクセス出来るため、この方式は比較的よく使われます。\\u003c/p\\u003e\\n\\u003cp data-sourcepos=\\\"14:1-14:245\\\"\\u003eしかし、ある種の V4L2 ドライバでは、mmap でユーザー空間にマッピングする際にキャッシュがオフになってしまってメモリアクセスが非常に遅くなり性能が出ない問題がありました。\\u003c/p\\u003e\\n\\u003cp data-sourcepos=\\\"16:1-16:102\\\"\\u003eこの問題を起こす V4L2 ドライバの一つとして、Xilinx の Video DMA があります。\\u003c/p\\u003e\\n\\u003cp data-sourcepos=\\\"20:1-20:63\\\"\\u003eこの記事では、そのメカニズムを説明します。\\u003c/p\\u003e\\n\\u003cp data-sourcepos=\\\"24:1-24:75\\\"\\u003eなお、この記事は、以前投稿した次記事の改訂版です。\\u003c/p\\u003e\\n\\u003cul data-sourcepos=\\\"26:1-32:0\\\"\\u003e\\n\\u003cli data-sourcepos=\\\"26:1-32:0\\\"\\u003e\\u003ca href=\\\"https://qiita.com/ikwzm/items/8f1c98efe6fd4ae2490a\\\" id=\\\"reference-48cf7bcf59237b3b354e\\\"\\u003e『V4L2 ストリーミングI/O(V4L2_MEMORY_MMAP) で性能が出ない問題)』 @Qiita\\u003c/a\\u003e\\u003c/li\\u003e\\n\\u003c/ul\\u003e\\n\\u003ch1 data-sourcepos=\\\"33:1-33:50\\\"\\u003e\\n\\u003cspan id=\\\"キャッシュがオフになるメカニズム\\\" class=\\\"fragment\\\"\\u003e\\u003c/span\\u003e\\u003ca href=\\\"#%E3%82%AD%E3%83%A3%E3%83%83%E3%82%B7%E3%83%A5%E3%81%8C%E3%82%AA%E3%83%95%E3%81%AB%E3%81%AA%E3%82%8B%E3%83%A1%E3%82%AB%E3%83%8B%E3%82%BA%E3%83%A0\\\"\\u003e\\u003ci class=\\\"fa fa-link\\\"\\u003e\\u003c/i\\u003e\\u003c/a\\u003eキャッシュがオフになるメカニズム\\u003c/h1\\u003e\\n\\u003ch2 data-sourcepos=\\\"37:1-37:50\\\"\\u003e\\n\\u003cspan id=\\\"v4l2-バッファのメモリアロケータ\\\" class=\\\"fragment\\\"\\u003e\\u003c/span\\u003e\\u003ca href=\\\"#v4l2-%E3%83%90%E3%83%83%E3%83%95%E3%82%A1%E3%81%AE%E3%83%A1%E3%83%A2%E3%83%AA%E3%82%A2%E3%83%AD%E3%82%B1%E3%83%BC%E3%82%BF\\\"\\u003e\\u003ci class=\\\"fa fa-link\\\"\\u003e\\u003c/i\\u003e\\u003c/a\\u003eV4L2 バッファのメモリアロケータ−\\u003c/h2\\u003e\\n\\u003cp data-sourcepos=\\\"40:1-40:86\\\"\\u003eV4L2 バッファのメモリアロケータ−には次の３種類があります。\\u003c/p\\u003e\\n\\u003cul data-sourcepos=\\\"42:3-45:0\\\"\\u003e\\n\\u003cli data-sourcepos=\\\"42:3-42:56\\\"\\u003evmalloc\\t\\t\\t: DMA を伴わない V4L2 ドライバ用\\u003c/li\\u003e\\n\\u003cli data-sourcepos=\\\"43:3-43:65\\\"\\u003edma-sg\\t\\t\\t: Scatter Gather に対応した DMA デバイス用\\u003c/li\\u003e\\n\\u003cli data-sourcepos=\\\"44:3-45:0\\\"\\u003edma-contig\\t: Scatter Gather に対応していない DMA デバイス用\\u003c/li\\u003e\\n\\u003c/ul\\u003e\\n\\u003cp data-sourcepos=\\\"46:1-46:66\\\"\\u003eこのうち、問題となるのは最後の dma-contig です。\\u003c/p\\u003e\\n\\u003ch3 data-sourcepos=\\\"49:1-49:11\\\"\\u003e\\n\\u003cspan id=\\\"vmalloc\\\" class=\\\"fragment\\\"\\u003e\\u003c/span\\u003e\\u003ca href=\\\"#vmalloc\\\"\\u003e\\u003ci class=\\\"fa fa-link\\\"\\u003e\\u003c/i\\u003e\\u003c/a\\u003evmalloc\\u003c/h3\\u003e\\n\\u003cp data-sourcepos=\\\"52:1-52:465\\\"\\u003evmalloc はDMAを伴わない V4L2 ドライバのためのメモリアロケータ−です。例えば、USB Camera のV4L2 ドライバがこれにあたります。USB の場合は USB のデバイスドライバが USB デバイスとのデータ転送を行い、V4L2 ドライバ自体は直接 USB デバイスとのデータ転送を行いません。そのため、カーネルが普通に使っている vmalloc を使ってメモリを確保します。\\u003c/p\\u003e\\n\\u003ch3 data-sourcepos=\\\"55:1-55:10\\\"\\u003e\\n\\u003cspan id=\\\"dma-sg\\\" class=\\\"fragment\\\"\\u003e\\u003c/span\\u003e\\u003ca href=\\\"#dma-sg\\\"\\u003e\\u003ci class=\\\"fa fa-link\\\"\\u003e\\u003c/i\\u003e\\u003c/a\\u003edma-sg\\u003c/h3\\u003e\\n\\u003cp data-sourcepos=\\\"58:1-58:409\\\"\\u003edma-sg は Scatter Gather に対応した DMA を持つデバイスのためのメモリアロケータ−です。Scatter Gather に対応しているため、バッファが物理メモリ空間上に連続していなくても DMA 転送が可能です。 dma-sg は Linux Kernel の DMA Mapping API を使ってメモリを確保します。しかし、mmap は DMA Mapping API を使っていません。\\u003c/p\\u003e\\n\\u003ch3 data-sourcepos=\\\"61:1-61:14\\\"\\u003e\\n\\u003cspan id=\\\"dma-contig\\\" class=\\\"fragment\\\"\\u003e\\u003c/span\\u003e\\u003ca href=\\\"#dma-contig\\\"\\u003e\\u003ci class=\\\"fa fa-link\\\"\\u003e\\u003c/i\\u003e\\u003c/a\\u003edma-contig\\u003c/h3\\u003e\\n\\u003cp data-sourcepos=\\\"64:1-64:561\\\"\\u003edma-contig は Scatter Gather に対応していない DMA を持つデバイスのためのメモリアロケータ−です。Scatter Gather に対応していないため、バッファは物理メモリ空間上に連続していなければなりません。dma-contig は Linux  Kernel の DMA Mapping API を使ってメモリを確保します。そして mmap も DMA Mapping API を使います。実は Linux Kernel の DMA Mapping API が提供する mmap は、Cache Cohe" <> ...
```


# Jasonとは
- Elixirで書けるJSONパーサ／ジェネレータ
- JSONの作成および後続の処理をするためにデータの形を加工する際に使用

# Jasonの導入方法
公式ドキュメント

https://hexdocs.pm/jason/readme.html

下記から画像の通りコピーでもいけます。

https://hex.pm/packages/jason

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677280/9c232e5b-4e31-bf54-50e1-6b5cffe73d9e.png)



mix.exsに書き込んで、`mix deps.get`します。
```diff_elixir:mix.exs
defp deps do
    [
      # {:dep_from_hexpm, "~> 0.3.0"},
      # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
-       {:httpoison, "~> 2.2"}
+       {:httpoison, "~> 2.2"},
+       {:jason, "~> 1.4"}
    ]
  end
```

```bash:bash
mix deps.get
```

# 関数を追加
Mixプロジェクト内の関数のパイプに`Jason.decode!/2`を追加します
```diff_elixir:lib/get_qiita_articles.ex
   def index do
     "https://qiita.com/api/v2/items?query=elixir"
     |> HTTPoison.get!()
     |> Map.get(:body)
+    |> Jason.decode!()
   end
```

# 使ってみた
iexを起動します
```bash:bash
iex -S mix
```
iex上で追加した関数を使用します
```diff_elixir:iex
GetQiitaArticles.index
```
下記のレスポンスが返ってきました
```diff_elixir:iex
[
  %{
    "body" => "\n\n\n\n\n\n# はじめに\n\n\nV4L2 のストリーミングI/O(V4L2_MEMORY_MMAP) はV4L2 ストリーミング I/O の方式の一つで、V4L2 ドライバ内(カーネル内)で確保した V4L2 バッファを mmap 機構を使ってユーザー空間にマッピングすることで、ユーザープログラムが V4L2 バッファにアクセスできるようにします。V4L2バッファをユーザー空間から直接アクセス出来るため、この方式は比較的よく使われます。\n\n\n\nしかし、ある種の V4L2 ドライバでは、mmap でユーザー空間にマッピングする際にキャッシュがオフになってしまってメモリアクセスが非常に遅くなり性能が出ない問題がありました。\n\nこの問題を起こす V4L2 ドライバの一つとして、Xilinx の Video DMA があります。\n\n\n\nこの記事では、そのメカニズムを説明します。\n\n\n\nなお、この記事は、以前投稿した次記事の改訂版です。\n\n* [『V4L2 ストリーミングI/O(V4L2_MEMORY_MMAP) で性能が出ない問題)』 @Qiita](https://qiita.com/ikwzm/items/8f1c98efe6fd4ae2490a)\n\n\n\n\n\n\n# キャッシュがオフになるメカニズム\n\n\n\n## V4L2 バッファのメモリアロケータ−\n\n\nV4L2 バッファのメモリアロケータ−には次の３種類があります。\n\n  * vmalloc\t\t\t: DMA を伴わない V4L2 ドライバ用\n  * dma-sg\t\t\t: Scatter Gather に対応した DMA デバイス用\n  * dma-contig\t: Scatter Gather に対応していない DMA デバイス用\n\nこのうち、問題となるのは最後の dma-contig です。\n\n\n### vmalloc\n\n\nvmalloc はDMAを伴わない V4L2 ドライバのためのメモリアロケータ−です。例えば、USB Camera のV4L2 ドライバがこれにあたります。USB の場合は USB のデバイスドライバが USB デバイスとのデータ転送を行い、V4L2 ドライバ自体は直接 USB デバイスとのデータ転送を行いません。そのため、カーネルが普通に使っている vmalloc を使ってメモリを確保します。\n\n\n### dma-sg\n\n\ndma-sg は Scatter Gather に対応した DMA を持つデバイスのためのメモリアロケータ−です。Scatter Gather に対応しているため、バッファが物理メモリ空間上に連続していなくても DMA 転送が可能です。 dma-sg は Linux Kernel の DMA Mapping API を使ってメモリを確保します。しかし、mmap は DMA Mapping API を使っていません。\n\n\n### dma-contig\n\n\ndma-contig は Scatter Gather に対応していない DMA を持つデバイスのためのメモリアロケータ−です。Scatter Gather に対応していないため、バッファは物理メモリ空間上に連続していなければなりません。dma-contig は Linux  Kernel の DMA Mapping API を使ってメモリを確保します。そして mmap も DMA Mapping API を使います。実は Linux Kernel の DMA Mapping API が提供する mmap は、Cache Coherence Hardware を持っていないと CPU Cache が無効になります。\n\nしたがって、この dma-contig を採用した V4L2 ドライバでV4L2_MEMORY_MMAP を使うと、Cache Coherence Hardware を持っていない場合は CPU Cache が無効になります。\n\n\n## dma-contig の mmap\n\n\ndma-contig の mmap は次のようになっています。\n\n\n```C:https://elixir.bootlin.com/linux/v6.1.97/source/drivers/media/common/videobuf2/videobuf2-dma-contig.c\nstatic int vb2_dc_mmap(void *buf_priv, struct vm_area_struct *vma)\n{\n\tstruct vb2_dc_buf *buf = buf_priv;\n\tint ret;\n\tif (!buf) {\n\t\tprintk(KERN_ERR \"No buffer to map\\n\");\n\t\treturn -EINVAL;\n\t}\n\tif (buf->non_coherent_mem)\n\t\tret = dma_mmap_noncontiguous(buf->dev, vma, buf->size,\n\t\t\t\t\t     buf->dma_sgt);\n\telse\n\t\tret = dma_mmap_attrs(buf->dev, vma, buf->cookie, buf->dma_addr,\n\t\t\t\t     buf->size, buf->attrs);\n\tif (ret) {\n\t\tpr_err(\"Remapping memory failed, error: %d\\n\", ret);\n\t\treturn ret;\n\t}\n\tvma->vm_flags\t\t|= VM_DONTEXPAND | VM_DONTDUMP;\n\tvma->vm_private_data\t= &buf->handler;\n\tvma->vm_ops\t\t= &vb2_common_vm_ops;\n\tvma->vm_ops->open(vma);\n\tpr_debug(\"%s: mapped dma addr 0x%08lx at 0x%08lx, size %lu\\n\",\n\t\t __func__, (unsigned long)buf->dma_addr, vma->vm_start,\n\t\t buf->size);\n\treturn 0;\n}\n```\n\n\n実際に mmap を行うのはLinux Kernel  の DMA Mapping API で提供される dma_mmap_attrs() です。なお、non_coherent_mem の場合は dma_mmap_noncontiguous() が呼ばれていますが、これは別の DMA Buffer をImport した時に使われるものなので、ここでは説明しません。\n\n\n\nLinux Kernel 5.0 以降の DMA Mapping API は dma-direct という実装が使われています。この dma-direct の説明と、CPU Cache が無効になるメカニズムについては、次の記事を参照してください。\n\n  * [『Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある (Linux Kernel の Cache 問題の扱い)』 @Qiita](https://qiita.com/ikwzm/items/f32985890b2013ef5528)\n  * [『Linux では Cache Coherence Hardware を持っていないとDMA Buffer をmmap する際に CPU Cache が無効になる』 @Qiita](https://qiita.com/ikwzm/items/0f77072158ce842018fc)\n\n\n\n結論だけを述べると、dma-contig の mmap は、Cache Coherence Hardware を持っていないと CPU Cache が無効になります。\n\n\n# 対処方法\n\n\n~~こちらに udmabuf を使って対処する方法を投稿しました。~~(2024年改定 この記事の内容は古くて現在は使えません。現在、dma-heap を使った対処方法を執筆中)\n\n* [「Linuxでユーザー空間で動作するプログラムとハードウェアがメモリを共有するためのデバイスドライバ(V4L2_MEMORY_USERPTR編)」@Qiita](https://qiita.com/ikwzm/items/c81e8b749576300fceee)\n\n\n\n\n\n\n# 参考\n\n\n\n## 「V4l2 V4L2_MEMORY_USERPTR:contiguous mapping is too small 4096/1228800」\n\n\nXilinx のフォーラムに次のスレッドがありました。\n\n\n\n* 「V4l2 V4L2_MEMORY_USERPTR:contiguous mapping is too small 4096/1228800」   \nhttps://forums.xilinx.com/t5/Embedded-Linux/V4l2-V4L2-MEMORY-USERPTR-contiguous-mapping-is-too-small-4096/td-p/825067\n\n\n\nXilinx の VDMA を使ってキャプチャーしようとしたら mmap によるデータ転送が遅いので、mmap の代わりにユーザー空間にバッファを確保して、それをV4L2 ドライバに渡したら、今度は連続した空間が小さすぎてエラーになったという話です。\n\nこれは考えてみれば当たり前な話で、Xilinx の VDMA は Scatter Gather に対応していないのでバッファは連続したメモリ空間になければなりません。\n\n\n\n" <> ...,
    "coediting" => false,
    "comments_count" => 0,
    "created_at" => "2024-08-22T12:09:23+09:00",
    "group" => nil,
    "id" => "474ababbc99cb4812bc7",
    "likes_count" => 0,
    "organization_url_name" => nil,
    "page_views_count" => nil,
    "private" => false,
    "reactions_count" => 0,
    "rendered_body" => "<h1 data-sourcepos=\"7:1-7:14\">\n<span id=\"はじめに\" class=\"fragment\"></span><a href=\"#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB\"><i class=\"fa fa-link\"></i></a>はじめに</h1>\n<p data-sourcepos=\"10:1-10:480\">V4L2 のストリーミングI/O(V4L2_MEMORY_MMAP) はV4L2 ストリーミング I/O の方式の一つで、V4L2 ドライバ内(カーネル内)で確保した V4L2 バッファを mmap 機構を使ってユーザー空間にマッピングすることで、ユーザープログラムが V4L2 バッファにアクセスできるようにします。V4L2バッファをユーザー空間から直接アクセス出来るため、この方式は比較的よく使われます。</p>\n<p data-sourcepos=\"14:1-14:245\">しかし、ある種の V4L2 ドライバでは、mmap でユーザー空間にマッピングする際にキャッシュがオフになってしまってメモリアクセスが非常に遅くなり性能が出ない問題がありました。</p>\n<p data-sourcepos=\"16:1-16:102\">この問題を起こす V4L2 ドライバの一つとして、Xilinx の Video DMA があります。</p>\n<p data-sourcepos=\"20:1-20:63\">この記事では、そのメカニズムを説明します。</p>\n<p data-sourcepos=\"24:1-24:75\">なお、この記事は、以前投稿した次記事の改訂版です。</p>\n<ul data-sourcepos=\"26:1-32:0\">\n<li data-sourcepos=\"26:1-32:0\"><a href=\"https://qiita.com/ikwzm/items/8f1c98efe6fd4ae2490a\" id=\"reference-48cf7bcf59237b3b354e\">『V4L2 ストリーミングI/O(V4L2_MEMORY_MMAP) で性能が出ない問題)』 @Qiita</a></li>\n</ul>\n<h1 data-sourcepos=\"33:1-33:50\">\n<span id=\"キャッシュがオフになるメカニズム\" class=\"fragment\"></span><a href=\"#%E3%82%AD%E3%83%A3%E3%83%83%E3%82%B7%E3%83%A5%E3%81%8C%E3%82%AA%E3%83%95%E3%81%AB%E3%81%AA%E3%82%8B%E3%83%A1%E3%82%AB%E3%83%8B%E3%82%BA%E3%83%A0\"><i class=\"fa fa-link\"></i></a>キャッシュがオフになるメカニズム</h1>\n<h2 data-sourcepos=\"37:1-37:50\">\n<span id=\"v4l2-バッファのメモリアロケータ\" class=\"fragment\"></span><a href=\"#v4l2-%E3%83%90%E3%83%83%E3%83%95%E3%82%A1%E3%81%AE%E3%83%A1%E3%83%A2%E3%83%AA%E3%82%A2%E3%83%AD%E3%82%B1%E3%83%BC%E3%82%BF\"><i class=\"fa fa-link\"></i></a>V4L2 バッファのメモリアロケータ−</h2>\n<p data-sourcepos=\"40:1-40:86\">V4L2 バッファのメモリアロケータ−には次の３種類があります。</p>\n<ul data-sourcepos=\"42:3-45:0\">\n<li data-sourcepos=\"42:3-42:56\">vmalloc\t\t\t: DMA を伴わない V4L2 ドライバ用</li>\n<li data-sourcepos=\"43:3-43:65\">dma-sg\t\t\t: Scatter Gather に対応した DMA デバイス用</li>\n<li data-sourcepos=\"44:3-45:0\">dma-contig\t: Scatter Gather に対応していない DMA デバイス用</li>\n</ul>\n<p data-sourcepos=\"46:1-46:66\">このうち、問題となるのは最後の dma-contig です。</p>\n<h3 data-sourcepos=\"49:1-49:11\">\n<span id=\"vmalloc\" class=\"fragment\"></span><a href=\"#vmalloc\"><i class=\"fa fa-link\"></i></a>vmalloc</h3>\n<p data-sourcepos=\"52:1-52:465\">vmalloc はDMAを伴わない V4L2 ドライバのためのメモリアロケータ−です。例えば、USB Camera のV4L2 ドライバがこれにあたります。USB の場合は USB のデバイスドライバが USB デバイスとのデータ転送を行い、V4L2 ドライバ自体は直接 USB デバイスとのデータ転送を行いません。そのため、カーネルが普通に使っている vmalloc を使ってメモリを確保します。</p>\n<h3 data-sourcepos=\"55:1-55:10\">\n<span id=\"dma-sg\" class=\"fragment\"></span><a href=\"#dma-sg\"><i class=\"fa fa-link\"></i></a>dma-sg</h3>\n<p data-sourcepos=\"58:1-58:409\">dma-sg は Scatter Gather に対応した DMA を持つデバイスのためのメモリアロケータ−です。Scatter Gather に対応しているため、バッファが物理メモリ空間上に連続していなくても DMA 転送が可能です。 dma-sg は Linux Kernel の DMA Mapping API を使ってメモリを確保します。しかし、mmap は DMA Mapping API を使っていません。</p>\n<h3 data-sourcepos=\"61:1-61:14\">\n<span id=\"dma-contig\" class=\"fragment\"></span><a href=\"#dma-contig\"><i class=\"fa fa-link\"></i></a>dma-contig</h3>\n<p data-sourcepos=\"64:1-64:561\">dma-contig は Scatter Gather に対応していない DMA を持つデバイスのためのメモリアロケータ−です。Scatter Gather に対応していないため、バッファは物理メモリ空間上に連続していなければなりません。dma-contig は Linux  Kernel の DMA Mapping API を使ってメモリを確保します。そして mmap も DMA Mapping API を使います。実は Linux Kernel の DMA Mapping API が提供する mmap は、Cache Coherence Hardware を持っていないと CPU Cache が無効になります。</p>\n<p data-sourcepos=\"66:1-66:197\">したがって、この dma-contig を採用した V4L2 ドライバでV4L2_MEMORY_MMAP を使うと、Cache Coherence Hardware を持っていない場合は CPU Cache が無効になります。</p>\n<h2 data-sourcepos=\"69:1-69:22\">\n<span id=\"dma-contig-の-mmap\" class=\"fragment\"></span><a href=\"#dma-contig-%E3%81%AE-mmap\"><i class=\"fa fa-link\"></i></a>dma-contig の mmap</h2>\n<p data-sourcepos=\"72:1-72:59\">dma-contig の mmap は次のようになっています。</p>\n<div class=\"code-frame\" data-lang=\"C\" data-sourcepos=\"75:1-103:3\">\n<div class=\"code-lang\"><span class=\"bold\">https://elixir.bootlin.com/linux/v6.1.97/source/drivers/media/common/videobuf2/videobuf2-dma-contig.c</span></div>\n<div class=\"highlight\"><pre><code><span class=\"k\">static</span> <span class=\"kt\">int</span> <span class=\"nf\">vb2_dc_mmap</span><span class=\"p\">(</span><span class=\"kt\">void</span> <span class=\"o\">*</span><span class=\"n\">buf_priv</span><span class=\"p\">,</span> <span class=\"k\">struct</span> <span " <> ...,
    "slide" => false,
    "stocks_count" => 0,
    "tags" => [
      %{"name" => "Linux", "versions" => []},
      %{"name" => "RaspberryPi", "versions" => []},
      %{"name" => "FPGA", "versions" => []},
      %{"name" => "xilinx", "versions" => []},
      %{"name" => "V4L2", "versions" => []}
    ],
    "team_membership" => nil,
    "title" => "V4L2 ストリーミングI/O(V4L2_MEMORY_MMAP) で性能が出ない問題 (2024年改訂版)",
    "updated_at" => "2024-08-22T12:20:22+09:00",
    "url" => "https://qiita.com/ikwzm/items/474ababbc99cb4812bc7",
    "user" => %{
      "description" => "元へっぽこ電子回路エンジニア。現在隠居中。どちらかというとVHDL派。最近はFPGA+SoC でいろいろやってます。github でもいろいろと公開してます。\r\nhttps://github.com/ikwzm",
      "facebook_id" => "",
      "followees_count" => 50,
      "followers_count" => 205,
      "github_login_name" => "ikwzm",
      "id" => "ikwzm",
      "items_count" => 245,
      "linkedin_id" => "",
      "location" => "横浜",
      "name" => "",
      "organization" => "隠居",
      "permanent_id" => 24981,
      "profile_image_url" => "https://qiita-image-store.s3.amazonaws.com/0/24981/profile-images/1473684232",
      "team_only" => false,
      "twitter_screen_name" => "ikwzm",
      "website_url" => ""
    }
  },
  %{
    "body" => "こんにちは！\nプログラミング未経験文系出身、Elixirの国に迷い込んだ？！見習いアルケミストのaliceと申します。\n今回はHTTPoison.get!/3を使ってみて学んだことをまとめます。\n\n# 目的\nHTTPoison.get!/3の使いどころ、導入方法の紹介。\n\n## 実行環境\nWindows 11 ＋ WSL2 ＋ Ubuntu 22.04\nElixir v1.17.0\nErlang v27.0\n\n# 前提\n## Qiita APIのアクセストークンを取得\n下記の記事を参考にQiita APIの`read_qiita`アクセストークンを取得しておきます\n\nhttps://qiita.com/koki_develop/items/57f86a1abc332ed2185d#%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%83%88%E3%83%BC%E3%82%AF%E3%83%B3%E3%82%92%E7%99%BA%E8%A1%8C%E3%81%99%E3%82%8B\n\n## `get_qiita_articles`という名前でmixプロジェクトを作成\n```bash:bash\nmix new get_qiita_articles\ncd get_qiita_articles\n```\n\n\n# HTTPoisonとは\n- Elixirで書けるHTTPクライアントのライブラリ(curl, POSTman, Talented API tester等と同じ)\n- (パイプで書いた処理等を)APIリクエストするときや、HTTPレスポンスを分析する際に使用する\n\n# HTTPoisonの導入方法\n公式ドキュメント\n\nhttps://hexdocs.pm/httpoison/readme.html\n\n下記から画像の通りコピーでもいけます。\n\nhttps://hex.pm/packages/httpoison\n\n![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677280/1dab6524-8411-a41a-73cb-92b3b456f5d0.png)\n\n\nmix.exsに書き込んで、`mix deps.get`します。\n```diff_elixir:mix.exs\ndefp deps do\n    [\n      # {:dep_from_hexpm, \"~> 0.3.0\"},\n      # {:dep_from_git, git: \"https://github.com/elixir-lang/my_dep.git\", tag: \"0.1.0\"}\n+       {:httpoison, \"~> 2.2\"}\n    ]\n  end\n```\n\n```bash:bash\nmix deps.get\n```\n\n# 関数を追加\nMixプロジェクト内に関数を追加します。\n今回はQiitaの記事一覧から\"Elixir\"で検索をかけたときの結果一覧を取得します[^1]\n```diff_elixir:lib/get_qiita_articles.ex\n+   def index do\n+     \"https://qiita.com/api/v2/items?query=elixir\"\n+     |> HTTPoison.get!()\n+   end\n```\n\n# 使ってみた\niexを起動します\n```bash:bash\niex -S mix\n```\niex上で追加した関数を使用します\n```diff_elixir:iex\nGetQiitaArticles.index\n```\n下記のレスポンスが返ってきました\n```diff_elixir:iex\n%HTTPoison.Response{\n  status_code: 200,\n  body: \"[{\\\"rendered_body\\\":\\\"\\\\u003cp data-sourcepos=\\\\\\\"1:1-2:83\\\\\\\"\\\\u003e\\\\u003cb\\\\u003e\\\\u003cfont color=\\\\\\\"red\\\\\\\"\\\\u003e$\\\\\\\\huge{元氣ですかーーーーッ！！！}$\\\\u003c/font\\\\u003e\\\\u003c/b\\\\u003e\\\\u003cbr\\\\u003e\\\\n\\\\u003cb\\\\u003e\\\\u003cfont color=\\\\\\\"red\\\\\\\"\\\\u003e$\\\\\\\\huge{元氣があればなんでもできる！}$\\\\u003c/font\\\\u003e\\\\u003c/b\\\\u003e\\\\u003c/p\\\\u003e\\\\n\\\\u003cp data-sourcepos=\\\\\\\"4:1-6:65\\\\\\\"\\\\u003e\\\\u003cb\\\\u003e\\\\u003cfont color=\\\\\\\"red\\\\\\\"\\\\u003e$\\\\\\\\huge{闘魂とは己に打ち克つこと。}$\\\\u003c/font\\\\u003e\\\\u003c/b\\\\u003e\\\\u003cbr\\\\u003e\\\\n\\\\u003cb\\\\u003e\\\\u003cfont color=\\\\\\\"red\\\\\\\"\\\\u003e$\\\\\\\\huge{そして闘いを通じて己の魂を磨いていく}$\\\\u003c/font\\\\u003e\\\\u003c/b\\\\u003e\\\\u003cbr\\\\u003e\\\\n\\\\u003cb\\\\u003e\\\\u003cfont color=\\\\\\\"red\\\\\\\"\\\\u003e$\\\\\\\\huge{ことだと思います}$\\\\u003c/font\\\\u003e\\\\u003c/b\\\\u003e\\\\u003c/p\\\\u003e\\\\n\\\\u003cp data-sourcepos=\\\\\\\"10:1-10:54\\\\\\\"\\\\u003e\\\\u003ciframe id=\\\\\\\"qiita-embed-content__36bd8d82e2a87f7b2f71ee773a7348ae\\\\\\\" src=\\\\\\\"https://qiita.com/embed-contents/link-card#qiita-embed-content__36bd8d82e2a87f7b2f71ee773a7348ae\\\\\\\" data-content=\\\\\\\"https%3A%2F%2Fqiita.com%2Fofficial-events%2F9ab96aa95d62fe3cbdd7\\\\\\\" frameborder=\\\\\\\"0\\\\\\\" scrolling=\\\\\\\"no\\\\\\\" loading=\\\\\\\"lazy\\\\\\\" style=\\\\\\\"width:100%;\\\\\\\" height=\\\\\\\"29\\\\\\\"\\\\u003e\\\\n\\\\u003c/iframe\\\\u003e\\\\n\\\\u003c/p\\\\u003e\\\\n\\\\u003ch1 data-sourcepos=\\\\\\\"12:1-12:14\\\\\\\"\\\\u003e\\\\n\\\\u003cspan id=\\\\\\\"はじめに\\\\\\\" class=\\\\\\\"fragment\\\\\\\"\\\\u003e\\\\u003c/span\\\\u003e\\\\u003ca href=\\\\\\\"#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB\\\\\\\"\\\\u003e\\\\u003ci class=\\\\\\\"fa fa-link\\\\\\\"\\\\u003e\\\\u003c/i\\\\u003e\\\\u003c/a\\\\u003eはじめに\\\\u003c/h1\\\\u003e\\\\n\\\\u003cp data-sourcepos=\\\\\\\"14:1-14:238\\\\\\\"\\\\u003e本記事は、「\\\\u003ca href=\\\\\\\"https://qiita.com/official-events/9ab96aa95d62fe3cbdd7\\\\\\\"\\\\u003epaiza×Qiita記事投稿キャンペーン「プログラミング問題をやってみて書いたコードを投稿しよう！」\\\\u003c/a\\\\u003e」イベント記事です。\\\\u003c/p\\\\u003e\\\\n\\\\u003cp data-sourcepos=\\\\\\\"16:1-16:67\\\\\\\"\\\\u003e私は\\\\u003ca href=\\\\\\\"https://elixir-lang.org/\\\\\\\" rel=\\\\\\\"nofollow noopener\\\\\\\" target=\\\\\\\"_blank\\\\\\\"\\\\u003eElixir\\\\u003c/a\\\\u003eで楽しんでみます。\\\\u003c/p\\\\u003e\\\\n\\\\u003cp data-sourcepos=\\\\\\\"18:1-18:31\\\\\\\"\\\\u003eC問題をやってみます。\\\\u003c/p\\\\u003e\\\\n\\\\u003ch1 data-sourcepos=\\\\\\\"20:1-20:23\\\\\\\"\\\\u003e\\\\n\\\\u003cspan id=\\\\\\\"参考にした記事\\\\\\\" class=\\\\\\\"fragment\\\\\\\"\\\\u003e\\\\u003c/span\\\\u003e\\\\u003ca href=\\\\\\\"#%E5%8F%82%E8%80%83%E3%81%AB%E3%81%97%E3%81%9F%E8%A8%98%E4%BA%8B\\\\\\\"\\\\u003e\\\\u003ci class=\\\\\\\"fa fa-link\\\\\\\"\\\\u003e\\\\u003c/i\\\\u003e\\\\u003c/a\\\\u003e参考にした記事\\\\u003c/h1\\\\u003e\\\\n\\\\u003cp data-sourcepos=\\\\\\\"22:1-22:58\\\\\\\"\\\\u003e\\\\" <> ...,
    "coediting" => false,
    "comments_count" => 0,
    "created_at" => "2024-08-21T19:25:46+09:00",
    "group" => nil,
    "id" => "786c10e573d3f47a8fae",
    "likes_count" => 1,
    "organization_url_name" => "fukuokaex",
    "page_views_count" => nil,
    "private" => false,
    "reactions_count" => 0,
    "rendered_body" => "<p data-sourcepos=\"1:1-3:79\">こんにちは！<br>\nプログラミング未経験文系出身、Elixirの国に迷い込んだ？！見習いアルケミストのaliceと申します。<br>\n今回はHTTPoison.get!/3を使ってみて学んだことをまとめます。</p>\n<h1 data-sourcepos=\"5:1-5:8\">\n<span id=\"目的\" class=\"fragment\"></span><a href=\"#%E7%9B%AE%E7%9A%84\"><i class=\"fa fa-link\"></i></a>目的</h1>\n<p data-sourcepos=\"6:1-6:61\">HTTPoison.get!/3の使いどころ、導入方法の紹介。</p>\n<h2 data-sourcepos=\"8:1-8:15\">\n<span id=\"実行環境\" class=\"fragment\"></span><a href=\"#%E5%AE%9F%E8%A1%8C%E7%92%B0%E5%A2%83\"><i class=\"fa fa-link\"></i></a>実行環境</h2>\n<p data-sourcepos=\"9:1-11:12\">Windows 11 ＋ WSL2 ＋ Ubuntu 22.04<br>\nElixir v1.17.0<br>\nErlang v27.0</p>\n<h1 data-sourcepos=\"13:1-13:8\">\n<span id=\"前提\" class=\"fragment\"></span><a href=\"#%E5%89%8D%E6%8F%90\"><i class=\"fa fa-link\"></i></a>前提</h1>\n<h2 data-sourcepos=\"14:1-14:48\">\n<span id=\"qiita-apiのアクセストークンを取得\" class=\"fragment\"></span><a href=\"#qiita-api%E3%81%AE%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%83%88%E3%83%BC%E3%82%AF%E3%83%B3%E3%82%92%E5%8F%96%E5%BE%97\"><i class=\"fa fa-link\"></i></a>Qiita APIのアクセストークンを取得</h2>\n<p data-sourcepos=\"15:1-15:102\">下記の記事を参考にQiita APIの<code>read_qiita</code>アクセストークンを取得しておきます</p>\n<p data-sourcepos=\"17:1-17:175\"><iframe id=\"qiita-embed-content__4301bc50c94a03adfccd349cda4d5620\" src=\"https://qiita.com/embed-contents/link-card#qiita-embed-content__4301bc50c94a03adfccd349cda4d5620\" data-content=\"https%3A%2F%2Fqiita.com%2Fkoki_develop%2Fitems%2F57f86a1abc332ed2185d%23%25E3%2582%25A2%25E3%2582%25AF%25E3%2582%25BB%25E3%2582%25B9%25E3%2583%2588%25E3%2583%25BC%25E3%2582%25AF%25E3%2583%25B3%25E3%2582%2592%25E7%2599%25BA%25E8%25A1%258C%25E3%2581%2599%25E3%2582%258B\" frameborder=\"0\" scrolling=\"no\" loading=\"lazy\" style=\"width:100%;\" height=\"29\">\n</iframe>\n</p>\n<h2 data-sourcepos=\"19:1-19:71\">\n<span id=\"get_qiita_articlesという名前でmixプロジェクトを作成\" class=\"fragment\"></span><a href=\"#get_qiita_articles%E3%81%A8%E3%81%84%E3%81%86%E5%90%8D%E5%89%8D%E3%81%A7mix%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%82%92%E4%BD%9C%E6%88%90\"><i class=\"fa fa-link\"></i></a><code>get_qiita_articles</code>という名前でmixプロジェクトを作成</h2>\n<div class=\"code-frame\" data-lang=\"bash\" data-sourcepos=\"20:1-23:3\">\n<div class=\"code-lang\"><span class=\"bold\">bash</span></div>\n<div class=\"highlight\"><pre><code>mix new get_qiita_articles\n<span class=\"nb\">cd </span>get_qiita_articles\n</code></pre></div>\n</div>\n<h1 data-sourcepos=\"26:1-26:17\">\n<span id=\"httpoisonとは\" class=\"fragment\"></span><a href=\"#httpoison%E3%81%A8%E3%81%AF\"><i class=\"fa fa-link\"></i></a>HTTPoisonとは</h1>\n<ul data-sourcepos=\"27:1-29:0\">\n<li data-sourcepos=\"27:1-27:108\">Elixirで書けるHTTPクライアントのライブラリ(curl, POSTman, Talented API tester等と同じ)</li>\n<li data-sourcepos=\"28:1-29:0\">(パイプで書いた処理等を)APIリクエストするときや、HTTPレスポンスを分析する際に使用する</li>\n</ul>\n<h1 data-sourcepos=\"30:1-30:26\">\n<span id=\"httpoisonの導入方法\" class=\"fragment\"></span><a href=\"#httpoison%E3%81%AE%E5%B0%8E%E5%85%A5%E6%96%B9%E6%B3%95\"><i class=\"fa fa-link\"></i></a>HTTPoisonの導入方法</h1>\n<p data-sourcepos=\"31:1-31:24\">公式ドキュメント</p>\n<p data-sourcepos=\"33:1-33:40\"><iframe id=\"qiita-embed-content__ea9a1d2e633e1928eed3a2d694bebe6d\" src=\"https://qiita.com/embed-contents/link-card#qiita-embed-content__ea9a1d2e633e1928eed3a2d694bebe6d\" data-content=\"https%3A%2F%2Fhexdocs.pm%2Fhttpoison%2Freadme.html\" frameborder=\"0\" scrolling=\"no\" loading=\"lazy\" style=\"width:100%;\" height=\"29\">\n</iframe>\n</p>\n<p data-sourcepos=\"35:1-35:57\">下記から画像の通りコピーでもいけます。</p>\n<p data-sourcepos=\"37:1-37:33\"><iframe id=\"qiita-embed-content__de4f76a38ab89ecbce8582eb9d6dbaf1\" src=\"https://qiita.com/embed-contents/link-card#qiita-embed-content__de4f76a38ab89ecbce8582eb9d6dbaf1\" data-content=\"https%3A%2F%2Fhex.pm%2Fpackages%2Fhttpoison\" frameborder=\"0\" scrolling=\"no\" loading=\"lazy\" style=\"width:100%;\" height=\"29\">\n</iframe>\n</p>\n<p data-sourcepos=\"39:1-39:121\"><a href=\"https://camo.qiitausercontent.com/872e8ce5fd574e0defed46f109d405d64bd8a4af/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3637373238302f31646162363532342d383431312d613431612d373363622d3932623362343536663564302e706e67\" target=\"_blank\" rel=\"nofollow noopener\"><img s" <> ...,
    "slide" => false,
    "stocks_count" => 0,
    "tags" => [
      %{"name" => "API", "versions" => []},
      %{"name" => "HTTP", "versions" => []},
      %{"name" => "初心者", "versions" => []},
      %{"name" => "Elixir", "versions" => []}
    ],
    "team_membership" => nil,
    "title" => "HTTPoison.get!の紹介",
    "updated_at" => "2024-08-21T19:25:46+09:00",
    "url" => "https://qiita.com/Alicesky2127/items/786c10e573d3f47a8fae",
    "user" => %{
      "description" => "StartupWeekendで逃げ癖だけは改善したと思いたい人間です。\r\nプログラミングはほぼ未経験の見習いアルケミスト。\r\n\r\n※移行中のためご迷惑をおかけしております。移行前の記事はnoteから読めます。",
      "facebook_id" => "",
      "followees_count" => 40,
      "followers_count" => 23,
      "github_login_name" => "Alice2127",
      "id" => "Alicesky2127",
      "items_count" => 63,
      "linkedin_id" => "",
      "location" => "",
      "name" => "alicesky 2127",
      "organization" => "",
      "permanent_id" => 677280,
      "profile_image_url" => "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677280/profile-images/1650540703",
      "team_only" => false,
      "twitter_screen_name" => "Alicesky2127",
      "website_url" => "https://note.com/alicesky2127"
    }
  },
  ...(長いので以下略)
]
```


`Jason.decode!`を使用して取得したbodyを見やすく整形することができました(^▽^)/

# ～Elixirの国のご案内～
↓Elixirって何ぞや？と思ったらこちらもどぞ。Elixirは先端のアレコレをだいたい全部できちゃいます:laughing::sparkles::sparkles:

https://qiita.com/piacerex/items/09876caa1e17169ec5e1

↓ゼロからElixirを始めるなら「エリクサーチ」がおすすめ！私もエンジニア未経験から学習中です。

https://elixir-lang.info/topics/entry_column


↓[We Are The Alchemists, my friends!:bouquet:](https://qiita.com/torifukukaiou/items/6bcd5bbb80df9e594e9e "Awesome-san's Awesome article")[^10]
Elixirコミュニティは本当に優しくて温かい人たちばかり！
私が挫折せずにいられるのもこの恵まれた環境のおかげです。
まずは気軽にコミュニティを訪れてみてください。[^11]


https://speakerdeck.com/elijo/elixirkomiyunitei-falsebu-kifang-guo-nei-onrainbian



[^10]: @torifukukaiouさんのAwesomeな名言をお借りしました。Elixirコミュニティを一言で表すと、これに尽きます。


[^11]: @kn339264さんの素敵なスライドをお借りしました。Elixirコミュニティはいろんな形で活動中！