PageSourceSearch

https://masahiko.info/archive/2020/04/24

html masahiko.info collected 2026-10-01 15:24:14 UTC 37,761 bytes, 1,054 lines download raw bytes

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="{&quot;hatenablog&quot;:{&quot;admin&quot;:{},&quot;analytics&quot;:{&quot;brand_property_id&quot;:&quot;&quot;,&quot;measurement_id&quot;:&quot;&quot;,&quot;non_sampling_property_id&quot;:&quot;&quot;,&quot;property_id&quot;:&quot;&quot;,&quot;separated_property_id&quot;:&quot;UA-29716941-20&quot;},&quot;blog&quot;:{&quot;blog_id&quot;:&quot;26006613555533190&quot;,&quot;content_seems_japanese&quot;:&quot;true&quot;,&quot;disable_ads&quot;:&quot;custom_domain&quot;,&quot;enable_ads&quot;:&quot;false&quot;,&quot;entry_show_footer_related_entries&quot;:&quot;false&quot;,&quot;force_pc_view&quot;:&quot;true&quot;,&quot;is_public&quot;:&quot;true&quot;,&quot;is_responsive_view&quot;:&quot;true&quot;,&quot;is_sleeping&quot;:&quot;false&quot;,&quot;lang&quot;:&quot;ja&quot;,&quot;name&quot;:&quot;Masahiko Isshiki | \u4e00\u8272\u653f\u5f66&quot;,&quot;owner_name&quot;:&quot;misshiki&quot;,&quot;uri&quot;:&quot;https://masahiko.info/&quot;},&quot;brand&quot;:&quot;pro&quot;,&quot;page_id&quot;:&quot;archive&quot;,&quot;permalink_entry&quot;:null,&quot;pro&quot;:&quot;pro&quot;,&quot;router_type&quot;:&quot;blogs&quot;}}"
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 &middot; <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> &mdash; 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 &mdash; 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">&copy; 2003&ndash; Masahiko Isshiki <span aria-hidden="true">&middot;</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&amp;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.