PR TIMESデザイナー&エンジニアブログ BREAK TIMES

PR TIMES Developer Blog(デザイナー&エンジニアによる開発者ブログ)

PR TIMES Developer Blog

当ブログは下記URLに移転しました。
https://developers.prtimes.jp/

ブラウザに怒られないHTTPSサーバをLet's Encryptとnginxで作る - LINE BOT APIで遊ぶ 準備編

エンジニアの深川です。

今回はLINE BOT API Trial で遊んだ内容について書こうと思っていたのですが、

LINE Developers - BOT API - Overview

LINE BOT API のCallback URLはSSL通信なので、雑なHTTPサーバを用意すればいいかなという目論みは外れて、ドメイン取得、SSL証明書の発行、WEBサーバの設定とやって、HTTPS接続可能なWEBサーバを用意する必要があります。

今回はLINE BOT API Trial を使う前段ということで、お題がSSL証明書の警告の出ないHTTPSサーバの構築について。OSはCentOS6を想定

※ 追記:LINE BOT API Trial、追加募集開始とのことです。
【LINE】「LINE BOT API Trial Account」の追加募集を開始 | LINE Corporation | ニュース


f:id:breaktimes:20160425125520p:plain:w250


手順です。

1. ドメインの取得
2. Let's EncryptからSSL証明書の作成
3. nginxのインストールと設定

1. ドメインの取得

お名前.comとかムームードメインとかバリュードメインなどでサクッと取りましょう。
特に使い続ける必要が無いなら、linkとか安いドメインしてしまっていいと思います。ドメインを取得したら、そのままDNS AレコードをサーバのIPアドレスで登録します。

2. Let's EncryptからSSL証明書の取得

ここから本編です。
SSLの証明書の取得はLet's Encryptを利用します。Let's Encryptについては下記のリンクで確認してください。

letsencrypt.jp


Let's EncryptはPython2.6以下だど動かないので、その場合はPython2.7.9を入れましょう

mkdir src
cd src
wget https://www.python.org/ftp/python/2.7.9/Python-2.7.9.tgz
tar zxvf Python-2.7.9.tgz
cd Python-2.7.9
mkdir /opt/python
./configure --prefix=/opt/python
make
sudo make install

古いPythonをリネームして、新しい方にPathを通します。

which python
mv /usr/bin/python /usr/bin/python_old
ln -s /opt/python/bin/python /usr/bin/python
python --version
cd ../

Pythonのバージョンを上げると、yumが動かなくなるのでyum側を修正します。

vim /usr/bin/yum

下記のように一行目を修正します。

#!/usr/bin/python_old
import sys
try:
    import yum
except ImportError:
    print >> sys.stderr, """\
There was a problem importing one of the Python modules
required to run yum. The error leading to this problem was:

   %s

Please install a package which provides this module, or
verify that the module is installed correctly.

It's possible that the above module doesn't match the
current version of Python, which is:
%s

If you cannot solve this problem yourself, please go to 
the yum faq at:
  http://wiki.linux.duke.edu/YumFaq
  
""" % (sys.exc_value, sys.version)
    sys.exit(1)

sys.path.insert(0, '/usr/share/yum-cli')
try:
    import yummain
    yummain.user_main(sys.argv[1:], exit_code=True)
except KeyboardInterrupt, e:
    print >> sys.stderr, "\n\nExiting on user cancel."
    sys.exit(1)

やっとLet's Encryptに着手できます……

git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt
./letsencrypt-auto certonly -a standalone -d www.example.com
sudo ls -la /etc/letsencrypt/live/www.example.com

lsの結果がこんな感じなら成功です(ドメインは適宜自分のものに変更してください)

  • cert.pem
  • privkey.pem
  • chain.pem
  • fullchain.pem

3. nginxのインストールと設定

sudo yum -y insatall nginx
sudo nginx
sudo vim /etc/nginx/conf.d/default.conf

3-7行目に適合する部分を変更します。

server {
    listen       80  default_server;
    listen       443 ssl;
    server_name  www.example.com;
    ssl_certificate     /etc/letsencrypt/live/www.example.com/cert.pem;
    ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

設定の再読み込み後、httpsで対象のドメインにアクセスできれば完了です。

sudo /etc/init.d/nginx reload

f:id:breaktimes:20160425125249p:plain

次回こそ、LINE BOT APIについて書きます。

React NativeでサクッとIOSアプリを作ってみた

PR TIMESエンジニアの吉です。本日はスマートフォンアプリ開発について話したいと思います。

基本的にIOSアプリはSwiftObjective-CAndroidJavaで開発しますが学習コストが必要です。シンプルなアプリあるいはプロトタイプのアプリなど早くアプリを作りたい場合はSwiftjavaを使わなくても作れる方法はいろいろあります。 Monaca, PhoneGap, Titanium Mobile, React Native...

私はプロジェクト性質や開発メンバーのスキルなどを考慮してどれを選ぶのかを決めるべきたと思っています。適切な判断をするためには様々な技術を積極的に触ってみるのがいいでしょう。

このブログで紹介したいのはReact Nativeです。 f:id:breaktimes:20160422133322p:plain

開発元はfacebookjavascriptを使ってとても簡単にアプリを開発できるのが特徴です。今年のF8イベントのアプリもReact Nativeで開発したようでダウンロードして使ってみたらすごく完成度が高いアプリでした。

F8

F8

ソースコードも公開されているので本格的に勉強してみたい方はぜひ中身を確認してみてください。 github.com

本ブログではReact Nativeの公式ドキュメントのチュートリアルを参考にして書きました。 instagram APIとReact Nativeを使用して簡単なIOSアプリを作ってみました。

準備

1.homebrewでファイル監視ツールのwatchmanとjavascriptチェッカーツールのflowをインストールする

brew install watchman flow

2.node4.0以上のバージョンをインストール - nvmかnodebrewを利用バージョンコントロールすることをおすすめ

3.xcode7.0以上のバージョンをインストール

セットアップ

1.react nativeのcliをインストール

npm install -g react-native-cli

2.react nativeのプロジェクトファイルを作成する

react-native init react_ios_app

上記のコマンドで生成されたreact_ios_app/index.ios.jsファイルを修正します。

ソースコードの解説

使用するコンポーネントを読み込み

import React, {
  AppRegistry,
  Component,
  Image,
  ListView,
  StyleSheet,
  Text,
  View,
} from 'react-native';

InstagramのリクエストURLを定義

アクセストークン生成方法についてはInstagramデベロッパーページを参照してください。

var ACCESS_TOKEN = '';
var API_URL = 'https://api.instagram.com/v1';
var PARAMS = '/users/self/media/recent/?access_token=' + ACCESS_TOKEN;
var INSTAGRAM_REQUEST_URL = API_URL + PARAMS;

クラスとコンストラクタの定義

みなさんご存知のようにクラスが生成されるときに呼び出されるconstructorにリスト表示で使用するListViewのデータソースを初期化します。

class react_ios_app extends Component {

  constructor (props) {
    super(props);
    this.state = {
       dataSource: new ListView.DataSource({
         rowHasChanged: (row1, row2) => row1 !== row2, }),
         loaded: false,
    };
  }

Instagram APIから取得したデータをセットする

componentDidMountはコンポーネントがロードされた直後に1回だけ呼び出されます。

  componentDidMount() {
    this.fetchData();
  }

  fetchData() {
    fetch(INSTAGRAM_REQUEST_URL)
      .then((response) => response.json())
      .then((responseData) => {
        this.setState({
          dataSource: this.state.dataSource.cloneWithRows(responseData.data),
          loaded: true,
        });
      })
      .done();
  }

レンダリング

Instagram APIコール前はローディングの文字をAPIからデータ取得完了後は実データをリストに表示する処理です。

  render() {
    if (!this.state.loaded) {
      return this.renderLoadingView();
    }
    return (
      <ListView
        dataSource={this.state.dataSource}
        renderRow={this.renderMovie}
        style={styles.listView}
      />

    );
  }

  renderLoadingView() {
    return (
      <View style={styles.container}>
        <Text>
          Loading Photos ...
        </Text>
      </View>
    );
  }

  renderMovie(feed) {
    return (
      <View style={styles.container}>
        <Image
          source={{uri: feed.images.thumbnail.url}}
          style={styles.thumbnail}
        />
        <View style={styles.rightContainer}>
          <Text style={styles.title}>{feed.caption.text}</Text>
          <Text style={styles.year}>{feed.caption.created_time}</Text>
        </View>
      </View>
    );
  }
}

スタイル設定

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  thumbnail: {
    width: 150,
    height: 150,
  },
  rightContainer: {
    flex: 1,
  },
  title: {
    fontSize: 13,
    marginBottom: 8,
    textAlign: 'center',
  },
  year: {
    fontSize: 13,
    textAlign: 'center',
  },
  listView: {
    paddingTop: 20,
    backgroundColor: '#F5FCFF',
  },
});

全てのソースコードに関しては私のGitHubに公開しました。

github.com

iosアプリをビルドする

react-native run-ios


react native ビルド

感想

react nativeを利用するためにはreact.jsの使い方をある程度覚えないといけないことに気づきました。それにしてもswift,javaを使わずjavascriptだけで数時間でシンプルなアプリを開発できるのはすごく嬉しいですね。

使い方次第ではfacebookのf8アプリのような洗練されたアプリも開発できますし、ほぼ同じコードでIOS, Androidのアプリが同時開発できます。React Nativeは現時点でバージョン0.24です。メージャーリリースはしてないので仕事で導入するのはまだ早いと思いますが、これからもっと使いやすく高機能になると思いますのでみなさんもぜひ使ってみてはいかがでしょうか。

Chefでメール送信開発環境をサクッと作る

こんにちは!エンジニアの落合です。

前回の記事で、メール送信機能における開発環境について書かせていただきました。
開発環境なので、基本的に毎回同じものを使います。chefのようなプロビジョニングが有効的です!
具体的な詳細は、前回の記事で確認していただければと思います。
今回は、Chefで簡単に送信開発環境をできるレシピを紹介したいと思います。

fileの配置

まずは、設定ファイルをあらかじめ取得しておいて、設定変更を行い、
files/default内に配置しておきます。
今回使用するファイルは以下の通りです。

  • aliases.regexp
  • transport_maps
  • main.cf
  • dovecot.conf
  • 10-mail.conf
  • 10-auth.conf

recipeの作成

それでは、recipeを作成したいと思います。
まずは、postfixを起動できる状態にして、postfixの設定を変更します。

service "postfix" do
    supports :status => true, :restart => true, :reload => true
    action [ :enable, :start ]
end

#postfixの設定を変更
cookbook_file "/etc/aliases.regexp" do
  source "aliases.regexp"
  mode "0644"
end
cookbook_file "/etc/postfix/transport_maps" do
  source "transport_maps"
  mode "0644"
end
cookbook_file "/etc/postfix/main.cf" do
  source "main.cf"
  mode "0644"
end

次にユーザーを作成して、受信できる状態にします。

## ID   catchall
## PASS catchall
user "catchall" do
    comment "catchall"
    home "/home/catchall"
    shell "/bin/bash"
    password "$1$ks.iXsX.$tTErfotf/Zg2n.0zZlFxl1"
    supports :manage_home => true
end

bash "catchallsetup" do
  cwd catpath
  code <<-EOH
    sudo su
    usermod -s /bin/false catchall
  EOH
  notifies :reload, 'service[postfix]'
end

最後に受信できるように受信サーバーの設定を設定を行います。

yum_package "dovecot" do
  action :install
end
cookbook_file "/etc/dovecot/dovecot.conf" do
  source "dovecot.conf"
  mode "0644"
end
cookbook_file "/etc/dovecot/conf.d/10-auth.conf" do
  source "10-auth.conf"
  mode "0644"
end
cookbook_file "/etc/dovecot/conf.d/10-mail.conf" do
  source "10-mail.conf"
  mode "0644"
end
directory "/home/catchall/mail/.imap/INBOX" do
  recursive true
  owner "catchall"
  group "catchall"
  action :create
end

最後に、dovecotを再起動すれば完璧です!

service "dovecot" do
  supports :status => true, :restart => true, :reload => true
  action [ :enable, :restart ]
end

これを行ったら、rainloop等のWEBメーラーツールを使用して、受信できるような環境を用意しましょう!
それに関しての手順は、前回の記事を参照して下さい!

メール送信機能における開発環境

VR関連のコンテンツやガジェトおすすめ8選

デザイナーの新井です。Oculus RiftHTC Viveなどのハイエンドのヘッドマウントディスプレイが発売され、VRが一般家庭でも楽しめるようになりました。スマートフォンをヘッドセットに装着して使用するタイプのGear VRなど手が出やすい価格のものが発表され盛り上がりを見せていますね。VRを楽しむためのコンテンツも揃ってきましたので今回はVR関連のコンテンツやコンテンツを作るガジェットなどを紹介したいと思います。

続きを読む

古いPHPアプリケーションの移行について考えてみる

エンジニアのアカイです。

レガシーマイグレーションなどと聞くと、基幹システムで大規模なリプレースを行って、 プロジェクトが炎上…というようなものを想像してしまいますが、 Webアプリケーションにおいても同様の問題が多く発生する時期なのではないかと思います。 実際、ここ数年私もそういうシステムばかり触っているような気がします。

モデルケース

  1. 大きな分類での機能(フロント機能/管理機能など)がすべて一か所に集中している
  2. ドキュメントがなく、詳細仕様はコードを解析しなければならない
  3. データベースの構成変更は管理されていない状態
  4. 運用中のシステムであるため、長期のメンテナンスは実施できない
  5. 新しい機能のリリース頻度が高い

このような状況では、開発者はシステム全体を新しいものに入れ替えることを考えますが、 上記のような項目が足かせになり、実現は困難になります。

コードレベルでの移行(クラス/メソッドのリライトなど)が、 実際に多く行われている方法だと思います。 これは、大きな変更を行わずともすぐに実施できるからですが、 根本的な問題の解決には至らないことが多いです。

従って、今回は上記の「大きな機能分類」を別のシステムで再構築する、 という観点から移行を考えてみたいと思います。

続きを読む

人感センサーと連携したアプリをつくりたい☆*:.。.1.検討編

PR TIMES エンジニアのうさみです。今年1月に新オフィスに移転してから、もうすぐで3ヶ月・・・暖かい季節になってまいりました☆

f:id:breaktimes:20160125200724j:plain

移転の際に設置した弊社オリジナルの受付アプリも、それだけの間、お客様にご利用いただいているのですが、そろそろ機能改善も含めつつ新しい機能も盛り込んでバージョンアップをしたいなと考えています。

新機能として一番に取り入れたいことは、人感センサーを利用して受付アプリ側でアクションを起こすことです。具体的には、以下のようなことを実現したいです。

お客様がエントランスにいらっしゃったら人感センサーが感知して受付アプリが◯◯◯をする (◯◯◯の箇所は考案中)

人感センサーというと電子工作の知識を必要としそうですが、あいにく私は詳しくはありません。。そんな私でも実現できる方法がきっとあるはず!という思いで調べてみましたところ・・・ありました! 私の技術力の範囲では以下のどちらかの方法で実現ができそうです。

1. 超小型PC「Raspberry Pi」で人感センサーを自作する

<必要なもの>

・Raspberry Pi2 Model B ボード&ケースセット (Standard, Clear)
www.amazon.co.jp

・Raspberry Pi 赤外線モーションセンサー PIR Infrared Motion Sensor
www.amazon.co.jp

・ジャンパワイヤ(メス~メス) 10本セット
www.amazon.co.jp

<金額>

5,980円 + 1,400円 + 492円 = 7,872円

※以上は参考にさせていただいた記事内の一例です。調べていたところ、もっと安価に自作できそうでした。

2. SONYのスマートDIYキット「MESH」の人感タグを利用する

<参考>

meshprj.com
qiita.com

<必要なもの>

・MESH Motion(人感)タグ
www.amazon.co.jp

<金額>

6,980円


「Raspberry Pi」の方はPCですので、人感センサーだけではなく他の用途でも利用することができて自由度が高いと思いますが、プログラムを組んだりセンサーを取り付けたりと知識が必要とされます。

「MESH」の人感タグの方は、人感センサーとしての用途に特化しており、また専用のMESHアプリを利用してアクションを起こさせるため自由度は低いと思いますが、小学生でもMESHを使った仕組みを作れるとのことで簡単に利用できそうです。

 「たんじゅんなのにすごいことができる」(小学校5年男子)
 「かんたんにできたからびっくりした」(小学校3年女子)
 「工夫して自分の想いのままに工作できた」(小学校5年女子)


meshprj.com


エンジニア的には「Raspberry Pi」を使って人感センサーとしての用途だけでなく、他のことも実現してみたい!という気持ちもあるのですが、エントランスに設置して外観的にスマートなのはどちらであるかと考えると・・・「MESH」を利用して今回実現したいことをクリアできればいいかなと思います。

ちなみに・・・「MESH」には人感タグを含め以下のタグがありますので、いろんなタグを揃えて新しい仕組みをつくるのも楽しそうですね☆

  • LEDタグ : いろいろな色に光ります。
  • ボタンタグ : シンプルなボタンです。
  • 人感タグ : 人の動きを検知できます。
  • 動きタグ : 動きを検知することができます。
  • 明るさタグ : 明るさの変化を検知できます。
  • 温度・湿度タグ : 温湿度の変化を検知できます。
  • GPIOタグ : 電子工作の無線化や、できることを拡張します。

「MESH」でこんなことができるよ! というレシピも紹介されていて、見ているだけでも楽しいです ( ´ - ` )

recipe.meshprj.com


まだ、実物は手元になく実際どうなるかわかりませんが!
進捗がありましたら、2.導入編をお届けしたいと思います☆*:.。.

phantomjsでサイトのキャプチャーをとる

エンジニアの呉です。
今回紹介したいのはコマンドラインから使えるWebブラウザーであるphantomjsです。そもそも、なんでphantomjsを使うのか?それはWebサイトのキャプチャーをとるために、最初wkhtmltoimageを使ったけど、スマホ版はうまく撮れなかったため、いろいろを調べた結果はphantomjsを決めました。

phantomjsについて

phantomjsはコマンドラインから使えるブラウザーです。レンダリングエンジンには「WebKit」が採用されています。phantomjsを利用すると、コマンドラインから、Webブラウザーを操作して、ブラウザー内に表示されるデータを取得したり、スクリーンショットを撮ったりすることができます。Webサイトからデータを取り出すスクレイピングにも使えます。

続きを読む

PR TIMESエンジニア開発環境をのぞき見

こんにちわ、PR TIMESエンジニアの花田です。
今回のブログのテーマは

「PR TIMESエンジニアはどのような環境で仕事をしているのか」

技術記事がメインとなっているBREAK TIMESなので、少し角度を変えて、PR TIMESエンジニアはどのような環境で仕事をしているのかを紹介したいと思います。

まずはPR TIMESエンジニアが使用しているパソコンは主にMACを使用しています、社内エンジニア9割はMAC、希望すればデュアルモニター仕様に!
Macbookを使用しているエンジニアはthunderbolt display!

f:id:breaktimes:20160330154259j:plain
私はimac+デュアルモニター仕様にしています。

支給されるimacはスペックも高性能!
f:id:breaktimes:20160330154318j:plain
f:id:breaktimes:20160330154336j:plain
phpstorm/illustrator/photoshop/googlecrome/等複数のアプリケーションを開いてもストレスフリーで作業を行えるので、作業効率抜群です!

もちろんトラックパッドも常備
(写真は1ですが、トラックパッド2もあります)、デザイナーであればペンタブの支給も!

f:id:breaktimes:20160330154401j:plain

しかし、性能が良くてもエンジニアも人間です、パソコンは疲れなくても人間は疲れます・・・
そんな時は社内にあるTIMES GARDENにて休憩♪

f:id:breaktimes:20160330154431j:plain
コーヒーメーカーもあるのでコーヒーを淹れて・・・

f:id:breaktimes:20160330154455j:plain
ソファでくつろいでアイデアを練るなんて事も♪

必要な本は全て支給されるため、好きな本を見て勉強が出来るのでスキルアップがとてもしやすいです♪
f:id:breaktimes:20160330154515j:plain



いかがでしたか?
私が何故このように環境をブログに書きたいと思ったのは、道具・環境について私の好きな文献があり、

アメリカのHCI(ヒューマン・コンピュータ・インターフェイス)研究者テリー・ウィノグラードはハイデッガーを引用しながら、『普段は文字を入力しているときに、パソコンのキーボード自体を意識することはないが(道具的存在)、なんらかの処理の問題で、入力した文字がすぐに表示されないと、キーボードのキーが「引っかかる」という属性をもって現れてくる(ブレイクダウン)事物的存在になる』と述べた(『コンピュータと認知を理解する』,1989)。 つまり道具に何か問題が発生すると、その道具が意識に上り、それ自体を対象として扱う(事物的存在になる)。しかし、道具に問題が起きなければ、それ自体は透明性があり、たとえばキーボードでは「文章を書く」ということに集中できる(道具的存在になる)。

文献のように、集中出来る道具・環境にて仕事をしているため作業効率が高く、結果生産性の向上に繋がっています。
環境と道具がエンジニアの質に繋がると日々感じ、一人でも多くの方に共感してもらえるかなと思い今回のブログを書きました。
もっと他の事も書きたかったのですが、また次の機会にでもPR TIMESエンジニア開発環境を紹介します♪

$.ajaxファイルアップロードでの進捗表示

こんにちは。フロントエンドエンジニアの本間です。 

今日は$.ajaxファイルアップロードでプログレスバー表示についてです。 

UIUXにおいて体感速度を短縮するのは重要で、同じ待ち時間でも進捗表示することによって体感速度が向上します。

さらにプログレスバーの色や模様によっても体感速度が変わってくるという研究結果もでているようです。


gigazine.net


PRTIMESでは企業管理画面のリリース配信登録画面でワードファイルをアップする際に使っています。
 
やり方は$.ajaxの引数にxhrオブジェクトを渡し、progressイベントハンドラで取得します。

$.ajax({
    url  : api.url,
    async: true,
    xhr : function(){
        var XHR = $.ajaxSettings.xhr();
        if(XHR.upload){
            XHR.upload.addEventListener('progress',function(e){
                var progre = parseInt(e.loaded/e.total*100);
                $hoge.css({width: progre+'%'});
            }, false);
        }
        return XHR;
    },
})


簡単ですね。

8行目e.totalがトータルサイズでe.loadedがアップし終わったファイルサイズです。それをパーセントに直して次の行で$hogeの横幅に代入してます。

プログレスバーは必要な時に表示してアップロード後に、消すといった使い方がほとんどだと思いますので、 表示切り替えはbeforeSendとcompleteを使うといいと思います。

生のjavascriptの場合は下記 

var req = new XMLHttpRequest();
req.addEventListener('progress', updateProgress, false);
req.open();

function updateProgress(e) {
    var progre = parseInt(e.loaded/e.total*100);
    document.getElementById(hoge).style.width=progre+'%';
}


非同期前提なのでasyncがfalseだと取得できません。
ですので古いブラウザ対応などでよくやる空のiframeからsubmitしてレスポンスを親に渡すやり方でも取得できませんのでご注意!

ちなみにprogressイベントのブラウザ対応状況は下記です。
 

PC

ChromeFirefoxInternet ExplorerOperaSafari
7以上3.5以上10以上12以上対応


mobile

Android Android WebviewFirefox MobileSafari MobileIE Mobile
対応対応1.0以上対応10.0以上


今回はファイルアップロードでそこまで長くない時間でしたが、時間のかかる処理をする際に楽しげなアニメーションGifを動かしたり、広告スペースに活用したりと工夫してあるサイトも多いですね。

体感時間について下記の記事が面白かったのでご紹介致します。

第46回 体感時間のコントロール | WIRED VISION

待っているという事実を一瞬忘れさせるのが体感時間短縮の鍵ですね。
最後まで読んでいただきありがとうございます。

PR TIMESは東証マザーズに上場しました!

PR TIMESフロントエンジニアの山田です。
※この記事はエイプリルフールではありません!

f:id:breaktimes:20160401093752j:plain
昨日、3月31日にPR TIMESは東証マザーズに上場しました。
prtimes.co.jp

なかなか体験することができないセレモニーにも参加することができ、感慨深い想いです。

エンジニアも含め参加した社員も、静かに見守る、その場を楽しむ、興奮して写真を撮りまくるなど様々な反応でしたが、サービスをご利用頂いている方々に感謝し、そしてサービスをより良くしていこうという想いは皆変わらないと思います。
prtimes.jp


そんなPR TIMESのエンジニアチームでは一緒にサービスを発展させて頂ける仲間を募集しています。興味を持たれた方は以下のフォームからご応募ください。
オフィス訪問も受け付けていますので、お気軽にどうぞ。