2020年1月振り返り

今年から1ヶ月ごとの振り返りを書いていく。

理由は、毎年毎年年末になると何してたのか思い出せず自分の棚卸しさえできてないけど、毎月書けば振り返りもしやすそうだから。

とりあえず、お試しで毎月書くようにするよ!

仕事

  • 今関わっているチームの小さいプロジェクトが一段落しそうってことで、去年よりも時間的に余裕のある仕事ができている
  • 本番運用時にエラーや障害の検知、運用時に毎回検知しておきたいログ等をメール、Slack、Push通知で知らせるように、AWS CDKでCloudWatch Alarm, Cloud Watch Logsのフィルターを作成
  • CloudWatch Alarmのアクションで実行されるAWS Lambdaをserverless frameworkで実装(Rust)
  • バグ修正
  • Cコンパイラの実装は関数宣言まで(https://www.sigbus.info/compilerbook)

プライベート

  • https://100list.app のLP修正
  • Androidアプリの実装(急ぎます)
  • Pythonでスクレイピングのためのコード書いた
    • 期日のほんとギリギリでデータ取れたので良かった
  • 1/11(土)にジムに契約して、1/13日(日)からジム行き始めた
    • 週3でジムに通って1時間ほど鍛えるのが目標だけど、週5ぐらいで行ってるし継続できてる
    • チェストプレス、ショルダープレス、アブドミナル、ラットプルダウンあたりのマシンで70kgを軽々できるようになるのが直近の目標
      • どのマシンもまだ50kg台程度しか重量上げられてない。。。
    • ランニングは20kmぐらい走れるようになりたい
      • ジム行き始めは10分もきつかったけど、今は9km/h で25分ぐらい走れるようになったよ(体調次第のところもある)
    • 体重はまだ全然減らないんだけど?
    • プロテインとかサプリメントも飲みだしたよ
  • 30日プランクチャレンジも始めた
    • この記事書いてる日で9日目  * 今の自己ベストは105秒
  • 1/25に梅田のb-monsterに初めて行った
    • 朝7時から自分の限界まで追い込むので最高
    • まだ入会してないけど、あれだけ追い込めるなら価値あるから悩んでる
    • 朝から活動するの良いですね(いつも起きるの遅いから改善必須)
  • ブログは技術ネタのみで今年50記事書くのが目標で、今月4記事
  • AtCoderの練習問題を解き始めた
    • コンテストはまだ参加してない

最後に

やりたいことを管理して日頃から見返すとやる気出るからLISTっていうアプリはおすすめです!

https://100list.app

Amazon Linux2にPython3をインストールする

Pythonは書いたことなかったんですがスクレイピングするためにサクッと書いて、それをローカルではなくEC2上で動かす必要性が出てきました。

利用しようとしたAmazon Linux2にプリインストールされているのはPythonの2系なのですが、ローカルで書いたスクリプトはPython3系で書いたため、EC2上にPython3をインストールする必要がありました。

そのときに実行した手順を備忘録として書いておきます。

前提

  • Amazon Linux 2 AMI(ami-011facbea5ec0363b)でEC2を起動

手順

Python3をインストール

sudo amazon-linux-extras install python3 -y

pip3をアップデート

sudo pip3 install --upgrade pip

Python3のバージョンを確認

python3 --version

Python 3.6.2(現時点だと3.8.1が最新なので、ちょっと古いね...)

必要なパッケージをインストールする

pip3 install boto3
pip3 install requests
pip3 install beautifulsoup4

おまけ

端末から抜けたりしても、スクリプトは実行し続けてほしい場合は、nohup使うと良いよ

nohup python3 main.py > ~/output.log &

プロセス確認する場合

ps aux | grep main.py

Serverless FrameworkとGoでAWS利用費を毎朝Slackに通知する

f:id:ryskit:20200119180331p:plain

以前、「AWS LambdaでAWS利用費を毎朝Slackに通知する」というタイトルで記事を書きました。 この中では、Serverless Frameworkを使わず、Goで書いたコードをビルドしてZip化、AWSリソースは手作業で作成、デプロイももちろん手作業でZipをアップロードしていました。

blog.ryskit.com

ただ正直、AWSリソースを手で作成するの面倒だし、修正してコマンド一発でデプロイしたいところです。

で、今回それを解決するためにServerless Frameworkを導入し、手作業ではなくターミナルからコマンドでデプロイできるようにします。

それでは、いってみましょう!

前提

AWS LambdaでAWS利用費を毎朝Slackに通知する - そうきたか で作成したコードを利用します。

ソースコードはこちらからダウンロードできます。

github.com

Serverless Frameworkをインストールする

すでに僕の環境にはNodeが入っていたので、npmでインストールしました。

npm install -g serverless

以下のリンク先にインストール方法は書いてあるので、参考にしてみてください!

serverless.com

Serverless Frameworkの設定ファイルを作る

以下のようなコマンドを実行すれば、ServerlessFrameworkの雛形を作成できますが今回は使いません。

serverless create -u https://github.com/serverless/serverless-golang/ -p hello-go-lambda

今回はすでに作成した環境があるので、そこにserverless.yml という名前のファイルを作成します。

service: aws-billing-notification

provider:
  name: aws
  runtime: go1.x
  stage: prd
  region: ap-northeast-1
  iamRoleStatements:
    - Effect: Allow
      Action:
        - "logs:CreateLogGroup"
        - "logs:CreateLogStream"
        - "logs:PutLogEvents"
        - "ce:GetCostAndUsage"
      Resource:
        - "*"

package:
 exclude:
   - ./**
 include:
   - ./bin/**

functions:
  billing-notification:
    handler: bin/main
    events:
      - schedule: cron(0 22 * * ? *)

あと、もう一つ作業があります。ファイルをリネームします。

以前、billing-notification.goという名前でファイルを作成していたのですが、main.go という名前にリネームしておいてください。

リネームできたら以下のコマンドでビルドします。

GOOS=linux go build -o bin/main

これで準備は完了です。

デプロイ

serverless frameworkのCLIコマンドでデプロイします。

以下のように実行してみてください。

sls deploy

これでしばらく待って、AWS Lambda, IAMロール, CloudwatchEvent等が作成されていればOKです!

試してみよう

以下のコマンドを実行して、請求金額がSlackに通知できれば完璧です!!

sls invoke -f billing-notification

最後に

いかがでしたでしょうか?

手作業で作成してデプロイするよりも遥かに簡単になりました!

以下に対応したコードをあげているので、参考にして試してみてください!

github.com

AWS CDKで作成したリソースのARN文字列を取得して加工する方法

f:id:ryskit:20200109205701p:plain

AWS-CDKではいくつかのコンストラクトでAWSリソースを作成することが可能です。

今回は低レベルのコンストラクトを利用したAWSリソースのArnを取得して、その文字列を加工してCWAlarmのDimensionのvalueに渡そうとしたときに詰まった部分を書いていきます。

前提

  • AWS-CDKはTypeScriptで記述している
  • Application LoadBalancerはCfnLoadBalanerを使ってリソースを作成している

実現したいこと

Application LoadBalancer(ALB)のTargetResponseTime(リクエストがロードバランサーから送信され、ターゲットからの応答を受信するまでの経過時間 (秒))をメトリクスとしてCloudWatchAlarmを作成したい。

Application LoadBalancerメトリクスの説明

ALBのTargetResponseTimeをメトリクスとする場合、リソースを作成するときにディメンションに以下のどれかを指定する必要がある。

  • LoadBalancer
  • AvailabilityZone、LoadBalancer
  • TargetGroup、LoadBalancer
  • TargetGroup、AvailabilityZone、LoadBalancer

参考: Application Load Balancer の CloudWatch メトリクス

今回は、LoadBalancerのみを指定するが、 以下の説明に記載されているように指定する必要があります。

ディメンション 説明
LoadBalancer ロードバランサーでメトリクスデータをフィルタリングします。ロードバランサーを次のように指定します。app/ロードバランサー名/1234567890123456 (ロードバランサー ARN の最後の部分)。

ALBのARNの例: arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:loadbalancer/app/example-alb/abcdefg123456789

ディメンションには上記のARNのloadbalancer/以降の文字列をValueとして渡してあげれば問題ない。

問題点

例えば、以下のようなALBのリソースを記述したコードがあります。

const alb = new elb.CfnLoadBalancer(this, 'example', {
   ....
});

alb.ref のように書くとARNを取得できるので、以下のようにリソースを作成するコードを書いてみたけど、 作成されたCW AlarmのLoadBalancerのディメンションには、そのままのARN arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:loadbalancer/app/example-alb/a123bcd456e7f8g9 が指定されており、TargetResponseTimeを取得できない状態でした。

※ alb.refの返り値は文字列です

const albDimentionValue = alb.ref.replace(/.+loadbalancer\/(.+)/, '$1');
const albTargetResponseTimeAlarm = new cw.CfnAlarm(this, 'targetResponseTimeAlarm', {
      actionsEnabled: true,
      alarmName: 'TargetResponseTimeAlarm',
      alarmActions: [scalingPolicy.ref],
      comparisonOperator: "GreaterThanOrEqualToThreshold",
      threshold: 3,
      evaluationPeriods: 3,
      namespace: "AWS/ApplicationELB",
      metricName: "TargetResponseTime",
      statistic: "Average",
      dimensions: [
        {
          name: "LoadBalancer",
          value: albDimentionValue
        }
      ],
      period: cdk.Duration.minutes(1).toSeconds(),
    });
    albTargetResponseTimeAlarm.addDependsOn(scalingPolicy);

解決策

どうやって解決したかというと、CloudFormationにもある組み込み関数を使えば、ARNの文字列を加工することができました。 CDKにもCloudFormationと同じ組み込み関数がcoreに定義されているのでそれを利用しました。

const splitAlbArn = cdk.Fn.split('/', alb.ref);
const albDimensionValue = `${cdk.Fn.select(1, splitAlbArn)}/${cdk.Fn.select(2, splitAlbArn)}/${cdk.Fn.select(3, splitAlbArn)}`;
const albTargetResponseTimeAlarm = new cw.CfnAlarm(this, 'targetResponseTimeAlarm', {
      actionsEnabled: true,
      alarmName: 'TargetResponseTimeAlarm',
      alarmActions: [scalingPolicy.ref],
      comparisonOperator: "GreaterThanOrEqualToThreshold",
      threshold: 3,
      evaluationPeriods: 3,
      namespace: "AWS/ApplicationELB",
      metricName: "TargetResponseTime",
      statistic: "Average",
      dimensions: [
        {
          name: "LoadBalancer",
          value: albDimensionValue
        }
      ],
      period: cdk.Duration.minutes(1).toSeconds(),
    });
    albTargetResponseTimeAlarm.addDependsOn(scalingPolicy);

最後に

AWS-CDKに関する記事はまだまだ少ないので、参考になれば幸いです。

AppThemeでNoActionBarを指定して、ToolbarにOptionMenuを表示したい

f:id:ryskit:20200108210016p:plain

まだまだAndroid開発のことがわからない、ryskitです。

ActionBarにオプションメニューを表示するには、 onCreateOptionsMenu() をActivityに書いてあげれば表示できると理解していたので書いてみたけど、表示されない。

なんでかなと思ってサクッと調べたことを書きます。

前提

  • styleで Theme.AppCompat.Light.NoActionBar がparentのAppThemeを使用
  • onCreateOptionsMenu() はoverrideしてちゃんと表示できるようにしていた
  • ToolBarをlayout側で定義している

結論

さっそく結論から言うと、styleで Theme.AppCompat.Light.NoActionBar がparentのAppThemeを使っているから、Activity側でToolbarのオブジェクトを setSupportActionBar() にToolbarを渡してあげると表示できた!

ちゃんとGoogleもドキュメント書いてくれてたよ!

developer.android.com

デフォルトのActionBarとToolbarどっち使えば良い?

GoogleさんはデフォルトのテーマのActionBarには機能がドンドン追加されてて、デバイスによって挙動が変わってくると言ってるみたい。

Toolbar のサポート ライブラリのバージョンには最新の機能が追加されており、サポート ライブラリを使用できるすべてのデバイスでこれらの機能を使用できます。 サポートライブラリのツールバーを使用すると、さまざまなデバイスでアプリが一貫して動作するようになります。

あと、上記のようなことも言ってるので、基本的にNoActionBar指定して、Toolbarを使うほうが良さそう。

最後に

Android開発は難しく感じるけど、新しいことをやるのはやはり楽しい! モバイル開発になれてない人は一緒に頑張りましょう!

AWS LambdaでAWS利用費を毎朝Slackに通知する

f:id:ryskit:20200102190802p:plain

明けましておめでとうございます! 今年もよろしくお願いします!

今年は、「個人ブログで技術ネタ50記事書く」という目標も立てたので早速1本目を書きます!

今回作りたいのはAWS Lambdaを使ってAWS利用費を毎朝通知する仕組みです。

イメージとしては、今日が2019年12月25日なら、2019年12月1日から2019年12月24日までのAWS利用費を朝7:00にSlackに通知するというものです。

では、さっそくいってみましょう!

Slack Appを作る

まず、AWS利用費を通知するためにSlack Appを作成して通知先のエンドポイントを発行する必要があります。

以下のURLにアクセスします。

https://api.slack.com/apps

アクセスしたら、 Create New App をクリックします。

f:id:ryskit:20200102172328p:plain

クリックするとモーダルが表示されるので、名前Workspace を指定します。

Workspace は自身のものや会社のSlackのWordspaceを指定すれば良いと思います。

f:id:ryskit:20200102172701p:plain

Create App をしたら以下のように Basic Informationのページに遷移するので、 そこで表示されている、Incoming Webhook をクリックします。

f:id:ryskit:20200102173102p:plain

Incoming Webhook をクリックしたら、以下のページに遷移します。

Activate Incoming webhookをon にしてあげます。

f:id:ryskit:20200102174011p:plain

すると、以下のように表示内容が変わります。

まだ、WorkspaceにWebhookを追加してない状態なので、Add New Webhook to Workspace をクリックします。

f:id:ryskit:20200102174209p:plain

クリックしたら、以下のようにアクセス権限を与えて良いか確認されます。 どのチャンネルにAWS利用費を通知するか決めたら、そのチャンネルを選択して、許可 をクリックします。

f:id:ryskit:20200102173417p:plain

許可したら、Webhookが追加されます。

ここで発行されたWebhook URLが必要になってくるので、コピーしておくなどしておいてください。

f:id:ryskit:20200102174734p:plain

ひとまず、Slack Appの準備は完了です。

AWS Lambdaのコードを書く

次はSlackへ通知するための、AWS Lambdaを作っていきます。 サクッとやってしまいたいのでFramework等は使わず、GoでLambdaを書いてみたかったので言語はGoを使います。

コードはこんな感じ。

package main

import (
    "bytes"
    "context"
    "encoding/json"
    "fmt"
    "github.com/aws/aws-lambda-go/lambda"
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/costexplorer"
    "net/http"
    "time"
)

const (
    SlackApi   string = "ここにSlack Appで発行したWebhook URLをコピペする"
    DateLayout string = "2006-01-02"
)

func NewCostExplorerClient() *costexplorer.CostExplorer {
    sess := session.Must(session.NewSessionWithOptions(session.Options{
        Config: aws.Config{
            Region: aws.String("ap-northeast-1"),
        },
        SharedConfigState: session.SharedConfigEnable,
    }))
    return costexplorer.New(sess, aws.NewConfig().WithRegion("ap-northeast-1"))
}

type CostInfo struct {
    Start  string `json:"start"`
    End    string `json:"end"`
    Amount string `json:"amount"`
}

type SlackMessage struct {
    Text string `json:"text"`
    Mrkdwn bool `json:"mrkdwn"`
}

type TimeStringHelper struct {
    Location *time.Location
    Now time.Time
}

func NewTimeStringHelper(locationName string) *TimeStringHelper {
    location, _ := time.LoadLocation(locationName)
    return &TimeStringHelper{
        Location: location,
        Now: time.Now().In(location),
    }
}

func (helper TimeStringHelper) GetBeginningOfLastMonth() string {
    return time.Date(helper.Now.Year(), helper.Now.Month() -1, 1, 0, 0, 0, 0, helper.Location).Format(DateLayout)
}

func (helper TimeStringHelper) GetBeginningOfMonth() string {
    return time.Date(helper.Now.Year(), helper.Now.Month(), 1, 0, 0, 0, 0, helper.Location).Format(DateLayout)
}

func (helper TimeStringHelper) GetYesterday() string {
    return time.Date(helper.Now.Year(), helper.Now.Month(), helper.Now.Day() -1, 0, 0, 0, 0, helper.Location).Format(DateLayout)
}

func (helper TimeStringHelper) GetToday() string {
    return time.Date(helper.Now.Year(), helper.Now.Month(), helper.Now.Day(), 0, 0, 0, 0, helper.Location).Format(DateLayout)
}

func (helper TimeStringHelper) IsTodayFirst() bool {
    return helper.Now.Day() == 1
}

func (helper TimeStringHelper) GetStartTimePeriod() string {
    if helper.IsTodayFirst() {
        return helper.GetBeginningOfLastMonth()
    } else {
        return helper.GetBeginningOfMonth()
    }
}


func GetCostInfo(helper *TimeStringHelper) *CostInfo {
    start := helper.GetStartTimePeriod()
    end := helper.GetToday()
    costExplorer := NewCostExplorerClient()
    output, err := costExplorer.GetCostAndUsage(&costexplorer.GetCostAndUsageInput{
        Granularity: aws.String("MONTHLY"),
        Metrics: []*string{
            aws.String("AmortizedCost"),
        },
        TimePeriod: &costexplorer.DateInterval{
            Start: aws.String(start),
            End:   aws.String(end),
        },
    })
    if err != nil {
        panic(err)
    }
    total := output.ResultsByTime[0].Total["AmortizedCost"]
    amount := aws.StringValue(total.Amount)

    return &CostInfo{
        Start:  start,
        End:    end,
        Amount: amount,
    }
}

func makeSlackMessage(costInfo *CostInfo, helper *TimeStringHelper) SlackMessage {
    return SlackMessage{
        Text: fmt.Sprintf("*期間*: `%s ~ %s`\n*料金*: `$%s`",
            costInfo.Start,
            helper.GetYesterday(),
            costInfo.Amount),
        Mrkdwn: true}
}

func PostToSlack(message SlackMessage) {
    input, _ := json.Marshal(message)
    fmt.Println(string(input))
    http.Post(SlackApi, "application/json", bytes.NewBuffer(input))
}

type Response struct {
    Message []byte `json:"message"`
}

func BillingNotification(ctx context.Context) (Response, error) {
    helper := NewTimeStringHelper("Asia/Tokyo")
    fmt.Println(helper.Now.Format("2006/01/02 15:04:05"))
    costInfo := GetCostInfo(helper)
    message := makeSlackMessage(costInfo, helper)
    PostToSlack(message)
    json, _ := json.Marshal(message)
    return Response{Message: json}, nil
}

func main() {
    lambda.Start(BillingNotification)
}

Githubにもアップしてるので、試してみたい方はぜひ使ってみてください。

github.com

コードに関して全ては説明しないですが、ピックアップして説明します。

AWS利用費の取得には、Cost Explorer を使います。 以下の部分ですね。

GranularityにはMONTHLY を指定します。 TimePeriodは、利用料の取得期間です。 たとえば、Startに 2019-12-01 、 Endに 2019-12-31を指定すると、 2019-12-01 から 2019-12-30までのAWS利用料を取得できます。 ここが間違えやすところかもしれません。

参考: https://docs.aws.amazon.com/aws-cost-management/latest/APIReference/API_GetCostAndUsage.html#awscostmanagement-GetCostAndUsage-request-TimePeriod

output, err := costExplorer.GetCostAndUsage(&costexplorer.GetCostAndUsageInput{
    Granularity: aws.String("MONTHLY"),
    Metrics: []*string{
        aws.String("AmortizedCost"),
    },
    TimePeriod: &costexplorer.DateInterval{
        Start: aws.String(start),
        End:   aws.String(end),
    },
})

Slackへ通知する際のmessageのpayloadも決まっているので、 それに合わせてメッセージをPostする必要があります。

func makeSlackMessage(costInfo *CostInfo, helper *TimeStringHelper) SlackMessage {
    return SlackMessage{
        Text: fmt.Sprintf("*期間*: `%s ~ %s`\n*料金*: `$%s`",
            costInfo.Start,
            helper.GetYesterday(),
            costInfo.Amount),
        Mrkdwn: true}
}

参照: api.slack.com

定数のSlackApi にはSlack Appで発行したWebhookのURLを貼り付けておいてください。

これができたら、ビルドしてzip化します。

ビルドは以下のコマンドで実行してください。

オプションをつけ忘れるとLambdaが実行できないので気をつけましょう!

GOARCH=amd64 GOOS=linux go build

ビルドしたら実行ファイルが生成されるので、以下のコマンドでzip化します。

zip billing-notification.zip ./billing-notification

そうすると、billing-notification.zip というzipファイルが生成されます。 これはあとでAWSコンソールでLambda関数を作るときに使います。

AWSコンソールからLambda実行用IAMサービスロールを作成する

IAMサービスロールにアタッチするポリシーのJSONは以下のように書きます。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents",
                "ce:GetCostAndUsage"
            ],
            "Resource": "*"
        }
    ]
}

IAMサービスロールはLambdaを選択してください。

f:id:ryskit:20200102181522p:plain

あとはよしなにIAMサービスロールを作成します。

AWSコンソールからLambdaの関数を作成する

AWSコンソールからLambdaを開いて作成してきます。

関数名: billing-notification ランタイム: Go 1.x 実行ロール: 先程作成したサービスロールを指定するので、既存のロールを使用する を選択し、セレクトボックスから作成したロールを探して選択します。

f:id:ryskit:20200102182049p:plain

関数を作成できたら、LambdaのトリガーにCloudWatch Events を指定しておいてください。

そして、zip化したLambdaのコードをアップロードします。

ハンドラ名は billing-notification と入力し、保存します。

f:id:ryskit:20200102182941p:plain

もうこれでSlackに通知することができます!

試しにテストしてみましょう。

テストイベントの設定をします。 作成したことがあれば以下のように表示されますし、してなければ テストイベントの設定 と表示されているはず?なので、 テスト をクリックします。

f:id:ryskit:20200102183614p:plain

もし新規で作る場合は以下のようにモーダルが表示されるので、適当な名前をつけて保存してください。

f:id:ryskit:20200102183805p:plain

そして、もう一度テストをクリックすると、Slackに利用料が通知されるはず!!

f:id:ryskit:20200102183930p:plain

ほぼできた🎉🎉🎉

作業もあと少しです!

AWSコンソールからCloudWatch Eventsの設定

Slackに通知する仕組みは作れました。

あとは、毎朝7時にAWS Lambdaを実行するようにしておきたいですよね?

そのためにCloucWatch Eventsを利用します。

Lambdaを作成したときにトリガーにCloudWatch Eventsを指定したのはそのためです。

それでは、AWSコンソールからCloudWatchを開きます。

開いたら以下のように、ルールと書かれた箇所をクリックします。

f:id:ryskit:20200102184644p:plain

クリックしたら以下のようにルールの作成をクリックします。

f:id:ryskit:20200102184907p:plain

そうしたら、以下のように設定してみてください。

Cron式0 22 * * ? * と指定していますが、UTC表記なのでこのままで問題ありません。

設定できたら 設定の詳細 をクリックします。

f:id:ryskit:20200102184801p:plain

ステップ 2: ルールの詳細を設定する 画面では、状態を有効化してルールを作成してください。

これで、毎朝7時にLambdaが実行されてSlackに通知が来るはずです🎉🎉🎉

f:id:ryskit:20200102185242p:plain

最後に

いかがでしたでしょうか?

Lambdaを使えばサクッとAWS利用費を通知できるので、今どれぐらい使っていて請求が来るのか把握しやすくなりました!

もしこの記事が良ければ、Twitterなどでシェアしてくださいね!

読んでくださってありがとうございました!

※ アイキャッチには@tentenのGopher by tenntenn CC BY 3.0を利用させていただいています。

Gitのあるコミット間で変更されたファイルを一覧で取得したい

git diffコマンドのオプションである --name-only をつけてあげると変更ファイルの一覧を取得できます。

git diff --name-only [コミットID] [コミットID]

以下のように出力されるので、これを加工する場合はパイプでつないでいけば良いですね。

wp-includes/js/dist/list-reusable-blocks.min.js
wp-includes/js/dist/media-utils.js
wp-includes/js/dist/media-utils.min.js
wp-includes/js/dist/notices.js
wp-includes/js/dist/notices.min.js
wp-includes/js/dist/nux.js
wp-includes/js/dist/nux.min.js
wp-includes/js/dist/plugins.js
wp-includes/js/dist/plugins.min.js
wp-includes/js/dist/priority-queue.js
wp-includes/js/dist/priority-queue.min.js
wp-includes/js/dist/redux-routine.js
wp-includes/js/dist/redux-routine.min.js
wp-includes/js/dist/rich-text.js
wp-includes/js/dist/rich-text.min.js
wp-includes/js/dist/server-side-render.js
wp-includes/js/dist/server-side-render.min.js
wp-includes/js/dist/shortcode.js
wp-includes/js/dist/shortcode.min.js
wp-includes/js/dist/token-list.js
wp-includes/js/dist/token-list.min.js
wp-includes/js/dist/url.js
wp-includes/js/dist/url.min.js
wp-includes/js/dist/vendor/lodash.js
wp-includes/js/dist/vendor/lodash.min.js
wp-includes/js/dist/vendor/react-dom.js
wp-includes/js/dist/vendor/react-dom.min.js
wp-includes/js/dist/vendor/react.js
wp-includes/js/dist/vendor/react.min.js
wp-includes/js/dist/vendor/wp-polyfill-fetch.min.js
wp-includes/js/dist/vendor/wp-polyfill.js
wp-includes/js/dist/vendor/wp-polyfill.min.js

おまけ

xargsの -I オプションを使うことで、標準入力で受け取った値をxargsに渡した引数のコマンドの任意の位置に展開することが可能です。 なので、git diff --name-onlyとxargs -Iを組み合わせることで、以下のようなことができます。

git diff --name-only c62ce56 52f858f | xargs -IIN scp IN aws-dev:/home/ec2-user

これはgit diffであるコミット間で変更されたファイルの一覧を標準出力してパイプでxargsに渡しています。 そして、パイプで受け取った標準入力は、xargsの-I オプションで任意の位置に展開してscpコマンドを実行してサーバーにファイルをコピーしています。 IN は自分で決めた値で、ここはXXXやYYYでも問題ありません。

CSSで画像をトリミングするためにobject-fitを使ってたら痛い目を見ました

久しぶりにHTMLコーディングをすることがありました。

大きい画像をCSSでトリミングして良い感じに表示したいなと思い、object-fit: cover; を使って良い感じに表示できてすごく便利になったものだなと感心してました。

で、あとから画像の比率がおかしいと指摘があり、ChromeやSafari・Firefoxで見ても崩れてないからキャッシュの仕業かなと思ってたんですが違いました。

ええ、コイツです。

f:id:ryskit:20190923231519p:plain

object-fit って便利なんですけど、IEが対応してくれてないのが残念だ。。。。

と思ってたら、JSでなんとか対応してくれるライブラリがありました。

object-fit-images ライブラリ

github.com

1. CSSを記述する

使い方は簡単で、ChromeやSafari・Firefoxはobject-fitを使えるので、その部分のCSSだけ外出しして以下のようにCSSを書いておきます。

.object-fit-img {
    object-fit: cover;
    font-family: 'object-fit: cover;';
}

大事なのは、 font-family: 'object-fit: cover;'; と記述している部分。 ここに書いているものがIEで適用されるので、ここを書き忘れるとIEでobject-fitが動きません。

これを書き忘れて、IEでも動かねーじゃねーかとハマってしまいました。。。ごめんなさい。

2. ofi.min.js ファイルを読み込む&有効にする

object-fit-images をダウンロードすると、 dist ディレクトリの下に、 ofi.min.js が入っているのでそれをheadタグ内で読み込めるように設定してください。

その後、JSファイルやスクリプトタグの中で、以下のように記述してください。

objectFitImages('img.object-fit-img');

これがないと、IEで有効にならないので注意。 img.object-fit-img は class名:  object-fit-img が付けられたimgタグに対して有効にするとしています。 ここはよしなに変更してください。

3. object-fitを使いたいimgタグにクラス名を付ける

1.で記述したクラス名をimgタグのクラス名に追加してください。 これでIEでもobject-fitが使えるようになります!

<img class="object-fit-img" src="...">

最後に

Web制作って久しぶりにやると楽しいけど、各ブラウザへの対応とかどこまで保証するかとか大変だなと思いました。

個人的にサーバー書いてるほうが楽しいな!

MVVMアーキテクチャでAPIからビール情報を取得して表示するコードを書くのに役立った記事をまとめておく

PUNK APIというBREW DOGのビール情報を返してくれるAPIがあり、それを使って簡単なデータ表示アプリをMVVMアーキテクチャで作ったときに役立った記事のリンクを備忘録としてまとめておく。

ライブラリは以下を利用した。

  • HTTP通信周り
    • OkHttp4
    • Retrofit2
  • Serde
    • GSON
  • DI
    • Koin
  • Databinding
  • Coroutine

先輩の記事

前々からプライベートでAndroidアプリを作ることが決まっていて、 Androidアプリ開発自体が初めてなので、イマイチどのライブラリを使えば良いか分からなかったり、そもそも使い方もどうやるんだろうと試行錯誤していて、 同じ会社の先輩に相談したりしていた。

たまたま、TwitterでRetrofit2やmoshiの記事を連投していると、その先輩がこういうので作ってみるといいよーとわざわざサンプルアプリを作って共有してくださってかなり理解も進んだような気がする!ありがとうございます!

そのサンプルアプリについての記事がこれ。

dev.classmethod.jp

Githubのリポジトリはこれ。

github.com

Android開発で書籍に出てくるようなサンプルアプリを作ったあと右往左往している状態なら、ひとまずリポジトリのコードを読んで試してみると良いかも!

Databindingを学ぶならこれ

たぶん技術書典で販売されていたものだと思う。 これは読んでいてすごく勉強になった。感謝!

booth.pm

Databinding + RecyclerViewで悩んだらこれ

記事ではないけど、サンプルアプリのコードを読めばいろいろ理解できるからおすすめ!

このリポジトリは良かった。

github.com

Retrofit2

square.github.io

qiita.com

Koin

Koinは先輩のコード読んだりドキュメント読んだり、記事読んだりしたぐらい。 やっぱり、ドキュメント読みつつ、他人のコードを読むのが一番理解できる。

insert-koin.io

qiita.com

Coroutine

ココらへんを読んだ気がする。まだまだ使いこなせてないから頑張るぞ!

qiita.com

qiita.com

最後に

自分のコードはある程度、書き直してからGithubのリポジトリにアップする予定です。