1<!DOCTYPE html> 2<html 3 lang="ja" 4 5 6data-admin-domain="//blog.hatena.ne.jp" 7data-admin-origin="https://blog.hatena.ne.jp" 8data-author="misshiki" 9data-avail-langs="ja en" 10data-blog="misshiki.hateblo.jp" 11data-blog-host="misshiki.hateblo.jp" 12data-blog-is-public="1" 13data-blog-name="Masahiko Isshiki | ä¸è²æ¿å½¦" 14data-blog-owner="misshiki" 15data-blog-show-ads="" 16data-blog-show-sleeping-ads="" 17data-blog-uri="https://masahiko.info/" 18data-blog-uuid="26006613555533190" 19data-blogs-uri-base="https://masahiko.info" 20data-brand="pro" 21data-data-layer="{"hatenablog":{"admin":{},"analytics":{"brand_property_id":"","measurement_id":"","non_sampling_property_id":"","property_id":"","separated_property_id":"UA-29716941-20"},"blog":{"blog_id":"26006613555533190","content_seems_japanese":"true","disable_ads":"custom_domain","enable_ads":"false","entry_show_footer_related_entries":"false","force_pc_view":"true","is_public":"true","is_responsive_view":"true","is_sleeping":"false","lang":"ja","name":"Masahiko Isshiki | \u4e00\u8272\u653f\u5f66","owner_name":"misshiki","uri":"https://masahiko.info/"},"brand":"pro","page_id":"archive","permalink_entry":null,"pro":"pro","router_type":"blogs"}}" 22data-device="pc" 23data-dont-recommend-pro="false" 24data-global-domain="https://hatena.blog" 25data-globalheader-color="b" 26data-globalheader-type="pc" 27data-has-touch-view="1" 28data-help-url="https://help.hatenablog.com" 29data-hide-header="1" 30data-no-suggest-touch-view="1" 31data-page="archive" 32data-parts-domain="https://hatenablog-parts.com" 33data-plus-available="1" 34data-pro="true" 35data-router-type="blogs" 36data-sentry-dsn="https://[email protected]/1195218" 37data-sentry-environment="production" 38data-sentry-sample-rate="0.1" 39data-static-domain="https://cdn.blog.st-hatena.com" 40data-version="1434c159586844e737cefa96b82ae4" 41 42 43 44 45 46 itemscope 47 itemtype="http://schema.org/Blog" 48 49 50 data-initial-state="{}" 51 52 > 53 <head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb#"> 54 55 56 57 58 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 59 60 61 62 63 64 65 66 <meta name="robots" content="max-image-preview:large" /> 67 68 69 <meta charset="utf-8"/> 70 <meta http-equiv="X-UA-Compatible" content="IE=7; IE=9; IE=10; IE=11" /> 71 <title>2020-04-24ãã1æ¥éã®è¨äºä¸è¦§ - Masahiko Isshiki | ä¸è²æ¿å½¦</title> 72 73 74 <link rel="canonical" href="https://masahiko.info/archive/2020/04/24"/> 75 76 77 78 79 80<meta itemprop="name" content="2020-04-24ãã1æ¥éã®è¨äºä¸è¦§ - Masahiko Isshiki | ä¸è²æ¿å½¦"/> 81 82 <meta itemprop="image" content="https://cdn.blog.st-hatena.com/images/theme/og-image-1500.png"/> 83 84 85 <meta property="og:title" content="2020-04-24ãã1æ¥éã®è¨äºä¸è¦§ - Masahiko Isshiki | ä¸è²æ¿å½¦"/> 86<meta property="og:type" content="blog"/> 87 <meta property="og:url" content="https://masahiko.info/archive/2020/04/24"/> 88 89 90 91 92 <meta property="og:image" content="https://cdn.blog.st-hatena.com/images/theme/og-image-1500.png"/> 93 94<meta property="og:image:alt" content="2020-04-24ãã1æ¥éã®è¨äºä¸è¦§ - Masahiko Isshiki | ä¸è²æ¿å½¦"/> 95 <meta property="og:description" content="ä¸è²æ¿å½¦ã®ãããã£ã¼ã«ãããã°ãéçºãã¼ã«ãå·çã»æ´»åæ å ±ãã¾ã¨ããå人ãã¼ã¿ã«ãµã¤ãã§ãã" /> 96<meta property="og:site_name" content="Masahiko Isshiki | ä¸è²æ¿å½¦"/> 97 98 <meta name="twitter:card" content="summary" /> <meta name="twitter:title" content="2020-04-24ãã1æ¥éã®è¨äºä¸è¦§ - Masahiko Isshiki | ä¸è²æ¿å½¦" /> <meta name="twitter:description" content="ä¸è²æ¿å½¦ã®ãããã£ã¼ã«ãããã°ãéçºãã¼ã«ãå·çã»æ´»åæ å ±ãã¾ã¨ããå人ãã¼ã¿ã«ãµã¤ãã§ãã" /> <meta name="twitter:app:name:iphone" content="ã¯ã¦ãªããã°ã¢ããª" /> 99 <meta name="twitter:app:id:iphone" content="583299321" /> 100 <meta name="twitter:app:url:iphone" content="hatenablog:///open?uri=https%3A%2F%2Fmasahiko.info%2Farchive%2F2020%2F04%2F24" /> <meta name="twitter:site" content="@isshiki" /> 101 102 103 104
105<script 106 id="embed-gtm-data-layer-loader" 107 data-data-layer-page-specific="" 108> 109(function() { 110 function loadDataLayer(elem, attrName) { 111 if (!elem) { return {}; } 112 var json = elem.getAttribute(attrName); 113 if (!json) { return {}; } 114 return JSON.parse(json); 115 } 116 117 var globalVariables = loadDataLayer( 118 document.documentElement, 119 'data-data-layer' 120 ); 121 var pageSpecificVariables = loadDataLayer( 122 document.getElementById('embed-gtm-data-layer-loader'), 123 'data-data-layer-page-specific' 124 ); 125 126 var variables = [globalVariables, pageSpecificVariables]; 127 128 if (!window.dataLayer) { 129 window.dataLayer = []; 130 } 131 132 for (var i = 0; i < variables.length; i++) { 133 window.dataLayer.push(variables[i]); 134 } 135})(); 136</script>
136 137 138<!-- Google Tag Manager -->
139<script>
vendor: 327 bytes, lines 139-143
139(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': 140new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], 141j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= 142'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); 143})(window,document,'script','dataLayer','
143GTM-P4CXTW
vendor: 3 bytes, line 143
143');
143</script>
143 144<!-- End Google Tag Manager --> 145 146 147 148 149 150 151 152 153 154 155 156 <link rel="shortcut icon" href="https://masahiko.info/icon/favicon"> 157<link rel="apple-touch-icon" href="https://masahiko.info/icon/touch"> 158<link rel="icon" sizes="192x192" href="https://masahiko.info/icon/link"> 159 160 161 162<link rel="alternate" type="application/atom+xml" title="Atom" href="https://masahiko.info/feed"/> 163<link rel="alternate" type="application/rss+xml" title="RSS2.0" href="https://masahiko.info/rss"/> 164 165 166 167 <link rel="author" href="http://www.hatena.ne.jp/misshiki/"> 168 169 170 171 172 173 174 175 176 177<link rel="stylesheet" type="text/css" href="https://cdn.blog.st-hatena.com/css/blog.css?version=1434c159586844e737cefa96b82ae4"/> 178 179 180 <link rel="stylesheet" type="text/css" href="https://usercss.blog.st-hatena.com/blog_style/26006613555533190/c0b89beb780cbedfb8abec000b31b38c0f5d4c8a"/> 181 182 183 184 185 186 187
188<script> </script>
188 189 190 191<style> 192 div#google_afc_user, 193 div.google-afc-user-container, 194 div.google_afc_image, 195 div.google_afc_blocklink { 196 display: block !important; 197 } 198</style> 199 200 201 202 203 204 205 <meta name="viewport" content="width=device-width, initial-scale=1">
206<script> 207(function() { 208 if (location.pathname !== '/' && location.pathname !== '/index') return; 209 if (window.__lpLandingScriptLoaded) return; 210 window.__lpLandingScriptLoaded = true; 211 212 function lpUpdateTokyoTime() { 213 var el = document.getElementById('tokyo-time'); 214 if (!el) return; 215 var fmt = new Intl.DateTimeFormat('en-US', { 216 timeZone: 'Asia/Tokyo', 217 hour: '2-digit', 218 minute: '2-digit', 219 second: '2-digit', 220 hour12: true 221 }); 222 el.textContent = fmt.format(new Date()); 223 } 224 225 window.lpCopyEmail = function(btn) { 226 var u = btn.getAttribute('data-u'); 227 var d = btn.getAttribute('data-d'); 228 var display = btn.querySelector('.email-display'); 229 if (!u || !d || !display) return; 230 231 var addr = u + String.fromCharCode(64) + d; 232 if (!btn.getAttribute('data-revealed')) { 233 display.textContent = u + ' [at] ' + d; 234 btn.setAttribute('data-revealed', '1'); 235 return; 236 } 237 238 if (!navigator.clipboard || !navigator.clipboard.writeText) { 239 display.textContent = addr; 240 return; 241 } 242 243 navigator.clipboard.writeText(addr).then(function() { 244 var prev = display.textContent; 245 display.textContent = 'copied to clipboard!'; 246 display.classList.add('copied'); 247 setTimeout(function() { 248 display.textContent = prev; 249 display.classList.remove('copied'); 250 }, 1600); 251 }); 252 }; 253 254 function lpBindEmail() { 255 var btn = document.querySelector('[data-lp-email]'); 256 if (!btn || btn.getAttribute('data-lp-bound')) return; 257 btn.setAttribute('data-lp-bound', '1'); 258 btn.addEventListener('click', function() { 259 window.lpCopyEmail(btn); 260 }); 261 } 262 263 function lpInitLanding() { 264 lpUpdateTokyoTime(); 265 lpBindEmail(); 266 if (!window.__lpTokyoTimer) { 267 window.__lpTokyoTimer = setInterval(lpUpdateTokyoTime, 1000); 268 } 269 } 270 271 if (document.readyState === 'loading') { 272 document.addEventListener('DOMContentLoaded', lpInitLanding); 273 } else { 274 lpInitLanding(); 275 } 276})(); 277</script>
277 278 279<!-- Site Policy 2026-09-25 --> 280<link rel="icon" href="https://re.masahiko.info/img/brand/favicon.ico" sizes="48x48"> 281<link rel="icon" href="https://re.masahiko.info/img/brand/favicon.svg" type="image/svg+xml" sizes="any"> 282<link rel="apple-touch-icon" href="https://re.masahiko.info/img/brand/favicon-192.png">
283<script>(() => { 284 "use strict"; 285 const isPreview = document.documentElement.hasAttribute("data-policy-preview"); 286 if (location.pathname.replace(/\/+$/, "") !== "/site-policy" && !isPreview) return; 287 288 const root = document.documentElement; 289 const storageKey = "mi-blog-theme"; 290 const cookieKey = "mi-theme"; 291 const cookieDomain = "masahiko.info"; 292 const cookieMaxAge = 60 * 60 * 24 * 365; 293 const media = window.matchMedia("(prefers-color-scheme: dark)"); 294 const validModes = new Set(["system", "light", "dark"]); 295 const icons = { system: "â", light: "â¼", dark: "â¾" }; 296 const labels = { system: "System", light: "Light", dark: "Dark" }; 297 298 const canShareCookie = location.hostname === cookieDomain 299 || location.hostname.endsWith(`.${cookieDomain}`); 300 const readCookieMode = () => { 301 if (!canShareCookie) return null; 302 const prefix = `${cookieKey}=`; 303 const item = document.cookie.split("; ").find((value) => value.startsWith(prefix)); 304 if (!item) return null; 305 try { 306 const stored = decodeURIComponent(item.slice(prefix.length)); 307 return validModes.has(stored) ? stored : null; 308 } catch { 309 return null; 310 } 311 }; 312 const writeCookieMode = (mode) => { 313 if (!canShareCookie) return; 314 document.cookie = `${cookieKey}=${encodeURIComponent(mode)}; Domain=${cookieDomain}; Path=/; Max-Age=${cookieMaxAge}; SameSite=Lax; Secure`; 315 }; 316 const readLocalMode = () => { 317 try { 318 const stored = localStorage.getItem(storageKey); 319 return validModes.has(stored) ? stored : null; 320 } catch { 321 return null; 322 } 323 }; 324 const writeLocalMode = (mode) => { 325 try { localStorage.setItem(storageKey, mode); } catch {} 326 }; 327 const readMode = () => { 328 const sharedMode = readCookieMode(); 329 if (sharedMode) { 330 writeLocalMode(sharedMode); 331 return sharedMode; 332 } 333 const localMode = readLocalMode(); 334 if (localMode) { 335 writeCookieMode(localMode); 336 return localMode; 337 } 338 return "system"; 339 }; 340 341 const resolveTheme = (mode) => mode === "system" ? (media.matches ? "dark" : "light") : mode; 342 const applyMode = (mode) => { 343 const safeMode = validModes.has(mode) ? mode : "system"; 344 const resolved = resolveTheme(safeMode); 345 root.dataset.miThemeMode = safeMode; 346 if (safeMode === "system") delete root.dataset.miTheme; 347 else root.dataset.miTheme = resolved; 348 root.style.colorScheme = resolved; 349 document.querySelectorAll("[data-policy-theme-choice]").forEach((button) => { 350 button.setAttribute("aria-pressed", String(button.dataset.policyThemeChoice === safeMode)); 351 }); 352 const trigger = document.querySelector(".mi-policy-theme__trigger"); 353 if (trigger) { 354 trigger.setAttribute("aria-label", `表示ãã¼ã: ${labels[safeMode]}`); 355 trigger.querySelector("[data-policy-theme-icon]").textContent = icons[safeMode]; 356 } 357 }; 358 359 const bind = () => { 360 const switcher = document.querySelector("[data-policy-theme-switch]"); 361 if (!switcher) return; 362 const trigger = switcher.querySelector(".mi-policy-theme__trigger"); 363 const options = switcher.querySelector(".mi-policy-theme__options"); 364 const close = () => { options.hidden = true; trigger.setAttribute("aria-expanded", "false"); }; 365 applyMode(readMode()); 366 trigger.addEventListener("click", () => { 367 const opening = options.hidden; 368 options.hidden = !opening; 369 trigger.setAttribute("aria-expanded", String(opening)); 370 }); 371 switcher.querySelectorAll("[data-policy-theme-choice]").forEach((button) => { 372 button.addEventListener("click", () => { 373 const mode = button.dataset.policyThemeChoice; 374 writeCookieMode(mode); 375 writeLocalMode(mode); 376 applyMode(mode); 377 close(); 378 trigger.focus(); 379 }); 380 }); 381 document.addEventListener("pointerdown", (event) => { if (!switcher.contains(event.target)) close(); }); 382 document.addEventListener("keydown", (event) => { if (event.key === "Escape") close(); }); 383 }; 384 385 applyMode(readMode()); 386 if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", bind, { once: true }); 387 else bind(); 388 const followSystem = () => { if ((root.dataset.miThemeMode || "system") === "system") applyMode("system"); }; 389 if (typeof media.addEventListener === "function") media.addEventListener("change", followSystem); 390 else media.addListener(followSystem); 391 const syncSavedMode = () => applyMode(readMode()); 392 window.addEventListener("pageshow", syncSavedMode); 393 window.addEventListener("focus", syncSavedMode); 394 window.addEventListener("storage", (event) => { 395 if (event.key === storageKey) syncSavedMode(); 396 }); 397})();</script>
397 398 399<!-- Tools pages RC: deploy the stylesheet to S3 before adding this block to Hatena head HTML. --> 400<link rel="stylesheet" href="https://re.masahiko.info/css/masahiko-tools-v1.css"> 401<style> 402body.static-page-tools .mi-tools-local-nav__list a[aria-current="page"] { 403 border-bottom-color: var(--mi-tools-accent); 404 color: var(--mi-tools-text); 405} 406@media (max-width: 639px) { 407 body.static-page-tools .mi-tools-local-nav__list { 408 grid-template-columns: repeat(4, minmax(0, 1fr)); 409 gap: 0; 410 } 411 body.static-page-tools .mi-tools-local-nav__list li, 412 body.static-page-tools .mi-tools-local-nav__list a { 413 min-width: 0; 414 } 415 body.static-page-tools .mi-tools-local-nav__list a { 416 min-height: 52px; 417 flex-direction: column; 418 justify-content: center; 419 padding: 5px 2px; 420 font-size: 11px; 421 line-height: 1.45; 422 text-align: center; 423 } 424 body.static-page-tools .mi-tools-index__segment { 425 display: block; 426 } 427} 428@media (max-width: 359px) { 429 body.static-page-tools .mi-tools-local-nav__list a { 430 font-size: 10px; 431 } 432} 433</style>
434<script>(() => { 435 "use strict"; 436 const normalizePath = (value) => value.replace(/\/+$/, "") || "/"; 437 const isPreview = document.documentElement.hasAttribute("data-tools-preview"); 438 const toolsPaths = ["/tools","/tools/web","/tools/python","/tools/ai"]; 439 const currentPath = normalizePath(location.pathname); 440 const activePath = isPreview 441 ? normalizePath(document.documentElement.getAttribute("data-tools-preview-path") || "/tools") 442 : currentPath; 443 if (!toolsPaths.includes(currentPath) && !isPreview) return; 444 445 const localNavMarkup = "<nav class=\"mi-tools-local-nav\" aria-label=\"ãã¼ã«ã«ãã´ãªã¼\">\n <div class=\"mi-tools-local-nav__inner\">\n <ul class=\"mi-tools-local-nav__list\">\n <li><a href=\"https://masahiko.info/tools\" aria-label=\"ã¢ããªã»æ¡å¼µæ©è½\"><span class=\"mi-tools-index__segment\">ã¢ããª</span><span class=\"mi-tools-index__segment\">ã»æ¡å¼µ</span></a></li>\n <li><a href=\"https://masahiko.info/tools/web\" aria-label=\"Webãã¼ã«ã»ãã¼ã¿å¯è¦å\"><span class=\"mi-tools-index__segment\">Webã»</span><span class=\"mi-tools-index__segment\">å¯è¦å</span></a></li>\n <li><a href=\"https://masahiko.info/tools/python\" aria-label=\"Pythonã»éçºã¦ã¼ãã£ãªãã£\"><span class=\"mi-tools-index__segment\">Python</span><span class=\"mi-tools-index__segment\">ã»éçº</span></a></li>\n <li><a href=\"https://masahiko.info/tools/ai\" aria-label=\"AIã»æ©æ¢°å¦ç¿ã»GeoAIï¼Notebookã»ææ\"><span class=\"mi-tools-index__segment\">AIã»æ©æ¢°å¦ç¿</span><span class=\"mi-tools-index__segment\">ã»Notebook</span></a></li>\n </ul>\n </div>\n</nav>"; 446 const globalNavMarkup = `<div class="mi-site-bar"> 447 <nav class="mi-site-nav" aria-label="ä¸è²æ¿å½¦ã®ãµã¤ã"> 448 <a href="https://masahiko.info/">Home</a> 449 <a href="https://www.masahiko.info/">Profile</a> 450 <a href="https://blog.masahiko.info/">Blog</a> 451 <a href="https://www.masahiko.info/articles">Articles</a> 452 <a href="https://masahiko.info/tools" aria-current="page">Tools</a> 453 </nav> 454 </div>`; 455 const switcherMarkup = `<div class="mi-theme-switch" data-tools-theme-switch> 456 <button type="button" class="mi-theme-trigger" aria-label="表示ãã¼ã: System" aria-expanded="false" aria-controls="mi-theme-options" title="表示ãã¼ã: System"> 457 <span data-mi-theme-icon aria-hidden="true">â</span> 458 </button> 459 <div id="mi-theme-options" class="mi-theme-options" role="group" aria-label="表示ãã¼ã" hidden> 460 <button type="button" data-mi-theme-choice="system" aria-pressed="true">System</button> 461 <button type="button" data-mi-theme-choice="light" aria-pressed="false">Light</button> 462 <button type="button" data-mi-theme-choice="dark" aria-pressed="false">Dark</button> 463 </div> 464 </div>`; 465 466 const hydrateChrome = () => { 467 document.body.classList.add("static-page-tools"); 468 const titleLink = document.querySelector("#title a"); 469 const description = document.querySelector("#blog-description"); 470 const titleInner = document.querySelector("#blog-title-inner"); 471 const topEditarea = document.querySelector("#top-editarea"); 472 if (!titleLink || !description || !titleInner || !topEditarea) return false; 473 titleLink.href = "https://masahiko.info/tools"; 474 titleLink.textContent = "ä¸è²æ¿å½¦ã®ãã¼ã«ã»ã³ã¼ã"; 475 description.textContent = "ã¢ããªãWebãã¼ã«ãã³ã¼ããNotebookãã¾ã¨ããå人éçºã¢ã¼ã«ã¤ãã§ãã"; 476 titleInner.querySelector("[data-tools-theme-switch]")?.remove(); 477 titleInner.insertAdjacentHTML("beforeend", switcherMarkup); 478 topEditarea.innerHTML = `${globalNavMarkup}${localNavMarkup}`; 479 topEditarea.querySelectorAll(".mi-tools-local-nav__list a").forEach((link) => { 480 const isCurrent = normalizePath(new URL(link.href, location.origin).pathname) === activePath; 481 if (isCurrent) link.setAttribute("aria-current", "page"); 482 else link.removeAttribute("aria-current"); 483 }); 484 return true; 485 }; 486 487 if (document.readyState === "loading") { 488 document.addEventListener("DOMContentLoaded", hydrateChrome, { once: true }); 489 } else { 490 hydrateChrome(); 491 } 492})();</script>
vendor: 1 bytes, line 492
492
493<script> 494if (["/tools","/tools/web","/tools/python","/tools/ai"].includes(location.pathname.replace(/\/+$/, "") || "/") || document.documentElement.hasAttribute("data-tools-preview")) { 495(() => { 496 "use strict"; 497 498 const root = document.documentElement; 499 const storageKey = "mi-blog-theme"; 500 const cookieKey = "mi-theme"; 501 const cookieDomain = "masahiko.info"; 502 const cookieMaxAge = 60 * 60 * 24 * 365; 503 const media = window.matchMedia("(prefers-color-scheme: dark)"); 504 const validModes = new Set(["system", "light", "dark"]); 505 const modeIcons = { system: "â", light: "â¼", dark: "â¾" }; 506 const modeLabels = { system: "System", light: "Light", dark: "Dark" }; 507 508 const canShareCookie = location.hostname === cookieDomain 509 || location.hostname.endsWith(`.${cookieDomain}`); 510 511 const readCookieMode = () => { 512 if (!canShareCookie) return null; 513 const prefix = `${cookieKey}=`; 514 const item = document.cookie.split("; ").find((value) => value.startsWith(prefix)); 515 if (!item) return null; 516 try { 517 const stored = decodeURIComponent(item.slice(prefix.length)); 518 return validModes.has(stored) ? stored : null; 519 } catch { 520 return null; 521 } 522 }; 523 524 const writeCookieMode = (mode) => { 525 if (!canShareCookie) return; 526 document.cookie = `${cookieKey}=${encodeURIComponent(mode)}; Domain=${cookieDomain}; Path=/; Max-Age=${cookieMaxAge}; SameSite=Lax; Secure`; 527 }; 528 529 const readLocalMode = () => { 530 try { 531 const stored = window.localStorage.getItem(storageKey); 532 return validModes.has(stored) ? stored : null; 533 } catch { 534 return null; 535 } 536 }; 537 538 const writeLocalMode = (mode) => { 539 try { window.localStorage.setItem(storageKey, mode); } catch {} 540 }; 541 542 const readMode = () => { 543 const sharedMode = readCookieMode(); 544 if (sharedMode) { 545 writeLocalMode(sharedMode); 546 return sharedMode; 547 } 548 const localMode = readLocalMode(); 549 if (localMode) { 550 writeCookieMode(localMode); 551 return localMode; 552 } 553 return "system"; 554 }; 555 556 const resolvedTheme = (mode) => { 557 if (mode === "light" || mode === "dark") return mode; 558 return media.matches ? "dark" : "light"; 559 }; 560 561 const applyMode = (mode) => { 562 const safeMode = validModes.has(mode) ? mode : "system"; 563 const resolved = resolvedTheme(safeMode); 564 root.classList.add("mi-theme-js"); 565 root.dataset.miThemeMode = safeMode; 566 if (safeMode === "system") delete root.dataset.miTheme; 567 else root.dataset.miTheme = resolved; 568 root.style.colorScheme = resolved; 569 document.querySelectorAll("[data-mi-theme-choice]").forEach((button) => { 570 button.setAttribute("aria-pressed", String(button.dataset.miThemeChoice === safeMode)); 571 }); 572 const trigger = document.querySelector(".mi-theme-trigger"); 573 if (trigger) { 574 const label = `表示ãã¼ã: ${modeLabels[safeMode]}`; 575 trigger.setAttribute("aria-label", label); 576 trigger.title = label; 577 const icon = trigger.querySelector("[data-mi-theme-icon]"); 578 if (icon) icon.textContent = modeIcons[safeMode]; 579 } 580 }; 581 582 const saveMode = (mode) => { 583 const safeMode = validModes.has(mode) ? mode : "system"; 584 writeCookieMode(safeMode); 585 writeLocalMode(safeMode); 586 applyMode(safeMode); 587 }; 588 589 const bindControls = () => { 590 const switcher = document.querySelector(".mi-theme-switch"); 591 const header = document.querySelector("#blog-title-inner"); 592 if (!switcher || !header) return; 593 const trigger = switcher.querySelector(".mi-theme-trigger"); 594 const options = switcher.querySelector(".mi-theme-options"); 595 if (!trigger || !options || switcher.dataset.miThemeBound === "true") return; 596 if (switcher.parentElement !== header) header.append(switcher); 597 switcher.dataset.miThemeBound = "true"; 598 switcher.classList.add("mi-theme-switch--ready"); 599 const closeOptions = (returnFocus = false) => { 600 options.hidden = true; 601 trigger.setAttribute("aria-expanded", "false"); 602 if (returnFocus) trigger.focus(); 603 }; 604 applyMode(readMode()); 605 trigger.addEventListener("click", () => { 606 const opening = options.hidden; 607 options.hidden = !opening; 608 trigger.setAttribute("aria-expanded", String(opening)); 609 if (opening) options.querySelector('[aria-pressed="true"]')?.focus(); 610 }); 611 switcher.querySelectorAll("[data-mi-theme-choice]").forEach((button) => { 612 button.addEventListener("click", () => { 613 saveMode(button.dataset.miThemeChoice); 614 closeOptions(true); 615 }); 616 }); 617 document.addEventListener("pointerdown", (event) => { 618 if (!switcher.contains(event.target)) closeOptions(); 619 }); 620 document.addEventListener("keydown", (event) => { 621 if (event.key === "Escape" && !options.hidden) closeOptions(true); 622 }); 623 switcher.addEventListener("focusout", () => { 624 requestAnimationFrame(() => { 625 if (!switcher.contains(document.activeElement)) closeOptions(); 626 }); 627 }); 628 }; 629 630 applyMode(readMode()); 631 if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", bindControl
631s, { once: true }); 632 else bindControls(); 633 634 const followSystem = () => { 635 if ((root.dataset.miThemeMode || "system") === "system") applyMode("system"); 636 }; 637 if (typeof media.addEventListener === "function") media.addEventListener("change", followSystem); 638 else if (typeof media.addListener === "function") media.addListener(followSystem); 639 640 const syncSavedMode = () => applyMode(readMode()); 641 window.addEventListener("pageshow", syncSavedMode); 642 window.addEventListener("focus", syncSavedMode); 643 window.addEventListener("storage", (event) => { 644 if (event.key === storageKey) syncSavedMode(); 645 }); 646})(); 647} 648</script>
648 649 650 651 652 653</head> 654 655 <body class="page-archive enable-top-editarea globalheader-off globalheader-ng-enabled"> 656 657 658 659<div id="globalheader-container" 660 data-brand="hatenablog" 661 style="display: none" 662 > 663 <iframe id="globalheader" height="37" frameborder="0" allowTransparency="true"></iframe> 664</div> 665 666 667 668 669 670 671 <div id="container"> 672 <div id="container-inner"> 673 <header id="blog-title" data-brand="hatenablog"> 674 <div id="blog-title-inner" > 675 <div id="blog-title-content"> 676 <h1 id="title"><a href="https://masahiko.info/">Masahiko Isshiki | ä¸è²æ¿å½¦</a></h1> 677 678 <h2 id="blog-description">ä¸è²æ¿å½¦ã®ãããã£ã¼ã«ãããã°ãéçºãã¼ã«ãå·çã»æ´»åæ å ±ãã¾ã¨ããå人ãã¼ã¿ã«ãµã¤ãã§ãã</h2> 679 680 </div> 681 </div> 682</header> 683 684 685 686 <div id="top-editarea"> 687 <!-- 688 masahiko.info - top edit area landing HTML 689 690 Deploy to: 691 ã¯ã¦ãªããã°ç®¡çç»é¢ -> ãã¶ã¤ã³ -> ã«ã¹ã¿ãã¤ãº -> ããã -> ã¿ã¤ãã«ä¸ 692 693 Notes: 694 - This HTML is rendered as #top-editarea on every page. 695 - design-css.css shows this landing only on body.page-index. 696 - JavaScript lives in header-html.html, deployed to the head_html field. 697--> 698 699<div class="lp"> 700 <header class="hero"> 701 <div class="hero-meta"> 702 <span class="tokyo"> 703 <span class="pulse"></span> 704 TOKYO · <span id="tokyo-time">--:--:-- AM</span> JST 705 </span> 706 </div> 707 708 <div class="container"> 709 <div class="name-block"> 710 <p class="hi">Hi, I'm</p> 711 <h1 class="name">Masahiko <em>Isshiki</em>.</h1> 712 <p class="name-jp" aria-label="ä¸è² æ¿å½¦"> 713 <span class="name-part name-family" aria-hidden="true">ä¸è²</span> 714 <span class="name-part name-given" aria-hidden="true">æ¿å½¦</span> 715 </p> 716 <p class="pronounce">/ MA-sa-HEE-ko EESH-kee /</p> 717 </div> 718 719 <p class="tag">A software engineer focused on <em>data, machine learning, and applied AI</em> — using real-world data to support better decision-making. Editor-in-chief of ï¼ IT's "Deep Insider," a Japanese tech media on AI and developer tools. Tokyo-based.</p> 720 <p class="tag-jp">ãã¼ã¿ã»æ©æ¢°å¦ç¿ã»AI æ´»ç¨ã軸ã«ãå®ä¸çã®ãã¼ã¿ãæææ±ºå®ã«æ´»ããã½ããã¦ã§ã¢ã¨ã³ã¸ãã¢ãï¼ ITãDeep Insiderãç·¨éé·ã¨ãã¦ãAI ã¨éçºè åãæ å ±ã®çºä¿¡ããã¦ãã¾ããæ±äº¬æ ç¹ã</p> 721 </div> 722 </header> 723 724 <main class="body"> 725 <div class="container"> 726 <section id="tools"> 727 <div class="label">Tools</div> 728 <div class="grid3"> 729 <a class="tool" href="https://chromewebstore.google.com/detail/smartre-for-gmail/didekpjkeflkjeffikpphaccodoaohid" target="_blank" rel="noopener"> 730 <div class="img"><img src="https://re.masahiko.info/img/landing/smartre.png" alt="SmartRe for Gmail screenshot"></div> 731 <div class="body-inner"> 732 <h3>SmartRe for Gmail</h3> 733 <span class="platform">Chrome Extension</span> 734 <p>Refines Gmail's reply quoting and headers for cleaner correspondence.</p> 735 </div> 736 </a> 737 738 <a class="tool" href="https://chromewebstore.google.com/detail/smarturls-copy-and-open-u/ekeecbnnlnmjimahpjnfdognobmabbfb" target="_blank" rel="noopener"> 739 <div class="img"><img src="https://re.masahiko.info/img/landing/smarturls.png" alt="SmartURLs screenshot"></div> 740 <div class="body-inner"> 741 <h3>SmartURLs</h3> 742 <span class="platform">Chrome Extension</span> 743 <p>Copy and open URLs faster with keyboard-first interactions.</p> 744 </div> 745 </a> 746 747 <a class="tool" href="https://addons.thunderbird.net/ja/thunderbird/addon/refwdformatter/" target="_blank" rel="noopener"> 748 <div class="img"><img src="https://re.masahiko.info/img/landing/refwdformatter.gif" alt="ReFwdFormatter screenshot"></div> 749 <div class="body-inner"> 750 <h3>ReFwdFormatter</h3> 751 <span class="platform">Thunderbird Add-on</span> 752 <p>Tidies up Re/Fwd subject lines in Thunderbird for international threads.</p> 753 </div> 754 </a> 755 </div> 756 757 <div class="other"> 758 <a href="https://github.com/isshiki/Promplet" target="_blank" rel="noopener">Promplet</a> 759 <a href="https://isshiki.github.io/job-future-explorer/" target="_blank" rel="noopener">
759Job Future Explorer</a> 760 <a href="https://isshiki.github.io/graph-viz-arena/" target="_blank" rel="noopener">Graph Viz Arena</a> 761 <a href="https://github.com/isshiki/geoai-open-lab" target="_blank" rel="noopener">geoai-open-lab</a> 762 <a href="https://github.com/isshiki/hype-cycle-curve" target="_blank" rel="noopener">hype-cycle-curve</a> 763 <a href="https://github.com/isshiki/machine-learning-with-python" target="_blank" rel="noopener">Machine Learning with Python</a> 764 </div> 765 <a class="tools-directory-link" href="https://masahiko.info/tools">View all tools, code, and notebooks</a> 766 </section> 767 768 <section id="websites" class="section-spaced"> 769 <div class="label">WebSITE</div> 770 <div class="sites"> 771 <a class="site" href="https://www.masahiko.info/"> 772 <strong>Profile</strong> 773 <em>www.masahiko.info</em> 774 <p class="desc">Personal homepage with profile, works, and contact.</p> 775 </a> 776 777 <a class="site" href="https://blog.masahiko.info/"> 778 <strong>BLOG</strong> 779 <em>blog.masahiko.info</em> 780 <p class="desc">Notes on AI, software, and tools — updated regularly.</p> 781 </a> 782 783 <a class="site" href="https://www.masahiko.info/articles"> 784 <strong>Articles</strong> 785 <em>www.masahiko.info/articles</em> 786 <p class="desc">Archive of published articles since 2003.</p> 787 </a> 788 </div> 789 </section> 790 791 <section id="connect" class="section-spaced"> 792 <div class="label">Connect</div> 793 <div class="connect"> 794 <a class="connect-card" href="https://x.com/isshiki" target="_blank" rel="noopener"> 795 <span class="icon">X</span> 796 <span><strong>@isshiki</strong><em>X (Twitter)</em></span> 797 </a> 798 799 <a class="connect-card hatena-card" href="https://b.hatena.ne.jp/misshiki/" target="_blank" rel="noopener"> 800 <span class="icon">B!</span> 801 <span><strong>misshiki</strong><em>ã¯ã¦ãªããã¯ãã¼ã¯</em></span> 802 </a> 803 804 <button class="connect-card email-card" type="button" data-lp-email data-u="masahiko-isshiki" data-d="googlegroups.com"> 805 <span class="icon">@</span> 806 <span><strong>Email</strong><em class="email-display">click to reveal</em></span> 807 </button> 808 </div> 809 </section> 810 </div> 811 </main> 812 813 <footer class="footer"> 814 <div class="container"> 815 <div class="copy">© 2003– Masahiko Isshiki <span aria-hidden="true">·</span> <a href="https://masahiko.info/site-policy">ãµã¤ãããªã·ã¼</a></div> 816 </div> 817 </footer> 818</div> 819 </div> 820 821 822 823 824 825 826 827<div id="content"> 828 <div id="content-inner"> 829 <div id="wrapper"> 830 <div id="main"> 831 <div id="main-inner"> 832 833 834 835 836 837 838 839 840 841 842 843 844 <h2 class="archive-heading"> 845 2020-04-24ãã1æ¥éã®è¨äºä¸è¦§ 846 </h2> 847 848 849 850 <div class="archive-entries"> 851 852 853 <section class="archive-entry test-archive-entry autopagerize_page_element" data-uuid="26006613555535306"> 854<div class="archive-entry-header"> 855 <div class="date archive-date"> 856 <a href="https://masahiko.info/archive/2020/04/24" rel="nofollow"> 857 <time datetime="2020-04-24" title="2020-04-24"> 858 <span class="date-year">2020</span><span class="hyphen">-</span><span class="date-month">04</span><span class="hyphen">-</span><span class="date-day">24</span> 859 </time> 860 </a> 861 </div> 862 863 <h1 class="entry-title"> 864 <a class="entry-title-link" href="https://masahiko.info/entry/2020/04/24/181834">ä¸è¨ã®ãµã¤ããããã¾ã</a> 865 866 867 </h1> 868</div> 869 870 871 872 873<div class="archive-entry-body"> 874 <p class="entry-description"> 875 876 ãã£ããã¾ãã²ãWebSITE ãã£ããã¾ãã²ãBLOG 877 878 </p> 879 880 881 <div class="archive-entry-tags-wrapper"> 882 <div class="archive-entry-tags"> </div> 883</div> 884 885 886 887 <span class="social-buttons"> 888 889 890 891 <span 892 class="star-container" 893 data-hatena-star-container 894 data-hatena-star-url="https://masahiko.info/entry/2020/04/24/181834" 895 data-hatena-star-title="ä¸è¨ã®ãµã¤ããããã¾ã" 896 data-hatena-star-variant="profile-icon" 897 data-hatena-star-profile-url-template="https://blog.hatena.ne.jp/{username}/" 898 ></span> 899 </span> 900</div> 901</section> 902 903 </div> 904 905 906 </div> 907 908 909 </div> 910 </div> 911 912 913<aside id="box2"> 914 915 <div id="box2-inner"> 916 917 </div> 918</aside> 919 920 921 922 </div> 923</div> 924 925 926 927 928 929 930 931 </div> 932 </div> 933 934 935 936 937 938 939 940<div class="quote-box"> 941 <div class="tooltip-quote tooltip-quote-stock"> 942 <i class="blogicon-quote" title="å¼ç¨ãã¹ããã¯"></i> 943 </div> 944 <div class="tooltip-quote tooltip-quote-tweet js-tooltip-quote-tweet"> 945 <a class="js-tweet-quote" target="_blank" data-track-name="quote-tweet" data-track-once> 946 <img src="https://cdn.blog.st-hatena.com/images/admin/quote/quote-x-icon.svg?version=1434c159586844e737cefa96b82ae4" title="å¼ç¨ãã¦æç¨¿ãã" > 947 </a> 948 </div> 949</div> 950 951<div class="quote-stock-panel" id="quote-stock-message-box" style="position: absolute; z-index: 3000"> 952 <div class="message-box" id="quote-stock-succeeded-message" style="display: none"> 953 <p>å¼ç¨ãã¹ããã¯ãã¾ãã</p> 954 <button class="btn btn-primary" id="quote-stock-show-editor-button" data-track-name="curation-quote-edit-button">ã¹ããã¯ä¸è¦§ãè¦ã</button> 955 <button class="btn quote-stock-close-message-button">éãã</button> 956 </div> 957 958 <div class="message-box" id="quote-login-required-message" style="display: none"> 959 <p>å¼ç¨ããã«ã¯ã¾ããã°ã¤ã³ãã¦ãã ãã</p> 960 <button class="btn btn-primary" id="quote-login-button">ãã°ã¤ã³</button> 961 <button class="btn quote-stock-close-message-button">éãã</button> 962 </div> 963 964 <div class="error-box" id="quote-stock-failed-message" style="display: none"> 965 <p>å¼ç¨ãã¹ããã¯ã§ãã¾ããã§ãããå度ã試ããã ãã</p> 966 <button class="btn quote-stock-close-message-button">éãã</button> 967 </div> 968 969 <div class="error-box" id="unstockable-quote-message-box" style="display: none; position: absolute; z-index: 3000;"> 970 <p>éå®å ¬éè¨äºã®ããå¼ç¨ã§ãã¾ããã</p> 971 </div> 972</div> 973
974<script type="x-underscore-template" id="js-requote-button-template"> 975 <div class="requote-button js-requote-button"> 976 <button class="requote-button-btn tipsy-top" title="å¼ç¨ãã"><i class="blogicon-quote"></i></button> 977 </div> 978</script>
978 979 980 981 982 983 <div id="hidden-subscribe-button" style="display: none;"> 984 <div class="hatena-follow-button-box btn-subscribe js-hatena-follow-button-box" 985 986 > 987 988 <a href="#" class="hatena-follow-button js-hatena-follow-button"> 989 <span class="subscribing"> 990 <span class="foreground">èªè ã§ã</span> 991 <span class="background">èªè ãããã</span> 992 </span> 993 <span class="unsubscribing" data-track-name="profile-widget-subscribe-button" data-track-once> 994 <span class="foreground">èªè ã«ãªã</span> 995 <span class="background">èªè ã«ãªã</span> 996 </span> 997 </a> 998 <div class="subscription-count-box js-subscription-count-box"> 999 <i></i> 1000 <u></u> 1001 <span class="subscription-count js-subscription-count"> 1002 </span> 1003 </div> 1004</div> 1005 1006 </div> 1007 1008 1009 1010 1011 1012 1013 1014 1015
1015<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
1015 1016
1017<script src="https://b.st-hatena.com/js/bookmark_button.js" charset="utf-8" async="async"></script>
1017 1018 1019
1020<script type="text/javascript" src="https://cdn.blog.st-hatena.com/js/external/jquery.min.js?v=1.12.4&version=1434c159586844e737cefa96b82ae4"></script>
1020 1021 1022 1023 1024 1025 1026 1027
1028<script src="https://cdn.blog.st-hatena.com/js/texts-ja.js?version=1434c159586844e737cefa96b82ae4"></script>
1028 1029 1030 1031 1032
1032<script id="vendors-js" data-env="production" src="https://cdn.blog.st-hatena.com/js/vendors.js?version=1434c159586844e737cefa96b82ae4" crossorigin="anonymous"></script>
1032 1033
1034<script id="hatenablog-js" data-env="production" src="https://cdn.blog.st-hatena.com/js/hatenablog.js?version=1434c159586844e737cefa96b82ae4" crossorigin="anonymous" data-page-id="archive-year-month-day"></script>
1034 1035 1036 1037
1037<script>Hatena.Diary.GlobalHeader.init()</script>
1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 </body> 1054</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.