[{"data":1,"prerenderedAt":825},["ShallowReactive",2],{"content-/mf-office-settings-export-import":3,"all-pages-for-dir":823,"og-image-/mf-office-settings-export-import":824},{"id":4,"title":5,"body":6,"category":804,"description":805,"extension":806,"meta":807,"navigation":411,"ogImage":808,"path":809,"project_name":810,"published":811,"publishedAt":812,"seo":813,"stem":814,"tags":815,"todo":821,"unpublished":811,"updatedAt":808,"__hash__":822},"pages/2026-03/2026-03-29/mf-office-settings-export-import.md","Chrome拡張 事業者設定エクスポート/インポート機能 - 全年度マトリクス出力とUI同期フロー",{"type":7,"value":8,"toc":778},"minimark",[9,14,18,21,25,28,36,38,42,46,53,56,59,66,69,83,89,195,198,201,212,216,223,225,228,231,267,270,272,276,279,282,285,289,296,498,507,511,514,517,519,522,526,529,532,550,561,563,566,570,577,584,741,744,747,750,754,757,760,762,765,768,771,774],[10,11,13],"h1",{"id":12},"chrome拡張-事業者設定エクスポートインポート機能","Chrome拡張 事業者設定エクスポート/インポート機能",[15,16,17],"p",{},"事業者設定を年度ごとに手作業で確認してスプレッドシートに転記していた作業を、Chrome拡張のボタン一発で全年度マトリクスとして出力できるようにした。さらにスプレッドシート上で編集した設定値をインポートで書き戻す双方向フローまで一日で組み上げた記録。",[19,20],"hr",{},[22,23,24],"h2",{"id":24},"事業者設定タブの新設",[15,26,27],{},"Chrome拡張の設定画面に「事業者設定」タブを追加した。既存の「自動仕訳ルール」タブや「エクスポートログ」タブと同じミラーカラムUIパターンに載せる形で、エクスポートボタンとインポートUIを配置する。",[15,29,30,31,35],{},"タブ追加自体は ",[32,33,34],"code",{},"popup.html"," にタブヘッダーとコンテンツ領域を足すだけだが、タブ切替ロジックが既存の手書きスイッチャーに依存していたため、新しいタブIDを配列に追加して回った。",[19,37],{},[22,39,41],{"id":40},"エクスポート機能-設定ページのスクレイピング","エクスポート機能: 設定ページのスクレイピング",[43,44,45],"h3",{"id":45},"全年度マトリクスの設計",[15,47,48,49,52],{},"会計ソフトの事業者設定ページ（",[32,50,51],{},"/offices/edit","）には、事業者番号、事業者名、業種区分、会計期間など数十の設定項目がフォーム要素として並んでいる。これを年度ごとにスクレイピングして、横軸=年度・縦軸=設定項目のマトリクスをスプレッドシートに出力する。",[15,54,55],{},"年度切替はCTI（Client-side Table Index）の既存ロジックを流用し、各年度に移動してからDOMを読み取る。",[43,57,58],{"id":58},"事業者番号の取得",[15,60,61,62,65],{},"事業者番号はフォーム要素ではなくページ上部の表示テキストに埋まっていた。",[32,63,64],{},"querySelector"," で取得するセレクタを追加し、マトリクスの先頭行に出力するようにした。",[43,67,68],{"id":68},"業種区分のラベル変換",[15,70,71,72,75,76,79,80,82],{},"業種区分は ",[32,73,74],{},"\u003Cselect>"," 要素の ",[32,77,78],{},"value"," がIDで、画面に表示されるのは日本語のラベル。",[32,81,78],{}," をそのまま書き出すと「1001」のような数値になってスプレッドシート上で意味が分からない。",[15,84,85,88],{},[32,86,87],{},"selectedOptions[0].textContent"," で表示中のラベルを取得する方式に切り替えた。",[90,91,96],"pre",{"className":92,"code":93,"language":94,"meta":95,"style":95},"language-javascript shiki shiki-themes vitesse-light vitesse-light","// ID値ではなく表示ラベルを取得\nconst industrySelect = doc.querySelector('select[name=\"industry_code\"]');\nconst industryLabel = industrySelect?.selectedOptions[0]?.textContent?.trim() ?? '';\n","javascript","",[32,97,98,107,147],{"__ignoreMap":95},[99,100,103],"span",{"class":101,"line":102},"line",1,[99,104,106],{"class":105},"sxvE3","// ID値ではなく表示ラベルを取得\n",[99,108,110,114,118,122,125,128,131,134,138,142,144],{"class":101,"line":109},2,[99,111,113],{"class":112},"stQ0i","const",[99,115,117],{"class":116},"s4oTP"," industrySelect",[99,119,121],{"class":120},"shFtX"," =",[99,123,124],{"class":116}," doc",[99,126,127],{"class":120},".",[99,129,64],{"class":130},"senZ8",[99,132,133],{"class":120},"(",[99,135,137],{"class":136},"sMJiu","'",[99,139,141],{"class":140},"sdGka","select[name=\"industry_code\"]",[99,143,137],{"class":136},[99,145,146],{"class":120},");\n",[99,148,150,152,155,157,159,162,165,168,172,175,178,180,183,186,189,192],{"class":101,"line":149},3,[99,151,113],{"class":112},[99,153,154],{"class":116}," industryLabel",[99,156,121],{"class":120},[99,158,117],{"class":116},[99,160,161],{"class":120},"?.",[99,163,164],{"class":116},"selectedOptions",[99,166,167],{"class":120},"[",[99,169,171],{"class":170},"sM54T","0",[99,173,174],{"class":120},"]?.",[99,176,177],{"class":116},"textContent",[99,179,161],{"class":120},[99,181,182],{"class":130},"trim",[99,184,185],{"class":120},"()",[99,187,188],{"class":112}," ??",[99,190,191],{"class":136}," ''",[99,193,194],{"class":120},";\n",[43,196,197],{"id":197},"シート1削除タイミングの修正",[15,199,200],{},"Google Sheets APIで新規スプレッドシートを作成すると、デフォルトで「シート1」が生成される。当初はスプレッドシート作成直後にシート1を削除していたが、シートが1枚もない状態でデータ書き込みシートを追加しようとするとAPIがエラーを返した。",[15,202,203,204,207,208,211],{},"修正として、エクスポート用シートとインポート用シートの2枚を先に ",[32,205,206],{},"addSheet"," で追加してから、最後にシート1を ",[32,209,210],{},"deleteSheet"," する順序に変えた。",[43,213,215],{"id":214},"codexレビュー3回","Codexレビュー3回",[15,217,218,219,222],{},"エクスポート機能の実装計画をCodexに3回投げた。1回目で「年度切替失敗時にマトリクスが歯抜けになるがエラーハンドリングがない」という指摘が返ってきて、年度切替失敗時はその年度列を ",[32,220,221],{},"\"ERROR\""," で埋める処理を追加した。2回目で「スクレイピング対象のセレクタがハードコードされている」と指摘されたが、これは対象ページの構造に依存するため現状維持とした。3回目は軽微な命名指摘のみで、そのままマージした。",[19,224],{},[22,226,227],{"id":227},"エクスポート時の2シート構成",[15,229,230],{},"エクスポートで生成するスプレッドシートに2枚のシートを作る方式にした。",[232,233,234,247],"table",{},[235,236,237],"thead",{},[238,239,240,244],"tr",{},[241,242,243],"th",{},"シート名",[241,245,246],{},"用途",[248,249,250,259],"tbody",{},[238,251,252,256],{},[253,254,255],"td",{},"事業者設定_エクスポート",[253,257,258],{},"全年度の推移表（読み取り専用の参照用）",[238,260,261,264],{},[253,262,263],{},"事業者設定_インポート",[253,265,266],{},"最新年度の設定値を縦に並べた編集用シート",[15,268,269],{},"インポート用シートは「項目名 / 現在値 / 新しい値」の3列構成で、ユーザーが「新しい値」列を編集してからインポートを実行する。編集対象が明確になるので、全年度マトリクスの中から「どこを変えるのか」を探す手間が消えた。",[19,271],{},[22,273,275],{"id":274},"インポート機能-計画変更とui実装","インポート機能: 計画変更とUI実装",[43,277,278],{"id":278},"当初計画からの方針転換",[15,280,281],{},"最初はCLI（Claude Code経由）でインポートを実行する設計で進めていた。スプレッドシートのデータを読み取り、APIで設定値を更新するスクリプトを書く想定だった。",[15,283,284],{},"しかし途中で「Chrome拡張のUI上でインポートできた方が直感的」という判断に変わり、自動仕訳ルールタブと同じUIパターンで実装する方向に切り替えた。ドライラン表示→確認→実行という3ステップのフローを組む。",[43,286,288],{"id":287},"fetch-apiによるフォームpost","fetch APIによるフォームPOST",[15,290,291,292,295],{},"インポートの核心部分は、設定ページのフォームを ",[32,293,294],{},"fetch"," で直接POSTする方式を採った。ページ遷移が発生しないため、連続して複数の設定項目を更新できる。",[90,297,299],{"className":92,"code":298,"language":94,"meta":95,"style":95},"// content scriptから設定ページのフォームをfetchで送信\nconst formData = new FormData();\nformData.append('field_name', newValue);\nformData.append('_method', 'patch');\nformData.append('authenticity_token', token);\n\nconst res = await fetch('/offices', {\n  method: 'POST',\n  body: formData,\n  credentials: 'include'\n});\n",[32,300,301,306,324,351,381,406,413,444,464,476,492],{"__ignoreMap":95},[99,302,303],{"class":101,"line":102},[99,304,305],{"class":105},"// content scriptから設定ページのフォームをfetchで送信\n",[99,307,308,310,313,315,318,321],{"class":101,"line":109},[99,309,113],{"class":112},[99,311,312],{"class":116}," formData",[99,314,121],{"class":120},[99,316,317],{"class":112}," new",[99,319,320],{"class":130}," FormData",[99,322,323],{"class":120},"();\n",[99,325,326,329,331,334,336,338,341,343,346,349],{"class":101,"line":149},[99,327,328],{"class":116},"formData",[99,330,127],{"class":120},[99,332,333],{"class":130},"append",[99,335,133],{"class":120},[99,337,137],{"class":136},[99,339,340],{"class":140},"field_name",[99,342,137],{"class":136},[99,344,345],{"class":120},",",[99,347,348],{"class":116}," newValue",[99,350,146],{"class":120},[99,352,354,356,358,360,362,364,367,369,371,374,377,379],{"class":101,"line":353},4,[99,355,328],{"class":116},[99,357,127],{"class":120},[99,359,333],{"class":130},[99,361,133],{"class":120},[99,363,137],{"class":136},[99,365,366],{"class":140},"_method",[99,368,137],{"class":136},[99,370,345],{"class":120},[99,372,373],{"class":136}," '",[99,375,376],{"class":140},"patch",[99,378,137],{"class":136},[99,380,146],{"class":120},[99,382,384,386,388,390,392,394,397,399,401,404],{"class":101,"line":383},5,[99,385,328],{"class":116},[99,387,127],{"class":120},[99,389,333],{"class":130},[99,391,133],{"class":120},[99,393,137],{"class":136},[99,395,396],{"class":140},"authenticity_token",[99,398,137],{"class":136},[99,400,345],{"class":120},[99,402,403],{"class":116}," token",[99,405,146],{"class":120},[99,407,409],{"class":101,"line":408},6,[99,410,412],{"emptyLinePlaceholder":411},true,"\n",[99,414,416,418,421,423,427,430,432,434,437,439,441],{"class":101,"line":415},7,[99,417,113],{"class":112},[99,419,420],{"class":116}," res",[99,422,121],{"class":120},[99,424,426],{"class":425},"sHkkW"," await",[99,428,429],{"class":130}," fetch",[99,431,133],{"class":120},[99,433,137],{"class":136},[99,435,436],{"class":140},"/offices",[99,438,137],{"class":136},[99,440,345],{"class":120},[99,442,443],{"class":120}," {\n",[99,445,447,451,454,456,459,461],{"class":101,"line":446},8,[99,448,450],{"class":449},"sz8Xr","  method",[99,452,453],{"class":120},":",[99,455,373],{"class":136},[99,457,458],{"class":140},"POST",[99,460,137],{"class":136},[99,462,463],{"class":120},",\n",[99,465,467,470,472,474],{"class":101,"line":466},9,[99,468,469],{"class":449},"  body",[99,471,453],{"class":120},[99,473,312],{"class":116},[99,475,463],{"class":120},[99,477,479,482,484,486,489],{"class":101,"line":478},10,[99,480,481],{"class":449},"  credentials",[99,483,453],{"class":120},[99,485,373],{"class":136},[99,487,488],{"class":140},"include",[99,490,491],{"class":136},"'\n",[99,493,495],{"class":101,"line":494},11,[99,496,497],{"class":120},"});\n",[15,499,500,502,503,506],{},[32,501,396],{}," はページ内の ",[32,504,505],{},"\u003Cmeta>"," タグから取得する。セッションが切れていると403が返るため、レスポンスのステータスコードを見てエラーメッセージを出す処理も入れた。",[43,508,510],{"id":509},"ドライラン同期実行フロー","ドライラン→同期実行フロー",[15,512,513],{},"インポートボタンを押すと、まずドライランが走る。スプレッドシートから読み取った「新しい値」と、現在の設定ページ上の値を比較して、差分がある項目だけをテーブルに表示する。",[15,515,516],{},"ユーザーが差分を目視確認して「同期実行」ボタンを押すと、差分のある項目だけをfetch POSTで更新する。全件完了後、再度設定ページを読み込んで結果を照合する。",[19,518],{},[22,520,521],{"id":521},"ログ記録の統合",[43,523,525],{"id":524},"エクスポートインポートのログ対応","エクスポート/インポートのログ対応",[15,527,528],{},"事業者設定のエクスポートとインポートの実行結果を、既存のログタブに記録するようにした。ログ一覧から詳細を開くと、どの設定項目が更新されたか（エクスポートなら何年度分を出力したか）が確認できる。",[43,530,531],{"id":531},"yearsプロパティ欠損バグ",[15,533,534,535,538,539,542,543,545,546,549],{},"ログ詳細表示で「全年度結合表示」を行う箇所で、",[32,536,537],{},"years"," プロパティが存在しないログレコードに対して ",[32,540,541],{},".length"," を呼んでクラッシュするバグがあった。事業者設定エクスポートのログには ",[32,544,537],{}," ではなく ",[32,547,548],{},"items"," という配列で記録していたため、プロパティ名の不一致が原因だった。",[15,551,552,553,556,557,560],{},"ログ詳細の表示ロジックに ",[32,554,555],{},"years ?? items"," のフォールバックを入れて、推移表パターンの ",[32,558,559],{},"colspan"," 計算と統一した。",[19,562],{},[22,564,565],{"id":565},"周辺の修正",[43,567,569],{"id":568},"json設定エクスポートのファイル名にjst日時を追加","JSON設定エクスポートのファイル名にJST日時を追加",[15,571,572,573,576],{},"Chrome拡張の設定をJSONファイルとしてエクスポートする機能で、ファイル名に日時を含めていたが、",[32,574,575],{},"new Date().toISOString()"," をそのまま使っていたためUTC時刻になっていた。深夜0時付近にエクスポートすると日付が前日になる。",[15,578,579,580,583],{},"JSTオフセット（+9時間）を加算した ",[32,581,582],{},"Date"," オブジェクトからファイル名を生成するように修正した。",[90,585,587],{"className":92,"code":586,"language":94,"meta":95,"style":95},"// UTC → JST変換してファイル名に使用\nconst jst = new Date(Date.now() + 9 * 60 * 60 * 1000);\nconst ts = jst.toISOString().slice(0, 19).replace(/[T:]/g, '-');\nconst filename = `extension-settings-${ts}.json`;\n",[32,588,589,594,642,709],{"__ignoreMap":95},[99,590,591],{"class":101,"line":102},[99,592,593],{"class":105},"// UTC → JST変換してファイル名に使用\n",[99,595,596,598,601,603,605,608,610,612,614,617,619,622,625,628,631,633,635,637,640],{"class":101,"line":109},[99,597,113],{"class":112},[99,599,600],{"class":116}," jst",[99,602,121],{"class":120},[99,604,317],{"class":112},[99,606,607],{"class":130}," Date",[99,609,133],{"class":120},[99,611,582],{"class":116},[99,613,127],{"class":120},[99,615,616],{"class":130},"now",[99,618,185],{"class":120},[99,620,621],{"class":112}," +",[99,623,624],{"class":170}," 9",[99,626,627],{"class":112}," *",[99,629,630],{"class":170}," 60",[99,632,627],{"class":112},[99,634,630],{"class":170},[99,636,627],{"class":112},[99,638,639],{"class":170}," 1000",[99,641,146],{"class":120},[99,643,644,646,649,651,653,655,658,661,664,666,668,670,673,676,679,681,684,686,690,693,695,698,700,702,705,707],{"class":101,"line":149},[99,645,113],{"class":112},[99,647,648],{"class":116}," ts",[99,650,121],{"class":120},[99,652,600],{"class":116},[99,654,127],{"class":120},[99,656,657],{"class":130},"toISOString",[99,659,660],{"class":120},"().",[99,662,663],{"class":130},"slice",[99,665,133],{"class":120},[99,667,171],{"class":170},[99,669,345],{"class":120},[99,671,672],{"class":170}," 19",[99,674,675],{"class":120},").",[99,677,678],{"class":130},"replace",[99,680,133],{"class":120},[99,682,683],{"class":136},"/",[99,685,167],{"class":120},[99,687,689],{"class":688},"snbK4","T:",[99,691,692],{"class":120},"]",[99,694,683],{"class":136},[99,696,697],{"class":425},"g",[99,699,345],{"class":120},[99,701,373],{"class":136},[99,703,704],{"class":140},"-",[99,706,137],{"class":136},[99,708,146],{"class":120},[99,710,711,713,716,718,721,724,727,730,733,736,739],{"class":101,"line":353},[99,712,113],{"class":112},[99,714,715],{"class":116}," filename",[99,717,121],{"class":120},[99,719,720],{"class":136}," `",[99,722,723],{"class":140},"extension-settings-",[99,725,726],{"class":425},"${",[99,728,729],{"class":140},"ts",[99,731,732],{"class":425},"}",[99,734,735],{"class":140},".json",[99,737,738],{"class":136},"`",[99,740,194],{"class":120},[43,742,743],{"id":743},"サービス一覧エクスポートのマージ方式変更",[15,745,746],{},"サービス一覧のエクスポート処理で、スプレッドシートを毎回新規作成していたのをマージ方式に変更した。既存のスプレッドシートURLが設定されていれば、そのシートにデータを追記する。URLが未設定のときだけ新規作成する。",[15,748,749],{},"これにより、別のタブで参照しているスプレッドシートURLが実行のたびに変わってしまう問題が解消された。",[43,751,753],{"id":752},"設定画面から自動仕訳ルールurl欄を削除","設定画面から自動仕訳ルールURL欄を削除",[15,755,756],{},"自動仕訳ルールのスプレッドシートURLを設定画面の入力欄とchrome.storageの両方で管理していたが、chrome.storageを唯一の情報源（single source of truth）にする方針で入力欄を削除した。",[15,758,759],{},"エクスポート実行時にchrome.storageへURLを自動保存するフローが既に動いていたので、手動入力欄がなくても困らない。設定画面のUIがすっきりした分、タブ切替時の初期化コードも減った。",[19,761],{},[22,763,764],{"id":764},"振り返り",[15,766,767],{},"朝の時点では「エクスポートだけ作って終わり」の予定だったが、エクスポート結果を見ているうちに「このまま書き戻せたら便利」という発想が湧いて、インポートまで一気に作り切った。ドライラン→確認→実行のフローは自動仕訳ルールタブで一度組んだパターンの流用なので、UIの配線は30分ほどで終わった。",[15,769,770],{},"Codexレビューを3回挟んだことで、エラーハンドリングの抜けを実装前に潰せたのは収穫だった。特に年度切替失敗時のマトリクス歯抜け問題は、手動テストだけでは気づきにくい。",[15,772,773],{},"fetch POSTでフォームを送信する方式は、ページ遷移なしで複数項目を連続更新できるため体感速度が段違いだった。10項目の更新が2秒で完了する。ページ遷移方式だと1項目ごとに3〜4秒かかるので、30秒以上の差が出る計算になる。",[775,776,777],"style",{},"html pre.shiki code .sxvE3, html code.shiki .sxvE3{--shiki-default:#A0ADA0;--shiki-dark:#A0ADA0}html pre.shiki code .stQ0i, html code.shiki .stQ0i{--shiki-default:#AB5959;--shiki-dark:#AB5959}html pre.shiki code .s4oTP, html code.shiki .s4oTP{--shiki-default:#B07D48;--shiki-dark:#B07D48}html pre.shiki code .shFtX, html code.shiki .shFtX{--shiki-default:#999999;--shiki-dark:#999999}html pre.shiki code .senZ8, html code.shiki .senZ8{--shiki-default:#59873A;--shiki-dark:#59873A}html pre.shiki code .sMJiu, html code.shiki .sMJiu{--shiki-default:#B5695977;--shiki-dark:#B5695977}html pre.shiki code .sdGka, html code.shiki .sdGka{--shiki-default:#B56959;--shiki-dark:#B56959}html pre.shiki code .sM54T, html code.shiki .sM54T{--shiki-default:#2F798A;--shiki-dark:#2F798A}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHkkW, html code.shiki .sHkkW{--shiki-default:#1E754F;--shiki-dark:#1E754F}html pre.shiki code .sz8Xr, html code.shiki .sz8Xr{--shiki-default:#998418;--shiki-dark:#998418}html pre.shiki code .snbK4, html code.shiki .snbK4{--shiki-default:#A65E2B;--shiki-dark:#A65E2B}",{"title":95,"searchDepth":109,"depth":109,"links":779},[780,781,788,789,794,798,803],{"id":24,"depth":109,"text":24},{"id":40,"depth":109,"text":41,"children":782},[783,784,785,786,787],{"id":45,"depth":149,"text":45},{"id":58,"depth":149,"text":58},{"id":68,"depth":149,"text":68},{"id":197,"depth":149,"text":197},{"id":214,"depth":149,"text":215},{"id":227,"depth":109,"text":227},{"id":274,"depth":109,"text":275,"children":790},[791,792,793],{"id":278,"depth":149,"text":278},{"id":287,"depth":149,"text":288},{"id":509,"depth":149,"text":510},{"id":521,"depth":109,"text":521,"children":795},[796,797],{"id":524,"depth":149,"text":525},{"id":531,"depth":149,"text":531},{"id":565,"depth":109,"text":565,"children":799},[800,801,802],{"id":568,"depth":149,"text":569},{"id":743,"depth":149,"text":743},{"id":752,"depth":149,"text":753},{"id":764,"depth":109,"text":764},"dev","会計サービス連携Chrome拡張に事業者設定タブを新設。設定ページのスクレイピングで全年度推移表をスプレッドシートに出力し、インポート機能でfetch POSTによるページ遷移なし同期を実装した記録","md",{},null,"/mf-office-settings-export-import","misc-dev",false,"2026-03-29T00:00:00.000Z",{"title":5,"description":805},"2026-03/2026-03-29/mf-office-settings-export-import",[816,817,818,819,820],"Chrome拡張機能","クラウド会計","Google Sheets API","HTMLスクレイピング","fetch API","memo","-VKtWtCmbFVlUjeyptotcVDH4lC_ZsUXsoiwOBkVRy8",[],"https://log.eurekapu.com/og/blog/mf-office-settings-export-import.png?v=2026-03-29T00%3A00%3A00.000Z&title=Chrome%E6%8B%A1%E5%BC%B5%20%E4%BA%8B%E6%A5%AD%E8%80%85%E8%A8%AD%E5%AE%9A%E3%82%A8%E3%82%AF%E3%82%B9%E3%83%9D%E3%83%BC%E3%83%88%2F%E3%82%A4%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%88%E6%A9%9F%E8%83%BD%20-%20%E5%85%A8%E5%B9%B4%E5%BA%A6%E3%83%9E%E3%83%88%E3%83%AA%E3%82%AF%E3%82%B9%E5%87%BA%E5%8A%9B%E3%81%A8UI%E5%90%8C%E6%9C%9F%E3%83%95%E3%83%AD%E3%83%BC&author=Kei%20Komatsu&sig=3487d8d2f0c1da1a",1782528822136]