masked雑記

IT関連の記事を書く

BacklogAPIを利用してファイルを添付する

目的

Backlog API を利用して課題にファイルを添付する。

Backlog API

developer.nulab.com

BacklogAPIを利用して課題にファイルを添付するには、「添付ファイルの送信」/api/v2/space/attachmentを行い添付ファイルのIDを発行し、その後「課題コメントの追加」/api/v2/issues/:issueIdOrKey/commentsを呼び出す必要がある。
今回はファイルアップロード部分を実装したかっただけなので、適当なプロジェクトの適当な課題にファイルを添付する。
RubyPythonで実装した。友人に依頼されて最初にRubyで書いたけど、友人はPython使ってるからPythonで書き直した。

Ruby

使用したgem

rest-client, '2.1.0'

共通部分実装

require 'json'
require 'uri'
require 'rest-client'

base_url = 'https://<組織名>.backlog.com'
api_key = '<Backlogの個人設定で発行したAPIキー>'

プロジェクト一覧を取得する

ファイルを添付するための課題がある適当なプロジェクトIDを取得する。

response = RestClient.get(
  "#{base_url}/api/v2/projects", 
  {params: { apiKey: api_key }})
project_id = JSON.parse(response.body)[0]['id']
puts "project_id: #{project_id}"

プロジェクトの課題を取得

プロジェクトIDからファイルを添付するための適当な課題IDを取得する。

response = RestClient.get(
  "#{base_url}/api/v2/issues",
  {params: {apiKey: api_key, projectId: [project_id]}})
issue_id = JSON.parse(response.body)[0]['id']
puts "issue_id: #{issue_id}"

ファイルをアップロード

ファイルをアップロードし、IDを発行する。

request = RestClient::Request.new(
  method: :post,
  url: "#{base_url}/api/v2/space/attachment?"\
  "#{URI.encode_www_form({apiKey: api_key})}",
  payload: {
    multipart: true,
    file: File.new('/tmp/test_text_1.txt', 'rb')
  })
response = request.execute
file_id = JSON.parse(response.body)['id']
puts "file_id: #{file_id}"

課題にファイルを添付

上記で取得した課題IDとファイルのIDを利用してコメントを作成する。

response = RestClient.post(
  "#{base_url}/api/v2/issues/#{issue_id}/comments?"\
  "#{URI.encode_www_form(
    {apiKey: api_key, content: 'ファイル添付テスト', 'attachmentId[]' => [file_id]})}", 
  {})
puts "code: #{response.code}"
puts "body: #{response.body}"

Python

使用したパッケージ

requests==2.22.0

共通部分実装

import urllib.parse
import requests

baseUrl = 'https://<組織名>.backlog.com'
apiKey = '<Backlogの個人設定で発行したAPIキー>'

プロジェクト一覧を取得する

ファイルを添付するための課題がある適当なプロジェクトIDを取得する。

projectUrl = "%s/api/v2/projects?apiKey=%s" % (baseUrl, apiKey)
response = requests.get(projectUrl).json()
projectId = response[0]['id']
print("projectId: %s" % projectId)

プロジェクトの課題を取得

プロジェクトIDからファイルを添付するための適当な課題IDを取得する。

issueUrl = "%s/api/v2/issues?apiKey=%s&projectId[]=%s" % (baseUrl, apiKey, projectId)
response = requests.get(issueUrl).json()
issueId = response[0]['id']
print("issueId: %s" % issueId)

ファイルをアップロード

ファイルをアップロードし、IDを発行する。

filePath = '/tmp/test_text_1.txt'
files = {'file': ('test_text_1.txt' ,open(filePath, 'rb'))}
uploadUrl = "%s/api/v2/space/attachment?apiKey=%s" % (baseUrl, apiKey)
response = requests.post(
    uploadUrl,
    files = files).json()
attachmentId = response['id']
print("attachmentId: %s" % attachmentId)

課題にファイルを添付

上記で取得した課題IDとファイルのIDを利用してコメントを作成する。

content = '添付コメント'
commentUrl = "%s/api/v2/issues/%s/comments?apiKey=%s&attachmentId[]=%s&content=%s" % (baseUrl, issueId, apiKey, attachmentId, urllib.parse.quote(content))
response = requests.post(commentUrl).json()
print("response: %s" % response)

unicornのloggerを変更する

なんでこんな記事を

unicornのloggerを変更したくて"unicorn logger"で検索したら船が出てくるので。
船をgoogle検索から除きたい場合は"-ship"とつけて検索してください。

www.google.com

ソースを読む

github.com

debug info warn error fatalが実装されてるオブジェクトを設定すればいい
デフォルトのロガーはconfiguratorのDEFAULTSにある通りLogger.new($stderr)

実装する

unicornに読み込ませる設定ファイルを作成する。

config/unicorn.rb

require 'json'

class MyLogger < Logger
  def format_message(severity, timestamp, progname, msg)
    JSON.dump({severity: severity, timestamp: timestamp, progname: progname, msg: msg}) + "\n"
  end
end

logger MyLogger.new(STDOUT)

今回は適当に標準出力にJSON形式のログを出力するようにしました。

実行結果

コマンド

bundle exec unicorn_rails -p 8080 -c config/unicorn.rb

結果

{"severity":"INFO","timestamp":"2019-07-14 22:54:32 +0900","progname":null,"msg":"listening on addr=0.0.0.0:8080 fd=9"}
{"severity":"INFO","timestamp":"2019-07-14 22:54:32 +0900","progname":null,"msg":"worker=0 spawning..."}
{"severity":"INFO","timestamp":"2019-07-14 22:54:32 +0900","progname":null,"msg":"master process ready"}
{"severity":"INFO","timestamp":"2019-07-14 22:54:32 +0900","progname":null,"msg":"worker=0 spawned pid=88745"}
{"severity":"INFO","timestamp":"2019-07-14 22:54:32 +0900","progname":null,"msg":"Refreshing Gem list"}
{"severity":"INFO","timestamp":"2019-07-14 22:54:35 +0900","progname":null,"msg":"worker=0 ready"}

できた。

Corretto11 + Maven + SpringBoot + Dockerでアプリを動かす

目的

Corretto11を利用してDockerコンテナを動かしたい

2019/3/17追記

Corretto11のDockerが公開されました。

corretto-11-docker/Dockerfile at 13edf15055f74d5cbe0c3f5f8a0c1665414cadfd · corretto/corretto-11-docker · GitHub

使用している環境

Docker version 18.09.2
Corretto11 (java version "11.0.2" 2019-01-15 LTS)
maven (Apache Maven 3.6.0 (97c98ec64a1fdfee7767ce5ffb20918da4f719f3; 2018-10-25T03:41:47+09:00))

プロジェクトを作成する

mvn -B archetype:generate -DgroupId=com.maskedgetter -DartifactId=rest-service -Dversion=1.0.0-SNAPSHOT -DarchetypeArtifactId=maven-archetype-quickstart

pom.xmlを編集

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.maskedgetter</groupId>
  <artifactId>rest-service</artifactId>
  <packaging>war</packaging>
  <version>1.0.0-SNAPSHOT</version>
  <name>rest-service</name>
  <url>http://maven.apache.org</url>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.3.RELEASE</version>
  </parent>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
  </dependencies>
  
  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
</project>

App.javaを編集

作成されたApp.javaを編集して、/にアクセスされた時に0を返すように実装する。

package com.maskedgetter;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class App extends SpringBootServletInitializer{
    public static void main( String[] args ){
        SpringApplication.run(App.class, args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(App.class);
    }

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String getZero() {
        return "0";
    }

}

warファイルを作成

mvn clean package spring-boot:repackage

Dockerfileを作成

FROM amazonlinux:2

ENV \
  JAVA_HOME=/opt/jdk \
  PATH=${JAVA_HOME}/bin:PATH \
  APP_NAMW=

RUN \
  yum -y update && \
  yum -y install wget gzip tar && \
  wget https://d2jnoze5tfhthg.cloudfront.net/amazon-corretto-11.0.2.9.1-linux-x64.tar.gz && \
  tar xvzf amazon-corretto-11.0.2.9.1-linux-x64.tar.gz && \
  rm amazon-corretto-11.0.2.9.1-linux-x64.tar.gz && \
  mv amazon-corretto-11.0.2.9.1-linux-x64/ /opt/jdk && \
  rm -rf /var/cache/yum/* && \
  yum clean all && \
  wget http://ftp.yz.yamagata-u.ac.jp/pub/network/apache/tomcat/tomcat-9/v9.0.16/bin/apache-tomcat-9.0.16.tar.gz && \
  tar xvzf apache-tomcat-9.0.16.tar.gz && \
  rm apache-tomcat-9.0.16.tar.gz && \
  mv apache-tomcat-9.0.16 /opt/tomcat

COPY ./target/rest-service-1.0.0-SNAPSHOT.war /opt/tomcat/webapps/rest-service.war

CMD ["sh", "/opt/tomcat/bin/catalina.sh", "run"]

Dockerイメージの作成と実行

docker build -t spring-corretto11 .
docker run --name spring-corretto11 -itd -p 8080:8080 spring-corretto11

リンクにアクセス
http://0.0.0.0:8080/rest-service/ f:id:lambdakura:20190226003654p:plain 0が出た

メモ

コンテナにアクセスしたい

docker exec -it spring-corretto11 /bin/bash

コンテナを止めたい

docker stop spring-corretto11

参考にしたサイト

Getting Started · Building a RESTful Web Service

Java SE Subscriptionを契約する

経緯

2019年1月でOracleJDK8のアップデートが切れる。

Oracle Java SE サポート・ロードマップ

JDKのバージョンアップを半年ごとに行うのが現実的でないため、保守契約を結ぼうという話になった。 日本オラクルに問い合わせした内容をまとめる。 正式名称は"Java SE Subscription"

Java SE Subscriptionについて

Java有償保守サービス Java SE Subscription | NTTデータ先端技術株式会社

NTTデータ先端技術株式会社様のサイトに

サポートのサービス提供者の違い 従来のJava商用サポートサービスは当社からご提供しておりましたが、Subscriptionモデルのサポートはオラクル社から直接提供されます。お客さまがお問合せする先もオラクル社になります。

と書かれていたので先ず日本オラクルに問い合わせた。 何度かやり取りをした内容をまとめると

  • Java SE Subscriptionは日本オラクルの直接の提供はない
  • Java SE SubscriptionはオラクルのPlatinumまたはGoldパートナーからのみ提供される
  • パートナーによってはJava SE Subscriptionの取り扱いはない

という内容が得られた。

ラクルパートナーについて

こちらのサイトでオラクルパートナーについて検索できる。

Oracle PartnerNetwork | Partner and Solutions Finder | Oracle

AWS EC2の取り扱いについて

Java SE Subscriptionの金額はプロセッサ単位と書いてある。

オラクル Java SE Subscription FAQ

1プロセッサ3,000円とかぼったくりやろこれぇ、もう新規案件でJava選べねーよ...

現在使用しているのがAWS EC2なのでvCPUしかない。 EC2は仮想CPUなんだけどどうなんだって聞いたら返答があった。 以下のリンクを参照してくださいとのこと

http://www.oracle.com/us/corporate/pricing/cloud-licensing-070579.pdf

どうやらハイパースレッディングが有効なプロセッサは2vCPUで1プロセッサ、無効なものは1vCPUで1プロセッサと計算するらしい。

結論

Java SE Subscriptionの契約を結ぶ場合はオラクルパートナーと契約を結ぶ。

2018/11/1 追記 とか思ってたらAmazon様からこんな記事が

Amazon LinuxでのJavaのLTS (Long-Term Support)提供について | Amazon Web Services ブログ

特に理由がなければAmazon Linux 2使いましょ

Unity試験 最速受験感想

Unity認定開発者試験を受験してきました。
日本では一般に公開される試験の第一回目にあたります。

結果

合格
25分で回答終了して退出しました。(1番最初の退出でした)
正答率は90%
受験者数は15名ほど

試験概要

maskedgetter.hatenablog.com

前回の記事でも書きましたが追記

  • 試験はwebブラウザで行う
  • 問題の回答し直しはできない
  • 16項目の1項目ごとに採点される
  • 出題はランダムに抽出される
  • バージョンは5.3基準(2017/10/15 現在)

所感

Unity公式コースウェア受けてて良かったと感じました。 それというのも試験全体の8割はUnity公式コースウェアの自己評価で出る問題の類題だったからです。
※出題がランダムなので一概には言えませんが

残りは一般的な業界知識とUnityの基本的な機能でした。

コースウェアを受験していないから合格は厳しいという訳ではないと思いますが、独特な問題文なのである程度の慣れは必要かなと思いました。
サンプル問題とか参考書がないの本当に厳しい。

Unity公式コースウェア

Unity公式コースウェアはproライセンスを持っていると3ヶ月、plusライセンスだと1ヶ月は無料で視聴することができます。 また、VRアカデミー様でもコースウェアの購入が可能となっています。

vracademy.jp

コースウェアない人向け

  • 試験範囲を理解しよう
    • 試験範囲に明記されているものは必ず出題されます。逆に書いていないものは出ません。
  • コンポーネント
    • 追加方法
    • Inspector
    • 設定項目の理解 「この項目は〜を設定している」
    • 実現方法の理解 「〜をするためには〜をすればいい」
  • Editor
    • 各種Windowの説明
      • Windowの呼び出し方
      • このWindowでは何ができるのか
    • Window内での操作方法
  • プログラミング
    • 使用する言語C#についてのある程度の理解
    • MonoBehaviourのイベント関数はいつ実行されるのか

普段Unityを使う際に、あまり自分で触らない部分については十分な理解を持って臨んだ方がいいと思います。

おわりに

合格してほんと嬉しい。資格があるからなんなんだって感じもしますが、自分にとってUnityを別の視点から見るいい機会になったと思います。
ありがとUnity

Unity試験について

今週の土曜日に試験なので

Unity試験概要

http://japan.unity3d.com/certification/unity-certified-developer-exam-objectives-2016-09-15-jpn.pdf

正式名称:Unity認定開発者試験(Unity Certified Developer Exam)
問題数 :100問
試験時間:90分
合格条件:70%以上
出題形式:選択問題、マッチング問題、カーソル問題
価格  :24,000円(税抜)

試験項目

  1. アニメーション
  2. アセット管理
  3. オーディオ
  4. Editorのインターフェース
  5. 職務における心構え
  6. ゲームアートの原則
  7. ゲームデザインの原則
  8. 業界情報
  9. ライティング
  10. MaterialとEffect
  11. ナビゲーションと経路探索
  12. Physics
  13. プログラミング
  14. プロジェクト管理
  15. サービス
  16. ユーザインタフェース

今後の試験展開

blogs.unity3d.com

2018年の早期に新しい3つの試験が出るらしいです。
日本に来るのは2019年かな?

Unity製ゲームで解像度設定によって速度が変わる

www.nicovideo.jp

www.nicovideo.jp

の駄菓子兄貴リスペクトのゲーム(Unity製)を見ていて

両者に共通する解像度設定によって速度が変わるという事象

について解析してみようと思った。
そんな事しなくていいから(良心)

事象の確認

まずは事象を観察すると以下の2点が挙げられる。

  • グラフィックボードの性能をあげると高速ディフェンス
  • グラフィクス設定をFastestにすると高速移動

したがって「フレームレートが上がるとそれに伴い加速度が増える」というのが見えてくる。

Unityのフレーム単位での処理について

Unityでは更新処理に使われる関数が複数存在するが、主に使われるのはUpdate関数かFixedUpdate関数だろう 関数の違いについて簡単に説明する。

Update

フレーム単位ごとに呼び出される。フレームレートが90なら1秒間に90回呼び出される。 主に入力系やカメラの移動などの記述をする。

FixedUpdate

独立したタイマーから呼び出される。デフォルト設定だと0.02秒に1回呼び出される。 この関数の直後に物理演算を実行するので、物理演算(Rigidbody)に関するものはこちらに記述する。


おそらくFixedUpdateでなくUpdateでオブジェクトに力をかけて加速させている。

検証

f:id:lambdakura:20171012005528p:plain

黄色い板に乗っている間だけ加速するようなゲームを作った

基底クラスBaseAccelerator

using UnityEngine;

public abstract class BaseAccelerator : MonoBehaviour {

    public float power = 50f;
    public bool isEnter = false;
    protected Rigidbody playerRig;

    public int addCount = 0;

    void OnCollisionEnter(Collision collision) {
        var obj = collision.gameObject;
        if (obj.CompareTag ("Player")) {
            playerRig = obj.GetComponent<Rigidbody> (); 
        }
        isEnter = true;
    }

    void OnCollisionExit(Collision collision) {
        isEnter = false;
    }
}

BaseAcceleratorを継承し、FixedUpdateで加速処理をするFUpdAccelerator

using UnityEngine;

public class FUpdAccelerator : BaseAccelerator {
    void FixedUpdate(){
        if (isEnter) {
            playerRig.AddForce (Vector3.right * power);
            addCount++;
        }
    }
}

BaseAcceleratorを継承し、Updateで加速処理をするUpdAccelerator

using UnityEngine;

public class UpdAccelerator : BaseAccelerator {   
    void Update(){
        if (isEnter) {
            playerRig.AddForce (Vector3.right * power);
            addCount++;
        }
    }
}



結果

FixedUpdateは全ての画面解像度とQuality設定で同一の地点で止まった f:id:lambdakura:20171012005946p:plain

一方Updateは画面解像度が下がるほど、Quality設定を下げるほど制動距離は伸びた。
640 x 480 Quality:VeryLow f:id:lambdakura:20171012010250p:plain

1366 x 768 Quality:Ultra f:id:lambdakura:20171012010449p:plain



結論

物理演算をさせるときはUpdateではなくFixedUpdateを使おう

参考

Unity - マニュアル: イベント関数の実行順

Unity - Update と FixedUpdate