フィネットエンジニアだより

株式会社フィネットのエンジニア感があるんだかないんだかよくわからないブログ

2019年度 暑気払い

こんばんわ

イベント委員会 森元です。

2019年度暑気払いを開催しました。

会場は例年通り倉敷アイビースクエアのビアガーデンです。

f:id:inet_engineer:20190825203718j:image

当日は天気が怪しかったですがなんとか乾杯は屋外で行えました。

f:id:inet_engineer:20190825203928j:image

曇りでも盛況です。

f:id:inet_engineer:20190825204212j:image

バエル盛り付けを目指した結果…

f:id:inet_engineer:20190825204852j:image

開始一時間もせずに雨が降ってきたので屋内のホールに移動…私が入社して初めての屋内なので割とわくわくしてました。

f:id:inet_engineer:20190825205141j:image

来年度のオープンセミナー岡山の会場もアイビースクエアの予定らしいです。

オープンセミナー2019@岡山

今年も内定者の方が参加してくれました。

かなり緊張してた印象ですが少しでも社内の雰囲気を感じていただけたなら良かったです。

今回の暑気払いは雨が降ったものの気温的にはとても快適で毎年これぐらいにしてくれって感じです…f:id:inet_engineer:20190825210641j:image

参加者も例年より多く盛り上がって皆さんリラックスできたのではないかと思います。

今年の夏も皆さんお疲れさまでした!!

ノベルティカンファレンス in 大阪を開催したいなと思っている話 #novecon

f:id:razon:20181027133700j:plain

ご安全に!角田です。

もはやどういう経緯でこんなこといい出したか思い出せないんですが、「ノベルティカンファレンスを大阪でやりたい!」という思いがあったみたいなのでそれに関して書いていきたいと思います。
興味のある方は @razon までご連絡いただけますと僕が大変喜びます。
各位よろしくお願いします。

ノベルティカンファレンスとは?

イベントやセミナー、勉強会で受け取る「ノベルティ」。

「ノベルティ」と一口に言っても、その種類は様々です。 担当者は日夜、何のノベルティにしようか、ロゴはどう入れるか、受け取った人は喜んでくれるのか・・・。 「ポイされたくない」という思いに悩まされていることでしょう。

悩んでいる方もそうでない方も、ノベルティについての思いをたくさんお持ちのことと思います。 そしてその背景には、自社のブランドへの思い、コミュニティへの情熱、受け取る方々への配慮などがあることでしょう。 このイベントでそれを語り合ってみませんか。

という訳でその名のとおりノベルティについて語り合うイベントです。
次回は8/5(月)に東京で開催です!

connpass.com

過去の開催実績

connpass.com

connpass.com

connpass.com

connpass.com

「岡山でもやりたい!」と言い続けたおかげで昨年は岡山開催が実現しました!
この勢いで別地方でも開催できるといいなと思ったから「大阪開催だ!」とか言い出したんだと思います。たぶん。
なんで大阪なのかはすまん、思い出せないんだ…。

募集したいもの

  • 会場を提供していただける企業様
    • 如何せんあまり土地勘もないもので、会場を提供していただける企業様がいらっしゃいましたらめちゃくちゃ嬉しいやつです。
  • 発表してくださる方
    • すごい発表とかでなくて大丈夫です!「こんなもの作ったよ!」とか、「こんな失敗があった…」みたいな、軽めのものでも全然OKです。
  • 作ったノベルティを展示したい方
  • いっそ「イベントの運営やってみたい」という方
  • 「話を聞いてみたい!」という方(5000兆人くらいいてほしい)

開催時期

  • 東京が8月開催なので、秋くらい?(ふんわり、要検討)
    • 平日開催のイメージです

さいごに

個人的には地元開催してとてもよかったイベントなので、是非この輪を広げていきたいと思っています!
ビビッと来た方からのご連絡を心よりお待ちしております!!

2019年度BBQ会を開催しました

f:id:razon:20190511131612j:plain

ご安全に!角田です。

毎年恒例のBBQ会を今年も開催しました。

f:id:razon:20190511115030j:plain
今年も CAMPING EQUIPMENT STORE さんに設営をお願いしています。午前中からかなり日差しが強く、ちょっと心配だったのですが日陰になっており割と過ごしやすかったです。

f:id:razon:20190511115039j:plain
設備がすごい

f:id:razon:20190511120954j:plain
メンバーが集まったので開会宣言です

f:id:razon:20190511123228j:plain 焼きます

f:id:razon:20190511123237j:plain
肉の暴力

f:id:razon:20190511124027j:plain
ケバブ(チョーうまかった)

f:id:razon:20190511125159j:plain
ホタテバターホイル(こんなんまずい筈がないですよね)

f:id:razon:20190511150555j:plain
おい
パイ食わねぇか

f:id:razon:20190511141331j:plain
今年も不穏な文章を読み上げる会が開催されました。
「書いた人の文才がすごい」と評判です。

f:id:razon:20190511150257j:plainf:id:razon:20190511131653j:plainf:id:razon:20190511125220j:plain

f:id:razon:20190511151846j:plain
最後は例のごとく集合写真です。

今年は社内外含め都合が合わない人がそこそこいたのが惜しまれるところなのですが、楽しいひとときを過ごすことができました。 来年もまた開催するので、ご都合よろしければ是非お越しください!

2019年度セキュリティ研修を開催しました

f:id:razon:20190420155231j:plain

ご安全に!角田です。

先週末の4/20(土)に、全社でのセキュリティ研修を開催しました。

例年は社内の会議室を利用していたのですが全社員を入れるにはちょっと手狭になってきたので、今年は倉敷天満屋さんの会議室をお借りして開催しました。

www.tenmaya.co.jp

第一部

第一部はスクール形式での座学になります。 コンテンツは社内のセキュリティ委員会による力作です。

f:id:razon:20190420141323j:plain f:id:razon:20190420142832j:plain f:id:razon:20190420142819j:plain

第二部

第二部はレクリエーション的なコンテンツを行うことが多いのですが、今年はメールの誤送信をしてしまったという設定で実際の規定に沿って報告書を作成するというワークショップを開催しました。 幸い今のところはこういったことを実際に行う機会はなかったのですが、シミュレーション的に運用することで「こういう運用のほうがよいのではないか」「報告書の様式はこうしたほうがよいのではないか」など、様々な意見が出てきて実際に運用してみることの大切さを改めて感じました。

f:id:razon:20190420162255j:plain f:id:razon:20190420162244j:plain f:id:razon:20190420170704j:plain

懇親会

毎年恒例になるのですが倉敷ロイヤルアートホテルさんで執り行いました。

www.royal-art-hotel.co.jp

f:id:razon:20190420180905j:plain f:id:razon:20190420181153j:plain f:id:razon:20190420200029j:plain f:id:razon:20190420200101j:plain

今年は3名の新入社員が新たに増えたので、インタビュータイムです。三者三様でまた新たな一面を見せてくれたのではと思います。

f:id:razon:20190420194112j:plain

最後は一丁締めで無事閉会です。

f:id:razon:20190420201323j:plain

年々この研修の雰囲気がよくなってきているなと感じているのですが、今年は意見の交換なども活発で、より話しやすい空気づくりができている実感がありました。(そのせいでちょっと時間が押し気味になってしまったところもあるのですが…)

来年もより盛会にできるよう、今後も精進していきたいところですね。

#pixela で #めそ子イラストコンテスト のイラストを描いた話

ご安全に!角田です。

めそ子イラストコンテストの締切が近づいてきたので慌てて Pixela でめそ子のイラストを描いたのでその技術的裏側について補足しておこうと思います。

mesoko.jp

ドット絵を描く

Pixelaは基本APIでpixelの値を入れる(色つけ)形なのでそのままではお絵かきには厳しいため、まずはドット絵用のツールでドット絵を描きます。 今回はPiskelを利用しました。はじめての利用だったけど使いやすかった!

www.piskelapp.com

最終的にはPixelaの色しか出せないので、Pixelaのグラフから各色を抜き出してカラーパレットに設定していきます。 色見本のブログがあったのでこれが大変役立ちました。

ryosms.livedoor.blog

描いたドット絵はこちら

Pixelaは縦が7ピクセル、横が50ピクセルちょいなので、7*50で描きました。

www.piskelapp.com www.piskelapp.com

ドット絵のピクセルを読み込んでPixelaに値を登録する

JSで画像をCanvasに読み込んで、1ピクセルずつ読んで色からグラフのquantityに変換してPixelaにAPIで登録していきます。 開始点の日付から1日ずつPixelを読み進めていく感じです。 今回はajisaiとmomijiのカラースキームを使ったのでその対応表を仕込んでいますが、他の色の対応表を作ればその色でいけます。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>image2pixela</title>
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>  
  <script type="text/javascript">
    // PixelaのAPIキーを指定
    const secret = 'thisissecret'
    // Pixelaのユーザ名を指定
    const userName = 'username'
    const urlBase = `https://pixe.la/v1/users/${userName}/graphs/`
    // Pixelaに登録するグラフと画像のファイル名を一致させる
    const targets = ['akari-saiki', 'hisaki-hanasaki']
    const colors = [{
      // ajisai
      '-10': [71,141,141],
      '-6': [85,170,170],
      '-4': [141,199,199],
      '-1': [199,226,226],
      '0': [238,238,238],
      '1': [234,213,255],
      '4': [213,170,255],
      '6': [170,85,255],
      '10': [106,0,213],
    }, {
      // momiji
      '-10': [106,177,35],
      '-6': [128,213,43],
      '-4': [170,226,114],
      '-1': [213,241,184],
      '0': [238,238,238],
      '1': [255,213,213],
      '4': [255,128,128],
      '6': [255,43,43],
      '10': [255,0,0],
    }]
    window.onload = () => {
      for(let i = 0; i < targets.length; i++) {
        const canvas = document.getElementById(targets[i])
        const ctx = canvas.getContext('2d')
        const img = new Image()
        // 他の画像形式の場合は拡張子調整してください
        img.src = `${targets[i]}.gif`
        img.onload = () => {
          ctx.drawImage(img, 0, 0)
          const data = ctx.getImageData(0, 0, canvas.width, canvas.height);
          const values = getValue(data, colors[i])
          // 基準日の1年前の週の日曜日から描画スタート
          const baseDate = '2019-02-23'
          const endDate = moment(baseDate)
          const startDate = moment(baseDate)
          startDate.subtract(1, 'years')
          startDate.subtract(startDate.day(), 'days')
          values.forEach(value => {
            fetch(
              urlBase + targets[i] + `/${startDate.format('YYYYMMDD')}`,
              {
                'mode': 'cors',
                'method': 'PUT', 
                'headers': {'X-USER-TOKEN': secret}, 
                'body': JSON.stringify({'quantity': value})
              }
            ).catch((error) => console.error(error))
            console.log(startDate.format('YYYYMMDD') + ':' + value)
            startDate.add(1, 'days')
          })
        }
      }
    }
    function getValue(data, colors) {
      const values = []
      for(let i = 0; i < data.width; i++) {
        for(let j = 0; j < data.height; j++) {
          var idx = (i + j * data.width) * 4
          Object.keys(colors).forEach(key => {
            const value = colors[key]
            if (data.data[idx] === value[0] &&
                data.data[idx + 1] === value[1] &&
                data.data[idx + 2] === value[2]) {
              values.push(key)
            }
          })
        }
      }
      return values;
    }
  </script>
</head>
<body>
  <canvas id="akari-saiki" width="50" height="7"></canvas>
  <canvas id="hisaki-hanasaki" width="50" height="7"></canvas>
</body>
</html>

画像を読み込んでCanvasに叩き込むのにセキュリティ的な制限があるためローカルでは動作しないので、何かしらのWebサーバを立ち上げて動かす必要があります。 画像ファイルはHTMLと同じパスに置きます。 なお読み込んだだけでそのままPixelaのAPIを叩きに行くアグレッシブな仕様です。

できあがったものがこちらになります

https://pixe.la/v1/users/razon/graphs/akari-saiki?date=20190223 https://pixe.la/v1/users/razon/graphs/hisaki-hanasaki?date=20190223

みんなもPixelaでお絵かきしてみてくれよな!

SUZURIのPixela Shopをそれっぽい感じにする

ご安全に!角田です。

Pixela Shopができましたね!

blog.a-know.me

ただちょっと気になってて、

ということなので、雑にGreasemonkeyを書いて解決していきます。

Greasemonkey - Wikipedia

できあがったものがこちらになります

gist.github.com

いい感じですね。
そんな訳でこのエンジニアブログも今年最後な気がするので、みなさまよいお年を!

あわせて読みたい

twilog.org

GASでつくる #Backlog 警察

ご安全に!角田です。

このエントリは、Backlog Advent Calendar 2018の26日目(勝手にやっているだけ)です。

adventar.org

この記事でやること

先の記事 でGAS使って興が乗ったので、ついでに期限切れのタスクをSlackに通知するBacklog警察もGASで実装してしまおうと思います。
よろしくお願いします。

🔑BacklogのAPIキー発行

個人設定 - API から、Backlog警察用のAPIキーを発行します。管理用のユーザとかでやるのが無難でしょうか。

backlog.com

🖇SlackのIncoming Webhook設定

SlackのアプリにIncoming Webhookを追加します。

f:id:razon:20181225104434p:plain
f:id:razon:20181225104808p:plain
f:id:razon:20181225104810p:plain
f:id:razon:20181225104811p:plain
WebhookのURLができました。

💨GASを書く

function BacklogPolice() {
  var response = fetchBacklogIssues();
  postSlack(JSON.parse(response));
}

var backlogNamespace = 'your_backlog_namespace';
var backlogUrl = 'https://' + backlogNamespace + '.backlog.jp/';

function fetchBacklogIssues() {
  var baseUrl = backlogUrl + 'api/v2/issues';
  var apiKey = 'your_backlog_api_key'
  // 取得対象のプロジェクトIDのリストを指定
  var projectIds = [n];
  var statusIds = [0, 1, 2, 3];
  var sysdate = new Date();
  sysdate.setDate(sysdate.getDate() - 1);
  var params = {
    'apiKey': apiKey,
    'dueDateUntil': formatDate(sysdate)
  };
  for (var i = 0; i < projectIds.length; i++) {
    params['projectId[' + i + ']'] = projectIds[i];
  }
  for (var i = 0; i < statusIds.length; i++) {
    params['statusId[' + i + ']'] = statusIds[i];
  }  
  var paramString = '';
  for (var key in params) {
    if (0 < paramString.length) {
      paramString += '&';
    }
    paramString += key + '=' + params[key];
  }
  return UrlFetchApp.fetch(baseUrl + '?' + paramString);
}

function postSlack(issues) {
  if (issues.length <= 0) {
    return;
  }
  var baseUrl = 'your_slack_incoming_webhook_url';
  var headers = {
    'Content-Type': 'application/json'
  };
  // ここはお好みでいい感じにカスタマイズしてください!
  var params = {
    'channel': '#backlog_notify',
    'username': 'Backlog警察',
    'icon_emoji': ':backlog:',
    'text': createPostMessage(issues),
  }
  var options = {
    'method': 'POST',
    'headers' : headers,
    'payload': JSON.stringify(params)
  };
  UrlFetchApp.fetch(baseUrl, options);
}

function createPostMessage(issues) {
  var message = '<!channel> Backlogのタスクが期限切れになっています!速やかにタスクを処理するか、期限日を調整してください。\n';
  for (var i = 0; i < issues.length; i++) {
    var issue = issues[i];
    message += '[' + issue.issueKey + ']: ';
    message += '<' + backlogUrl + 'view/' + issue.issueKey + '|' + issue.summary + '>';
    message += '[' + issue.status.name + '], ';
    message += formatDate(new Date(issue.dueDate)) + ', ';
    message += issue.assignee.name + '\n';
    return message;
  }
}

function formatDate(date) {
  var format = 'YYYY-MM-DD';
  format = format.replace(/YYYY/g, date.getFullYear());
  format = format.replace(/MM/g, ('0' + (date.getMonth() + 1)).slice(-2));
  format = format.replace(/DD/g, ('0' + date.getDate()).slice(-2));
  return format;
}

🔫GASのトリガーを追加

f:id:razon:20181225110056p:plain
f:id:razon:20181225110058p:plain
f:id:razon:20181225110100p:plain

💪できあがったものがこちらになります

f:id:razon:20181226091752p:plain

よかったですね。
いやよくないですね。あまりBacklog警察にはお世話になりたくないものです!