サイボウズでAndroidサマーインターンに参加したお話

こんにちは。こちらの記事では2023年8/21~9/1の期間に参加させていただいた、サイボウズ株式会社さんのAndroid2weekサマーインターンシップについて書き留めたいと思います。

参加までの経緯

私は普段、個人でkotlinを用いたAndroidアプリ開発を行っています。そこで実務レベルでAndroidアプリ開発を経験できるインターンシップを探していました。加えて現在修士1年であるため、就活の観点からもインターンシップを探していました。 4月頃にサポーターズ経由でサイボウズインターンシップ説明会を知り、参加することにしました。リモートで実施されていましたが、社員さんの気さくな雰囲気やインターンの紹介から、この会社のインターンに参加したいと思うようになりました。

選考

選考は書類選考->面接->参加決定 の流れでした。 面接ではインターン説明会に登壇されていた社員さんに面接していただき、緊張することなく行えました。

事前顔合わせ

インターン参加が決定した後、他のインターン生との顔合わせイベントがありました。イベントは本社オフィスで行われました。メンターさんや人事さんはもちろん、同じAndroid2weekコースのインターン生や、Android1weekコース、iosコースのインターン生とも交流でき、インターンの雰囲気を感じ取れるイベントでした。

インターン

インターンは自分を含めたインターン生3名とメンターさん3名の計6名を基本に行われました。インターンでは主に以下の内容を行いました。

  • ウォーミングアップ
  • スクラム開発
  • LT会
  • 成果発表
  • その他イベント

ウォーミングアップ

インターン開始後、まずはウォーミングアップとしてJetpack Composeのコンポーネントに触れました。はじめはインターン生が各々実装し、メンターさんがGithubでレビューをする形でした。その後、インターン生がモブプログラミング形式でJetpack Composeに無いMaterial Componentを実装しました。実際に作ったコンポーネントはListTile, 折りたたみリスト, SliverAppBar, Cardの4つでした。ウォーミングアップではJetpack Composeの再確認とモブプログラミングの練習が行えました。

スクラム開発

ウォーミングアップが終わったあと本格的にプロダクト開発がはじまりました。サイボウズでは一週間でワンスプリントとして開発が行われています。今回開発したプロダクトはサイボウズOfficeのAndroidアプリです。こちらのすでにリリースされているアプリに機能追加を行いました。 開発の大まかな流れとしては、バックログの確認->取り組むプロジェクトバックログアイテム(PBI)を選択->デザイン確認->実装->レビュー->修正->デザイナーさんの確認->品質管理 といった流れで行われました。 PBIは朝会などでPMさんやデザイナーさんQAさんと確認することでチームメンバー全員で情報共有する体制が整っていました。 実装はKotlinやいくつかのライブラリを使用したインターン生同士のモブプログラミングで行われました。すでに実装されていたり、似たような機能の実装がなされていたので、それらのコードを使用する形で大きく詰まることなく実装できました。 またテストコードをJUnitやmockKを使用して実装する機会がありました。個人開発ではなかなか書くタイミングがないテストコードですが、これを機に習慣的に書いていこうという気持ちになりました。

LT会

メンバーの交流を兼ねたLT会が実施されました。私は趣味のメモリースポーツについて発表しました。 ja.wikipedia.org

成果発表

インターン最終日に各コースの成果発表会が開催されました。他のコースでどのようなことが行われたか知る、良い機会となりました。

その他イベント

社長の青野さんとお話できる雑談会があり、サイボウズという会社を経営していくうえでの心構えなどを知ることができました。

最後に

2週間という期間でしたが、メンターさんや社員の方々と交流させていただいて、エンジニアとして視界が開けたと思います。今回のインターンの経験を糧にエンジニアとしての能力を向上させていきたいと思います。 本当にありがとうございました。

picoCTF 2019: Java Script Kiddle

picoCTF 2019: Java Script Kiddle

リンク

https://jupiter.challenges.picoctf.org/problem/58112/

問題

keyをformに入力してSubmitすると画像が表示される。画像にフラグがあるから適切な画像構築してね。

Solution

サイトのJavaScript読むと、pngを構築する関数assemble_png()が確認できる。

var bytes = [];
$.get("bytes", function(resp) {
    bytes = Array.from(resp.split(" "), x => Number(x));
});

function assemble_png(u_in) {
    var LEN = 16;
    var key = "0000000000000000";
    var shifter;
    if(u_in.length == LEN) {
        key = u_in;
    }
    var result = [];
    for(var i = 0; i < LEN; i++) {
        shifter = key.charCodeAt(i) - 48;
        for(var j = 0; j < (bytes.length / LEN); j++) {
            result[(j * LEN) + i] = bytes[(((j + shifter) * LEN) % bytes.length) + i]
        }
    }
    while(result[result.length - 1] == 0) {
        result = result.slice(0, result.length - 1);
    }
    document.getElementById("Area").src = "data:image/png;base64," + btoa(String.fromCharCode.apply(null, new Uint8Array(result)));
    return false;
}

var byteshttps://jupiter.challenges.picoctf.org/problem/58112/bytesの値を配列に代入している。 つまり上記のコードは、

  1. bytesにスペース区切りで配列を代入
  2. bytesの値を並べ替えて、resultに代入
  3. resultをバイナリデータとして読み込みbase64エンコードし画像として生成

pngファイル:

  • 以下の8バイトの signature から始まる89 50 4E 47 0D 0A 1A 0A

  • signatureのあとにIHDRというchunkがあり, 以下の8バイトのデータが続く00 00 00 0D 49 48 44 52

ということからresultの最初の 16 個の値が確定するのでkeyの候補を絞り込むことができる。

resultの最初の16個は, 以下のJavaScriptのコードの j = 0のときなので、

var result = [];
for(var i = 0; i < LEN; i++) {
    shifter = key.charCodeAt(i) - 48;
    for(var j = 0; j < (bytes.length / LEN); j++) {
        result[(j * LEN) + i] = bytes[(((j + shifter) * LEN) % bytes.length) + i]
    }
}

result[i]bytes[(key*LEN) % bytes.length + i]と等しいかを見ればよい。もし等しければ、その時のkeyの値は解の候補となる。

import requests

r = requests.get('https://jupiter.challenges.picoctf.org/problem/58112/bytes')
_bytes = [int(x) for x in r.text.split()]

# png header
result = [
    0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
    0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
]

for i in range(16):
    print("{:02d}".format(i) + "th possible key is: ", end="")
    for key in range(10):
        if result[i] == _bytes[(key * 16) % len(_bytes) + i]:
            print("{:x}".format(key), end=" ")
    print()

dp = [[] for _ in range(20)]
dp[0].append("")

for i in range(16):
    for key in range(10):
        if result[i] == _bytes[(key * 16) % len(_bytes) + i]:
            for d in dp[i]:
                dp[i + 1].append(d + str(key))

for d in dp[16]:
    print(d)

結果:

00th possible key is: 4 
01th possible key is: 8 
02th possible key is: 9 
03th possible key is: 4 
04th possible key is: 7 
05th possible key is: 4 
06th possible key is: 8 
07th possible key is: 4 
08th possible key is: 8 
09th possible key is: 5 6 
10th possible key is: 1 2 
11th possible key is: 6 
12th possible key is: 7 
13th possible key is: 1 
14th possible key is: 0 
15th possible key is: 4 
4894748485167104
4894748486167104
4894748485267104
4894748486267104

プロセスは終了コード 0 で終了しました

出力された4つのkeyをformに入力するとQRコードが生成されるので、それがflagとなる。

参考

https://kira924age.hatenadiary.com/entry/2019/12/31/192722

https://qiita.com/rch1223/items/35dcabe84f1ff96a3c51

TOEICで700点取る#2

Day 2

真偽不明の情報に踊らされた翌日、研究室の教授に詳細を聞いたところやはり真偽不明だった。ただ院試は英語でのプレゼンなので、やはり英語は学ぶべきである。よって当初の予定通りTOEIC700点を目指す。

やったこと

・トレーニンTOEICアプリ
play.google.com

のPart5Chapter1Lesson1~3を行った。
・上記レッスンで分からなかった英単語をAnkiに登録。

今後の表記

TOEICアプリ → Part1 Chapter1 Leasson1 = P1C1L1

TOEIC 700点を取る

Day 1

院試でTOEIC650点以上でないと脚切りされるという、嘘か真かわからない噂がある。現在430点の私はガクブルしている。
真であった場合、私は卒業後路頭に迷うことになる。それを回避するため、2/12に大学であるTOEICテストで650点以上をとらねばならない。そこできりのいい700点を約2ヶ月で取ることにする。

今日やったこと

TOEIC各パートのざっくりとした攻略ポイントを確認した。
スマホのアプリにTOEIC対策のものがあるのでその機能を確認。

E - Virus Tree 2

URL

atcoder.jp

問題

N個の頂点とN-1本の辺がある。頂点をK色の絵の具で塗り分ける。ただし2つの頂点の距離が2以下なら異なる色となる。このときの塗り分け方は何通りか?

解法

公式解説にあるように、頂点 x とその親が既に塗られているとき、x の子の数を cx とすると、x の子の塗り分け方はK−2Pcx 通りある。これをdfsで求める。

コード

https://atcoder.jp/contests/abc133/submissions/27681127

C - Max GCD 2

URL

atcoder.jp

問題

A <= x < y <= Bとなるようなx, yに対し、gcd(x, y)の最大値を求めよ。

解法

xとyを全探索するとO(N2)で死ぬので、gcd(x, y) = c について考える。最大値がcであると仮定した時、x, y は c の倍数でなければならない。言い換えると区間[A, B]にcの倍数が2つ以上ある時、gcd(x, y)=cとなり得る。 ( 区間[A, B]の c の倍数の数 )=( 1 以上 B 以下の c の倍数の数 )−( 1 以上 A−1 以下の c の倍数の数 )でもとまる。

コード

https://atcoder.jp/contests/jsc2021/submissions/27481247

E - Transformable Teacher

URL

atcoder.jp

問題

N人の身長Hiが与えられる。Nは奇数。そこにM個の自分の身長の候補Wiが与えられる。N+1人でペアを作ったときの、身長差の合計の最小値を求めよ。

解法

ペアを作るときに身長差が最適になるには、小さい順に並べて先頭からペアを作ることである。そこにクエリごとの自分の身長を最適な場所(lowerboundでわかる)にWを挿入し、身長差の合計を高速に計算したい。
身長差の合計は累積和を用いて計算する。左右からの累積和を用いて
left[i] = Hの左i個までの身長差の合計
right[i] = Hの右i個までの身長差の合計
としてWの挿入位置の左側にHがi個あったとすると
iが偶数の時:left[i]+right[N-i-1]+(Hi-W)
iが奇数の時:left[i-1]+right[N-i]+(W-Hi-1)
となる。

コード

https://atcoder.jp/contests/abc181/submissions/27480833

参考

https://drken1215.hatenablog.com/entry/2020/11/02/021500