MENU

【Python】FlaskアプリのLambdaデプロイ【AWS Lambda】

仕事でAuth0を使うことがあり、取り急ぎの動作サンプルとしてPythonのサンプルアプリAWS Lambdaにデプロイしようとした(会社的な都合でデプロイ環境はLambda一択)のですが、なかなかうまくいかなかったのでそれの対応を備忘として残しておきます。

FlaskアプリのLambdaデプロイ方法

色々とあるみたいですが、主なところはZappaServerless Frameworkを使ってデプロイするという方法みたいです。
もちろんパッケージをzipで固めてaws cliでLambdaに直接アップロードするという方法も出来なくはないですが、外部からhttpリクエストを受け付けるアプリケーションのため、API Gatewayも設定する必要があり、IAMの設定などを考えると自分でやるのではなく何らかのフレームワークの仕組みに乗っかってデプロイしたいなーと思いました。
また、LambdaにデプロイするのであればPythonだとChaliceが便利なので、サンプルアプリChaliceで書き直してしまえば良いかな(ルーティングなどの記述はほぼそのまま)とも思ったのですが、session管理やOAuthの機能などはChaliceデフォルトでは持っておらず外部ライブラリを導入する必要がありそうで面倒くさそうだったので断念しました。(とりあえず動くものを作るのが最優先だったので)

github.com

面倒だからgit cloneしたものをそのままデプロイしたい!!と思い、ZappaServerlessFrameworkを試してみることにしました。

Zappa

ZappaでのLambdaデプロイは以下の記事を参考にさせていただきました。

dev.classmethod.jp

基本的には↑の記事の手順そのままで行いました。
profileは会社のAWSアカウントのRoleがあるのでそこに合わせたものを指定し、S3 Bucketも既存のものを選択したぐらいです。
アプリケーション名は{{ pythonのファイル名 }}.{{ app名 }}ですが、サンプルアプリではserver.pyというファイルの中に、

app = Flask(__name__, static_url_path='/public', static_folder='./public')

という形でアプリが作成されているので、server.appとしています。

初期化が完了するとzappa_settings.jsonが作成されて以下の内容となります。

# zappa_settings.json
{
    "dev": {
        "app_function": "server.app",
        "aws_region": "us-west-2",
        "profile_name": "your-profile-name",
        "project_name": "your-project-name-",
        "runtime": "python3.8",
        "s3_bucket": "your-s3bucket-name"
    }
}

以下コマンドでデプロイします。

$ zappa deploy dev

するとAPI Gatewayの接続でエラーが出ているようです。

〜略〜

Deploying API Gateway..
Scheduling..
Unscheduled ddbe0735534d6bd0f7e78d48d34976715d7ca-handler.keep_warm_callback.
Scheduled ddbe0735534d6bd0f7e78d48d34976715d7ca-handler.keep_warm_callback with expression rate(4 minutes)!
Error: Warning! Status check on the deployed lambda failed. A GET request to '/' yielded a 502 response code.

zappa tailでログを確認すると、以下のエラーが出ていました。

$ zappa tail

〜略〜
[1623504007679] [DEBUG] 2021-06-12T13:20:07.679Z cdd125e4-8885-4e93-ab87-3675a29ac599 Zappa Event: {}
[1623504249069] Instancing..
[1623504250243] [ERROR] ImportError: /var/task/cryptography/hazmat/bindings/_padding.abi3.so: invalid ELF header
Traceback (most recent call last):
  File "/var/task/handler.py", line 602, in lambda_handler
    return LambdaHandler.lambda_handler(event, context)
  File "/var/task/handler.py", line 245, in lambda_handler
    handler = cls()
  File "/var/task/handler.py", line 139, in __init__
    self.app_module = importlib.import_module(self.settings.APP_MODULE)
  File "/var/lang/lib/python3.8/importlib/__init__.py", line 127, in import_module

〜略〜

Authlibでinvalid ELF headerのエラー

これを色々と調べてみると、cryptographyのソースコードの中にネイティブバイナリファイルが含まれているためのようです。
zappaはローカルのMacの環境でパッケージをダウンロード&インストールしてLambdaによしなにデプロイしてくれる、という仕組みのため、Macコンパイルされたバイナリが、Lambda側のAmazon Linuxの環境に不適合のため起きているようです。

github.com

dev.classmethod.jp

解消するためにはAmazon Linuxの環境でLambdaパッケージを作成しなくてはならないとのことなのですが、EC2を立ち上げて実施するのも面倒そうですし、わざわざDockerコンテナを立ち上げてaws configを設定して実施するのも面倒なので他の方法で実施することにしました。

Serverless Framework

Serverless Frameworkについては以下の記事を参考にさせていただきました。

blog.serverworks.co.jp

こちらも基本的には↑の記事そのままの手順を実施しております。

# serverless.yml
service: your-app-name

plugins:
  - serverless-python-requirements
  - serverless-wsgi

custom:
  wsgi:
    app:server.app
    packRequirements: false
  pythonRequirements:
    dockerizePip: true

provider:
  name: aws
  runtime: python3.8
  stage: dev
  region: us-west-2
  profile: your-profile-name


functions:
  app:
    handler: wsgi.handler
    events:
      - http: ANY /
      - http: 'ANY {proxy+}'

前述の通りaws環境のprofileがあるのでprofileを設定しました。
以下コマンドでデプロイします。

$ SLS_DEBUG=* sls deploy -v
Serverless: Deprecation warning: Detected ".env" files. In the next major release variables from ".env" files will be automatically loaded into the serverless build process. Set "useDotenv: true" to adopt that behavior now.
            More Info: https://www.serverless.com/framework/docs/deprecations/#LOAD_VARIABLES_FROM_ENV_FILES
Serverless: To ensure safe major version upgrades ensure "frameworkVersion" setting in service configuration (recommended setup: "frameworkVersion: ^2.45.2")

Serverless: Load command interactiveCli
Serverless: Load command config
Serverless: Load command config:credentials
Serverless: Load command config:tabcompletion
Serverless: Load command config:tabcompletion:install
Serverless: Load command config:tabcompletion:uninstall
Serverless: Load command create
Serverless: Load command install
Serverless: Load command package
Serverless: Load command deploy
Serverless: Load command deploy:function
Serverless: Load command deploy:list
Serverless: Load command deploy:list:functions
Serverless: Load command invoke
Serverless: Load command invoke:local
Serverless: Load command info
Serverless: Load command logs
Serverless: Load command metrics
Serverless: Load command print
Serverless: Load command remove
Serverless: Load command rollback
Serverless: Load command rollback:function
Serverless: Load command slstats
Serverless: Load command plugin
Serverless: Load command plugin
Serverless: Load command plugin:install
Serverless: Load command plugin
Serverless: Load command plugin:uninstall
Serverless: Load command plugin
Serverless: Load command plugin:list
Serverless: Load command plugin
Serverless: Load command plugin:search
Serverless: Load command config
Serverless: Load command config:credentials
Serverless: Load command upgrade
Serverless: Load command uninstall
Serverless: Load command requirements
Serverless: Load command requirements:clean
Serverless: Load command requirements:install
Serverless: Load command requirements:cleanCache
Serverless: Load command wsgi
Serverless: Load command wsgi:serve
Serverless: Load command wsgi:install
Serverless: Load command wsgi:clean
Serverless: Load command wsgi:command
Serverless: Load command wsgi:command:local
Serverless: Load command wsgi:exec
Serverless: Load command wsgi:exec:local
Serverless: Load command wsgi:manage
Serverless: Load command wsgi:manage:local
Serverless: Load command wsgi:flask
Serverless: Load command wsgi:flask:local
Serverless: Load command login
Serverless: Load command logout
Serverless: Load command generate-event
Serverless: Load command test
Serverless: Load command dashboard
Serverless: Load command output
Serverless: Load command output:get
Serverless: Load command output:list
Serverless: Load command param
Serverless: Load command param:get
Serverless: Load command param:list
Serverless: Load command studio

〜中略〜

Serverless: Invoke aws:info
Service Information
service: xxxxxxxxxxx
stage: dev
region: us-west-2
stack: xxxxxxxxxxx
resources: 12
api keys:
  None
endpoints:
  ANY - https://xxxxxxxxxxx.execute-api.us-west-2.amazonaws.com/dev
  ANY - https://xxxxxxxxxxx.execute-api.us-west-2.amazonaws.com/dev/{proxy+}
functions:
  app: xxxxxxxxxx
layers:
  None

Stack Outputs
AppLambdaFunctionQualifiedArn: arn:aws:lambda:us-west-2:xxxxxxxxxxxxx:function:cf-auth0-login-app-dev-app:9
ServiceEndpoint: https://xxxxxxxxxxi.us-west-2.amazonaws.com/dev
ServerlessDeploymentBucketName: xxxxxxxxxxxxxxxserverlessdeploymentbucket-wwfp1x062m4w

Serverless: Invoke aws:deploy:finalize

無事デプロイに成功したようです。

ところがServiceEndpoint: https://xxxxxxxxxxi.us-west-2.amazonaws.com/devで表示されているURLにブラウザからアクセスするとInternal Server Errorが返ってきてしまいました。

ClouwWatchのログを見ると以下のようなエラーが。。

[ERROR] Runtime.ImportModuleError: Unable to import module 'wsgi_handler': No module named 'werkzeug._compat'
Traceback (most recent call last):

Unable to import module 'wsgi': No module named 'werkzeugのエラー

こっちでもか〜。。という感じなのですが、また何らかのエラーを踏んでしまったようです。
以下のようなissueもありました。

github.com

github.com

AWS側の対応が出来ていないことが原因のようで、とりあえずFlaskのバージョンを下げれば解消出来るとのこと。

stackoverflow.com

requirements.txtにて特にそれぞれのバージョンは指定しなかったので依存関係が成り立つ最新バージョンがインストールされていたのですが、Flask==1.1.4を指定することで解消しました。

〜略〜
certifi
cffi
cfn-flip
chardet
click
cryptography
durationpy
Flask==1.1.4
future
hjson
idna
itsdangerous
Jinja2
〜略〜

ちなみに

Flask==1.1.4を指定すると、Zappaでのデプロイ時に起きていたinvalid ELF headerのエラーも起きなくなりました。
Flaskのバージョンを下げても依存関係にあるcryptographyは変わらず3.4.7のままなので謎です。。

おわりに

とりあえず動くものはデプロイ出来たもののなんやかんややり方調査から含めて5時間ぐらいかかってしまったのでなんだかんだChaliceで最初から書き直してしまったほうが早かったのではという気もしますが、まぁ初めて触った仕組みだったので勉強になったので良しとします。

東京湾〜外房・茨城エリアの海床地形マップのコンターマップを変更出来るようにしました

先日作成した、以下のマップを修正してデプロイし直しました。

Fishing Depth Map

kittagon.hateblo.jp

修正箇所

  • コンターマップの描画範囲を変更出来るようにした

  • はてなブログに掲載した記事をお知らせとして掲載

コンターマップの変更は、描画範囲の最大値をFormで送れるようにして、裏でプロットした画像を出力し直しているだけです。
と言っても画像はそのまま保存しているので描画し直しているのは最初だけですが。
デザインCSSフレームワークは、ちょこっとですがUIKitを使用しました。

はてなブログの記事ははてなAtomPUBを使って取得しています。 バックエンドはPythonで書いているので以下の記事を参考にさせていただきました。

cartman0.hatenablog.com

カテゴリごとに取得して表示しています。
本記事も表示されるはず。

ちょっとしたお勉強&お遊びレベルですが次はもっと広いエリアに対して表示出来るようにしていきたいです。

東京湾〜外房・茨城エリアの海床地形マップを作ってみました

昨年からシーバス釣りを始めました。(本当は渓流釣りがやりたいのですが近場には海しか無いので)
今年からショアジギングにも挑戦しようと思っており、また船釣りにもよく行くので、普段釣りをするエリアがどの程度の水深があるのか知りたいと思っておりました。
ネットを色々と調べたところThe Nippon Foundation-GEBCO Seabed 2030 Projectで無償で海床地形データが公開されていたため、とりあえず自分がよく釣りをする東京湾〜外房・茨城エリアの地形マップを作成してみました。

作ったもの

こんな感じでとりあえずherokuにデプロイして公開してみましたのでよろしければ見てみてください。

Fishing Depth Map f:id:ti_taka:20210529115409p:plain

ちょっとしたWebサービスにして育てていこうかと思いましたが現時点ではここで力尽きました。

使ったデータ

The Nippon Foundation-GEBCO Seabed 2030 Projectの200mメッシュ標高データを使用しております。
(全世界分公開されている!!凄い!!↑のページに色々とプロジェクトの取組みなども記載されているので後で読んでみようと思います。) 緯度経度15秒ごとのメッシュデータなので約450mごとのデータですかね。 釣りに使う、特にショアから狙うエリアの地形を把握するには少し粗いかもしれません。 もっとよいデータが見つかれば入れ替えようかと思います。有料データなら良いものがあるかもしれません。
自分がよく行く東京湾奥〜幕張ぐらいのエリアはやっぱり浅いな〜ぐらいに見てました。

やっていること

無償提供されている地形データをmatplotlibでプロット、画像出力しGoogle mapに重ねて表示してます。
プロットは↓を参考にしました。

[Pythonによる科学・技術計算] 2次元(カラー)等高線等の描画,可視化,matplotlib - Qiita

matplotlib - contour で等高線を描画する方法 - pystyle

データは以下の形式でダウンロードすることが出来、ncolsが横方向のデータ数、nrowsが縦方向のデータ数、xllcorneryllcornerが対象エリアの左下の緯度、経度座標になっております。cellsizeは文字通りセルのサイズです。
7行目以降が実際の標高データなのですが、このデータ、実際の地図の配置と同じ配置で並んでいる、つまりこのデータの一番下端の左端の座標がxllcorneryllcornerとなります。

ncols        517
nrows        583
xllcorner    139.183333333333
yllcorner    34.612500000000
cellsize     0.004166666667
NODATA_value -32767
 1290 1176 1215 1355 1462 1500 1354 1288 1370 1510 1488 1380 1258 1142 1037 944 865 907 971 983 1071 1253 1369 1330 1209 1100 1057(略)
 1312 1310 1295 1357 1490 1556 1463 1378 1378 1492 1391 1267 1170 1068 981 913 877 969 1104 1134 1134 1243 1370 1358 1216 1100 1102(略)
 1470 1496 1392 1463 1567 1553 1481 1420 1464 1528 1411 1296 1165 1057 959 892 920 1016 1135 1219 1269 1375 1426 1347 1222 1121 1117(略)
 1582 1599 1520 1546 1546 1519 1499 1504 1590 1520 1395 1266 1182 1085 973 905 988 1033 1042 1116 1194 1327 1427 1371 1241 1159 1222(略)
〜 以下略 〜
geo_data_file = open("{{ ファイルパス }}", "r")

〜〜 ヘッダー行読み取り 〜〜
x_point = xllcorner
y_point = yllcorner + cellsize * nrows

x = np.zeros(ncols)
y = np.zeros(nrows)
Z = np.zeros([nrows, ncols])
while True:
    line_txt = geo_data_file.readline()
    if line_txt:
        line_txt = line_txt.strip()
        line = line_txt.split(" ")
        col_no = 0
        for z in line:
            if float(z) > 0:
                Z[row_no][col_no] = 0
            else:
                Z[row_no][col_no] = float(z)
            if row_no == 0:
                x[col_no] = x_point
            x_point += cellsize
            col_no += 1

        x_point = xllcorner
        y[row_no] = y_point
        y_point -= cellsize
        row_no += 1
    else:
        break

geo_data_file.close()
X, Y = np.meshgrid(x, y)

cm = plt.cm.get_cmap('seismic')

vmin = -40
vmax = 40

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)

cont = plt.contour(X, Y, Z, 5, vmin=vmin, vmax=vmax, colors=['red'], levels=[-200, -100, -70, -50, -20, -10, -5, 0], linewidths=0.05, linestyles=["-"])
cont.clabel(fmt='%1.1f', fontsize=1)

ax.pcolormesh(X, Y, Z, cmap=cm, vmin=vmin, vmax=vmax)
ax.axis("off")
plt.subplots_adjust(left=0, right=1, bottom=0, top=1)
fig.savefig("img.png", dpi=600)

Google Mapsへの画像の重ね方は下記を参考にしました。

【マップ】Googleマップにオリジナル画像を重ねて表示 | WEB制作 活用事例 サンプル

vue.js上で動かそうと思いましたが難しそうだったので断念して結局そのまま使わせてもらってます。

let map;

function initMap() {
    var latlng = new google.maps.LatLng(35.52390135624109, 139.85743908123192);
    var map = new google.maps.Map(document.getElementById('map'), {
        zoom: 10,
        center: latlng
    });

    var sw = new google.maps.LatLng(34.6125, 139.183333333333);
    var ne = new google.maps.LatLng(37.041666666861, 141.33333333350703);
    var latlngImg = new google.maps.LatLngBounds(
        sw,ne
    );
    var groundOverlay = new google.maps.GroundOverlay(
        '/static/images/img.png',
        latlngImg,
        {map: map}
    );
}

でも結局。。

これを頑張ってプロットしてみてから海釣図V(かいちょうずV)で海底地形見れることに気付きました。 これめちゃめちゃ便利じゃないですか・・!こちらは「航海用電子参考図 new pec(ニューペック)」のデータを使っているとのことなのでデータも細かいし、アプリ自体もとても使いやすい!!
しばらくは釣り用にはこちらを使い、自分で作ったマップの方も色々と勉強用がてらちょこちょこ更新していこうと思います。

【はてなブログ無料版】Google Adsenseの申請通りました

最近ふと思い立ってこのブログで収益化できたらいいなと思いGoogle Adsenseに申請してみました。
はてなブログ無料版ではGoogle Adsenseは通りづらいという情報もよく見かけますが、結果的に2回の申請で承認されましたので、実施したことをまとめておきます(全てググったら出てくる内容なので独自に試してみた事柄はありません)。

申請時のブログの状況

  • 記事数:39(後述のプライバシーポリシーや問い合わせフォームを除く)
  • 一日のPV数:30程度(おいおいこのPV数でよく収益化とか言ったなというレベル)
  • 独自ドメイン:無し
  • URL設定:日本語無し
  • Google Analytics設定済み

ブログとしての戦闘力はかなりザコクラスですが、それでも通ったのでやはり巷で言われている通りPV数は無関係のようです。

最初に試したこと

redo5151.hatenablog.com

kimchikuwa.hatenablog.com

このあたりを参考にさせていただきまして、以下を実施しました。

上記3つはredoさんの記事を参考にさせていただき、作成・実施しました。 (プライバシーポリシーはコピペOKとのことでしたので、真に受けてバカ正直にコピペさせていただきました。本当に申し訳ございません&ありがとうございます。)

  • グローバルメニューの設置
    こちらは、kimchikuwaさんの記事を参考に作成いたしました。
    (html,css,jsすら自分で書かないなんてエンジニアとして恥ずかしい。。フロントエンドは苦手なんです。。)
  • 管理人プロフィールの設定
  • トップ画面のリダイレクトの設定

[1回目不承認]サイトの停止または利用不可で不承認の後試したこと

上記を試した後申請してみたところ、「サイトの停止または利用不可」で不承認となってしまいました。
f:id:ti_taka:20210527223031p:plain

原因について色々と検索してみても「何度も申請したら通った」や「お名前.comのリダイレクト設定を変えたら通った」などと、あまり釈然としない内容や本ブログには関係の無い内容が多かったので、何か少しでも出来ること、可能性を高められることが無いかと思い検索していたところ以下のような内容を発見いたしました。

kazuoblog20.com

この記事に書かれている

①「headに要素追加」内のコードをアドセンス審査用以外全て削除
②貼れるところ全てに審査用コードを貼りつけ

をどちらも試してみて再申請してみたところ、2日後に無事合格の通知を頂きました!

試してみれば意外とすんなりと通ったなという印象でした。(というか先人の知見が的確過ぎる!!)

おわりに

最近は実際に会ってカジュアルな雑談をする機会も減ってきているので、「最近こんなことしてみた!」とか「これ買ってみたんだけどめっちゃいい」みたいな、”他愛も無いけど聞いてみると割といいこと聞いた”レベルの話は聞く機会も発信する機会も少なくなってきていると感じております。
そんなちょっとした話題をブログに書くことで色んな方々に読んでいただき、更にはまれに好意的なリアクションもいただける、役に立てていただけるというのは少なからず嬉しいものがありますので、収益化を意識せずとも今で以上にブログを頑張って書いていきたいと思っておりますが、「収益化」というのもそのモチベーション維持の材料になれば良いかなーと思っております。
もちろんこの記事も、ほとんど他の人の情報を試しただけでしたが誰かの役にたてば幸いです。
引き続きよろしくお願いします!

HHKB Professional HYBRID Type-Sを購入して1年使っての感想とキーマッピングのカスタマイズ

結論

最高でした。あまりキーボードにこだわりがある方ではないですしキーボードを買うこと自体始めてですが本当に買ってよかったと思える品でした。

HHKB Professional HYBRID Type-Sとは

2019年12月10日に発売された高級キーボードHHKBシリーズの最新作!です。
自分も仕事柄メールやプログラミングでタイピングすることも多く、趣味でプログラミングもしていたので、HHKBはずっと気になっていたキーボードでした。
ただ家と会社両方で使うことも考えると、ただでさえPCが入って重いリュックにキーボードを入れて持ち歩くのも面倒だし、かといって持ち歩かずに家でPCを使うのと会社でPCを使うのとでキーボードの使用感が変わるのも嫌だったので少し悩んでいました。
そんな折にコロナ禍で仕事も大部分在宅になったので、思い切って買ってみました。
HHKB Professional HYBRID Type-Sにもいろいろな色、種類がありますが、やはり使用頻度が高い配列ということでJIS配列の黒を購入しました。

打キー感が最高

やはりこれが何より一番の理由ですね。 これは本当に凄いです。もともとPM的な業務が多かった(昨年は。今は実装がメインですが)ので社内外のメンバとメール、チャットでやり取りをすることも多く、ドキュメント作成も数多くしていたので、一日中タイピングしていたのですが、キーボードのタッチ感は本当に気持ちよくてずーっと文字を打っていたいと思うぐらいです。
具体的にどんな感覚なのかというと自分はあまり他のキーボードを触ったことがなかったのであまり比較は出来ないのでわかりません。。 が、以前バイト先でREALFORCEのキーボードでプログラミングしていたのですが、打キー感はそれと近いなーぐらいの感覚です。 まぁどちらも「静電容量無接点方式」とかいう仕組みのキーボードなので近いのでしょうが。
もちろんこの文章もHHKBを使ってタイピングしていますがいつまでも文字を打っていたいと思えるのですごく無駄な文章になっている気が。。

キーマッピングを自在に変更可能

Happy Hacking Keyboard キーマップ変更ツールというのが公式サイトからダウンロード出来るのですが、このアプリを使ってキーマッピングを好みのものに変更出来ます。
このキーマッピングの変更というのは、↑のソフトウェアで変更を管理するのではなく、HHKB本体のメモリに変更を書き込むようなので、PCに依存せず、接続するすべてのPCで変更したキーマッピングでキーボードを使用することが出来ます。

私の設定内容

私は以下の感じで設定しています。

変更前

通常状態(デフォルト状態)
通常状態(デフォルト状態)

Fnを押した際のキーマッピング(デフォルト状態)

変更後

通常状態
通常状態

Fnを押した際のキーマッピング
Fnを押した際のキーマッピング

  • 右下の矢印キーをすべて無効化(プログラミングしているときに _とか/を小指で押したいときにめちゃめちゃ押し間違って意図せずカーソル移動させちゃうので、、)
  • Vimのキーバインドが好きなので以下を設定(少し違いますが)
    • Fn + j ->
    • Fn + k ->
    • Fn + h ->
    • Fn + l ->
    • Fn + f -> PgDn
    • Fn + b -> PgUp
  • Fn押下時の矢印キー、+-PScScrLPusを無効化(普通に@とか:とか出るようにした。使わないしタイポの原因)
  • Fn押下時のInsCapsを無効化(何も反応しないようにした)
  • Fn + u -> BackSpaceFn + u -> Deleteを設定

上記を設定したら、本当にホームポジションから手を動かすことが少なくなり本当に快適にタイピングが出来るようになりました。

KarabinerでMacとWindowsでの文字種変更を共通化

現在、仕事でもプライベートでも、MacとWindowsどちらも使うという状況だったので、文字種変更だけでも共通化したいと思いました。
何も設定をしない状態だと、HHKBを接続した時の文字入力の変更は以下の通りとなっております。

  • Mac
    • ctrl + spaceで文字入力変更
  • Windows
    • Kanaでかな入力に変更
    • 左下のキー(画像の場所)で半角/全角キーと同等 f:id:ti_taka:20210507205102p:plain

通常のMacのJIS配列キーボードでもかなを押したら日本語入力になり、英数を押すと英語入力になるので、Windowsと使用感をあわせて、以下の感じにしました。

  • Mac
    • Kanaでかな入力に変更
    • 左下のキー(画像の場所)で英数入力に変更 f:id:ti_taka:20210507205102p:plain

Macでのキーマッピングの変更にはKarabiner-Elementsを使います。

↑の画像のキーはMacだと `として入力されるので、karabinerの設定で以下のように設定してあげます。

karabiner設定
karabiner設定

こうすることで、MacでもWindowsでもKanaを入力すれば日本語入力となり、上記画像のキーを押せば英数入力になるという感じで、かなり使いやすくなりました。
普段MacもWindowsもどちらも使うので、どちらに接続したとしても同じ使用感でタイピング出来るのは本当に気持ちいいです。

まとめ

1年使うまでもなく、2020年のベストバイの一品でした。
自分は色々とカスタマイズして使っていますが、それをしなくても打キー感の気持ちよさだけでも購入する価値のある品だと思います。
今回紹介した以外にも、HybridTypeなのでUSB給電でも電池駆動でもどちらでもいけますし、USB接続でBluetooth接続でもどちらも可能というのもなかなかありがたいです。
自分は基本的には有線接続で使っておりますが、家の中でちょっと移動して普段と違う場所でくつろぎながらーという場合でも気軽に持ち運んで使用出来るのも便利です。
ちなみに今では出社することは殆ど無いですが、前の部署だとコロナ禍でもそれなりに出社していたので、出社の際にキーボードを裸でバッグにしまうのは嫌だったので以下を購入して通勤してました。(今は全く使っていない。。)

Ruby Silverに合格しました

昨年社内異動があり、Ruby on Railsで開発する部署に配属となりました。
これまでも趣味レベルでプログラミングはやっていたけど、ガチの仕事でプロダクトコード書くのは学生時代のバイト以来で実に5年ぶりなので、ちゃんと体系立てて勉強せねばと思い、取り敢えずRubyの資格をとってみることにしました。
結果的に82点(75点合格なので割とギリ)で合格できたので、勉強内容を備忘として書きます。

色々自身の情報

進め方

正直、ざっと情報を調べた限りでは実務でのRails実装の経験は役に立たなそうだったので、0から暗記・勉強し始める気持ちではじめました。
他の経験談でも書かれていることですが、ざっくりとは以下の流れで進めました。

  1. 経験談など見て進め方ざっくり調べた
    • 見て「ふーん」程度の感じ
  2. 問題解きまくった

だけです。

勉強量

大体どの経験談の記事を見ても、一日○時間、合計○時間程度、って記載でしたが、自分にはあまりイメージが沸かず。。
正直自分自身も、子供面倒見ながら問題を解いたり、Youtube見ながら参考書読んだりダラダラとながら勉強をしていたことも多かったので、どの程度勉強したのか覚えておりません。
なので情報までに「どの程度問題を解いたか」で記載します。

  • 公式模擬問題集
    • 2回実施
      • 1回目44点。最初に現時点の実力試しとして実施。なんとなくでは解かず説明出来るものだけ回答したにしてもひどい点数。
      • 2回目点。色々勉強後。なんか行けそうかなーと思った。
  • RubyExamination
    • 5回実施
      • 50点、56点、86点、86点、90点
  • [改訂2版]Ruby技術者認定試験合格教本(Silver/Gold対応)Ruby公式資格教科書
    • 買って解いてみました。(お金をかけないとやる気にならないタイプなので)
    • 基礎力確認問題、模擬問題それぞれ2回ずつ
      • 基礎力確認問題:28点→44点(60点満点)
      • 模擬問題:60点→80点
    • 一応模擬問題だけでなく前段階の教科書部分の方も読みましたが、Silver試験の範囲に限って言えば初見の情報も少なくあまり得るものは無いなという印象でした。Goldの出題範囲のほうがObjectやModuleの継承、include時の挙動などが非常に詳細に解説されていてすごく興味深く、実務でも役に立つなーと思いました。

↑で解きまくったと書きましたが、実際に解いた回数としては、それぞれ問題数に差異はあれど合計11回ということになります。
もちろん解いた後は、問題、回答(選択肢も含めて)に出てきたメソッドはすべて公式リファレンスで確認するというのを繰り返し、よく出てくるメソッドは大体覚えました。
ファイル操作関係のメソッドは、正直実務でもあまり使っていなかったこともあり興味が沸かず、捨て問だと思ってあまり勉強しませんでした(笑)。

所感

あまりRubyの言語としての作り的なところは多くなく、メソッドの暗記が多いなーという印象でした。
もちろん変数定義のルール、スコープや、オブジェクト継承ルールなども出題されましたが、Rubyに限った話ではないのでプログラミング経験がある人であれば簡単に解けるかと。
特に配列、ハッシュ、文字列に関するメソッド(破壊的、非破壊的、似ているメソッドなど)を一通り覚えれば大丈夫だと思います。
(もちろん個人差やその時折々の出題によって変わってくると思いますが。自分のときはそこまで癖のある問題は出ませんでした。)

という感じで続いてGoldの勉強もして行こう〜!と思っていたのですが所属する開発チームでの今年度担当するプロダクトが色々変更があり、あまりRuby on Rails触らないかも。。むしろPythonのほうが触るのでは・・?となっているのでGoldまで取るか悩み中です。。

スティード400を復活 〜スプロケ・チェーン交換編(→結局フロントスプロケだけ)〜

先日プラグ交換を実施した際にスプロケ・チェーンの交換もやってみました。
(と思っていたのですが結局今回はフロントスプロケだけ交換しました。)

kittagon.hateblo.jp

参考にしたサイト

事前にこのあたりのブログを参考にさせていただき、予習しておきました。

seilife.blog.jp

ameblo.jp

ざっくりと以下の手順で実施できそうです。

  1. ジャッキアップ  → 2.の後でもOKですが高さ的にやりづらかったので最初に上げました。
  2. チェーンカット → 工具必要
  3. フロントスプロケカバー外す
  4. フロントスプロケ交換
  5. リアタイヤ外す
  6. リアスプロケ交換
  7. リアタイヤ戻す
  8. チェーンを取り付ける
  9. チェーンを締める
  10. フロントスプロケカバーを戻す

スプロケ・チェーンの適合

この辺りを参考に調査、確認してみました。

https://mtc.greeco-channel.com/honda/steed400_nc26_gear/

www.sunstar-kc.jp

検索結果

純正だとフロント:16丁、リア:45丁、チェーンリンク数:120、チェーンサイズ:525という感じみたいです。

今回は純正と同じセッティングということでこちらを購入することにしました。

あとは、今回は↑のブログでも紹介されていたチェーンカッターを購入して作業することにしました。

チェーンのカット

↑で購入したチェーンカッターはこんな感じで、チェーンにはめてボルトを回せば切れる仕組みみたいです。

チェーンカッター
チェーンカッター

チェーンカッター設置
チェーンカッター設置

この状態でボルトをどんどん回していくと↓のように少しずつボルトの先端がチェーンの結合部を押し込んで行って、穴があきます。(カシメ?っていうんですかね、細かい部品名称を知らないからうまく説明できない)
このときギアを入れておくとチェーンが回らなくてやりやすいです。(そもそもジャッキアップの前にやるべきだった。。)

チェーンカッター途中
チェーンカッター途中

穴があいた後は、ボルトをより長いものに交換して、チェーンの接合部を貫通させて切断します。

ボルト交換
ボルト交換

するとこんな感じで接合部のピンが外れてチェーンが切れます。

チェーンピン
チェーンピン

チェーン切断後
チェーン切断後

これで無事にチェーンが外せました。 チェーンがカットできて外すときはギアをニュートラルに入れておくと外しやすいです。

カット後チェーン
カット後チェーン

フロントスプロケ交換

次にフロントスプロケを交換します。
フロントスプロケを交換するにはエンジンの横のスプロケカバーを外して作業します。
赤枠のところのボルトとピンを外してカバーを手前に引っ張ると外せます。

スプロケカバー
スプロケカバー

カバー上部のピン拡大図

カバー上部のピン
カバー上部のピン

こんな感じで外せました。 スプロケを固定しているボルトを外します。

スプロケカバー外した後
スプロケカバー外した後

ボルトを外すとこんな感じ。
スプロケを固定している金具があるので、これを外します。
めちゃくちゃ錆びついてしまっていたのでCRC556なんかを吹きかけてペンチでゆっくり引っ張ってようやく取れました。

ボルト外し後
ボルト外し後

スプロケ固定金具外した後
スプロケ固定金具外した後

スプロケも引っ張れば外せます。
新旧スプロケ比較↓

新旧スプロケ比較
新旧スプロケ比較

結構厚みに差があります。が、古い方のスプロケは円盤中央部にくぼみがあるので実際に設置したときの厚みは同じです。(のはず)

新旧スプロケ比較厚み
新旧スプロケ比較厚み

新しいスプロケに歯車の山が合わない・・?

ついに新しいフロントスプロケを取り付けようとしたところ問題が発覚しました。
スプロケと、留める金具を重ねてみると、ボルトの位置を合わせると内側の歯車の山が合わなくなり、内側の歯車の山を合わせてしまうとボルトの位置が合わない感じになってました。

スプロケの歯車とボルトの位置
スプロケの歯車とボルトの位置

どう考えてもやり方がわからなくなってしまったので一旦今回は作業終了として、色々と確認することにしました。

以前も↓の記事のキャブ洗浄のやり方を教えてくれた友人に相談しました。
kittagon.hateblo.jp

どうやらこの留め具の金具は、スプロケの軸のところにある溝のところに位置するそう(なので歯車の山は関係なく回転出来る)で、ボルトの位置だけ合わせて留めるそうです。(というかもともと取り付けられてた写真確認したら確かにそうなってたわ。。)

スプロケ軸 溝
スプロケ軸 溝

なので下の感じ(赤がスプロケ、黄色が留め具の位置)

スプロケ軸
スプロケ軸
(ちなみにこれの元画像、友人から説明として送られてきたものなので転載元不明です。。すみません、、なんかまずかったらご連絡ください。。)

というわけで再トライ

後日↑のやり方で再度取り付けを試してみました。
↓の写真の赤枠の溝に留め具をつける感じですね。

スプロケ軸
スプロケ軸

こんな感じで取り付けます。

留め具取り付け
留め具取り付け

ボルトの位置もOKですね。

留め具取り付け正面
留め具取り付け正面

ボルトも取り付けちゃいます。

ボルト取り付け後
ボルト取り付け後

ボルト取り付け後
ボルト取り付け後

こんな感じで無事フロントスプロケ交換ができました。

続いてリアスプロケの交換とチェーンの取り付けも実施しようとしたのですが、後からタイヤの交換もしたいし、ブレーキシューの交換もしたいと思っていたので、今このタイミングでリアタイヤを外してスプロケ交換、戻してチェーンを取り付けてしまうと、また後日外さなくてはいけなくなってしまうので二度手間かと思い、今回のタイミングでは実施しないことにしました。
また後日タイヤ交換、ブレーキシュー交換のタイミングでリアスプロケ交換、チェーンの取り付けは行おうと思います。

まとめ

今回は当初スプロケとチェーンとを一気に交換してしまおうと思っていたのですが、リアのタイヤを外すのが大変そうなのと後からの作業を考えると二度手間になりそうだったので取り敢えずフロントスプロケだけの作業にしました。
とはいえフロントスプロケだけでもいろいろと詰まるポイントがあって苦労しましたが、なんとか完了させられてよかったです。