haneuma.log

生きるのをがんばりたい

発達障害と診断された

はじめに

会社勤めを始めてから異様に社会が辛くなったので、成人発達障害の検査を受けました。 検査の結果、自閉症スペクトラム障害かつ注意欠陥・多動性障害と診断されたので、検査の流れや自分の症状についてまとめておきます。

発達障害とは

発達障害とは、広義には言語や行動に何らかの不全を抱えた状態を指します。狭義には日本の行政上の定義や学術的な定義により、学習障害や注意欠陥・多動性障害、自閉症スペクトラム障害などを指します*1

狭義の定義に従えば発達障害といっても様々な障害を含みますが、ここでは自分が診断された障害についてのみ説明します。

まず、自閉症スペクトラム障害(以下、ASD)について。

ASD の主要な症状には、「コミュニケーション、対人関係の持続的な欠陥」と「限定された反復的な行動、興味、活動」の2つがあります*2。 人によって症状の強度や発現の仕方が異なるので、同じ ASD 患者でも異なる特徴を示します。ある ASD 患者の特徴が別の ASD 患者にも全く当てはまる、ということはないようです。

つぎに、 注意欠陥・多動性障害(以下、ADHD)について。

ADHD の主要な症状は、「不注意」「多動性・衝動性」の2つがあります*3。 これらの症状の詳細は ADHD の診断基準を定めた DSM-5 に詳しいですが、長いので省略します。不注意、多動・衝動性についてそれぞれ端的に説明するなら、不注意: 集中することや整理することが苦手、多動性・衝動性: 落ち着きがなくそわそわしていて順番待ちができない、といったところでしょうか。

ADHD 患者は主要な症状の強さで不注意優勢型、多動・衝動優勢型、混合型の3つに分類されます。自分の場合は不注意優勢型と診断されました。成人になって初めて診断を受ける患者はこちらに分類されることが多いらしいです(担当医談)。

病院と検査内容について

精神疾患なので精神科を受診しますが、どこでも検査をしてくれるわけではないので診断可能な病院を探します。また、成人してから初めての検査か?発達障害の中でもどの障害を検査したいのか?といった条件を気にする必要があります。自分の場合は「成人」「ASD を疑っている」「ADHD を疑っている」という条件になるので、成人向けの ASDADHD が診断できる発達障害検査を実施している病院を探しました。

東京都で受診する場合は、東京都福祉保健局が提供しているこちらの資料が参考になります: 発達障害 東京都福祉保健局

自分が受けた検査の内訳は以下の通りです:

  1. 知能検査(WAIS-Ⅲ)
  2. 記憶検査(WMS-R)
  3. インテーク面接
  4. 精神科医の面接

それぞれの検査や面接について説明します。

1つ目の、知能検査(WAIS-Ⅲ)について。 この検査では言語性 IQ と動作性 IQ、これらの合成得点である全検査 IQ の3つの指標が得られます。また、IQ の他に言語理解、作動記憶、知覚統合、処理速度の4つの郡指数が得られます*4。IQ や郡指数間での差を個人内差といい、個人内差が有意である場合、発達障害が疑われます。

2つ目の、記憶検査(WMS-R)について。 この検査では言語性記憶(聴覚情報の記憶力)、視覚性記憶(視覚情報の記憶力)、言語性記憶と視覚性記憶の合成得点である一般的記憶、注意集中力、遅延再生の5つの指標が得られます*5

WAIS-Ⅲ と WMS-R の2つの検査結果は、平均100標準偏差15のガウス分布で表されます。90-109が平均的、110-129が優れている、130-が非常に優れている、と評価されます。

3つ目の、インテーク面接について。 なんか専門家の人(医師ではないこと以外よく覚えてない)との面接を行います。提示された質問に回答した後、日常生活での困りごとを説明するように求められます。質問は医療機関のホームページに掲載されているような発達障害のセルフチェックを詳細にしたようなものと、幼少期の様子を尋ねるものでした。幼少期の様子の回答のために小学校の通信簿や親の同席があることが望ましいとのことでしたが、自分はどちらも用意しませんでした。

4つ目の、精神科医との面接について。 1~3の結果を元にした診断結果と症状や特性の説明、治療方針などを話します。どのような得手不得手があるのか、それはなぜか、といった説明がありました。

検査結果について

知能検査(WAIS-Ⅲ)

IQ および郡指数は平均~優れているという評価でした。郡指数では言語理解と知覚統合、言語理解と作動記憶の間に5%水準で、言語理解と処理速度の間に15%水準で有意な差がみられました。郡指数の大小は 言語理解 > 処理速度 > 作動記憶 > 知覚統合 の順になります。個人内差が有意であるため、発達障害を疑う材料の一つになります。

それぞれの郡指数がどのような能力を表すかを以下に示します*6:

  • 言語理解 言語理解、知識、概念化
  • 知覚統合 見て記憶したり判断したりする能力
  • 作動記憶 新たな情報を記憶、短期記憶に保持、処理する能力
  • 処理速度 複数の情報を処理する能力

郡指数算出のための下位検査ごとの評価点(平均10標準偏差3のガウス分布)において、作動記憶の検査である数唱の評価点が7、作動記憶の検査である算数の評価点が15であるなど、大きなばらつきがみられました。

以上の個人内差から、全体的な知的水準と比べてできないこと・苦手なことを強く意識しやすく、不全感を抱いたり自信を失ってしまいやすい、と言えます。

個人内差のまとめとして、以下の特徴が挙げられました:

  • 得意なこと
    • 語彙が豊富で説明を求められたときに具体的な説明をすること
    • 獲得された知識を元に、言語的な洞察によって課題に対する結論を導き出すこと
  • 苦手なこと
    • 聴覚からの情報を一時的に記憶に留めること

所見として、機械的で単純な記憶力が良い一方で処理を加えた記憶が難しいことが挙げられました。実用上の問題に例えれば、文章による明確な指示は理解して記憶することができますが、口頭での曖昧な指示を記憶することが難しく、何を指示されたのかを理解することが難しいです。

記憶検査(WMS-R)

検査結果より、指標は平均~優れているという評価でした。言語性記憶=聴覚情報の記憶力よりも視覚性記憶=視覚情報の記憶力が優れています。有意水準については不明です。指標の大小は 遅延再生 > 視覚性記憶 > 言語性記憶 > 注意/集中力の順でした。注意/集中力がきれいに平均=100で安心しました。

自分の症状について

ASD 由来の症状

コンテキストを想像して会話をするのが難しい、人の立場や考えを想像するのが難しい、独自の強いこだわりがありそれが害されると強く怒ったり軽いパニックになる、興味の偏り、などの症状があります。

コンテキストや想像力についての症状を端的に表す例として『「洗濯機回しておいて」と言われた時に、洗濯物を干すことができない』があります。 「洗濯機に乾燥機能がついていない場合は洗濯が完了したら洗濯物を干す必要があるので、洗濯機を稼働させる(=回す)だけでなく、洗濯物を干さなければ作業が完了したとは言えない」ということが分からないためにこのような現象が起きます。ちなみに、洗濯機を「回す」というのが「洗濯機に洗濯物を適量投入した後、洗剤類を適量投入し、水栓を開け、適切なコースで洗濯機を稼働させる」ということを指すのは、生活習慣によって強く認識しているので分かります。

こだわりについては、些細なことで事柄に不釣り合いなほど嫌がったり怒ったり固まったりします。例えば、事前の合意なく普段使っている机を整頓されたら、火がついたように怒るか、訳が分からなくてその場で机をぐちゃぐちゃにしてしまうと思います。どんなこだわりがあるのか挙げればきりがないですが、私物を勝手に動かしたり使ったりされるのはとても嫌がります。

興味の偏りについては自覚するエピソードが思いつかないですが、興味のないものに興味がないために自覚していないのかもしれません。

ADHD 由来の症状

注意を持続するのが難しく大抵の行動は2分で飽きてしまう、過剰に集中してしまい他の行動がおろそかになる、情報を整理するのが苦手で部屋や仕事の TODO などあらゆるものが散らかっている、音などの外部刺激が苦手で気を取られやすい、ものごとに取り掛かるのが難しくあらゆる TODO は限界まで先延ばしにされて期限を過ぎる、がんばれない、などの症状があります。

ADHD 由来の症状、とくに不注意に関するものは挙げればきりがないですが、最近困っているのは上記の症状です。

仕事にすぐ飽きてしまうので Twitterはてブ、関係のない社内ドキュメント、関係のないコードに気を取られてしまい、理想的に作業が進むことはまずありません。学生時代の勉強や授業も同様で、大学の講義を最後まで集中して聞けたことは一度もありません。逆になにかの拍子で過剰に集中してしまい、数時間ほどものごとに取り組むこともあります。例えば、今この文章を書き始めて4時間ほど経過しますが、この節を書くために時計を確認して初めて4時間経過していることに気づきました。食べかけの夕飯と起動したままの MHW:IB を放置しています。お腹は空いているしゲームはしたいですが、文章を書くことが気になってしまっているので仕方がありません。

小さい頃から掃除や整理整頓は苦手で、部屋はいつも散らかっています。いざ片付けようと思っても、何をどうすればよいか見当もつきません。何を捨てなければならないか、何を残さなければならないか、何をどこにしまえばよいかが一切分かりません。散らかった部屋を見ると固まってしまいます。

人が気にならない程度の物音を気にしてしまうので、人が集まるところは苦手です。オフィスで仕事中に他人の話し声が気になって気分が悪くなることがありました。急に音がするのも苦手なので、夜道で知人に声をかけられると必ずびっくりして声をかけた人にびっくりされて、それでさらにびっくりします。

事務手続きや振り込み、睡眠や食事などあらゆるものに取り組むのが難しいために、会社で必要な手続きはギリギリになるか期日を過ぎて担当者に注意され、公共料金の支払いは期日を過ぎ、寝る支度が面倒で睡眠障害になり、出かける支度が面倒で約束の時間には間に合わず、頼まれた仕事の期限もギリギリだったり遅れがちになっています。夏休みの宿題は当然、始業日に間に合ったことがありません。

がんばれないというのは、DSM-5 の診断項目の「精神的努力の持続が必要な課題を嫌う」というのが当てはまります。大学の編入試験勉強をがんばれずに落ちたりしました。がんばれるようになりたいものです。

治療について

診断から2ヶ月ほどしか経過していないため、治療として実施されていることは少ないです。 自分には薬物療法と病院が開催するワークショップへの参加と振り返り(予定)が実施されています。

薬物療法では、ADHD に対してストラテラを処方され、服用中です。ストラテラは少量から服用を始めて効果が出るまで徐々に量を増やしていく処方薬です。現在はごく少量を服用しているため、まだ効果はみられず、副作用も特にありません。ASD には処方できる薬がないため、何も服用していません。また、睡眠障害のために抗うつ剤レスリンを処方され、服用しています。睡眠障害発達障害とは別の疾患ですが、発達障害の患者が睡眠障害を発症することは多いようです。医師曰く、薬は一生服用するものではなく必要なときに適宜処方していくとのことです。

ワークショップへの参加は任意のため、診断後の1回目のワークショップは直前に面倒になってしまい参加できませんでした。次回は参加したいと思います。

おわりに

物心ついた頃から変わっているとか不思議ちゃんだと言われ続け、親にはちゃんとしろと言われ続け、小学校と中学校ではいじめられ、高専以降は何をやってもまともな成果が得られないという感覚と不全感に苛まれ、会社勤めを始めてついに適応障害(軽度)を発症して精神衛生をぶち壊すなどの人生を歩んできましたが、なんとなくそういった事象の理由が分かってよかったです。

発達障害と診断されてから精神疾患を持っていることに悩んだりしていますが、何も分からないよりは何か分かった方が解決策も実施しやすいとは考えているので、強く生きていきたいと思います。

免責事項

これは専門の資格を有さない筆者によって執筆された記事です。

本記事に記載される情報、特に発達障害や各種検査、処方薬については、事実と相違のない記述となるように努めてはいますが、筆者が正確性を保証するものではありません。 また、本記事に記載された情報を利用することで生じるいかなる被害や損害について、筆者が保証するものではありません。

プロメアを観た

はじめに

プロメアを観た、レイトショーで。

promare-movie.com

アツい、最高、優勝です。めちゃくちゃすき。 グレンラガンキルラキルをやってバーンでした。最高です。

いい心の揺さぶられ方をしたので、明日も元気に生きる気持ちになった。

ゲームマーケット2019春で買い物をした

はじめに

サークル参加じゃないです。ただの買い物です。

gamemarket.jp

朝に弱い人間なので13時くらいに行ったらいろいろ完売してて泣いた。 前回は試遊できなかったので、今回は試遊して買い物をするのを目標にした。目標は達成できたのでよかった。

買ったもの

  • インサイダーゲーム

ブラフゲーム。好きなやつ。人のでよく遊ぶので自分用を買った。

  • ソクラテスラ〜キメラティック偉人バトル〜/ソクラテスラ〜キメラティック偉人バトル〜 拡張版 死のプレゼンテーション

パーティーゲーム。3枚に分割された偉人のカードを組み合わせて戦う。 拡張版で大喜利モードが追加され、お題に合う偉人を召喚できた人にポイントがつくようになった。 試しに遊んだら「へヴァエリース一世一世」が召喚できました。

  • 宇宙の瞬き

レガシーゲーム。ジャケ買い

  • クク21

駆け引き/運ゲー。すごろくや版のデザインが好き。

  • 閻魔裁判

ワーカープレイスメント/拡大再生産ゲーム。閻魔裁判で現世での徳をアピールしてより良い来世を手に入れる。 「賽の河原で石を積む」アクションがやりたくて買った。

欲しかったもの

  • 神機共鳴コア・コネクション:暗躍のナブラ

デッキ構築ゲーム。買い物・アクションが共通のコストで行える。戦略性とさっくり感が両立してて良かった。 カードデザインがカッコいい。絵柄もカッコいい。試遊してたら完売して泣いた。誰か持ってたら僕と遊んでください。 エウレカセブン的な世界観が最高なんですよ、こういうの大好きです。もっとこういう世界観のゲーム増えてほしい。 第一弾(暗躍のナブラは第二弾)の本体と拡張は秋に再販を計画しているとのことなので、こちらも再販されることを祈って暮らします。

おわりに

コア・コネクション:暗躍のナブラ、再販待ってます。2019秋は早起きすると誓います。

Zombies are standing out とポルノグラフィティらしさ

下書きに漬けられていたので続きを書きました。高まりすぎて何書いたらいいか分かんなくなっちゃったんだね…。


PORNOGRAFFITTI 16th LIVE CIRCUIT "UNFADED" 福岡公演に参戦して高まったので、ポエムを書きます。

サブスクリプション解禁と "UNFADED"

UNFADADE に込めた意味を晴一さんが、サブスクリプションが解禁されたことで、シングル曲もカップリング曲も、昔の曲も今の曲も横並びになって、そういう中で昔の曲が「色褪せて」いないか、今の曲が「色褪せない」と良いとか、そういう話です。詳しくはライブに参戦してBlue-ray か DVD を買って MC を聞いてください。

色褪せない、横並びになった、という切り口で思い出すのは、人に「ポルノグラフィティ好きなんですよ」と言うとだいたい言われる

ポルノグラフィティは昔の曲が好きかな』

です。若干かなしくなりつつ、「あーそうなんすねー」とか「最近の曲もいいですよー」とか答えています。みなさん覚えはありますか。

一般的にファッションや機械など昔のものは古くなって色褪せがちですが、ポルノグラフィティの曲について僕の観測範囲では「昔の曲が好きだった」と称されがちです。これは、特定の世代で流行るという、アーティストの性質によるものだと思います。中高生の頃に好きだったものはずっと好き、みたいな話です。

つまり、むしろ色褪せることはなく、アポロやアゲハ蝶が煌々と輝き続ける一方、THE DAYやカメレオン・レンズには目が向けられていないのではないか、とか考えたりします。

そこで表題です。

Zombies are standing out

突然発表された配信限定シングルです。控えめに言ってめちゃくちゃカッコいい曲です。みんな聴くべき。

www.youtube.com

めちゃくちゃカッコいいんですが、「今までのポルノグラフィティと雰囲気が違う気がする…?」という気持ちが芽生えました。

方向性が変わったという点では、TAMA さんの脱退、ak.homma さんがプロデューサーから退くなど、制作体制の変更タイミングが2回ほどありました。そういったタイミングで、「この辺から曲の雰囲気変わった気がするなー」と感じます。 それはとても嬉しいことで、いろんなポルノグラフィティじゃん、最高、感謝、みたいな気持ちです。

Zombies are standing out も、そんな、ポルノグラフィティらしくないポルノグラフィティ、でもやっぱりポルノグラフィティだなあ、という、認識を深められた曲です。

色褪せないポルノグラフィティ

昔のポルノグラフィティも今のポルノグラフィティも変わらずポルノグラフィティで、いつのポルノグラフィティポルノグラフィティらしさがあり、「昔のポルノグラフィティが好き」な人の色褪せないポルノグラフィティらしさも大事にしてほしいけど、今のポルノグラフィティのらしさも感じてくれたらな、と思います。

以上、ポエムでした。


2019年9月7日/8日に20周年東京ドーム2DAYライブがあるよ!!!!!!!!!!!!!!!!!!!!! いこう!!!!!!!!!!!!!!!!!!!

sp.pornograffitti.jp

自宅に食洗機を導入した

はじめに

前からずっと欲しがっていた食洗機を買った。

食器洗い乾燥機 NP-TCM4 商品概要 | 食器洗い乾燥機/食器洗い機 | Panasonic

家事がとにかく嫌いなので、なるべく機械化していく試みとして導入した。

よかった点

食器を入れておけば洗浄されるのは、思ったより体験がよかった。 洗うぞ!と決意するより、詰めるぞ!と決意するほうがコストが低いので、気軽に食器を洗えるようになった。

手が荒れないのも嬉しい。 自炊をして毎日食器を洗うような生活をしていた頃は、ずっと手が荒れていた。 ゴム手袋をすれば手荒れは防げるけど、蒸れるのであまり気が進まなかった。 そういう問題が解決したのはめでたい。

わるかった点

食洗機はうるさいと聞いていた。確かに洗濯機みたいな音がする。 いつ食洗機を回すかは自分で制御可能なので、うるさくても良い時間に回すと良さそう。

食器をきれいに詰めるのが案外難しくて、少し面倒を感じる。慣れれば多少解決しそう。

設置

設置場所の都合上、電源コードを延長する必要があった。 食洗機は接地が必要な機器なので、秋葉原の電気街まで3ピンプラグのアース線が入った延長コードを探しに行った。 自分では見つけられなかったのでお店の人に聞いたら、普通に出してくれた。自作するはめにならなくてよかった。かまぼこ型のモールも出してくれた。

分岐水栓は説明書どおりに接続できた。ただ、六角レンチが合わずに蛇口の頭が外せないトラブルが発生したので、3日ほど設置作業を延期するはめになった。

工具が揃っていれば、設置作業はそれほど難しくなかった。

おわりに

食洗機はいいぞ

CliftonStrengths テストを受けた

追記 2020-08-25: 資質の説明の日本語版があったので、引用先をそちらに変更しました。また、残りの順位についての記事のリンクを追加しました。

はじめに

CliftonStrengths テストを受けた。

www.gallupstrengthscenter.com

CliftonStrengths テストは、質問に対する[そう思う・どちらかと言えばそう思う・どちらでもない・どちらかと言えばそう思わない・そう思わない]といった回答から受験者の強み=資質を分析するツールである。資質(theme)は4分類・34種ある*1

テストの結果から上位5つの資質を見れるライセンス($19.9)と、全ての順位の資質が見れるライセンス($49.99)、上位5つを見てから全ての順位の資質を見るためのライセンス($39.9)、の3つがある。

自分の思考や行動の傾向を探るのが好きで自分のことはなんとなくわかっているつもりでいたので、上位資質5つだけ見てみることにした。やすいし。

結果

  1. 内省 - Intellection (戦略的思考力)*2

    「内省」の資質が高い人は、知的な活動に多くの時間を費やします。内省的で、知的な議論が好きです。

  2. 着想 - Ideation (戦略的思考力)*3

    「着想」の資質が高い人は、新しいアイデアを考えるのが大好きです。見た目には共通点のない現象に、関連性を見出すことができます。

  3. 学習欲 - Learner (戦略的思考力)*4

    「学習欲」の資質が高い人は、学習意欲が旺盛で、常に向上を望んでいます。結果よりも学習すること自体に意義を見出します。

  4. 指令性 - Command (影響力)*5

    「指令性」の資質が高い人は、存在感があります。状況の主導権を握り、決断を下します。

  5. 個別化 - Individualization (人間関係構築力)*6

    「個別化」の資質が高い人は、一人ひとりが持つユニークな個性に興味をひかれます。異なるタイプの人たちの集団をまとめ、生産性の高いチームを作ることに長けています。

ライセンスに含まれる電子書籍や自身の資質に関するレポートに詳しいことが書いてあるので、各自参照してください。

感想

戦略的思考力が強いのは予想してたけど、指令性と個別化は意外だった。

言われてみれば自分に主導権が無い状態を強く嫌うので、指令性の資質に納得できる。「自分の意見を主張するのに迷いがなく、意見の対立に怯えない」というのも当てはまる。社会性がない、協調性がない、と言われるの、これのせいでは…?

個別化は自分を特性のある個として見てほしいとも言える。わかる。でかい主語で雑にくくられると「は?」ってなる。

内省と着想、学習欲は妥当っぽい。 頭使ってゲームするのが好きで、プレイについてあれこれ考えたり、人と議論したり、そういう過程自体を楽しいと思っている。 負けたらちょっと悔しいけど、勝ち負けに頓着しないところがある。なので、自分より十枚くらい上手なプレイヤーと遊ぶのが一番楽しい。仕事も同様かもしれない。

開発/研究チームのリーダー(チームメンバー全員僕より優秀)みたいな人になると強そう。ただ決定的な欠陥として、結果に頓着しないところがある。自身の資質に関するレポートにも、アウトプットせよ、と書いてあった。

まとめ

意識していなかった資質が見れてよかった。残りも見たくなった。今度ライセンス購入します。

追記 2020-08-25: 残りはこちら。 haneuma0628.hatenablog.jp

仕事のがんばり具合を記録して可視化する(記録する編)

はじめに

これは Yahoo! JAPAN 18 新卒 Advent Calendar 2018 の21日目の記事です。

みなさん仕事がんばってますか?自分は新卒らしくがんばっています。がんばっているので、がんばり具合を記録して可視化します。

やりたいことはだいたいこういうことです。 pokutuna.hatenablog.com

ざっくり書くと:

  • 開いているウィンドウのログを記録する
  • グラフにする

ということをやります。どんなウィンドウを開いていたかを時系列に並べてグラフにすれば「10時から1時間くらい Emacs 開いてるからコード書いてるんだな、がんばってるっぽいぞ!」というのがわかります。これががんばり具合です。

セキュリティ的に、社外秘を含む情報を扱う端末のログの外部送信は問題があるので、このような取り組みを社内の環境で行えるような仕組みを自分で作ります。今回は記録するところについて書きます。

できたもの

社用 PC が Mac なので Cocoa でアプリケーションを作ります。Swift は書いたことがないのでインターネットを駆使してがんばります。がんばると、このような JSON が獲得できます。

[
  {
    "kCGWindowAlpha" : 1,
    "kCGWindowLayer" : 0,
    "kCGWindowMemoryUsage" : 1128,
    "kCGWindowSharingState" : 0,
    "kCGWindowOwnerPID" : 39418,
    "kCGWindowNumber" : 154478,
    "kCGWindowOwnerName" : "Xcode",
    "kCGWindowStoreType" : 1,
    "kCGWindowBounds" : {
      "X" : 135,
      "Height" : 877,
      "Y" : 23,
      "Width" : 1305
    },
    "kCGWindowName" : "AppDelegate.swift"
  },
  {
    "kCGWindowAlpha" : 1,
    "kCGWindowLayer" : 0,
    "kCGWindowMemoryUsage" : 1128,
    "kCGWindowSharingState" : 1,
    "kCGWindowOwnerPID" : 2160,
    "kCGWindowNumber" : 151228,
    "kCGWindowOwnerName" : "Google Chrome",
    "kCGWindowStoreType" : 1,
    "kCGWindowBounds" : {
      "X" : 170,
      "Height" : 62,
      "Y" : 92,
      "Width" : 366
    },
    "kCGWindowName" : ""
  }, ...

開いているウィンドウの名前と、どのアプリケーションから起動されているかがわかりますね。おおむね重なり順も合っているはずですが、雑に作ったので怪しいかもしれない。 JSON が得られたので、Elasticsearch + Kibana で可視化できそうな感じがしますね。

しくみ

常駐の Cocoa App で5秒ごとにウィンドウログ取得して、JSON 形式で保存させています。XCode の気持ちになって、しかるべき場所にこのようなコードが書いてあると思ってください。

func applicationDidFinishLaunching(_ aNotification: Notification) {
    Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(self.saveLog), userInfo: nil, repeats: true)
}

@objc func saveLog() -> Void {
    let filename = self.getDocumentsDirectory().appendingPathComponent("\(NSDate().timeIntervalSince1970).json")

    let windowList = self.getWindowList()
    let data: Data = try! JSONSerialization.data(withJSONObject: windowList!, options: [])

    do {
        let windowInfoList = try JSONDecoder().decode([MyWindowInfo].self, from: data)

        let encoder = JSONEncoder()
        encoder.outputFormatting = .prettyPrinted
        let encoded = try! encoder.encode(windowInfoList)

        do {
            try String(data: encoded, encoding: .utf8)!.write(to: filename, atomically: true, encoding: String.Encoding.utf8)
        } catch {
            print(error)
        }
    } catch {
        print(error)
    }
}

getWindowListMyWindowInfo あたりが大事なので、詳しく説明します。

ウィンドウリストを取得する

CGWindowListCopyWindowInfo() でさっくりウィンドウリストが取得できます。CFArray で結果が返ってくるので、外側は NSArray にキャストします。中身は NSDictioanry とします。.optionAll ですべてのウィンドウを取ってくると常駐アプリケーションや Desktop プロセスなどのがんばり具合に寄与しないものが取れてしまうので、適当にフィルタします。高さが23以下のウィンドウは常駐アプリケーションで、layer が 0 より小さいのは Desktop プロセスとかその辺です。用途によっては自作のフィルタではなく、CGWindowListCopyWindowInfo() のオプションでいい感じに必要なウィンドウだけ取得することもできます。

func getWindowList() -> [NSDictionary]? {
        guard let windowList: NSArray = CGWindowListCopyWindowInfo(.optionAll, kCGNullWindowID) else {
            return nil
        }

        let swiftWindowList = windowList as! [NSDictionary]

        let filteredWindowList = swiftWindowList.filter { (windowIndo: NSDictionary) -> Bool in
            var flag: Bool = true

            // Bounds filter
            let bounds = windowIndo[kCGWindowBounds] as! NSDictionary
            let height = bounds["Height"] as! Int
            if height <= 23 {
                flag = false
            }

            // Layer filter
            let layer = windowIndo[kCGWindowLayer] as! Int
            if layer < 0 {
                flag = false
            }

            return flag
        }

        return filteredWindowList
    }

JSON に変換する

getWindowList() で得られるのは NSDictionary の NSArray なので、JSON 文字列に変換していきます。 JSONSerialization -> JSONDecode -> JSONEncode という手順でやります。 Serialization で潰したデータを一旦 Decode して、人間に優しい表記で Encode する感じです。

平たく書くとこうなっています。例外の気持ちになって、しかるべきコードに読み替えてください。

let windowList = self.getWindowList()  // -> [NSDictionary]

// windowList を1行に潰す
let data: Data = JSONSerialization.data(withJSONObject: windowList, options: [])

// ねじ込む
let windowInfoList = JSONDecoder().decode([MyWindowInfo].self, from: data)

// 人間に優しい表記にする
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let encoded = encoder.encode(windowInfoList)
let dst = String(data: encoded, encoding: .utf8)!

Decode するときは Codable を使います。潰したデータを任意の構造体にねじ込めます。便利ですね。

struct MyWindowInfo: Codable {
    var kCGWindowAlpha: Double
    var kCGWindowBounds: MyWindowBounds
    var kCGWindowIsOnscreen: Bool?
    var kCGWindowLayer: Int
    var kCGWindowMemoryUsage: Int
    var kCGWindowName: String?
    var kCGWindowNumber: Int
    var kCGWindowOwnerName: String
    var kCGWindowOwnerPID: Int
    var kCGWindowSharingState: Int
    var kCGWindowStoreType: Int

    struct MyWindowBounds: Codable {
        var Height: Int
        var Width: Int
        var X: Int
        var Y: Int
    }
}

ログについて

ログは溜めて使ってこそ価値がありますね。弊社もそのようにやっています。そういうわけで、運用にあたって調べておきたいことを調べておきます。

容量・転送

常駐アプリケーションで5秒毎にテキストデータを生成しているので、ログが気になります。見てみると1ファイルあたり 44KB でした。 1時間で 60 * 60 / 5 * 44 = 31680KB になります。32MB くらいですね。今月の必要労働時間は147時間15分らしいので、1ヶ月で (147 * 60 * 60 + 15 * 60) / 5 * 44 = 4664880KB になります。4.7GB くらいですね。 保存期間を1年間とすると 56GB くらいになります。現実的な容量ですね。

また、ログの保存と可視化のために、適当なサーバに定期的に転送する必要があります。 1時間ごとに転送するとして 32MB くらいなので、現代のインターネットなら問題なさそうです。 社内のネットワークを計測したところ、7.80MB/sec でした。5,6秒あれば転送できそうです。

メモリ使用量

だいたい 12MB くらい食べています。社用 PC のメモリは 16GBなので、常駐させても問題なさそうです。

セキュリティ

ウィンドウ名に社外秘情報が含まれる可能性があるので、生ログは社内にしまっておく必要があります。

まとめ

いつ、どのくらい、どんなウィンドウ(アプリケーション)を開いていたかのログを使って、仕事のがんばり具合を記録・可視化する取り組みについて書きました。 この記事では Cocoa でロガーを作るところと、ログの保管について少しだけ検証しました。可視化するところは作業中なので、また別の記事に書きます。

Swift は初めて書いたので、記事内のソースコードについてコメントがあればぜひお願いします。また、このプログラムは社内の GHE に置いているので、興味のある方は入社して一緒にがんばり具合を記録しましょう。

以上、Yahoo! JAPAN 18 新卒 Advent Calendar 2018 の21日目の記事でした。

参考