備忘録

何かあったとき用に

Kubernetes 上に code-server を構築

TL;DR

  • 自宅鯖の Kubernetes (シングルノード) 上に code-server をデプロイした
  • Ingress (nginx-ingress-controller) を使用して外部からもアクセスできるように
  • 外部アクセスでコンテナ <-> ホスト間のファイルの編集が可能になった

環境

  • Host OS: Gentoo Linux (5.15.26-gentoo)
  • Kubernetes Engine: RKE2 v1.22.7-rke2r2
  • Helm: v3.8.0
  • code-server: v4.2.0
  • nginx-ingress-controller は RKE2 にてすでにデプロイされているので, それを使用.
    • 別の k8s engine 使う場合はデプロイは必要になるかもしれません.

ディレクトリ構造

(一部省略してます)

. (/home/kash)
├── manifests
│   ├── code-server
│   │   ├── helm-charts
...

code-server では, ~/manifests 以下を編集できるようになっています. また, code-server/helm-charts については後述します.

内容

code-server デプロイまで

ここは code-server に載ってる Helm でのインストール方法*1 を少し変えたものとなります. また, home という namespace で今回はデプロイしています.

$ git clone https://github.com/coder/code-server
$ mv code-server/ci/helm-chart ./manifests
$ cd manifests

code-server の chart を一部変更するために以下の YAML ファイルを作成 (overwrite.yaml):

ingress:
  enabled: true
  ingressClassName: "nginx"
  hosts:
    - host: <ホスト名>
      paths:
        - /

resources:
  requests:
    cpu: 100m
    memory: 1000Mi

extraVolumeMounts:
  - name: manifests
    mountPath: /k8s/manifests
    existingClaim: code-server-manifests

上記の YAML ファイルでは, Ingress の有効化及びホストやパスの設定, リソースの requests の決定, 追加でマウントする Volume (~/manifests) を指定しています.

code-server の chart は実質完成したので, 次に, PersistentVolume, PersistentVolumeClaim のマニフェストを作成します.

pv.yaml:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: code-server
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
parameters:
  type: pd-standard
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: code-server
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  storageClassName: code-server
  claimRef:
    name: code-server
    namespace: home
  hostPath:
    path: "/k8s_mnt/code-server"
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: code-server-manifests
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  storageClassName: code-server
  claimRef:
    name: code-server-manifests
    namespace: home
  hostPath:
    path: "/k8s_mnt/code-server-manifests"

StorageClass では, 特に動的プロビジョンするわけではないので, provisionerkubernetes.io/no-provisioner を指定し, parameters.typeSSD というわけではないので pd-standard です. PersistentVolume では, デフォルトと Volume と追加の Volume が必要なので二つの PersistentVolume を作成しています. claimRefhome/code-serverhome/code-server-manifests という形で Claim できるようにしています. hostPath では, /k8s_mnt/ 上でマウントできるようにしています.

pvc.yaml:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: code-server-manifests
  namespace: home
  labels:
    app.kubernetes.io/name: code-server-manifests
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: "code-server"

PersistentVolumeClaim において, home/code-server はデフォルトの chart で定義されるので, home/code-server-manifests のみの PersistentVolumeClaim の作成となります. ここは特に言うことはないです.

以上が完了したら,

$ kubectl apply -f pv.yaml -f pvc.yaml

で, PersistentVolume, PersistentVolumeClaim を作成します. そのあと,

$ helm upgrade --install code-server helm-chart -f overwrite.yaml

で, code-server をデプロイ. パスワードの表示のコマンドが出るので, 打って出力をメモします.

公開

$ kubectl describe ingress -n home code-server

にて, Backend の ClusterIP が降られていることが確認できたら公開できるので, 指定したホスト名を自宅鯖に向けることで公開が完了し, ホスト名で code-server にアクセスできます. ログインには, 先ほどのパスワードが必要なのでそれでログインできます.

自宅環境のお話

この記事は, TUT Advent Calendar 2021 の 1 日目の記事です.
知らぬ間に 12 月入ろうとしていて焦りました.

前置き

なんか作ろうかなと思ったけど, 研究がとにかく忙しかったため自宅環境のお話にします.
研究のお話は近々話したいですね.

自身の自宅環境

PC 環境

自身の PC 周りの環境は以下の環境があります:

デスクトップ環境

2020 年 10 月ぐらいに自作.
基本的にゲームやら 3D 処理など重い処理を動かすのに使っています. 最近は FF14 ばっかりですが…

スペック:

  • CPU: Ryzen 7 3700X
  • CPU クーラー: Noctua NH-U12A
  • メモリ: 16GB * 4 (Corsair VENGEANCE LPX Series/CMK32GX4M2A2666C16)
  • SSD:
  • GPU: ASUS GeForce RTX 3070 Noctua Edition*2
  • マザーボード: ASUS ROG STRIX B550-F GAMING (WI-FI)
  • 電源: Seasonic FOCUS+ 750W
  • ケース: Define 7 Clear Tempered Glass
Macbook Pro 13inch 2020 年モデル

2020 年 5 月購入.

16GB メモリ, 1TB メモリ, CPU を i7 にしてます. M1 Mac も魅力的だったけど x86_64 環境がまだまだ現役なので…
常に持ち歩いています.

Dynabook

大学入学時に購入したもの. Windows 消し飛ばして Ubuntu 18.04 ぶち込んだやつです. 現在は, Ubuntu 20.04 になっております.
こちらも常に持ち歩いていますが, 最近は使いどころが少なくなり出番も減り気味…TeX 環境があるのでレポート作成時には役立っております.

ThinkPad X240

2020 年 9 月ぐらいに知り合いから安く譲ってもらったもの.
Arch Linux をぶち込んでおりますが, あんまり使っておらず…pacman -Syuu したら多分ぶっ壊れそう.

サーバ環境

自宅にあるサーバは現在, HP Z240 Workstation に Gentoo Linux をぶち込んだものを使っています. パッケージをアップデートするときは emerge --sync しましょう.
本格的な稼働はまだ行っておりませんが, いつかしたいところですね.

多分いつかサーバは増える予定.

ネットワーク環境

自宅で以下の機器を使ったネットワークを構築しています. (ネットワーク図は時間の都合上作れてないです…申し訳ないです)

YAMAHA RTX830

2021 年 3 月末購入.

自宅ネットワークを構築したいという意気込みから購入. 今では自宅の中核を担っております. IPoE と PPPoE のネットワークを VLAN で分離していい感じです.

ちなみに, このネットワーク構成するためにプロバイダ変えたりと色々と苦労しました.

Allied Telesis AT-x210-24GT

2021 年 7 月ぐらいに購入.

ルータで分離した IPoE と PPPoE ネットワークを巡らせるために.
24 ポートもあるので中々迫力があります.

Aruba AP-225

2021 年 8 月ぐらいに購入.

Wi-Fi のアクセスポイントとして役立っております.

そのほか

キーボードに HHKB 使ったり, 自作キーボードを作ったり色々とやっています.
サーバにも NIC つけたりなども行っています.

最後に

なんか気付いたら 11 月終わっててこれ投稿する時間も遅くなってしまって出だしからちょっと怪しい雰囲気なのはすみません…
あと, 記事内容もなんかやばいことになっているしいきなりハードル上げた感が半端ない気がする.

脚注

*1:買った少し後ぐらいに 2k ぐらい安くなって 980 Pro も発売されたのでちょっとつらみ

*2:RTX2060 Super から買い替え, Noctua 好きなので…ちなみに 13 万ぐらいしました

はてなリモートインターンシップ 2021 に参加してきました!

久しぶりの長文なので文章が変かもしれませんが, そこはご了承ください><

背景

大学 3 年になってそろそろインターンに参加しないとまずいなあ (本当は 2 年のうちに参加したかったが某ウイルスのせいでおじゃんになった) という気持ちになっており, 某スプレッドシートTwitter の FF 内の様子を見て, どのインターンに参加しようか悩んでました.
去年, 長い知り合いである id:SlashNephy さんが参加していたはてなインターンを思い出し, そのブログ記事を見て参加してみたいと思い, 今回のはてなインターンに応募しました.

参加までの流れ

毎年, はてなインターンの応募ではホームページ上で仕掛けを施しており, それを解いた者が応募資格を得る感じです. 今回の方式は, ページ上で Developer Tools を開き, Console で JavaScript の関数を叩くというシンプルなものでしたが, 中々面白い仕組みだなあと思いました.

選考では, 応募時に書いた GitHub などから始まり, そこから面接, 合格か不合格かが決まる感じでした.

面接

面接では, まず人事の方から軽い説明や質問を (何分か忘れましたが) 受けて, そのあと担当者の方 (私の場合は id:cockscomb さん) と面接する感じでした. 自分はインターン初応募で面接すらやったことないのでかなり緊張しましたが, 担当者さんとは技術的な話で盛り上がり, 面接というよりもむしろ技術談話みたいな話となっていて緊張感は終盤ほぼなくなっていました.

Docker の話やらコンテナの話やらしたり, こういうときはこうすればよいよねと話したり, 本当に面接か?みたいな感じでしたが, それだけでも受けた価値があったと感じております.

その翌日には, 合格通知が来ておりましたが, 何故か Gmail のプロモーション欄に入っており, 通知が来なかったため 3 週間ぐらい気づいていませんでした…本当に申し訳ございません…

参加決定後

参加決定後は, 事前交流会や歓迎会などを経て, はてなの貸与 PC や Slack や Discord, Scrapbox といった業務に必要なツールを使って講義や開発を行いました. 1 週目に講義 + 開発パート, 2, 3 週目に実際に配属されたチームでの開発を行いました. チーム開発では, 自分がシステムプラットフォーム部を第一希望に出していましたが, 実際にそこに配属されておりとても嬉しかったです.

事前交流会/歓迎会

事前交流会では, 今回参加するインターン生とはてな CTO などの方々とお酒を交わしながらレクリエーションをしたりお話をしたりして盛り上がりました.
1 日目にも歓迎会があり, そこでは互いの自己紹介などを行って, インターン生やはてなの方々と楽しんでました.

講義パート

講義パートでは, 様々な講義が行われておりました. 流石にすべての講義を列挙するのは自分の文章能力では厳しいので, いくつか印象が強かったものを列挙します.

Kubernetes 講義

Kubernetes (k8s) 講義では, id:masayosu さんが講義を行っていました.
内容としては, Kubernetes がどういう仕組みで動いているか詳しいところまで説明されており, なるほど~と思いましたが, 理解が追いつきませんでした. これに加えて, 実際に minikube を使って, ローカル環境で Kubernetes を動かし, 変更を取り込むといったことまでやりました. 特に印象的だったのが, ビルド時間の長さでした. 余裕で数分かかってほえ~と声が出ました.

フロントエンド講義

フロントエンド講義では, id:Pasta-K さんがフロントエンドに関して講義を行いました.
内容は現在の JavaScript の書き方や, TypeScript の話, そして JSX (React) の話がありました. 中身がとても濃く, 資料自体もとてもよくて, もし講義パートで薦めたいものはどれですか?と聞かれたらこのフロントエンド講義と答えるぐらい素晴らしいものでした.

AWS 講義

AWS 講義では, AWS の方が実際に講師として講義を行い, 開発パートで使ったサービスを用いて AWS にデプロイをするということを行いました.
自分自身, AWS を使うのは初めてであったことと, Microsoft Azure にて失敗した前科があるので, ちょっぴり不安でしたが最終的にデプロイまでたどり着いて感動しました.
苦労した点として, AWS の IAM の設定や ECRの設定でつまづいてパイプラインが落ちまくった点です. みんなしてパイプラインが通るか祈っていたのが印象的でした.

開発パート

開発パートでは, Kubernetes や gRPC を使ったマークダウンパーサの実装を行いました. 内容としては去年のとほぼ同じで, パーサ実装 -> 独自機能追加 or fetcher 作成のどちらかとなります. 実際に作業ログを Scrapbox 上で取って, 作業を行いました.
自分は両方やりましたが, fetcher 作成に関しては時間と AWS 講義で使ったコードを反映したせいでテストができなく完成までにはいきませんでした.
独自記法に関しては, 当初はカウンタ記法という訪れるごとにカウンタが増えるインターネット老人会が苦しむようなものを実装しようと思いましたが, 思った以上に難しいと思い, UUID 記法というものに変更しました.

以下が UUID 記法の結果です:

f:id:KashEight:20210903153654p:plain

実際のコードは https://github.com/KashEight/Hatena-Intern-2021-k8s にあります.

また, 5 日目の講評では自分の書いたコードがけっこう取り上げられていてうれしかったです.

チーム開発

2 週目からは配属されたチーム (システムプラットフォーム部) でメンターとともに開発を行いました. チームメンバーは私と id:heyhoe さんでメンターは id:nabeop さんと id:halfrack さんでした.

やったこと

流石に, 詳しいことは NDA の関係上言えませんが, 作ったものとしては, 社内で利用する踏み台サーバ*1をアプリケーションレベルで可視化し, SLI (Service Level Indicator) として利用できるようなシステムを構築しました. 目的として, 作成前の構成では AWS NLB の CloudWatch Metrics による Healthy Host Count を利用した SLI を利用していましたが, NLB は L4 機器であり分類が難しいこと, 接続しているユーザの挙動を直接見れていないという理由から内部, つまりアプリケーション側の情報を利用した SLI が必要ということとなりました.

今回作成する構成では踏み台サーバの sshd のログが CloudWatch Logs に保存されている状態なので, それを GCP の BigQuery に流して可視化し, SLI として使うという感じです. 最終的には以下のような構成となりました*2:

+------------------------------------------------------------------+ +---------------------------------------------------+
|AWS                                                               | |Google Cloud                                       |
|                                                                  | |                                                   |
|                                                                  | |                                                   |
|                                                                  | |                                                   |
|  +-----------------+    +---------------------+    +---------+   | |  +------------------------------+     +--------+  |
|  | CloudWatch Logs +--->|Kinesis Data Firehose+--->|S3 Bucket+---+-+->|BigQuery Data Transfer Service+---->|BigQuery|  |
|  +-----------------+    +-------+---^---------+    +---------+   | |  +------------------------------+     +--------+  |
|                                 |   |                            | |                                                   |
|                                 |   |                            | |                                                   |
|                                 |   |                            | |                                                   |
|                              +--v---+---+                        | |                                                   |
|                              |AWS Lambda|                        | |                                                   |
|                              +----------+                        | |                                                   |
|                                                                  | |                                                   |
+------------------------------------------------------------------+ +---------------------------------------------------+

これらを構成し, 最終的には一部を IaC 化するまでに至りました.

最後に BigQuery のデータを Google Data Portal を用いて可視化して SLI の形として持っていく感じにしました.

苦労したこと

苦労したこととして, 何を SLI にするかや, AWS, GCP の権限周りの設定, BigQuery の SQLスキーマの設定, Google Data Portal の扱い方などたくさんあります.
特に, Google Data Portal や BigQuery には大いに悩まされ, 半分ぐらいはこの設定に費やした気がします.
また, SLI にする要素を考えるときにこれらも大きく変化するため本当にこの部分は苦労しました.

その他

上記の講義や開発, チーム開発以外にも, はてなの方々と Among us をしたり, DJ/VJ をしたりして楽しみました.
こういったゲームや音楽をはてなの方々とやったり聞いたりする機会はまずないので, とても有意義なものでした.

まとめ

講義+開発パートでは, 実際に手を動かしたり, 詳しいことを聞いたりした非常にレベルの高いものでありました. また, チーム開発でも, 個人ではまずできないようなことをやらしていただき実際にそれを公開するということは私にとって貴重な経験でした.

自分は初めてインターンを受けた身ですが, はてなを選んで正解だったと思います. このようなレベルの高いインターンを用意できるという点で本当にはてなを選ぶ価値はとても高いと思いました!

追記 (2021/09/03 18:43) CTO 賞をいただきました!はてなの皆さんそしてインターン生もありがとうございました!最高の夏!

*1:AWS EC2 上に存在

*2:補足: この図は正確ではなく大雑把にこうなっているという感じです, 実際はもう少し分離されてたりします

React をさくっと使う (with parcel)

この記事は TUT Advent Calendar 2019 1 日目の記事です.
初日から遅刻しかけてるの大丈夫か?

やりたいこと

create-react-app だと色々機能が多いので, さくっとかつすぐ React を触れるような構成を作る.
React プロジェクトに parcel を使用して bundle するだけ.
package 導入には yarn 使ってます. npm の方は適宜読み替えてください.

環境

  • Node.js: v12.13.1
  • yarn: 1.19.2
  • react/react-dom: 16.12.0
  • parcel-bundler: 1.12.4

手順

必要な package を追加

$ yarn init

とかでプロジェクト初期化する. 次に以下を実行して, プロジェクトに必要な package を入れる.

$ yarn add react react-dom
$ yarn add --dev parcel-bundler

作成

ソースコードは普通に長い (というか貼り付けるのが面倒な) ので GitHub に上げているから参照してください.
コンポーネントにはモダンな Functional Component, 昔ながらの Class Component どちらとも利用している. (やっていることは同じだが)

ちなみに, このプロジェクトでは node_modules/ 除いて以下のような構成になっている:

./
├── package.json
├── src
│   ├── component.js
│   ├── index.css
│   ├── index.html
│   └── index.jsx
└── yarn.lock

実行

package.json に以下を追記:

"scripts": {
    "start": "parcel src/index.html",
    "build": "parcel build src/index.html"
  }

これで, yarn startでテストサーバを起動でき, yarn build でビルドができる.

f:id:KashEight:20191201183553p:plain

Chrome 上でこのように表示されて, それぞれのボタンが反映されればおそらく大丈夫なはず.

注意

React で Class Component を使う際, メソッドを呼び出すときに, this を bind する必要があり, 煩わしくて class property*1 使うかもしれないけど, そもそもまだそれは ECMAScript で標準化されていない実装なので, 使うときは babel を用いてトランスパイルする必要があるから気をつけてほしい.

余談

実は parcel は CSS もモジュールとして読み込んで bundle してくれるので HTML に直書きしなくてもやってくれる.
なので, js 内で import "./index.css" しても別に問題ない. (なんなら parcel のホームページもそんな使い方の例を示してるし)
あと Sass とか, TypeScript とかも自動的に読み込んでくれるので本格的なものを作る必要ないなら parcel で十分な気がする. webpack だと設定面倒だし.

最後に, 最近忙しいのマジでどうにかしてくれ…実際にこれ遅刻しかけてるし…

*1:クラス直下の宣言 (コンストラクタ経由をしない宣言), これにはアロー関数も含まれる. つまり, クラス内のアロー関数宣言はメソッドではなくプロパティ扱い

Nuxt2 + TypeScriptの環境構築

この記事はKaigen Discord Advent Calendar 2018 13日目の記事です。

前置き

Nuxt.jsでTypeScriptを導入した環境を構築するのにかなり苦労したので同じことをしようと思う人と自分に向けてまとめておく。
最終的なテンプレートはGitHubにあげていますのでご参考に。

環境

  • Node.js: 10.14.1
  • Nuxt: 2.3.4

構築過程

プロジェクト作成

まず

$ yarn create nuxt-app

でNuxtプロジェクトを作る。構成は以下の画像のようにした。

f:id:KashEight:20181206205904p:plain

今回は環境構築だけなのでサーバサイドフレームワークやUIフレームワークは使わず, また, APIをいじいじするわけでもないのでAxiosも入れない。Universalアプリケーション作るわけでもないのでSPA。lintはかけたいのでeslintやprettierは今回のプロジェクトで導入した。

プロジェクトを作成したらとりあえず

$ yarn run dev

で動かしてみる。
Nuxt v2.3.4ではこのような画面が出たら成功。

f:id:KashEight:20181206213350p:plain

TypeScriptの導入

TypeScriptとWebpack用のloaderとnodeの型宣言ファイルを導入する

$ yarn add -D typescript ts-loader @types/node

Nuxt(というよりかはVueファイル)で使用するパッケージを導入

$ yarn add vue-class-component vue-property-decorator vuex-class

vue-class-componentやvue-property-decoratorをベースとしたnuxt-class-componentnuxt-property-decoratorがnuxt-communityで公開されているがどちらともメンテナンスが滞ってる(nuxt-property-decoratorは最近メンテナンスが再開された?)し, どちらともベースとなるもので事足りるのとそっちの方が機能が多いので別に導入しなくていいと思う。

TypeScriptをビルドできるようにする

TypeScriptをビルドできるようにWebpackの設定をいじってみる。
Nuxtではnuxt.config.jsのbuildプロパティ*1でWebpackの設定をいじるほか, モジュール*2という形でもWebpackの設定をいじることができる。
前者の方法では軽く設定を変える程度で複数プロジェクトで同じようなことをしない場合, そうではない場合は後者の方法を用いるのがいいでしょう。
今回のような場合は後者の方法で実装したほうがよさそう。
幸いにもNuxt2ではないがTypeScriptのテンプレートがあったのでそれを参考にNuxt2用に実装してみる。
まず, modules/typescript.jsとmodulesフォルダとjsファイルを作り以下のコードを記入する。(一応, tsxにも対応できるようにした)

module.exports = function() {
    // Nuxtで.ts/.tsxファイルを解決させる
    this.nuxt.options.extensions.push('ts', 'tsx')
    // Webpackの設定
    this.extendBuild(config => {
        // .ts/.tsxをビルドできるようにts-loaderを追加する。
        config.module.rules.push({
            test: /\.tsx?$/,
            exclude: /(node_modules)/,
            loader: 'ts-loader',
            options: {
                appendTsSuffixTo: [/\.vue$/]
            }
        })
        // Webpackのextensionsに.tsが入っていない場合解決できるようにする
        if (!config.resolve.extensions.includes('.ts')) {
            config.resolve.extensions.push('.ts')
        }
        // Webpackのextensionsに.tsxが入っていない場合解決できるようにする
        if (!config.resolve.extensions.includes('.tsx')) {
            config.resolve.extensions.push('.tsx')
        }
    })
}

次にモジュールを読み込めるようにnuxt.config.jsに以下を追記する。

modules: ['~modules/typescript.js']

tsconfig.jsonは以下のようにした。

{
    "compilerOptions": {
        "target": "es5",
        "lib": ["dom", "es2015", "es2016", "es2017"],
        "module": "es2015",
        "moduleResolution": "node",
        "alwaysStrict": true,
        "experimentalDecorators": true,
        "noImplicitAny": false,
        "noImplicitThis": true,
        "strictNullChecks": true,
        "sourceMap": true,
        "removeComments": true,
        "suppressImplicitAnyIndexErrors": true,
        "allowSyntheticDefaultImports": true,
        "allowJs": true,
        "baseUrl": ".",
        "paths": {
            "~/*": ["./*"],
            "@/*": ["./*"]
        },
        "typeRoots": [
            "node_modules/@types",
            "types"
        ]
    },
    "exclude": [
        "node_modules"
    ]
}

vscodeだと以下のようなファイルエラーが出ますが無視して構いません。(理由はよくわからないです…分かる人は教えてくれれば幸いです。)

[ts] 入力ファイルを上書きすることになるため、ファイル <rootPath>/modules/typescript.js' を書き込めません。

2/20追記: コメントにて

tsconfing.jsonのcompilerOptionsにoutdirかoutFileを指定するとエラーがなくなるようです。
変換しない場合は、"outFile": "" とするかまたは存在しないデタラメなフォルダを指定すればいいようです。

という指摘をいただきました。
確認はまだしていないのですがこれでそのvscodeのエラーは回避できるようです。
7ccさんありがとうございます!

最後に, VueでTypeScriptが使用できるように型宣言ファイルをtypes/index.d.tsのように作成して以下を記入する。

declare module '*.vue' {
    import Vue from 'vue'
    export default Vue
}

TypeScriptを使用する

pages/index.vueでTypeScriptを使用してみる。ソースは以下のようにした。

<template>
  <section class="container">
    <div>
      <logo/>
      <h1 class="title">
        {{ title }}
      </h1>
      <h2 class="subtitle">
        {{ fuwa }}
      </h2>
      <div class="links">
        <a
          href="https://nuxtjs.org/"
          target="_blank"
          class="button--green">Documentation</a>
        <a
          href="https://github.com/nuxt/nuxt.js"
          target="_blank"
          class="button--grey">GitHub</a>
      </div>
    </div>
  </section>
</template>

<script lang="ts">
import Vue from 'vue'
import Component from 'vue-class-component'
import Logo from '~/components/Logo.vue'

@Component({
    components: {
        Logo
    }
})
export default class extends Vue {
    title = 'hoge'
    desc = 'fuwa'
}
</script>

<style>
.container {
  min-height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  text-align: center;
}

.title {
  font-family: 'Quicksand', 'Source Sans Pro', -apple-system, BlinkMacSystemFont,
    'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  display: block;
  font-weight: 300;
  font-size: 100px;
  color: #35495e;
  letter-spacing: 1px;
}

.subtitle {
  font-weight: 300;
  font-size: 42px;
  color: #526488;
  word-spacing: 5px;
  padding-bottom: 15px;
}

.links {
  padding-top: 15px;
}
</style>

ビルドしてみる

一度, yarn run lint --fixyarn run devをしてビルドしてみよう。
localhost:3000に接続してみて以下の画像のようになったら成功。

f:id:KashEight:20181207011810p:plain

これでTypeScriptの導入は終了した。

TypeScriptにlintをかける

TypeScriptを導入したはいいけれども.ts/.tsxファイルや.vueファイル内のscript部分にはlintはかからない。
そこでtslintやtypescript-eslint-parserを導入してlintをかけようと思う。今回はeslintを導入しているのとtslintとvueの相性が悪いのでtypescript-eslint-parserを使ってlintをかける。
まず必要となるパッケージを追加する。

$ yarn add -D typescript-eslint-parser eslint-plugin-typescript

nuxt.config.js

config.module.rules.push({
    enforce: 'pre',
    test: /\.(js|vue)$/,
    loader: 'eslint-loader',
    exclude: /(node_modules)/
})

を以下のように変更

config.module.rules.push({
     enforce: 'pre',
     test: /\.(js|ts|vue)$/,
     loader: 'eslint-loader',
     exclude: /(node_modules)/
})

.eslintrc.jsに以下を追記

overrides: [
    {
        files: ["*.ts", "*.vue"],
        parserOptions: {
            parser: "typescript-eslint-parser"
        },
        plugins: ['vue', 'prettier', 'typescript']
    }
]

これでTypeScriptにlintがかかるようになった。

余談

この記事を作るきっかけとしてyarn create nuxt-appでeslintとprettierを導入して初期の状態でビルドするとエラーを吐いて導入できなかったのがあった。
原因は.vueファイル内のscriptの言語がTypeScriptだと初期のeslintのパーサであるbabel-eslintで解析してしまうためそれを回避するために記事中に書いたTypeScriptにlintをかけるような方法を取らなければいけなかった。
この記事を書いてる最中にNuxtのバージョンが上がったため新しいバージョンで試したところ, エラーを吐かずにすんなりビルドを通した。
今までの苦労はなんだったんだろう…。

脚注

楽しいHypixel: PaintBall編

この記事はKaigen Discord Advent Calendar 5日目の記事です。 PaintBall編とか言ってるけど続くかはわかりません。

前書き

この記事はHypixelのPaintBallの魅力と楽しみ方の一つを自分なりに伝えるための記事なのでそんな本格的なことは書かないつもりです。
あと(こんな紹介記事書いてるけど)別にPaintBallが上手いわけではないのでKillstreakの選び方やPerkの選び方などは参考程度に留めておいてください。

PaintBallってなんぞや

(知ってる人は飛ばして構いません)
ゲームルールは

"2チームに分かれて雪玉投げあって相手のチームの残機を先に0にしたチームの勝利"

…これだけ見るとただの雪合戦と何が違うのか, そしてなんの面白さがあるのかわかりにくいかもしれません。
普通のPaintBallならつまらないでしょうけどここはあの"Hypixel", 普通ではないんです。
じゃあ何が違うのか?説明していきましょう。

豊富なShop

まずはHypixel恒例のShopを見ていきましょう。
Classic Games Lobbyへ行きPaintBallのShopを覗いてみます。 f:id:KashEight:20181201020354p:plain
5つの項目がありますが特に重要なのは上の3つです。それぞれ見ていきましょう。

Hat

f:id:KashEight:20181201020642p:plain
(テクスチャバグっててごめんなさい)
見る限りたくさんあって頭(Hatだけに)が混乱するかと思いますがこれらは大きく2種類にわけることができます。
一つは安価で購入できるBlockHat, もう一つは高価なSkullHatです。(BlockHat, SkullHatはそれぞれわかりやすくするために自分がつけた名称なので正しい名称ではないのでご注意を)
この二つの説明の前にまずはHatの説明をしましょう。

Hatとは

Hatは購入して装着することで試合にてHatに応じた効果を得ることができます。ただエフェクトを出す(意味のないネタ)Hatやゲームに大きな影響をもたらすHatまで多種多様なHatがこのPaintBallでは存在しており, ゲームをプレイする上では必要不可欠な存在です。
Hatを装着するにはShopで, 購入したHatをクリックするだけで装着, 次の試合から効果を得られます。逆に言えば装着するまでその効果は得られないということです。
勿論装着できるHatは一人一つまで, でないとゲームバランスは崩壊するからね。(元から壊れてるとか言わない)

このHatの量を見て大抵の方は「けどこんなたくさんの中から一つとか選べないよぉ~><」ってなると思います。
そこでBlockHat, SkullHatと分け, それぞれの中で必要なものをピックアップしましょう。まずはこの二種類の説明から。

BlockHatはブロック型のHatで安価(4,200コイン)で購入できるものです。コインがない序盤に購入しやすいです。
一方, SkullHatはプレイヤーの頭の形をしたHatでかなり高価(50,000/75,000コイン)です。クールタイムがありますがその分価値にあった性能を出してくれるのでコインが溜まったら買うのが良いと思います。

次にこの二種類の中から必要なものを紹介します。

BlockHat

  • Speed Hat
    -> 常時Speed2が付与, PaintBallのマップは広いので速く移動できるのは試合の勝敗を大きく分けます。

BlockHatはこの一つだけで十分です。というかこれを選ばないでどう試合すればいいかレベルなので必ず買いましょう。

SkullHat

  • Rezzus Hat
    -> スニークすると5秒間雪玉にホーミング性能がつく, クールタイムは70秒
  • Paintballkitty Hat
    -> 常時Speed2が付与, スニークすることで5秒間Speed3が付与される, クールタイムは70秒

SkullHatは基本的に高いのもあって最初のうちは手を出すことは難しいかもしれません。最初のうちはSpeed Hatでプレイしてコインに余裕が出てきて買おうと思ったらこの二つのどちらかを買えばいいと思います。
私のオススメは二番目のPaintballkitty Hatです。Speed Hatの上位互換版なのでHatを変えても違和感は全く無いです。
Rezzus HatはSpeed2は付与されませんが雪玉のホーミング性能が最強です。狭いマップではこれに敵うHatはないでしょう。

Perk

f:id:KashEight:20181201030640p:plain
Hatとは違って一気に数が少なくなりました。
けれどもPaintBallの中で一番重要な部分であり一番コインを必要とするのがこのPerkです。
ではこのPerkとはなにか, そしてどれを選べばいいのかこれから説明します。

Perkとは

Perkはレベル制となっておりHatとは違って買い切りではありません。
レベルの上限はそれぞれのPerkによって違い, 短いもので5レベル, 長いもので50レベルまであります。
全部上限まで開放するのはかなりの時間をPaintBallに捧げる必要はあるので現実的ではありません, そこでこの中からHatのように必要なものをピックアップしましょう。

  • Fortune
    -> 敵をKillした際にKillstreakをさらに1個貰える確率が増える。一レベル上げるごとに5%増加。上限は20レベル(100%)
  • Superluck
    -> 敵をKillした際に雪玉を10個貰える確率が増加する。一レベル上げるごとに5%増加。上限は20レベル(100%)
  • Headstart
    -> 初めから持っているKillCoinを増やすことができる。一レベル上げるごとに1KillCoinを得る。上限は5レベル(5KillCoins)

他にもGodfatherやEnduranceがありますがとりあえずこの三つを上限にすることを目標にすればいいかと思います。
どれを先に上げるかですが自分はFortune, Headstart, Superluckの順にあげるのがおすすめです。どのPerkにも言えることですが買うごとに値段は上昇していくため最適解としては

Fortune(途中まで) -> Headstart(3か4レベルまで) -> Superluck -> Fortune(最後まで)

が良いかもしれませんね。

Killstreak

f:id:KashEight:20181201034039p:plain
数が多くなりましたが, これも同じように説明していきましょう。

Killstreakとは

敵をKillしたときにもらえるKillCoinを使って使用できるスキルです。雪玉を遠くに速く投げることができるKillstreakから敵を全滅させるKillstreakまで色々なKillstreakが存在します。
ちなみに, 先程の画像以外にも初めから所持しているKillstreakもあるので画像が全てのKillstreakというわけではないです。
試合で使えるKillstreakをピックアップしていきましょう。

  • Strong Arm
    -> 30秒間雪玉の飛ぶ速度が早くなり, 遠くに飛ぶようになる。消費KillCoinは4, しかも初めから所持している。
  • Triple Shot
    -> 30秒間投げた雪玉が3方向に飛ぶようになる。Strong Armと併用可。消費KillCoinは3
  • Nuke
    -> カウントダウンが始まり5秒後に「リスポーン時の無敵時間中以外」の敵を全員Killする。Killした敵一人ごとに1KillCoin手に入る。クールタイムは60秒, 消費KillCoinは25
  • +10
    -> 味方の残機を10増やす。初めから使える+3(消費KillCoinは5)の上位互換, これで勝敗が大きく分かれることがある。消費KillCoinは15
  • Force Field
    -> 15秒間無敵になる。コストが高いがその分敵をKillすれば元は取れる。ただしKillstreakを使った攻撃(TNT Rain, Revengeなど)には無敵はきかない。クールタイムは60秒?(情報がないのでわからない), 消費KillCoinは50

マップにもよるけどほとんどのマップで使えるKillstreakを列挙しました。これ以外にもLightningやEnder Pearlと言ったマップによってはかなり強いKillstreakもあるので適宜使い分けよう。特にNukeは狭いマップやプレイヤーが少ない試合では効果を発揮できないことが多いです。

豊富なマップ

HypixelのPaintBallのマップは少人数用から大人数用まで色々なマップが存在しています。
マップは人の好みが分かれますがとりあえずの参考として自分の好きなマップを上げたいと思います。

  • Mansion
    -> 少人数マップ, かなり狭いのもあってLightningが大いに活躍できる。
  • Herobrine
    -> 大人数マップ, リスキル等でここで100Killを叩き出すことはよくある。自分も何回か出した。
  • Juice
    -> 少人数マップ, Lightningが活躍できるので楽しい。
  • Victorian
    -> 大人数マップ, Herobrineと同じくリスキルができる。

初心者のうちはマップに慣れないだろうけど慣れてきたらどのマップに自分は合ってるかわかるので是非ともいろんなマップに挑戦していただきたい。
まずは試合でKill数1位を目指して頑張ろう!

まとめ

PaintBallは初心者には取っ付きにくいですがコツさえ掴めば誰でもできるものです。
自分も最初はKillされてばかりでしたがやっていくうちに逆にKillをする方になっていたのでどんなことにも当てはまりますが徐々に慣れていくことが大切だと思います。
もしPaintBallに興味を持ったならば是非とも参加してみてください!というかしてほしい, ただでさえ人が少ないから。

kivyでシステムフォントを使用できるようにする

デフォルトでシステムフォントを使用したい場合

from kivy.resources import resource_add_path
from kivy.core.text import LabelBase, DEFAULT_FONT

resource_add_path("<システムフォントのパス>")
LabelBase.register(DEFAULT_FONT, "<使用したいフォントのファイル名>")

適宜システムフォントを使用したい場合

今回はLabelのみで行う。

kvlangなし:

from kivy.app import App
from kivy.uix.label import Label

class MainApp(App):
    def build(self):
        return Label(text="hoge", font_name="<使用したいフォントのファイル名>")

kvlangあり:
(main.py)

from kivy.app import App

class MainApp(App):
    pass

(main.kv)

Label
    text: "hoge"
    font_name: "<使用したいフォントのファイル名>"