diff --git a/2023/07/05/trace-of-line-01/index.html b/2023/07/05/trace-of-line-01/index.html
index b57c170..5ee9523 100644
--- a/2023/07/05/trace-of-line-01/index.html
+++ b/2023/07/05/trace-of-line-01/index.html
@@ -24,7 +24,7 @@
-
+
diff --git a/2023/07/05/zhihu-aac-old/index.html b/2023/07/05/zhihu-aac-old/index.html
index 41f527b..856b0c5 100644
--- a/2023/07/05/zhihu-aac-old/index.html
+++ b/2023/07/05/zhihu-aac-old/index.html
@@ -25,7 +25,7 @@
-
+
diff --git a/2023/07/06/zerotier-planet-convert/index.html b/2023/07/06/zerotier-planet-convert/index.html
index 3c3b931..72227a5 100644
--- a/2023/07/06/zerotier-planet-convert/index.html
+++ b/2023/07/06/zerotier-planet-convert/index.html
@@ -24,7 +24,7 @@
-
+
diff --git a/2023/07/10/trace-of-line-02/index.html b/2023/07/10/trace-of-line-02/index.html
index bed61ca..6003117 100644
--- a/2023/07/10/trace-of-line-02/index.html
+++ b/2023/07/10/trace-of-line-02/index.html
@@ -24,7 +24,7 @@
-
+
diff --git a/2023/08/04/permission-system-design-share/index.html b/2023/08/04/permission-system-design-share/index.html
index aba2adf..8e41cac 100644
--- a/2023/08/04/permission-system-design-share/index.html
+++ b/2023/08/04/permission-system-design-share/index.html
@@ -24,7 +24,7 @@
-
+
diff --git a/2023/08/04/test-latex/index.html b/2023/08/04/test-latex/index.html
index a38765c..79d6cdc 100644
--- a/2023/08/04/test-latex/index.html
+++ b/2023/08/04/test-latex/index.html
@@ -24,7 +24,7 @@
-
+
diff --git a/about/index.html b/about/index.html
index 7fe39df..dc70a24 100644
--- a/about/index.html
+++ b/about/index.html
@@ -24,7 +24,7 @@
-
+
diff --git a/service-worker.js b/service-worker.js
index e5da7d8..3f1b67e 100644
--- a/service-worker.js
+++ b/service-worker.js
@@ -1,2 +1,2 @@
-if(!self.define){let e,i={};const a=(a,c)=>(a=new URL(a+".js",c).href,i[a]||new Promise((i=>{if("document"in self){const e=document.createElement("script");e.src=a,e.onload=i,document.head.appendChild(e)}else e=a,importScripts(a),i()})).then((()=>{let e=i[a];if(!e)throw new Error(`Module ${a} didn’t register its module`);return e})));self.define=(c,d)=>{const r=e||("document"in self?document.currentScript.src:"")||location.href;if(i[r])return;let s={};const n=e=>a(e,r),f={module:{uri:r},exports:s,require:n};i[r]=Promise.all(c.map((e=>f[e]||n(e)))).then((e=>(d(...e),s)))}}define(["./workbox-afb8f5db"],(function(e){"use strict";self.addEventListener("message",(e=>{e.data&&"SKIP_WAITING"===e.data.type&&self.skipWaiting()})),e.precacheAndRoute([{url:"2023/07/05/trace-of-line-01/index.html",revision:"288205fe18fcc5f7d275be0d0901e376"},{url:"2023/07/05/zhihu-aac-old/index.html",revision:"cd33fe593ef78b965ce18a6eeb44cbf0"},{url:"2023/07/06/zerotier-planet-convert/index.html",revision:"7d3e7af7593938b157abcd1b8ae3a668"},{url:"2023/07/10/trace-of-line-02/index.html",revision:"eeec1ce9b0bceaf1da62fd667a63b942"},{url:"2023/08/04/permission-system-design-share/index.html",revision:"b0170858a97ebf95068701274e8d507a"},{url:"2023/08/04/test-latex/index.html",revision:"c9439eb190ead877e1157fc77f28f2c0"},{url:"404.html",revision:"76574a7c44c7fc51cc41e1f2989f32e9"},{url:"about/index.html",revision:"5ed8c36a96ce16a68e963e6d92a3b044"},{url:"archives/2023/07/index.html",revision:"f4a6300899b3192a174f52e6792e7c11"},{url:"archives/2023/08/index.html",revision:"1ed4990ac0fdc0cbab8cc992ab00dc72"},{url:"archives/2023/index.html",revision:"6f858cc0ac256f326752ec240fd5c940"},{url:"archives/index.html",revision:"3baddcc8190fe2eb525a32ac503d26d9"},{url:"baidu_verify_codeva-0rhRRODu4H.html",revision:"242837d47be8b7c244eb3b8bfc38e027"},{url:"categories/index.html",revision:"d9cf92fff99e60355e2192d4f79ea84a"},{url:"css/gitalk.css",revision:"5ce280d86637a41c57fdc51fd463237a"},{url:"css/highlight-dark.css",revision:"be3af4b8abf2074e66acb737867c43dc"},{url:"css/highlight.css",revision:"fdd56de5edd1e833674574fdc74bbfe7"},{url:"css/main.css",revision:"7d6d29df18411568c1ae622605bc1907"},{url:"icons/128.png",revision:"375571427b866e32e2d7a9525272a488"},{url:"icons/144.png",revision:"a84f4fe235872bb9be14ebc801f5e4f4"},{url:"icons/192.png",revision:"e0236ca23ccfa319f4b9a698e56ab2e2"},{url:"icons/256.png",revision:"20eb0091d61f49caba3cd63c9ac00a7e"},{url:"icons/512.png",revision:"2c8af612559477d53b8e2dbce84b724c"},{url:"img/avatar.png",revision:"2d9aa61e592b26e2745f3c161c48c397"},{url:"img/default.png",revision:"beb05a6b5b201044b6d80cacdf29f905"},{url:"img/fluid.png",revision:"5603316bb5bc54a9d5cab14fddd4c510"},{url:"img/image-1.png",revision:"4d772ced566ade339ca6718c7ed38674"},{url:"img/image-2.png",revision:"dcfafd0cc238b0a63a733edd1a70bcfe"},{url:"img/image-3.png",revision:"5ba9885de31a8d1e8df04a1d915b1069"},{url:"img/image-4.png",revision:"3d2983fa8549bb6a93b7b905a6baea9c"},{url:"img/image-5.png",revision:"55692e23130e9504505085798384e43e"},{url:"img/image.png",revision:"18a13cfe951c406bbb4da3a7e7bc8ca2"},{url:"img/loading.gif",revision:"15657539044e11a19a1c6c7e3073d1b3"},{url:"img/police_beian.png",revision:"b769e8dfde5660239317ed60758dba13"},{url:"index.html",revision:"1d9fba42d94fa5e630bfed062a8bf244"},{url:"js/boot.js",revision:"7683fab2fc9d03a3a659aa956b3a54e8"},{url:"js/color-schema.js",revision:"605f587be2ab3d36472bb03ac27ede65"},{url:"js/events.js",revision:"7fa076a71a5559d89af6b0c6dfd3a0d2"},{url:"js/img-lazyload.js",revision:"fab30a410e5f490fce3f977a6936a714"},{url:"js/leancloud.js",revision:"fb4a815ccdb5d851d00561dbb62251c4"},{url:"js/local-search.js",revision:"9dc47a0b7b6bacfd16541c9b2b5b6bc5"},{url:"js/plugins.js",revision:"6c10bee3f659ca91b534bf4a81d62f1e"},{url:"js/utils.js",revision:"f7ce9014de1cd7358eeb3aba81c8efe2"},{url:"links/index.html",revision:"d4d7a01004a55c1837a7f85c8dc5ebde"},{url:"tags/cxzlw/index.html",revision:"1aa2389fcf6b0aedb0b5713131368df4"},{url:"tags/index.html",revision:"e54b95772ec74d3591f5f2bdd7d09305"},{url:"tags/Zerotier/index.html",revision:"438595addf53c9863592eff9657e0d0e"},{url:"tags/反爬/index.html",revision:"f48e356602c710b08058f200c12f1f1e"},{url:"tags/小说/index.html",revision:"0c21302da4e4508a153e36ab7591efe5"},{url:"tags/知乎/index.html",revision:"f332e50dfb9c21caf6532151f03fa13b"},{url:"tags/离谱网文/index.html",revision:"6bdf9d905b275a4817145eb2c1aac997"},{url:"tags/自建Planet/index.html",revision:"46426c0df5e6c6b74266a6f2eef41f3e"},{url:"tags/路过的某个学渣/index.html",revision:"5bac00ff0bf3c331155e8fa96e562946"},{url:"tags/飞石/index.html",revision:"833957a9774a4f5ed488c3feeda00af0"}],{})}));
+if(!self.define){let e,i={};const a=(a,c)=>(a=new URL(a+".js",c).href,i[a]||new Promise((i=>{if("document"in self){const e=document.createElement("script");e.src=a,e.onload=i,document.head.appendChild(e)}else e=a,importScripts(a),i()})).then((()=>{let e=i[a];if(!e)throw new Error(`Module ${a} didn’t register its module`);return e})));self.define=(c,d)=>{const r=e||("document"in self?document.currentScript.src:"")||location.href;if(i[r])return;let s={};const n=e=>a(e,r),f={module:{uri:r},exports:s,require:n};i[r]=Promise.all(c.map((e=>f[e]||n(e)))).then((e=>(d(...e),s)))}}define(["./workbox-66a1f6b7"],(function(e){"use strict";self.addEventListener("message",(e=>{e.data&&"SKIP_WAITING"===e.data.type&&self.skipWaiting()})),e.precacheAndRoute([{url:"2023/07/05/trace-of-line-01/index.html",revision:"94a6f87db0cc9a24ca576dc6650a20f0"},{url:"2023/07/05/zhihu-aac-old/index.html",revision:"4646a98dc4af75c48ddd0ebf7bbe9e89"},{url:"2023/07/06/zerotier-planet-convert/index.html",revision:"db1ed5b8d20a7bfc0c4211c1bc8ca0fc"},{url:"2023/07/10/trace-of-line-02/index.html",revision:"72fc7cef3c1077a7191a4104cc262a41"},{url:"2023/08/04/permission-system-design-share/index.html",revision:"936c31fface906ae2179444b63fd750f"},{url:"2023/08/04/test-latex/index.html",revision:"6f0fe4f46267a950c01f444837e552b0"},{url:"404.html",revision:"76574a7c44c7fc51cc41e1f2989f32e9"},{url:"about/index.html",revision:"3dd6df6fc15b8ea2cf8edeb2bc2db903"},{url:"archives/2023/07/index.html",revision:"f4a6300899b3192a174f52e6792e7c11"},{url:"archives/2023/08/index.html",revision:"1ed4990ac0fdc0cbab8cc992ab00dc72"},{url:"archives/2023/index.html",revision:"6f858cc0ac256f326752ec240fd5c940"},{url:"archives/index.html",revision:"3baddcc8190fe2eb525a32ac503d26d9"},{url:"baidu_verify_codeva-0rhRRODu4H.html",revision:"242837d47be8b7c244eb3b8bfc38e027"},{url:"categories/index.html",revision:"d9cf92fff99e60355e2192d4f79ea84a"},{url:"css/gitalk.css",revision:"5ce280d86637a41c57fdc51fd463237a"},{url:"css/highlight-dark.css",revision:"be3af4b8abf2074e66acb737867c43dc"},{url:"css/highlight.css",revision:"fdd56de5edd1e833674574fdc74bbfe7"},{url:"css/main.css",revision:"7d6d29df18411568c1ae622605bc1907"},{url:"icons/128.png",revision:"375571427b866e32e2d7a9525272a488"},{url:"icons/144.png",revision:"a84f4fe235872bb9be14ebc801f5e4f4"},{url:"icons/192.png",revision:"e0236ca23ccfa319f4b9a698e56ab2e2"},{url:"icons/256.png",revision:"20eb0091d61f49caba3cd63c9ac00a7e"},{url:"icons/512.png",revision:"2c8af612559477d53b8e2dbce84b724c"},{url:"img/avatar.png",revision:"2d9aa61e592b26e2745f3c161c48c397"},{url:"img/default.png",revision:"beb05a6b5b201044b6d80cacdf29f905"},{url:"img/fluid.png",revision:"5603316bb5bc54a9d5cab14fddd4c510"},{url:"img/image-1.png",revision:"4d772ced566ade339ca6718c7ed38674"},{url:"img/image-2.png",revision:"dcfafd0cc238b0a63a733edd1a70bcfe"},{url:"img/image-3.png",revision:"5ba9885de31a8d1e8df04a1d915b1069"},{url:"img/image-4.png",revision:"3d2983fa8549bb6a93b7b905a6baea9c"},{url:"img/image-5.png",revision:"55692e23130e9504505085798384e43e"},{url:"img/image.png",revision:"18a13cfe951c406bbb4da3a7e7bc8ca2"},{url:"img/loading.gif",revision:"15657539044e11a19a1c6c7e3073d1b3"},{url:"img/police_beian.png",revision:"b769e8dfde5660239317ed60758dba13"},{url:"index.html",revision:"1d9fba42d94fa5e630bfed062a8bf244"},{url:"js/boot.js",revision:"7683fab2fc9d03a3a659aa956b3a54e8"},{url:"js/color-schema.js",revision:"605f587be2ab3d36472bb03ac27ede65"},{url:"js/events.js",revision:"7fa076a71a5559d89af6b0c6dfd3a0d2"},{url:"js/img-lazyload.js",revision:"fab30a410e5f490fce3f977a6936a714"},{url:"js/leancloud.js",revision:"fb4a815ccdb5d851d00561dbb62251c4"},{url:"js/local-search.js",revision:"9dc47a0b7b6bacfd16541c9b2b5b6bc5"},{url:"js/plugins.js",revision:"6c10bee3f659ca91b534bf4a81d62f1e"},{url:"js/utils.js",revision:"f7ce9014de1cd7358eeb3aba81c8efe2"},{url:"links/index.html",revision:"d4d7a01004a55c1837a7f85c8dc5ebde"},{url:"tags/cxzlw/index.html",revision:"1aa2389fcf6b0aedb0b5713131368df4"},{url:"tags/index.html",revision:"e54b95772ec74d3591f5f2bdd7d09305"},{url:"tags/Zerotier/index.html",revision:"438595addf53c9863592eff9657e0d0e"},{url:"tags/反爬/index.html",revision:"f48e356602c710b08058f200c12f1f1e"},{url:"tags/小说/index.html",revision:"0c21302da4e4508a153e36ab7591efe5"},{url:"tags/知乎/index.html",revision:"f332e50dfb9c21caf6532151f03fa13b"},{url:"tags/离谱网文/index.html",revision:"6bdf9d905b275a4817145eb2c1aac997"},{url:"tags/自建Planet/index.html",revision:"46426c0df5e6c6b74266a6f2eef41f3e"},{url:"tags/路过的某个学渣/index.html",revision:"5bac00ff0bf3c331155e8fa96e562946"},{url:"tags/飞石/index.html",revision:"833957a9774a4f5ed488c3feeda00af0"}],{}),e.registerRoute(/^https:\/\/lib\.baomitu\.com\/.*/,new e.CacheFirst,"GET"),e.registerRoute(/^https:\/\/at\.alicdn\.com\/.*/,new e.CacheFirst,"GET"),e.registerRoute(/^https:\/\/blog\.cxzlw\.top\/manifest\.json/,new e.NetworkFirst,"GET")}));
//# sourceMappingURL=service-worker.js.map
diff --git a/service-worker.js.map b/service-worker.js.map
index 5d35990..ee5fd57 100644
--- a/service-worker.js.map
+++ b/service-worker.js.map
@@ -1 +1 @@
-{"version":3,"file":"service-worker.js","sources":["../../../../../tmp/64faf248a8b489f66d073be1e39fdeb8/service-worker.js"],"sourcesContent":["import {precacheAndRoute as workbox_precaching_precacheAndRoute} from '/home/runner/work/blog/blog/node_modules/workbox-precaching/precacheAndRoute.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\n\n\n\n\n\n\nself.addEventListener('message', (event) => {\n if (event.data && event.data.type === 'SKIP_WAITING') {\n self.skipWaiting();\n }\n});\n\n\n\n\n/**\n * The precacheAndRoute() method efficiently caches and responds to\n * requests for URLs in the manifest.\n * See https://goo.gl/S9QRab\n */\nworkbox_precaching_precacheAndRoute([\n {\n \"url\": \"2023/07/05/trace-of-line-01/index.html\",\n \"revision\": \"288205fe18fcc5f7d275be0d0901e376\"\n },\n {\n \"url\": \"2023/07/05/zhihu-aac-old/index.html\",\n \"revision\": \"cd33fe593ef78b965ce18a6eeb44cbf0\"\n },\n {\n \"url\": \"2023/07/06/zerotier-planet-convert/index.html\",\n \"revision\": \"7d3e7af7593938b157abcd1b8ae3a668\"\n },\n {\n \"url\": \"2023/07/10/trace-of-line-02/index.html\",\n \"revision\": \"eeec1ce9b0bceaf1da62fd667a63b942\"\n },\n {\n \"url\": \"2023/08/04/permission-system-design-share/index.html\",\n \"revision\": \"b0170858a97ebf95068701274e8d507a\"\n },\n {\n \"url\": \"2023/08/04/test-latex/index.html\",\n \"revision\": \"c9439eb190ead877e1157fc77f28f2c0\"\n },\n {\n \"url\": \"404.html\",\n \"revision\": \"76574a7c44c7fc51cc41e1f2989f32e9\"\n },\n {\n \"url\": \"about/index.html\",\n \"revision\": \"5ed8c36a96ce16a68e963e6d92a3b044\"\n },\n {\n \"url\": \"archives/2023/07/index.html\",\n \"revision\": \"f4a6300899b3192a174f52e6792e7c11\"\n },\n {\n \"url\": \"archives/2023/08/index.html\",\n \"revision\": \"1ed4990ac0fdc0cbab8cc992ab00dc72\"\n },\n {\n \"url\": \"archives/2023/index.html\",\n \"revision\": \"6f858cc0ac256f326752ec240fd5c940\"\n },\n {\n \"url\": \"archives/index.html\",\n \"revision\": \"3baddcc8190fe2eb525a32ac503d26d9\"\n },\n {\n \"url\": \"baidu_verify_codeva-0rhRRODu4H.html\",\n \"revision\": \"242837d47be8b7c244eb3b8bfc38e027\"\n },\n {\n \"url\": \"categories/index.html\",\n \"revision\": \"d9cf92fff99e60355e2192d4f79ea84a\"\n },\n {\n \"url\": \"css/gitalk.css\",\n \"revision\": \"5ce280d86637a41c57fdc51fd463237a\"\n },\n {\n \"url\": \"css/highlight-dark.css\",\n \"revision\": \"be3af4b8abf2074e66acb737867c43dc\"\n },\n {\n \"url\": \"css/highlight.css\",\n \"revision\": \"fdd56de5edd1e833674574fdc74bbfe7\"\n },\n {\n \"url\": \"css/main.css\",\n \"revision\": \"7d6d29df18411568c1ae622605bc1907\"\n },\n {\n \"url\": \"icons/128.png\",\n \"revision\": \"375571427b866e32e2d7a9525272a488\"\n },\n {\n \"url\": \"icons/144.png\",\n \"revision\": \"a84f4fe235872bb9be14ebc801f5e4f4\"\n },\n {\n \"url\": \"icons/192.png\",\n \"revision\": \"e0236ca23ccfa319f4b9a698e56ab2e2\"\n },\n {\n \"url\": \"icons/256.png\",\n \"revision\": \"20eb0091d61f49caba3cd63c9ac00a7e\"\n },\n {\n \"url\": \"icons/512.png\",\n \"revision\": \"2c8af612559477d53b8e2dbce84b724c\"\n },\n {\n \"url\": \"img/avatar.png\",\n \"revision\": \"2d9aa61e592b26e2745f3c161c48c397\"\n },\n {\n \"url\": \"img/default.png\",\n \"revision\": \"beb05a6b5b201044b6d80cacdf29f905\"\n },\n {\n \"url\": \"img/fluid.png\",\n \"revision\": \"5603316bb5bc54a9d5cab14fddd4c510\"\n },\n {\n \"url\": \"img/image-1.png\",\n \"revision\": \"4d772ced566ade339ca6718c7ed38674\"\n },\n {\n \"url\": \"img/image-2.png\",\n \"revision\": \"dcfafd0cc238b0a63a733edd1a70bcfe\"\n },\n {\n \"url\": \"img/image-3.png\",\n \"revision\": \"5ba9885de31a8d1e8df04a1d915b1069\"\n },\n {\n \"url\": \"img/image-4.png\",\n \"revision\": \"3d2983fa8549bb6a93b7b905a6baea9c\"\n },\n {\n \"url\": \"img/image-5.png\",\n \"revision\": \"55692e23130e9504505085798384e43e\"\n },\n {\n \"url\": \"img/image.png\",\n \"revision\": \"18a13cfe951c406bbb4da3a7e7bc8ca2\"\n },\n {\n \"url\": \"img/loading.gif\",\n \"revision\": \"15657539044e11a19a1c6c7e3073d1b3\"\n },\n {\n \"url\": \"img/police_beian.png\",\n \"revision\": \"b769e8dfde5660239317ed60758dba13\"\n },\n {\n \"url\": \"index.html\",\n \"revision\": \"1d9fba42d94fa5e630bfed062a8bf244\"\n },\n {\n \"url\": \"js/boot.js\",\n \"revision\": \"7683fab2fc9d03a3a659aa956b3a54e8\"\n },\n {\n \"url\": \"js/color-schema.js\",\n \"revision\": \"605f587be2ab3d36472bb03ac27ede65\"\n },\n {\n \"url\": \"js/events.js\",\n \"revision\": \"7fa076a71a5559d89af6b0c6dfd3a0d2\"\n },\n {\n \"url\": \"js/img-lazyload.js\",\n \"revision\": \"fab30a410e5f490fce3f977a6936a714\"\n },\n {\n \"url\": \"js/leancloud.js\",\n \"revision\": \"fb4a815ccdb5d851d00561dbb62251c4\"\n },\n {\n \"url\": \"js/local-search.js\",\n \"revision\": \"9dc47a0b7b6bacfd16541c9b2b5b6bc5\"\n },\n {\n \"url\": \"js/plugins.js\",\n \"revision\": \"6c10bee3f659ca91b534bf4a81d62f1e\"\n },\n {\n \"url\": \"js/utils.js\",\n \"revision\": \"f7ce9014de1cd7358eeb3aba81c8efe2\"\n },\n {\n \"url\": \"links/index.html\",\n \"revision\": \"d4d7a01004a55c1837a7f85c8dc5ebde\"\n },\n {\n \"url\": \"tags/cxzlw/index.html\",\n \"revision\": \"1aa2389fcf6b0aedb0b5713131368df4\"\n },\n {\n \"url\": \"tags/index.html\",\n \"revision\": \"e54b95772ec74d3591f5f2bdd7d09305\"\n },\n {\n \"url\": \"tags/Zerotier/index.html\",\n \"revision\": \"438595addf53c9863592eff9657e0d0e\"\n },\n {\n \"url\": \"tags/反爬/index.html\",\n \"revision\": \"f48e356602c710b08058f200c12f1f1e\"\n },\n {\n \"url\": \"tags/小说/index.html\",\n \"revision\": \"0c21302da4e4508a153e36ab7591efe5\"\n },\n {\n \"url\": \"tags/知乎/index.html\",\n \"revision\": \"f332e50dfb9c21caf6532151f03fa13b\"\n },\n {\n \"url\": \"tags/离谱网文/index.html\",\n \"revision\": \"6bdf9d905b275a4817145eb2c1aac997\"\n },\n {\n \"url\": \"tags/自建Planet/index.html\",\n \"revision\": \"46426c0df5e6c6b74266a6f2eef41f3e\"\n },\n {\n \"url\": \"tags/路过的某个学渣/index.html\",\n \"revision\": \"5bac00ff0bf3c331155e8fa96e562946\"\n },\n {\n \"url\": \"tags/飞石/index.html\",\n \"revision\": \"833957a9774a4f5ed488c3feeda00af0\"\n }\n], {});\n\n\n\n\n\n\n\n\n"],"names":["self","addEventListener","event","data","type","skipWaiting","workbox_precaching_precacheAndRoute","url","revision"],"mappings":"0nBAmBAA,KAAKC,iBAAiB,WAAYC,IAC5BA,EAAMC,MAA4B,iBAApBD,EAAMC,KAAKC,MAC3BJ,KAAKK,aACP,IAWFC,EAAAA,iBAAoC,CAClC,CACEC,IAAO,yCACPC,SAAY,oCAEd,CACED,IAAO,sCACPC,SAAY,oCAEd,CACED,IAAO,gDACPC,SAAY,oCAEd,CACED,IAAO,yCACPC,SAAY,oCAEd,CACED,IAAO,uDACPC,SAAY,oCAEd,CACED,IAAO,mCACPC,SAAY,oCAEd,CACED,IAAO,WACPC,SAAY,oCAEd,CACED,IAAO,mBACPC,SAAY,oCAEd,CACED,IAAO,8BACPC,SAAY,oCAEd,CACED,IAAO,8BACPC,SAAY,oCAEd,CACED,IAAO,2BACPC,SAAY,oCAEd,CACED,IAAO,sBACPC,SAAY,oCAEd,CACED,IAAO,sCACPC,SAAY,oCAEd,CACED,IAAO,wBACPC,SAAY,oCAEd,CACED,IAAO,iBACPC,SAAY,oCAEd,CACED,IAAO,yBACPC,SAAY,oCAEd,CACED,IAAO,oBACPC,SAAY,oCAEd,CACED,IAAO,eACPC,SAAY,oCAEd,CACED,IAAO,gBACPC,SAAY,oCAEd,CACED,IAAO,gBACPC,SAAY,oCAEd,CACED,IAAO,gBACPC,SAAY,oCAEd,CACED,IAAO,gBACPC,SAAY,oCAEd,CACED,IAAO,gBACPC,SAAY,oCAEd,CACED,IAAO,iBACPC,SAAY,oCAEd,CACED,IAAO,kBACPC,SAAY,oCAEd,CACED,IAAO,gBACPC,SAAY,oCAEd,CACED,IAAO,kBACPC,SAAY,oCAEd,CACED,IAAO,kBACPC,SAAY,oCAEd,CACED,IAAO,kBACPC,SAAY,oCAEd,CACED,IAAO,kBACPC,SAAY,oCAEd,CACED,IAAO,kBACPC,SAAY,oCAEd,CACED,IAAO,gBACPC,SAAY,oCAEd,CACED,IAAO,kBACPC,SAAY,oCAEd,CACED,IAAO,uBACPC,SAAY,oCAEd,CACED,IAAO,aACPC,SAAY,oCAEd,CACED,IAAO,aACPC,SAAY,oCAEd,CACED,IAAO,qBACPC,SAAY,oCAEd,CACED,IAAO,eACPC,SAAY,oCAEd,CACED,IAAO,qBACPC,SAAY,oCAEd,CACED,IAAO,kBACPC,SAAY,oCAEd,CACED,IAAO,qBACPC,SAAY,oCAEd,CACED,IAAO,gBACPC,SAAY,oCAEd,CACED,IAAO,cACPC,SAAY,oCAEd,CACED,IAAO,mBACPC,SAAY,oCAEd,CACED,IAAO,wBACPC,SAAY,oCAEd,CACED,IAAO,kBACPC,SAAY,oCAEd,CACED,IAAO,2BACPC,SAAY,oCAEd,CACED,IAAO,qBACPC,SAAY,oCAEd,CACED,IAAO,qBACPC,SAAY,oCAEd,CACED,IAAO,qBACPC,SAAY,oCAEd,CACED,IAAO,uBACPC,SAAY,oCAEd,CACED,IAAO,2BACPC,SAAY,oCAEd,CACED,IAAO,0BACPC,SAAY,oCAEd,CACED,IAAO,qBACPC,SAAY,qCAEb,CAAA"}
\ No newline at end of file
+{"version":3,"file":"service-worker.js","sources":["../../../../../tmp/d2808e9162306fde06a78741fa5ef377/service-worker.js"],"sourcesContent":["import {registerRoute as workbox_routing_registerRoute} from '/home/runner/work/blog/blog/node_modules/workbox-routing/registerRoute.mjs';\nimport {CacheFirst as workbox_strategies_CacheFirst} from '/home/runner/work/blog/blog/node_modules/workbox-strategies/CacheFirst.mjs';\nimport {NetworkFirst as workbox_strategies_NetworkFirst} from '/home/runner/work/blog/blog/node_modules/workbox-strategies/NetworkFirst.mjs';\nimport {precacheAndRoute as workbox_precaching_precacheAndRoute} from '/home/runner/work/blog/blog/node_modules/workbox-precaching/precacheAndRoute.mjs';/**\n * Welcome to your Workbox-powered service worker!\n *\n * You'll need to register this file in your web app.\n * See https://goo.gl/nhQhGp\n *\n * The rest of the code is auto-generated. Please don't update this file\n * directly; instead, make changes to your Workbox build configuration\n * and re-run your build process.\n * See https://goo.gl/2aRDsh\n */\n\n\n\n\n\n\n\n\nself.addEventListener('message', (event) => {\n if (event.data && event.data.type === 'SKIP_WAITING') {\n self.skipWaiting();\n }\n});\n\n\n\n\n/**\n * The precacheAndRoute() method efficiently caches and responds to\n * requests for URLs in the manifest.\n * See https://goo.gl/S9QRab\n */\nworkbox_precaching_precacheAndRoute([\n {\n \"url\": \"2023/07/05/trace-of-line-01/index.html\",\n \"revision\": \"94a6f87db0cc9a24ca576dc6650a20f0\"\n },\n {\n \"url\": \"2023/07/05/zhihu-aac-old/index.html\",\n \"revision\": \"4646a98dc4af75c48ddd0ebf7bbe9e89\"\n },\n {\n \"url\": \"2023/07/06/zerotier-planet-convert/index.html\",\n \"revision\": \"db1ed5b8d20a7bfc0c4211c1bc8ca0fc\"\n },\n {\n \"url\": \"2023/07/10/trace-of-line-02/index.html\",\n \"revision\": \"72fc7cef3c1077a7191a4104cc262a41\"\n },\n {\n \"url\": \"2023/08/04/permission-system-design-share/index.html\",\n \"revision\": \"936c31fface906ae2179444b63fd750f\"\n },\n {\n \"url\": \"2023/08/04/test-latex/index.html\",\n \"revision\": \"6f0fe4f46267a950c01f444837e552b0\"\n },\n {\n \"url\": \"404.html\",\n \"revision\": \"76574a7c44c7fc51cc41e1f2989f32e9\"\n },\n {\n \"url\": \"about/index.html\",\n \"revision\": \"3dd6df6fc15b8ea2cf8edeb2bc2db903\"\n },\n {\n \"url\": \"archives/2023/07/index.html\",\n \"revision\": \"f4a6300899b3192a174f52e6792e7c11\"\n },\n {\n \"url\": \"archives/2023/08/index.html\",\n \"revision\": \"1ed4990ac0fdc0cbab8cc992ab00dc72\"\n },\n {\n \"url\": \"archives/2023/index.html\",\n \"revision\": \"6f858cc0ac256f326752ec240fd5c940\"\n },\n {\n \"url\": \"archives/index.html\",\n \"revision\": \"3baddcc8190fe2eb525a32ac503d26d9\"\n },\n {\n \"url\": \"baidu_verify_codeva-0rhRRODu4H.html\",\n \"revision\": \"242837d47be8b7c244eb3b8bfc38e027\"\n },\n {\n \"url\": \"categories/index.html\",\n \"revision\": \"d9cf92fff99e60355e2192d4f79ea84a\"\n },\n {\n \"url\": \"css/gitalk.css\",\n \"revision\": \"5ce280d86637a41c57fdc51fd463237a\"\n },\n {\n \"url\": \"css/highlight-dark.css\",\n \"revision\": \"be3af4b8abf2074e66acb737867c43dc\"\n },\n {\n \"url\": \"css/highlight.css\",\n \"revision\": \"fdd56de5edd1e833674574fdc74bbfe7\"\n },\n {\n \"url\": \"css/main.css\",\n \"revision\": \"7d6d29df18411568c1ae622605bc1907\"\n },\n {\n \"url\": \"icons/128.png\",\n \"revision\": \"375571427b866e32e2d7a9525272a488\"\n },\n {\n \"url\": \"icons/144.png\",\n \"revision\": \"a84f4fe235872bb9be14ebc801f5e4f4\"\n },\n {\n \"url\": \"icons/192.png\",\n \"revision\": \"e0236ca23ccfa319f4b9a698e56ab2e2\"\n },\n {\n \"url\": \"icons/256.png\",\n \"revision\": \"20eb0091d61f49caba3cd63c9ac00a7e\"\n },\n {\n \"url\": \"icons/512.png\",\n \"revision\": \"2c8af612559477d53b8e2dbce84b724c\"\n },\n {\n \"url\": \"img/avatar.png\",\n \"revision\": \"2d9aa61e592b26e2745f3c161c48c397\"\n },\n {\n \"url\": \"img/default.png\",\n \"revision\": \"beb05a6b5b201044b6d80cacdf29f905\"\n },\n {\n \"url\": \"img/fluid.png\",\n \"revision\": \"5603316bb5bc54a9d5cab14fddd4c510\"\n },\n {\n \"url\": \"img/image-1.png\",\n \"revision\": \"4d772ced566ade339ca6718c7ed38674\"\n },\n {\n \"url\": \"img/image-2.png\",\n \"revision\": \"dcfafd0cc238b0a63a733edd1a70bcfe\"\n },\n {\n \"url\": \"img/image-3.png\",\n \"revision\": \"5ba9885de31a8d1e8df04a1d915b1069\"\n },\n {\n \"url\": \"img/image-4.png\",\n \"revision\": \"3d2983fa8549bb6a93b7b905a6baea9c\"\n },\n {\n \"url\": \"img/image-5.png\",\n \"revision\": \"55692e23130e9504505085798384e43e\"\n },\n {\n \"url\": \"img/image.png\",\n \"revision\": \"18a13cfe951c406bbb4da3a7e7bc8ca2\"\n },\n {\n \"url\": \"img/loading.gif\",\n \"revision\": \"15657539044e11a19a1c6c7e3073d1b3\"\n },\n {\n \"url\": \"img/police_beian.png\",\n \"revision\": \"b769e8dfde5660239317ed60758dba13\"\n },\n {\n \"url\": \"index.html\",\n \"revision\": \"1d9fba42d94fa5e630bfed062a8bf244\"\n },\n {\n \"url\": \"js/boot.js\",\n \"revision\": \"7683fab2fc9d03a3a659aa956b3a54e8\"\n },\n {\n \"url\": \"js/color-schema.js\",\n \"revision\": \"605f587be2ab3d36472bb03ac27ede65\"\n },\n {\n \"url\": \"js/events.js\",\n \"revision\": \"7fa076a71a5559d89af6b0c6dfd3a0d2\"\n },\n {\n \"url\": \"js/img-lazyload.js\",\n \"revision\": \"fab30a410e5f490fce3f977a6936a714\"\n },\n {\n \"url\": \"js/leancloud.js\",\n \"revision\": \"fb4a815ccdb5d851d00561dbb62251c4\"\n },\n {\n \"url\": \"js/local-search.js\",\n \"revision\": \"9dc47a0b7b6bacfd16541c9b2b5b6bc5\"\n },\n {\n \"url\": \"js/plugins.js\",\n \"revision\": \"6c10bee3f659ca91b534bf4a81d62f1e\"\n },\n {\n \"url\": \"js/utils.js\",\n \"revision\": \"f7ce9014de1cd7358eeb3aba81c8efe2\"\n },\n {\n \"url\": \"links/index.html\",\n \"revision\": \"d4d7a01004a55c1837a7f85c8dc5ebde\"\n },\n {\n \"url\": \"tags/cxzlw/index.html\",\n \"revision\": \"1aa2389fcf6b0aedb0b5713131368df4\"\n },\n {\n \"url\": \"tags/index.html\",\n \"revision\": \"e54b95772ec74d3591f5f2bdd7d09305\"\n },\n {\n \"url\": \"tags/Zerotier/index.html\",\n \"revision\": \"438595addf53c9863592eff9657e0d0e\"\n },\n {\n \"url\": \"tags/反爬/index.html\",\n \"revision\": \"f48e356602c710b08058f200c12f1f1e\"\n },\n {\n \"url\": \"tags/小说/index.html\",\n \"revision\": \"0c21302da4e4508a153e36ab7591efe5\"\n },\n {\n \"url\": \"tags/知乎/index.html\",\n \"revision\": \"f332e50dfb9c21caf6532151f03fa13b\"\n },\n {\n \"url\": \"tags/离谱网文/index.html\",\n \"revision\": \"6bdf9d905b275a4817145eb2c1aac997\"\n },\n {\n \"url\": \"tags/自建Planet/index.html\",\n \"revision\": \"46426c0df5e6c6b74266a6f2eef41f3e\"\n },\n {\n \"url\": \"tags/路过的某个学渣/index.html\",\n \"revision\": \"5bac00ff0bf3c331155e8fa96e562946\"\n },\n {\n \"url\": \"tags/飞石/index.html\",\n \"revision\": \"833957a9774a4f5ed488c3feeda00af0\"\n }\n], {});\n\n\n\n\nworkbox_routing_registerRoute(/^https:\\/\\/lib\\.baomitu\\.com\\/.*/, new workbox_strategies_CacheFirst(), 'GET');\nworkbox_routing_registerRoute(/^https:\\/\\/at\\.alicdn\\.com\\/.*/, new workbox_strategies_CacheFirst(), 'GET');\nworkbox_routing_registerRoute(/^https:\\/\\/blog\\.cxzlw\\.top\\/manifest\\.json/, new workbox_strategies_NetworkFirst(), 'GET');\n\n\n\n\n"],"names":["self","addEventListener","event","data","type","skipWaiting","workbox_precaching_precacheAndRoute","url","revision","workbox","registerRoute","workbox_strategies_CacheFirst","workbox_strategies_NetworkFirst"],"mappings":"0nBAsBAA,KAAKC,iBAAiB,WAAYC,IAC5BA,EAAMC,MAA4B,iBAApBD,EAAMC,KAAKC,MAC3BJ,KAAKK,aACP,IAWFC,EAAAA,iBAAoC,CAClC,CACEC,IAAO,yCACPC,SAAY,oCAEd,CACED,IAAO,sCACPC,SAAY,oCAEd,CACED,IAAO,gDACPC,SAAY,oCAEd,CACED,IAAO,yCACPC,SAAY,oCAEd,CACED,IAAO,uDACPC,SAAY,oCAEd,CACED,IAAO,mCACPC,SAAY,oCAEd,CACED,IAAO,WACPC,SAAY,oCAEd,CACED,IAAO,mBACPC,SAAY,oCAEd,CACED,IAAO,8BACPC,SAAY,oCAEd,CACED,IAAO,8BACPC,SAAY,oCAEd,CACED,IAAO,2BACPC,SAAY,oCAEd,CACED,IAAO,sBACPC,SAAY,oCAEd,CACED,IAAO,sCACPC,SAAY,oCAEd,CACED,IAAO,wBACPC,SAAY,oCAEd,CACED,IAAO,iBACPC,SAAY,oCAEd,CACED,IAAO,yBACPC,SAAY,oCAEd,CACED,IAAO,oBACPC,SAAY,oCAEd,CACED,IAAO,eACPC,SAAY,oCAEd,CACED,IAAO,gBACPC,SAAY,oCAEd,CACED,IAAO,gBACPC,SAAY,oCAEd,CACED,IAAO,gBACPC,SAAY,oCAEd,CACED,IAAO,gBACPC,SAAY,oCAEd,CACED,IAAO,gBACPC,SAAY,oCAEd,CACED,IAAO,iBACPC,SAAY,oCAEd,CACED,IAAO,kBACPC,SAAY,oCAEd,CACED,IAAO,gBACPC,SAAY,oCAEd,CACED,IAAO,kBACPC,SAAY,oCAEd,CACED,IAAO,kBACPC,SAAY,oCAEd,CACED,IAAO,kBACPC,SAAY,oCAEd,CACED,IAAO,kBACPC,SAAY,oCAEd,CACED,IAAO,kBACPC,SAAY,oCAEd,CACED,IAAO,gBACPC,SAAY,oCAEd,CACED,IAAO,kBACPC,SAAY,oCAEd,CACED,IAAO,uBACPC,SAAY,oCAEd,CACED,IAAO,aACPC,SAAY,oCAEd,CACED,IAAO,aACPC,SAAY,oCAEd,CACED,IAAO,qBACPC,SAAY,oCAEd,CACED,IAAO,eACPC,SAAY,oCAEd,CACED,IAAO,qBACPC,SAAY,oCAEd,CACED,IAAO,kBACPC,SAAY,oCAEd,CACED,IAAO,qBACPC,SAAY,oCAEd,CACED,IAAO,gBACPC,SAAY,oCAEd,CACED,IAAO,cACPC,SAAY,oCAEd,CACED,IAAO,mBACPC,SAAY,oCAEd,CACED,IAAO,wBACPC,SAAY,oCAEd,CACED,IAAO,kBACPC,SAAY,oCAEd,CACED,IAAO,2BACPC,SAAY,oCAEd,CACED,IAAO,qBACPC,SAAY,oCAEd,CACED,IAAO,qBACPC,SAAY,oCAEd,CACED,IAAO,qBACPC,SAAY,oCAEd,CACED,IAAO,uBACPC,SAAY,oCAEd,CACED,IAAO,2BACPC,SAAY,oCAEd,CACED,IAAO,0BACPC,SAAY,oCAEd,CACED,IAAO,qBACPC,SAAY,qCAEb,CAAE,GAKwBC,EAAAC,cAAC,mCAAoC,IAAIC,aAAiC,OAC1EF,EAAAC,cAAC,iCAAkC,IAAIC,aAAiC,OACxEF,EAAAC,cAAC,8CAA+C,IAAIE,eAAmC"}
\ No newline at end of file
diff --git a/workbox-66a1f6b7.js b/workbox-66a1f6b7.js
new file mode 100644
index 0000000..e1177b7
--- /dev/null
+++ b/workbox-66a1f6b7.js
@@ -0,0 +1,2 @@
+define(["exports"],(function(t){"use strict";try{self["workbox:core:6.5.4"]&&_()}catch(t){}const e=(t,...e)=>{let s=t;return e.length>0&&(s+=` :: ${JSON.stringify(e)}`),s};class s extends Error{constructor(t,s){super(e(t,s)),this.name=t,this.details=s}}try{self["workbox:routing:6.5.4"]&&_()}catch(t){}const n=t=>t&&"object"==typeof t?t:{handle:t};class r{constructor(t,e,s="GET"){this.handler=n(e),this.match=t,this.method=s}setCatchHandler(t){this.catchHandler=n(t)}}class i extends r{constructor(t,e,s){super((({url:e})=>{const s=t.exec(e.href);if(s&&(e.origin===location.origin||0===s.index))return s.slice(1)}),e,s)}}class o{constructor(){this.t=new Map,this.i=new Map}get routes(){return this.t}addFetchListener(){self.addEventListener("fetch",(t=>{const{request:e}=t,s=this.handleRequest({request:e,event:t});s&&t.respondWith(s)}))}addCacheListener(){self.addEventListener("message",(t=>{if(t.data&&"CACHE_URLS"===t.data.type){const{payload:e}=t.data,s=Promise.all(e.urlsToCache.map((e=>{"string"==typeof e&&(e=[e]);const s=new Request(...e);return this.handleRequest({request:s,event:t})})));t.waitUntil(s),t.ports&&t.ports[0]&&s.then((()=>t.ports[0].postMessage(!0)))}}))}handleRequest({request:t,event:e}){const s=new URL(t.url,location.href);if(!s.protocol.startsWith("http"))return;const n=s.origin===location.origin,{params:r,route:i}=this.findMatchingRoute({event:e,request:t,sameOrigin:n,url:s});let o=i&&i.handler;const a=t.method;if(!o&&this.i.has(a)&&(o=this.i.get(a)),!o)return;let c;try{c=o.handle({url:s,request:t,event:e,params:r})}catch(t){c=Promise.reject(t)}const h=i&&i.catchHandler;return c instanceof Promise&&(this.o||h)&&(c=c.catch((async n=>{if(h)try{return await h.handle({url:s,request:t,event:e,params:r})}catch(t){t instanceof Error&&(n=t)}if(this.o)return this.o.handle({url:s,request:t,event:e});throw n}))),c}findMatchingRoute({url:t,sameOrigin:e,request:s,event:n}){const r=this.t.get(s.method)||[];for(const i of r){let r;const o=i.match({url:t,sameOrigin:e,request:s,event:n});if(o)return r=o,(Array.isArray(r)&&0===r.length||o.constructor===Object&&0===Object.keys(o).length||"boolean"==typeof o)&&(r=void 0),{route:i,params:r}}return{}}setDefaultHandler(t,e="GET"){this.i.set(e,n(t))}setCatchHandler(t){this.o=n(t)}registerRoute(t){this.t.has(t.method)||this.t.set(t.method,[]),this.t.get(t.method).push(t)}unregisterRoute(t){if(!this.t.has(t.method))throw new s("unregister-route-but-not-found-with-method",{method:t.method});const e=this.t.get(t.method).indexOf(t);if(!(e>-1))throw new s("unregister-route-route-not-registered");this.t.get(t.method).splice(e,1)}}let a;const c=()=>(a||(a=new o,a.addFetchListener(),a.addCacheListener()),a);function h(t,e,n){let o;if("string"==typeof t){const s=new URL(t,location.href);o=new r((({url:t})=>t.href===s.href),e,n)}else if(t instanceof RegExp)o=new i(t,e,n);else if("function"==typeof t)o=new r(t,e,n);else{if(!(t instanceof r))throw new s("unsupported-route-type",{moduleName:"workbox-routing",funcName:"registerRoute",paramName:"capture"});o=t}return c().registerRoute(o),o}const u={googleAnalytics:"googleAnalytics",precache:"precache-v2",prefix:"workbox",runtime:"runtime",suffix:"undefined"!=typeof registration?registration.scope:""},l=t=>[u.prefix,t,u.suffix].filter((t=>t&&t.length>0)).join("-"),f=t=>t||l(u.precache),w=t=>t||l(u.runtime);function d(t,e){const s=new URL(t);for(const t of e)s.searchParams.delete(t);return s.href}class p{constructor(){this.promise=new Promise(((t,e)=>{this.resolve=t,this.reject=e}))}}const y=new Set;try{self["workbox:strategies:6.5.4"]&&_()}catch(t){}function g(t){return"string"==typeof t?new Request(t):t}class m{constructor(t,e){this.h={},Object.assign(this,e),this.event=e.event,this.u=t,this.l=new p,this.p=[],this.g=[...t.plugins],this.m=new Map;for(const t of this.g)this.m.set(t,{});this.event.waitUntil(this.l.promise)}async fetch(t){const{event:e}=this;let n=g(t);if("navigate"===n.mode&&e instanceof FetchEvent&&e.preloadResponse){const t=await e.preloadResponse;if(t)return t}const r=this.hasCallback("fetchDidFail")?n.clone():null;try{for(const t of this.iterateCallbacks("requestWillFetch"))n=await t({request:n.clone(),event:e})}catch(t){if(t instanceof Error)throw new s("plugin-error-request-will-fetch",{thrownErrorMessage:t.message})}const i=n.clone();try{let t;t=await fetch(n,"navigate"===n.mode?void 0:this.u.fetchOptions);for(const s of this.iterateCallbacks("fetchDidSucceed"))t=await s({event:e,request:i,response:t});return t}catch(t){throw r&&await this.runCallbacks("fetchDidFail",{error:t,event:e,originalRequest:r.clone(),request:i.clone()}),t}}async fetchAndCachePut(t){const e=await this.fetch(t),s=e.clone();return this.waitUntil(this.cachePut(t,s)),e}async cacheMatch(t){const e=g(t);let s;const{cacheName:n,matchOptions:r}=this.u,i=await this.getCacheKey(e,"read"),o=Object.assign(Object.assign({},r),{cacheName:n});s=await caches.match(i,o);for(const t of this.iterateCallbacks("cachedResponseWillBeUsed"))s=await t({cacheName:n,matchOptions:r,cachedResponse:s,request:i,event:this.event})||void 0;return s}async cachePut(t,e){const n=g(t);var r;await(r=0,new Promise((t=>setTimeout(t,r))));const i=await this.getCacheKey(n,"write");if(!e)throw new s("cache-put-with-no-response",{url:(o=i.url,new URL(String(o),location.href).href.replace(new RegExp(`^${location.origin}`),""))});var o;const a=await this.R(e);if(!a)return!1;const{cacheName:c,matchOptions:h}=this.u,u=await self.caches.open(c),l=this.hasCallback("cacheDidUpdate"),f=l?await async function(t,e,s,n){const r=d(e.url,s);if(e.url===r)return t.match(e,n);const i=Object.assign(Object.assign({},n),{ignoreSearch:!0}),o=await t.keys(e,i);for(const e of o)if(r===d(e.url,s))return t.match(e,n)}(u,i.clone(),["__WB_REVISION__"],h):null;try{await u.put(i,l?a.clone():a)}catch(t){if(t instanceof Error)throw"QuotaExceededError"===t.name&&await async function(){for(const t of y)await t()}(),t}for(const t of this.iterateCallbacks("cacheDidUpdate"))await t({cacheName:c,oldResponse:f,newResponse:a.clone(),request:i,event:this.event});return!0}async getCacheKey(t,e){const s=`${t.url} | ${e}`;if(!this.h[s]){let n=t;for(const t of this.iterateCallbacks("cacheKeyWillBeUsed"))n=g(await t({mode:e,request:n,event:this.event,params:this.params}));this.h[s]=n}return this.h[s]}hasCallback(t){for(const e of this.u.plugins)if(t in e)return!0;return!1}async runCallbacks(t,e){for(const s of this.iterateCallbacks(t))await s(e)}*iterateCallbacks(t){for(const e of this.u.plugins)if("function"==typeof e[t]){const s=this.m.get(e),n=n=>{const r=Object.assign(Object.assign({},n),{state:s});return e[t](r)};yield n}}waitUntil(t){return this.p.push(t),t}async doneWaiting(){let t;for(;t=this.p.shift();)await t}destroy(){this.l.resolve(null)}async R(t){let e=t,s=!1;for(const t of this.iterateCallbacks("cacheWillUpdate"))if(e=await t({request:this.request,response:e,event:this.event})||void 0,s=!0,!e)break;return s||e&&200!==e.status&&(e=void 0),e}}class R{constructor(t={}){this.cacheName=w(t.cacheName),this.plugins=t.plugins||[],this.fetchOptions=t.fetchOptions,this.matchOptions=t.matchOptions}handle(t){const[e]=this.handleAll(t);return e}handleAll(t){t instanceof FetchEvent&&(t={event:t,request:t.request});const e=t.event,s="string"==typeof t.request?new Request(t.request):t.request,n="params"in t?t.params:void 0,r=new m(this,{event:e,request:s,params:n}),i=this.v(r,s,e);return[i,this.q(i,r,s,e)]}async v(t,e,n){let r;await t.runCallbacks("handlerWillStart",{event:n,request:e});try{if(r=await this.U(e,t),!r||"error"===r.type)throw new s("no-response",{url:e.url})}catch(s){if(s instanceof Error)for(const i of t.iterateCallbacks("handlerDidError"))if(r=await i({error:s,event:n,request:e}),r)break;if(!r)throw s}for(const s of t.iterateCallbacks("handlerWillRespond"))r=await s({event:n,request:e,response:r});return r}async q(t,e,s,n){let r,i;try{r=await t}catch(i){}try{await e.runCallbacks("handlerDidRespond",{event:n,request:s,response:r}),await e.doneWaiting()}catch(t){t instanceof Error&&(i=t)}if(await e.runCallbacks("handlerDidComplete",{event:n,request:s,response:r,error:i}),e.destroy(),i)throw i}}const v={cacheWillUpdate:async({response:t})=>200===t.status||0===t.status?t:null};function q(t,e){const s=e();return t.waitUntil(s),s}try{self["workbox:precaching:6.5.4"]&&_()}catch(t){}function U(t){if(!t)throw new s("add-to-cache-list-unexpected-type",{entry:t});if("string"==typeof t){const e=new URL(t,location.href);return{cacheKey:e.href,url:e.href}}const{revision:e,url:n}=t;if(!n)throw new s("add-to-cache-list-unexpected-type",{entry:t});if(!e){const t=new URL(n,location.href);return{cacheKey:t.href,url:t.href}}const r=new URL(n,location.href),i=new URL(n,location.href);return r.searchParams.set("__WB_REVISION__",e),{cacheKey:r.href,url:i.href}}class L{constructor(){this.updatedURLs=[],this.notUpdatedURLs=[],this.handlerWillStart=async({request:t,state:e})=>{e&&(e.originalRequest=t)},this.cachedResponseWillBeUsed=async({event:t,state:e,cachedResponse:s})=>{if("install"===t.type&&e&&e.originalRequest&&e.originalRequest instanceof Request){const t=e.originalRequest.url;s?this.notUpdatedURLs.push(t):this.updatedURLs.push(t)}return s}}}class b{constructor({precacheController:t}){this.cacheKeyWillBeUsed=async({request:t,params:e})=>{const s=(null==e?void 0:e.cacheKey)||this.L.getCacheKeyForURL(t.url);return s?new Request(s,{headers:t.headers}):t},this.L=t}}let E,C;async function x(t,e){let n=null;if(t.url){n=new URL(t.url).origin}if(n!==self.location.origin)throw new s("cross-origin-copy-response",{origin:n});const r=t.clone(),i={headers:new Headers(r.headers),status:r.status,statusText:r.statusText},o=e?e(i):i,a=function(){if(void 0===E){const t=new Response("");if("body"in t)try{new Response(t.body),E=!0}catch(t){E=!1}E=!1}return E}()?r.body:await r.blob();return new Response(a,o)}class O extends R{constructor(t={}){t.cacheName=f(t.cacheName),super(t),this._=!1!==t.fallbackToNetwork,this.plugins.push(O.copyRedirectedCacheableResponsesPlugin)}async U(t,e){const s=await e.cacheMatch(t);return s||(e.event&&"install"===e.event.type?await this.C(t,e):await this.O(t,e))}async O(t,e){let n;const r=e.params||{};if(!this._)throw new s("missing-precache-entry",{cacheName:this.cacheName,url:t.url});{const s=r.integrity,i=t.integrity,o=!i||i===s;n=await e.fetch(new Request(t,{integrity:"no-cors"!==t.mode?i||s:void 0})),s&&o&&"no-cors"!==t.mode&&(this.N(),await e.cachePut(t,n.clone()))}return n}async C(t,e){this.N();const n=await e.fetch(t);if(!await e.cachePut(t,n.clone()))throw new s("bad-precaching-response",{url:t.url,status:n.status});return n}N(){let t=null,e=0;for(const[s,n]of this.plugins.entries())n!==O.copyRedirectedCacheableResponsesPlugin&&(n===O.defaultPrecacheCacheabilityPlugin&&(t=s),n.cacheWillUpdate&&e++);0===e?this.plugins.push(O.defaultPrecacheCacheabilityPlugin):e>1&&null!==t&&this.plugins.splice(t,1)}}O.defaultPrecacheCacheabilityPlugin={cacheWillUpdate:async({response:t})=>!t||t.status>=400?null:t},O.copyRedirectedCacheableResponsesPlugin={cacheWillUpdate:async({response:t})=>t.redirected?await x(t):t};class N{constructor({cacheName:t,plugins:e=[],fallbackToNetwork:s=!0}={}){this.P=new Map,this.T=new Map,this.W=new Map,this.u=new O({cacheName:f(t),plugins:[...e,new b({precacheController:this})],fallbackToNetwork:s}),this.install=this.install.bind(this),this.activate=this.activate.bind(this)}get strategy(){return this.u}precache(t){this.addToCacheList(t),this.k||(self.addEventListener("install",this.install),self.addEventListener("activate",this.activate),this.k=!0)}addToCacheList(t){const e=[];for(const n of t){"string"==typeof n?e.push(n):n&&void 0===n.revision&&e.push(n.url);const{cacheKey:t,url:r}=U(n),i="string"!=typeof n&&n.revision?"reload":"default";if(this.P.has(r)&&this.P.get(r)!==t)throw new s("add-to-cache-list-conflicting-entries",{firstEntry:this.P.get(r),secondEntry:t});if("string"!=typeof n&&n.integrity){if(this.W.has(t)&&this.W.get(t)!==n.integrity)throw new s("add-to-cache-list-conflicting-integrities",{url:r});this.W.set(t,n.integrity)}if(this.P.set(r,t),this.T.set(r,i),e.length>0){const t=`Workbox is precaching URLs without revision info: ${e.join(", ")}\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;console.warn(t)}}}install(t){return q(t,(async()=>{const e=new L;this.strategy.plugins.push(e);for(const[e,s]of this.P){const n=this.W.get(s),r=this.T.get(e),i=new Request(e,{integrity:n,cache:r,credentials:"same-origin"});await Promise.all(this.strategy.handleAll({params:{cacheKey:s},request:i,event:t}))}const{updatedURLs:s,notUpdatedURLs:n}=e;return{updatedURLs:s,notUpdatedURLs:n}}))}activate(t){return q(t,(async()=>{const t=await self.caches.open(this.strategy.cacheName),e=await t.keys(),s=new Set(this.P.values()),n=[];for(const r of e)s.has(r.url)||(await t.delete(r),n.push(r.url));return{deletedURLs:n}}))}getURLsToCacheKeys(){return this.P}getCachedURLs(){return[...this.P.keys()]}getCacheKeyForURL(t){const e=new URL(t,location.href);return this.P.get(e.href)}getIntegrityForCacheKey(t){return this.W.get(t)}async matchPrecache(t){const e=t instanceof Request?t.url:t,s=this.getCacheKeyForURL(e);if(s){return(await self.caches.open(this.strategy.cacheName)).match(s)}}createHandlerBoundToURL(t){const e=this.getCacheKeyForURL(t);if(!e)throw new s("non-precached-url",{url:t});return s=>(s.request=new Request(t),s.params=Object.assign({cacheKey:e},s.params),this.strategy.handle(s))}}const P=()=>(C||(C=new N),C);class T extends r{constructor(t,e){super((({request:s})=>{const n=t.getURLsToCacheKeys();for(const r of function*(t,{ignoreURLParametersMatching:e=[/^utm_/,/^fbclid$/],directoryIndex:s="index.html",cleanURLs:n=!0,urlManipulation:r}={}){const i=new URL(t,location.href);i.hash="",yield i.href;const o=function(t,e=[]){for(const s of[...t.searchParams.keys()])e.some((t=>t.test(s)))&&t.searchParams.delete(s);return t}(i,e);if(yield o.href,s&&o.pathname.endsWith("/")){const t=new URL(o.href);t.pathname+=s,yield t.href}if(n){const t=new URL(o.href);t.pathname+=".html",yield t.href}if(r){const t=r({url:i});for(const e of t)yield e.href}}(s.url,e)){const e=n.get(r);if(e){return{cacheKey:e,integrity:t.getIntegrityForCacheKey(e)}}}}),t.strategy)}}t.CacheFirst=class extends R{async U(t,e){let n,r=await e.cacheMatch(t);if(!r)try{r=await e.fetchAndCachePut(t)}catch(t){t instanceof Error&&(n=t)}if(!r)throw new s("no-response",{url:t.url,error:n});return r}},t.NetworkFirst=class extends R{constructor(t={}){super(t),this.plugins.some((t=>"cacheWillUpdate"in t))||this.plugins.unshift(v),this.K=t.networkTimeoutSeconds||0}async U(t,e){const n=[],r=[];let i;if(this.K){const{id:s,promise:o}=this.j({request:t,logs:n,handler:e});i=s,r.push(o)}const o=this.M({timeoutId:i,request:t,logs:n,handler:e});r.push(o);const a=await e.waitUntil((async()=>await e.waitUntil(Promise.race(r))||await o)());if(!a)throw new s("no-response",{url:t.url});return a}j({request:t,logs:e,handler:s}){let n;return{promise:new Promise((e=>{n=setTimeout((async()=>{e(await s.cacheMatch(t))}),1e3*this.K)})),id:n}}async M({timeoutId:t,request:e,logs:s,handler:n}){let r,i;try{i=await n.fetchAndCachePut(e)}catch(t){t instanceof Error&&(r=t)}return t&&clearTimeout(t),!r&&i||(i=await n.cacheMatch(e)),i}},t.precacheAndRoute=function(t,e){!function(t){P().precache(t)}(t),function(t){const e=P();h(new T(e,t))}(e)},t.registerRoute=h}));
+//# sourceMappingURL=workbox-66a1f6b7.js.map
diff --git a/workbox-66a1f6b7.js.map b/workbox-66a1f6b7.js.map
new file mode 100644
index 0000000..0db78df
--- /dev/null
+++ b/workbox-66a1f6b7.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"workbox-66a1f6b7.js","sources":["node_modules/workbox-core/_version.js","node_modules/workbox-core/_private/logger.js","node_modules/workbox-core/models/messages/messageGenerator.js","node_modules/workbox-core/_private/WorkboxError.js","node_modules/workbox-routing/_version.js","node_modules/workbox-routing/utils/constants.js","node_modules/workbox-routing/utils/normalizeHandler.js","node_modules/workbox-routing/Route.js","node_modules/workbox-routing/RegExpRoute.js","node_modules/workbox-routing/Router.js","node_modules/workbox-routing/utils/getOrCreateDefaultRouter.js","node_modules/workbox-routing/registerRoute.js","node_modules/workbox-core/_private/cacheNames.js","node_modules/workbox-core/_private/cacheMatchIgnoreParams.js","node_modules/workbox-core/_private/Deferred.js","node_modules/workbox-core/models/quotaErrorCallbacks.js","node_modules/workbox-strategies/_version.js","node_modules/workbox-strategies/StrategyHandler.js","node_modules/workbox-core/_private/timeout.js","node_modules/workbox-core/_private/getFriendlyURL.js","node_modules/workbox-core/_private/executeQuotaErrorCallbacks.js","node_modules/workbox-strategies/Strategy.js","node_modules/workbox-strategies/plugins/cacheOkAndOpaquePlugin.js","node_modules/workbox-core/_private/waitUntil.js","node_modules/workbox-precaching/_version.js","node_modules/workbox-precaching/utils/createCacheKey.js","node_modules/workbox-precaching/utils/PrecacheInstallReportPlugin.js","node_modules/workbox-precaching/utils/PrecacheCacheKeyPlugin.js","node_modules/workbox-core/_private/canConstructResponseFromBodyStream.js","node_modules/workbox-precaching/utils/getOrCreatePrecacheController.js","node_modules/workbox-core/copyResponse.js","node_modules/workbox-precaching/PrecacheStrategy.js","node_modules/workbox-precaching/PrecacheController.js","node_modules/workbox-precaching/PrecacheRoute.js","node_modules/workbox-precaching/utils/generateURLVariations.js","node_modules/workbox-precaching/utils/removeIgnoredSearchParams.js","node_modules/workbox-strategies/CacheFirst.js","node_modules/workbox-strategies/NetworkFirst.js","node_modules/workbox-precaching/precacheAndRoute.js","node_modules/workbox-precaching/precache.js","node_modules/workbox-precaching/addRoute.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:core:6.5.4'] && _();\n}\ncatch (e) { }\n","/*\n Copyright 2019 Google LLC\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\nconst logger = (process.env.NODE_ENV === 'production'\n ? null\n : (() => {\n // Don't overwrite this value if it's already set.\n // See https://github.com/GoogleChrome/workbox/pull/2284#issuecomment-560470923\n if (!('__WB_DISABLE_DEV_LOGS' in globalThis)) {\n self.__WB_DISABLE_DEV_LOGS = false;\n }\n let inGroup = false;\n const methodToColorMap = {\n debug: `#7f8c8d`,\n log: `#2ecc71`,\n warn: `#f39c12`,\n error: `#c0392b`,\n groupCollapsed: `#3498db`,\n groupEnd: null, // No colored prefix on groupEnd\n };\n const print = function (method, args) {\n if (self.__WB_DISABLE_DEV_LOGS) {\n return;\n }\n if (method === 'groupCollapsed') {\n // Safari doesn't print all console.groupCollapsed() arguments:\n // https://bugs.webkit.org/show_bug.cgi?id=182754\n if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) {\n console[method](...args);\n return;\n }\n }\n const styles = [\n `background: ${methodToColorMap[method]}`,\n `border-radius: 0.5em`,\n `color: white`,\n `font-weight: bold`,\n `padding: 2px 0.5em`,\n ];\n // When in a group, the workbox prefix is not displayed.\n const logPrefix = inGroup ? [] : ['%cworkbox', styles.join(';')];\n console[method](...logPrefix, ...args);\n if (method === 'groupCollapsed') {\n inGroup = true;\n }\n if (method === 'groupEnd') {\n inGroup = false;\n }\n };\n // eslint-disable-next-line @typescript-eslint/ban-types\n const api = {};\n const loggerMethods = Object.keys(methodToColorMap);\n for (const key of loggerMethods) {\n const method = key;\n api[method] = (...args) => {\n print(method, args);\n };\n }\n return api;\n })());\nexport { logger };\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { messages } from './messages.js';\nimport '../../_version.js';\nconst fallback = (code, ...args) => {\n let msg = code;\n if (args.length > 0) {\n msg += ` :: ${JSON.stringify(args)}`;\n }\n return msg;\n};\nconst generatorFunction = (code, details = {}) => {\n const message = messages[code];\n if (!message) {\n throw new Error(`Unable to find message for code '${code}'.`);\n }\n return message(details);\n};\nexport const messageGenerator = process.env.NODE_ENV === 'production' ? fallback : generatorFunction;\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { messageGenerator } from '../models/messages/messageGenerator.js';\nimport '../_version.js';\n/**\n * Workbox errors should be thrown with this class.\n * This allows use to ensure the type easily in tests,\n * helps developers identify errors from workbox\n * easily and allows use to optimise error\n * messages correctly.\n *\n * @private\n */\nclass WorkboxError extends Error {\n /**\n *\n * @param {string} errorCode The error code that\n * identifies this particular error.\n * @param {Object=} details Any relevant arguments\n * that will help developers identify issues should\n * be added as a key on the context object.\n */\n constructor(errorCode, details) {\n const message = messageGenerator(errorCode, details);\n super(message);\n this.name = errorCode;\n this.details = details;\n }\n}\nexport { WorkboxError };\n","\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:routing:6.5.4'] && _();\n}\ncatch (e) { }\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n/**\n * The default HTTP method, 'GET', used when there's no specific method\n * configured for a route.\n *\n * @type {string}\n *\n * @private\n */\nexport const defaultMethod = 'GET';\n/**\n * The list of valid HTTP methods associated with requests that could be routed.\n *\n * @type {Array}\n *\n * @private\n */\nexport const validMethods = [\n 'DELETE',\n 'GET',\n 'HEAD',\n 'PATCH',\n 'POST',\n 'PUT',\n];\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { assert } from 'workbox-core/_private/assert.js';\nimport '../_version.js';\n/**\n * @param {function()|Object} handler Either a function, or an object with a\n * 'handle' method.\n * @return {Object} An object with a handle method.\n *\n * @private\n */\nexport const normalizeHandler = (handler) => {\n if (handler && typeof handler === 'object') {\n if (process.env.NODE_ENV !== 'production') {\n assert.hasMethod(handler, 'handle', {\n moduleName: 'workbox-routing',\n className: 'Route',\n funcName: 'constructor',\n paramName: 'handler',\n });\n }\n return handler;\n }\n else {\n if (process.env.NODE_ENV !== 'production') {\n assert.isType(handler, 'function', {\n moduleName: 'workbox-routing',\n className: 'Route',\n funcName: 'constructor',\n paramName: 'handler',\n });\n }\n return { handle: handler };\n }\n};\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { assert } from 'workbox-core/_private/assert.js';\nimport { defaultMethod, validMethods } from './utils/constants.js';\nimport { normalizeHandler } from './utils/normalizeHandler.js';\nimport './_version.js';\n/**\n * A `Route` consists of a pair of callback functions, \"match\" and \"handler\".\n * The \"match\" callback determine if a route should be used to \"handle\" a\n * request by returning a non-falsy value if it can. The \"handler\" callback\n * is called when there is a match and should return a Promise that resolves\n * to a `Response`.\n *\n * @memberof workbox-routing\n */\nclass Route {\n /**\n * Constructor for Route class.\n *\n * @param {workbox-routing~matchCallback} match\n * A callback function that determines whether the route matches a given\n * `fetch` event by returning a non-falsy value.\n * @param {workbox-routing~handlerCallback} handler A callback\n * function that returns a Promise resolving to a Response.\n * @param {string} [method='GET'] The HTTP method to match the Route\n * against.\n */\n constructor(match, handler, method = defaultMethod) {\n if (process.env.NODE_ENV !== 'production') {\n assert.isType(match, 'function', {\n moduleName: 'workbox-routing',\n className: 'Route',\n funcName: 'constructor',\n paramName: 'match',\n });\n if (method) {\n assert.isOneOf(method, validMethods, { paramName: 'method' });\n }\n }\n // These values are referenced directly by Router so cannot be\n // altered by minificaton.\n this.handler = normalizeHandler(handler);\n this.match = match;\n this.method = method;\n }\n /**\n *\n * @param {workbox-routing-handlerCallback} handler A callback\n * function that returns a Promise resolving to a Response\n */\n setCatchHandler(handler) {\n this.catchHandler = normalizeHandler(handler);\n }\n}\nexport { Route };\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { assert } from 'workbox-core/_private/assert.js';\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { Route } from './Route.js';\nimport './_version.js';\n/**\n * RegExpRoute makes it easy to create a regular expression based\n * {@link workbox-routing.Route}.\n *\n * For same-origin requests the RegExp only needs to match part of the URL. For\n * requests against third-party servers, you must define a RegExp that matches\n * the start of the URL.\n *\n * @memberof workbox-routing\n * @extends workbox-routing.Route\n */\nclass RegExpRoute extends Route {\n /**\n * If the regular expression contains\n * [capture groups]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#grouping-back-references},\n * the captured values will be passed to the\n * {@link workbox-routing~handlerCallback} `params`\n * argument.\n *\n * @param {RegExp} regExp The regular expression to match against URLs.\n * @param {workbox-routing~handlerCallback} handler A callback\n * function that returns a Promise resulting in a Response.\n * @param {string} [method='GET'] The HTTP method to match the Route\n * against.\n */\n constructor(regExp, handler, method) {\n if (process.env.NODE_ENV !== 'production') {\n assert.isInstance(regExp, RegExp, {\n moduleName: 'workbox-routing',\n className: 'RegExpRoute',\n funcName: 'constructor',\n paramName: 'pattern',\n });\n }\n const match = ({ url }) => {\n const result = regExp.exec(url.href);\n // Return immediately if there's no match.\n if (!result) {\n return;\n }\n // Require that the match start at the first character in the URL string\n // if it's a cross-origin request.\n // See https://github.com/GoogleChrome/workbox/issues/281 for the context\n // behind this behavior.\n if (url.origin !== location.origin && result.index !== 0) {\n if (process.env.NODE_ENV !== 'production') {\n logger.debug(`The regular expression '${regExp.toString()}' only partially matched ` +\n `against the cross-origin URL '${url.toString()}'. RegExpRoute's will only ` +\n `handle cross-origin requests if they match the entire URL.`);\n }\n return;\n }\n // If the route matches, but there aren't any capture groups defined, then\n // this will return [], which is truthy and therefore sufficient to\n // indicate a match.\n // If there are capture groups, then it will return their values.\n return result.slice(1);\n };\n super(match, handler, method);\n }\n}\nexport { RegExpRoute };\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { assert } from 'workbox-core/_private/assert.js';\nimport { getFriendlyURL } from 'workbox-core/_private/getFriendlyURL.js';\nimport { defaultMethod } from './utils/constants.js';\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { normalizeHandler } from './utils/normalizeHandler.js';\nimport { WorkboxError } from 'workbox-core/_private/WorkboxError.js';\nimport './_version.js';\n/**\n * The Router can be used to process a `FetchEvent` using one or more\n * {@link workbox-routing.Route}, responding with a `Response` if\n * a matching route exists.\n *\n * If no route matches a given a request, the Router will use a \"default\"\n * handler if one is defined.\n *\n * Should the matching Route throw an error, the Router will use a \"catch\"\n * handler if one is defined to gracefully deal with issues and respond with a\n * Request.\n *\n * If a request matches multiple routes, the **earliest** registered route will\n * be used to respond to the request.\n *\n * @memberof workbox-routing\n */\nclass Router {\n /**\n * Initializes a new Router.\n */\n constructor() {\n this._routes = new Map();\n this._defaultHandlerMap = new Map();\n }\n /**\n * @return {Map>} routes A `Map` of HTTP\n * method name ('GET', etc.) to an array of all the corresponding `Route`\n * instances that are registered.\n */\n get routes() {\n return this._routes;\n }\n /**\n * Adds a fetch event listener to respond to events when a route matches\n * the event's request.\n */\n addFetchListener() {\n // See https://github.com/Microsoft/TypeScript/issues/28357#issuecomment-436484705\n self.addEventListener('fetch', ((event) => {\n const { request } = event;\n const responsePromise = this.handleRequest({ request, event });\n if (responsePromise) {\n event.respondWith(responsePromise);\n }\n }));\n }\n /**\n * Adds a message event listener for URLs to cache from the window.\n * This is useful to cache resources loaded on the page prior to when the\n * service worker started controlling it.\n *\n * The format of the message data sent from the window should be as follows.\n * Where the `urlsToCache` array may consist of URL strings or an array of\n * URL string + `requestInit` object (the same as you'd pass to `fetch()`).\n *\n * ```\n * {\n * type: 'CACHE_URLS',\n * payload: {\n * urlsToCache: [\n * './script1.js',\n * './script2.js',\n * ['./script3.js', {mode: 'no-cors'}],\n * ],\n * },\n * }\n * ```\n */\n addCacheListener() {\n // See https://github.com/Microsoft/TypeScript/issues/28357#issuecomment-436484705\n self.addEventListener('message', ((event) => {\n // event.data is type 'any'\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n if (event.data && event.data.type === 'CACHE_URLS') {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const { payload } = event.data;\n if (process.env.NODE_ENV !== 'production') {\n logger.debug(`Caching URLs from the window`, payload.urlsToCache);\n }\n const requestPromises = Promise.all(payload.urlsToCache.map((entry) => {\n if (typeof entry === 'string') {\n entry = [entry];\n }\n const request = new Request(...entry);\n return this.handleRequest({ request, event });\n // TODO(philipwalton): TypeScript errors without this typecast for\n // some reason (probably a bug). The real type here should work but\n // doesn't: `Array | undefined>`.\n })); // TypeScript\n event.waitUntil(requestPromises);\n // If a MessageChannel was used, reply to the message on success.\n if (event.ports && event.ports[0]) {\n void requestPromises.then(() => event.ports[0].postMessage(true));\n }\n }\n }));\n }\n /**\n * Apply the routing rules to a FetchEvent object to get a Response from an\n * appropriate Route's handler.\n *\n * @param {Object} options\n * @param {Request} options.request The request to handle.\n * @param {ExtendableEvent} options.event The event that triggered the\n * request.\n * @return {Promise|undefined} A promise is returned if a\n * registered route can handle the request. If there is no matching\n * route and there's no `defaultHandler`, `undefined` is returned.\n */\n handleRequest({ request, event, }) {\n if (process.env.NODE_ENV !== 'production') {\n assert.isInstance(request, Request, {\n moduleName: 'workbox-routing',\n className: 'Router',\n funcName: 'handleRequest',\n paramName: 'options.request',\n });\n }\n const url = new URL(request.url, location.href);\n if (!url.protocol.startsWith('http')) {\n if (process.env.NODE_ENV !== 'production') {\n logger.debug(`Workbox Router only supports URLs that start with 'http'.`);\n }\n return;\n }\n const sameOrigin = url.origin === location.origin;\n const { params, route } = this.findMatchingRoute({\n event,\n request,\n sameOrigin,\n url,\n });\n let handler = route && route.handler;\n const debugMessages = [];\n if (process.env.NODE_ENV !== 'production') {\n if (handler) {\n debugMessages.push([`Found a route to handle this request:`, route]);\n if (params) {\n debugMessages.push([\n `Passing the following params to the route's handler:`,\n params,\n ]);\n }\n }\n }\n // If we don't have a handler because there was no matching route, then\n // fall back to defaultHandler if that's defined.\n const method = request.method;\n if (!handler && this._defaultHandlerMap.has(method)) {\n if (process.env.NODE_ENV !== 'production') {\n debugMessages.push(`Failed to find a matching route. Falling ` +\n `back to the default handler for ${method}.`);\n }\n handler = this._defaultHandlerMap.get(method);\n }\n if (!handler) {\n if (process.env.NODE_ENV !== 'production') {\n // No handler so Workbox will do nothing. If logs is set of debug\n // i.e. verbose, we should print out this information.\n logger.debug(`No route found for: ${getFriendlyURL(url)}`);\n }\n return;\n }\n if (process.env.NODE_ENV !== 'production') {\n // We have a handler, meaning Workbox is going to handle the route.\n // print the routing details to the console.\n logger.groupCollapsed(`Router is responding to: ${getFriendlyURL(url)}`);\n debugMessages.forEach((msg) => {\n if (Array.isArray(msg)) {\n logger.log(...msg);\n }\n else {\n logger.log(msg);\n }\n });\n logger.groupEnd();\n }\n // Wrap in try and catch in case the handle method throws a synchronous\n // error. It should still callback to the catch handler.\n let responsePromise;\n try {\n responsePromise = handler.handle({ url, request, event, params });\n }\n catch (err) {\n responsePromise = Promise.reject(err);\n }\n // Get route's catch handler, if it exists\n const catchHandler = route && route.catchHandler;\n if (responsePromise instanceof Promise &&\n (this._catchHandler || catchHandler)) {\n responsePromise = responsePromise.catch(async (err) => {\n // If there's a route catch handler, process that first\n if (catchHandler) {\n if (process.env.NODE_ENV !== 'production') {\n // Still include URL here as it will be async from the console group\n // and may not make sense without the URL\n logger.groupCollapsed(`Error thrown when responding to: ` +\n ` ${getFriendlyURL(url)}. Falling back to route's Catch Handler.`);\n logger.error(`Error thrown by:`, route);\n logger.error(err);\n logger.groupEnd();\n }\n try {\n return await catchHandler.handle({ url, request, event, params });\n }\n catch (catchErr) {\n if (catchErr instanceof Error) {\n err = catchErr;\n }\n }\n }\n if (this._catchHandler) {\n if (process.env.NODE_ENV !== 'production') {\n // Still include URL here as it will be async from the console group\n // and may not make sense without the URL\n logger.groupCollapsed(`Error thrown when responding to: ` +\n ` ${getFriendlyURL(url)}. Falling back to global Catch Handler.`);\n logger.error(`Error thrown by:`, route);\n logger.error(err);\n logger.groupEnd();\n }\n return this._catchHandler.handle({ url, request, event });\n }\n throw err;\n });\n }\n return responsePromise;\n }\n /**\n * Checks a request and URL (and optionally an event) against the list of\n * registered routes, and if there's a match, returns the corresponding\n * route along with any params generated by the match.\n *\n * @param {Object} options\n * @param {URL} options.url\n * @param {boolean} options.sameOrigin The result of comparing `url.origin`\n * against the current origin.\n * @param {Request} options.request The request to match.\n * @param {Event} options.event The corresponding event.\n * @return {Object} An object with `route` and `params` properties.\n * They are populated if a matching route was found or `undefined`\n * otherwise.\n */\n findMatchingRoute({ url, sameOrigin, request, event, }) {\n const routes = this._routes.get(request.method) || [];\n for (const route of routes) {\n let params;\n // route.match returns type any, not possible to change right now.\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const matchResult = route.match({ url, sameOrigin, request, event });\n if (matchResult) {\n if (process.env.NODE_ENV !== 'production') {\n // Warn developers that using an async matchCallback is almost always\n // not the right thing to do.\n if (matchResult instanceof Promise) {\n logger.warn(`While routing ${getFriendlyURL(url)}, an async ` +\n `matchCallback function was used. Please convert the ` +\n `following route to use a synchronous matchCallback function:`, route);\n }\n }\n // See https://github.com/GoogleChrome/workbox/issues/2079\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n params = matchResult;\n if (Array.isArray(params) && params.length === 0) {\n // Instead of passing an empty array in as params, use undefined.\n params = undefined;\n }\n else if (matchResult.constructor === Object && // eslint-disable-line\n Object.keys(matchResult).length === 0) {\n // Instead of passing an empty object in as params, use undefined.\n params = undefined;\n }\n else if (typeof matchResult === 'boolean') {\n // For the boolean value true (rather than just something truth-y),\n // don't set params.\n // See https://github.com/GoogleChrome/workbox/pull/2134#issuecomment-513924353\n params = undefined;\n }\n // Return early if have a match.\n return { route, params };\n }\n }\n // If no match was found above, return and empty object.\n return {};\n }\n /**\n * Define a default `handler` that's called when no routes explicitly\n * match the incoming request.\n *\n * Each HTTP method ('GET', 'POST', etc.) gets its own default handler.\n *\n * Without a default handler, unmatched requests will go against the\n * network as if there were no service worker present.\n *\n * @param {workbox-routing~handlerCallback} handler A callback\n * function that returns a Promise resulting in a Response.\n * @param {string} [method='GET'] The HTTP method to associate with this\n * default handler. Each method has its own default.\n */\n setDefaultHandler(handler, method = defaultMethod) {\n this._defaultHandlerMap.set(method, normalizeHandler(handler));\n }\n /**\n * If a Route throws an error while handling a request, this `handler`\n * will be called and given a chance to provide a response.\n *\n * @param {workbox-routing~handlerCallback} handler A callback\n * function that returns a Promise resulting in a Response.\n */\n setCatchHandler(handler) {\n this._catchHandler = normalizeHandler(handler);\n }\n /**\n * Registers a route with the router.\n *\n * @param {workbox-routing.Route} route The route to register.\n */\n registerRoute(route) {\n if (process.env.NODE_ENV !== 'production') {\n assert.isType(route, 'object', {\n moduleName: 'workbox-routing',\n className: 'Router',\n funcName: 'registerRoute',\n paramName: 'route',\n });\n assert.hasMethod(route, 'match', {\n moduleName: 'workbox-routing',\n className: 'Router',\n funcName: 'registerRoute',\n paramName: 'route',\n });\n assert.isType(route.handler, 'object', {\n moduleName: 'workbox-routing',\n className: 'Router',\n funcName: 'registerRoute',\n paramName: 'route',\n });\n assert.hasMethod(route.handler, 'handle', {\n moduleName: 'workbox-routing',\n className: 'Router',\n funcName: 'registerRoute',\n paramName: 'route.handler',\n });\n assert.isType(route.method, 'string', {\n moduleName: 'workbox-routing',\n className: 'Router',\n funcName: 'registerRoute',\n paramName: 'route.method',\n });\n }\n if (!this._routes.has(route.method)) {\n this._routes.set(route.method, []);\n }\n // Give precedence to all of the earlier routes by adding this additional\n // route to the end of the array.\n this._routes.get(route.method).push(route);\n }\n /**\n * Unregisters a route with the router.\n *\n * @param {workbox-routing.Route} route The route to unregister.\n */\n unregisterRoute(route) {\n if (!this._routes.has(route.method)) {\n throw new WorkboxError('unregister-route-but-not-found-with-method', {\n method: route.method,\n });\n }\n const routeIndex = this._routes.get(route.method).indexOf(route);\n if (routeIndex > -1) {\n this._routes.get(route.method).splice(routeIndex, 1);\n }\n else {\n throw new WorkboxError('unregister-route-route-not-registered');\n }\n }\n}\nexport { Router };\n","/*\n Copyright 2019 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { Router } from '../Router.js';\nimport '../_version.js';\nlet defaultRouter;\n/**\n * Creates a new, singleton Router instance if one does not exist. If one\n * does already exist, that instance is returned.\n *\n * @private\n * @return {Router}\n */\nexport const getOrCreateDefaultRouter = () => {\n if (!defaultRouter) {\n defaultRouter = new Router();\n // The helpers that use the default Router assume these listeners exist.\n defaultRouter.addFetchListener();\n defaultRouter.addCacheListener();\n }\n return defaultRouter;\n};\n","/*\n Copyright 2019 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { WorkboxError } from 'workbox-core/_private/WorkboxError.js';\nimport { Route } from './Route.js';\nimport { RegExpRoute } from './RegExpRoute.js';\nimport { getOrCreateDefaultRouter } from './utils/getOrCreateDefaultRouter.js';\nimport './_version.js';\n/**\n * Easily register a RegExp, string, or function with a caching\n * strategy to a singleton Router instance.\n *\n * This method will generate a Route for you if needed and\n * call {@link workbox-routing.Router#registerRoute}.\n *\n * @param {RegExp|string|workbox-routing.Route~matchCallback|workbox-routing.Route} capture\n * If the capture param is a `Route`, all other arguments will be ignored.\n * @param {workbox-routing~handlerCallback} [handler] A callback\n * function that returns a Promise resulting in a Response. This parameter\n * is required if `capture` is not a `Route` object.\n * @param {string} [method='GET'] The HTTP method to match the Route\n * against.\n * @return {workbox-routing.Route} The generated `Route`.\n *\n * @memberof workbox-routing\n */\nfunction registerRoute(capture, handler, method) {\n let route;\n if (typeof capture === 'string') {\n const captureUrl = new URL(capture, location.href);\n if (process.env.NODE_ENV !== 'production') {\n if (!(capture.startsWith('/') || capture.startsWith('http'))) {\n throw new WorkboxError('invalid-string', {\n moduleName: 'workbox-routing',\n funcName: 'registerRoute',\n paramName: 'capture',\n });\n }\n // We want to check if Express-style wildcards are in the pathname only.\n // TODO: Remove this log message in v4.\n const valueToCheck = capture.startsWith('http')\n ? captureUrl.pathname\n : capture;\n // See https://github.com/pillarjs/path-to-regexp#parameters\n const wildcards = '[*:?+]';\n if (new RegExp(`${wildcards}`).exec(valueToCheck)) {\n logger.debug(`The '$capture' parameter contains an Express-style wildcard ` +\n `character (${wildcards}). Strings are now always interpreted as ` +\n `exact matches; use a RegExp for partial or wildcard matches.`);\n }\n }\n const matchCallback = ({ url }) => {\n if (process.env.NODE_ENV !== 'production') {\n if (url.pathname === captureUrl.pathname &&\n url.origin !== captureUrl.origin) {\n logger.debug(`${capture} only partially matches the cross-origin URL ` +\n `${url.toString()}. This route will only handle cross-origin requests ` +\n `if they match the entire URL.`);\n }\n }\n return url.href === captureUrl.href;\n };\n // If `capture` is a string then `handler` and `method` must be present.\n route = new Route(matchCallback, handler, method);\n }\n else if (capture instanceof RegExp) {\n // If `capture` is a `RegExp` then `handler` and `method` must be present.\n route = new RegExpRoute(capture, handler, method);\n }\n else if (typeof capture === 'function') {\n // If `capture` is a function then `handler` and `method` must be present.\n route = new Route(capture, handler, method);\n }\n else if (capture instanceof Route) {\n route = capture;\n }\n else {\n throw new WorkboxError('unsupported-route-type', {\n moduleName: 'workbox-routing',\n funcName: 'registerRoute',\n paramName: 'capture',\n });\n }\n const defaultRouter = getOrCreateDefaultRouter();\n defaultRouter.registerRoute(route);\n return route;\n}\nexport { registerRoute };\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\nconst _cacheNameDetails = {\n googleAnalytics: 'googleAnalytics',\n precache: 'precache-v2',\n prefix: 'workbox',\n runtime: 'runtime',\n suffix: typeof registration !== 'undefined' ? registration.scope : '',\n};\nconst _createCacheName = (cacheName) => {\n return [_cacheNameDetails.prefix, cacheName, _cacheNameDetails.suffix]\n .filter((value) => value && value.length > 0)\n .join('-');\n};\nconst eachCacheNameDetail = (fn) => {\n for (const key of Object.keys(_cacheNameDetails)) {\n fn(key);\n }\n};\nexport const cacheNames = {\n updateDetails: (details) => {\n eachCacheNameDetail((key) => {\n if (typeof details[key] === 'string') {\n _cacheNameDetails[key] = details[key];\n }\n });\n },\n getGoogleAnalyticsName: (userCacheName) => {\n return userCacheName || _createCacheName(_cacheNameDetails.googleAnalytics);\n },\n getPrecacheName: (userCacheName) => {\n return userCacheName || _createCacheName(_cacheNameDetails.precache);\n },\n getPrefix: () => {\n return _cacheNameDetails.prefix;\n },\n getRuntimeName: (userCacheName) => {\n return userCacheName || _createCacheName(_cacheNameDetails.runtime);\n },\n getSuffix: () => {\n return _cacheNameDetails.suffix;\n },\n};\n","/*\n Copyright 2020 Google LLC\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\nfunction stripParams(fullURL, ignoreParams) {\n const strippedURL = new URL(fullURL);\n for (const param of ignoreParams) {\n strippedURL.searchParams.delete(param);\n }\n return strippedURL.href;\n}\n/**\n * Matches an item in the cache, ignoring specific URL params. This is similar\n * to the `ignoreSearch` option, but it allows you to ignore just specific\n * params (while continuing to match on the others).\n *\n * @private\n * @param {Cache} cache\n * @param {Request} request\n * @param {Object} matchOptions\n * @param {Array} ignoreParams\n * @return {Promise}\n */\nasync function cacheMatchIgnoreParams(cache, request, ignoreParams, matchOptions) {\n const strippedRequestURL = stripParams(request.url, ignoreParams);\n // If the request doesn't include any ignored params, match as normal.\n if (request.url === strippedRequestURL) {\n return cache.match(request, matchOptions);\n }\n // Otherwise, match by comparing keys\n const keysOptions = Object.assign(Object.assign({}, matchOptions), { ignoreSearch: true });\n const cacheKeys = await cache.keys(request, keysOptions);\n for (const cacheKey of cacheKeys) {\n const strippedCacheKeyURL = stripParams(cacheKey.url, ignoreParams);\n if (strippedRequestURL === strippedCacheKeyURL) {\n return cache.match(cacheKey, matchOptions);\n }\n }\n return;\n}\nexport { cacheMatchIgnoreParams };\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n/**\n * The Deferred class composes Promises in a way that allows for them to be\n * resolved or rejected from outside the constructor. In most cases promises\n * should be used directly, but Deferreds can be necessary when the logic to\n * resolve a promise must be separate.\n *\n * @private\n */\nclass Deferred {\n /**\n * Creates a promise and exposes its resolve and reject functions as methods.\n */\n constructor() {\n this.promise = new Promise((resolve, reject) => {\n this.resolve = resolve;\n this.reject = reject;\n });\n }\n}\nexport { Deferred };\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n// Callbacks to be executed whenever there's a quota error.\n// Can't change Function type right now.\n// eslint-disable-next-line @typescript-eslint/ban-types\nconst quotaErrorCallbacks = new Set();\nexport { quotaErrorCallbacks };\n","\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:strategies:6.5.4'] && _();\n}\ncatch (e) { }\n","/*\n Copyright 2020 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { assert } from 'workbox-core/_private/assert.js';\nimport { cacheMatchIgnoreParams } from 'workbox-core/_private/cacheMatchIgnoreParams.js';\nimport { Deferred } from 'workbox-core/_private/Deferred.js';\nimport { executeQuotaErrorCallbacks } from 'workbox-core/_private/executeQuotaErrorCallbacks.js';\nimport { getFriendlyURL } from 'workbox-core/_private/getFriendlyURL.js';\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { timeout } from 'workbox-core/_private/timeout.js';\nimport { WorkboxError } from 'workbox-core/_private/WorkboxError.js';\nimport './_version.js';\nfunction toRequest(input) {\n return typeof input === 'string' ? new Request(input) : input;\n}\n/**\n * A class created every time a Strategy instance instance calls\n * {@link workbox-strategies.Strategy~handle} or\n * {@link workbox-strategies.Strategy~handleAll} that wraps all fetch and\n * cache actions around plugin callbacks and keeps track of when the strategy\n * is \"done\" (i.e. all added `event.waitUntil()` promises have resolved).\n *\n * @memberof workbox-strategies\n */\nclass StrategyHandler {\n /**\n * Creates a new instance associated with the passed strategy and event\n * that's handling the request.\n *\n * The constructor also initializes the state that will be passed to each of\n * the plugins handling this request.\n *\n * @param {workbox-strategies.Strategy} strategy\n * @param {Object} options\n * @param {Request|string} options.request A request to run this strategy for.\n * @param {ExtendableEvent} options.event The event associated with the\n * request.\n * @param {URL} [options.url]\n * @param {*} [options.params] The return value from the\n * {@link workbox-routing~matchCallback} (if applicable).\n */\n constructor(strategy, options) {\n this._cacheKeys = {};\n /**\n * The request the strategy is performing (passed to the strategy's\n * `handle()` or `handleAll()` method).\n * @name request\n * @instance\n * @type {Request}\n * @memberof workbox-strategies.StrategyHandler\n */\n /**\n * The event associated with this request.\n * @name event\n * @instance\n * @type {ExtendableEvent}\n * @memberof workbox-strategies.StrategyHandler\n */\n /**\n * A `URL` instance of `request.url` (if passed to the strategy's\n * `handle()` or `handleAll()` method).\n * Note: the `url` param will be present if the strategy was invoked\n * from a workbox `Route` object.\n * @name url\n * @instance\n * @type {URL|undefined}\n * @memberof workbox-strategies.StrategyHandler\n */\n /**\n * A `param` value (if passed to the strategy's\n * `handle()` or `handleAll()` method).\n * Note: the `param` param will be present if the strategy was invoked\n * from a workbox `Route` object and the\n * {@link workbox-routing~matchCallback} returned\n * a truthy value (it will be that value).\n * @name params\n * @instance\n * @type {*|undefined}\n * @memberof workbox-strategies.StrategyHandler\n */\n if (process.env.NODE_ENV !== 'production') {\n assert.isInstance(options.event, ExtendableEvent, {\n moduleName: 'workbox-strategies',\n className: 'StrategyHandler',\n funcName: 'constructor',\n paramName: 'options.event',\n });\n }\n Object.assign(this, options);\n this.event = options.event;\n this._strategy = strategy;\n this._handlerDeferred = new Deferred();\n this._extendLifetimePromises = [];\n // Copy the plugins list (since it's mutable on the strategy),\n // so any mutations don't affect this handler instance.\n this._plugins = [...strategy.plugins];\n this._pluginStateMap = new Map();\n for (const plugin of this._plugins) {\n this._pluginStateMap.set(plugin, {});\n }\n this.event.waitUntil(this._handlerDeferred.promise);\n }\n /**\n * Fetches a given request (and invokes any applicable plugin callback\n * methods) using the `fetchOptions` (for non-navigation requests) and\n * `plugins` defined on the `Strategy` object.\n *\n * The following plugin lifecycle methods are invoked when using this method:\n * - `requestWillFetch()`\n * - `fetchDidSucceed()`\n * - `fetchDidFail()`\n *\n * @param {Request|string} input The URL or request to fetch.\n * @return {Promise}\n */\n async fetch(input) {\n const { event } = this;\n let request = toRequest(input);\n if (request.mode === 'navigate' &&\n event instanceof FetchEvent &&\n event.preloadResponse) {\n const possiblePreloadResponse = (await event.preloadResponse);\n if (possiblePreloadResponse) {\n if (process.env.NODE_ENV !== 'production') {\n logger.log(`Using a preloaded navigation response for ` +\n `'${getFriendlyURL(request.url)}'`);\n }\n return possiblePreloadResponse;\n }\n }\n // If there is a fetchDidFail plugin, we need to save a clone of the\n // original request before it's either modified by a requestWillFetch\n // plugin or before the original request's body is consumed via fetch().\n const originalRequest = this.hasCallback('fetchDidFail')\n ? request.clone()\n : null;\n try {\n for (const cb of this.iterateCallbacks('requestWillFetch')) {\n request = await cb({ request: request.clone(), event });\n }\n }\n catch (err) {\n if (err instanceof Error) {\n throw new WorkboxError('plugin-error-request-will-fetch', {\n thrownErrorMessage: err.message,\n });\n }\n }\n // The request can be altered by plugins with `requestWillFetch` making\n // the original request (most likely from a `fetch` event) different\n // from the Request we make. Pass both to `fetchDidFail` to aid debugging.\n const pluginFilteredRequest = request.clone();\n try {\n let fetchResponse;\n // See https://github.com/GoogleChrome/workbox/issues/1796\n fetchResponse = await fetch(request, request.mode === 'navigate' ? undefined : this._strategy.fetchOptions);\n if (process.env.NODE_ENV !== 'production') {\n logger.debug(`Network request for ` +\n `'${getFriendlyURL(request.url)}' returned a response with ` +\n `status '${fetchResponse.status}'.`);\n }\n for (const callback of this.iterateCallbacks('fetchDidSucceed')) {\n fetchResponse = await callback({\n event,\n request: pluginFilteredRequest,\n response: fetchResponse,\n });\n }\n return fetchResponse;\n }\n catch (error) {\n if (process.env.NODE_ENV !== 'production') {\n logger.log(`Network request for ` +\n `'${getFriendlyURL(request.url)}' threw an error.`, error);\n }\n // `originalRequest` will only exist if a `fetchDidFail` callback\n // is being used (see above).\n if (originalRequest) {\n await this.runCallbacks('fetchDidFail', {\n error: error,\n event,\n originalRequest: originalRequest.clone(),\n request: pluginFilteredRequest.clone(),\n });\n }\n throw error;\n }\n }\n /**\n * Calls `this.fetch()` and (in the background) runs `this.cachePut()` on\n * the response generated by `this.fetch()`.\n *\n * The call to `this.cachePut()` automatically invokes `this.waitUntil()`,\n * so you do not have to manually call `waitUntil()` on the event.\n *\n * @param {Request|string} input The request or URL to fetch and cache.\n * @return {Promise}\n */\n async fetchAndCachePut(input) {\n const response = await this.fetch(input);\n const responseClone = response.clone();\n void this.waitUntil(this.cachePut(input, responseClone));\n return response;\n }\n /**\n * Matches a request from the cache (and invokes any applicable plugin\n * callback methods) using the `cacheName`, `matchOptions`, and `plugins`\n * defined on the strategy object.\n *\n * The following plugin lifecycle methods are invoked when using this method:\n * - cacheKeyWillByUsed()\n * - cachedResponseWillByUsed()\n *\n * @param {Request|string} key The Request or URL to use as the cache key.\n * @return {Promise} A matching response, if found.\n */\n async cacheMatch(key) {\n const request = toRequest(key);\n let cachedResponse;\n const { cacheName, matchOptions } = this._strategy;\n const effectiveRequest = await this.getCacheKey(request, 'read');\n const multiMatchOptions = Object.assign(Object.assign({}, matchOptions), { cacheName });\n cachedResponse = await caches.match(effectiveRequest, multiMatchOptions);\n if (process.env.NODE_ENV !== 'production') {\n if (cachedResponse) {\n logger.debug(`Found a cached response in '${cacheName}'.`);\n }\n else {\n logger.debug(`No cached response found in '${cacheName}'.`);\n }\n }\n for (const callback of this.iterateCallbacks('cachedResponseWillBeUsed')) {\n cachedResponse =\n (await callback({\n cacheName,\n matchOptions,\n cachedResponse,\n request: effectiveRequest,\n event: this.event,\n })) || undefined;\n }\n return cachedResponse;\n }\n /**\n * Puts a request/response pair in the cache (and invokes any applicable\n * plugin callback methods) using the `cacheName` and `plugins` defined on\n * the strategy object.\n *\n * The following plugin lifecycle methods are invoked when using this method:\n * - cacheKeyWillByUsed()\n * - cacheWillUpdate()\n * - cacheDidUpdate()\n *\n * @param {Request|string} key The request or URL to use as the cache key.\n * @param {Response} response The response to cache.\n * @return {Promise} `false` if a cacheWillUpdate caused the response\n * not be cached, and `true` otherwise.\n */\n async cachePut(key, response) {\n const request = toRequest(key);\n // Run in the next task to avoid blocking other cache reads.\n // https://github.com/w3c/ServiceWorker/issues/1397\n await timeout(0);\n const effectiveRequest = await this.getCacheKey(request, 'write');\n if (process.env.NODE_ENV !== 'production') {\n if (effectiveRequest.method && effectiveRequest.method !== 'GET') {\n throw new WorkboxError('attempt-to-cache-non-get-request', {\n url: getFriendlyURL(effectiveRequest.url),\n method: effectiveRequest.method,\n });\n }\n // See https://github.com/GoogleChrome/workbox/issues/2818\n const vary = response.headers.get('Vary');\n if (vary) {\n logger.debug(`The response for ${getFriendlyURL(effectiveRequest.url)} ` +\n `has a 'Vary: ${vary}' header. ` +\n `Consider setting the {ignoreVary: true} option on your strategy ` +\n `to ensure cache matching and deletion works as expected.`);\n }\n }\n if (!response) {\n if (process.env.NODE_ENV !== 'production') {\n logger.error(`Cannot cache non-existent response for ` +\n `'${getFriendlyURL(effectiveRequest.url)}'.`);\n }\n throw new WorkboxError('cache-put-with-no-response', {\n url: getFriendlyURL(effectiveRequest.url),\n });\n }\n const responseToCache = await this._ensureResponseSafeToCache(response);\n if (!responseToCache) {\n if (process.env.NODE_ENV !== 'production') {\n logger.debug(`Response '${getFriendlyURL(effectiveRequest.url)}' ` +\n `will not be cached.`, responseToCache);\n }\n return false;\n }\n const { cacheName, matchOptions } = this._strategy;\n const cache = await self.caches.open(cacheName);\n const hasCacheUpdateCallback = this.hasCallback('cacheDidUpdate');\n const oldResponse = hasCacheUpdateCallback\n ? await cacheMatchIgnoreParams(\n // TODO(philipwalton): the `__WB_REVISION__` param is a precaching\n // feature. Consider into ways to only add this behavior if using\n // precaching.\n cache, effectiveRequest.clone(), ['__WB_REVISION__'], matchOptions)\n : null;\n if (process.env.NODE_ENV !== 'production') {\n logger.debug(`Updating the '${cacheName}' cache with a new Response ` +\n `for ${getFriendlyURL(effectiveRequest.url)}.`);\n }\n try {\n await cache.put(effectiveRequest, hasCacheUpdateCallback ? responseToCache.clone() : responseToCache);\n }\n catch (error) {\n if (error instanceof Error) {\n // See https://developer.mozilla.org/en-US/docs/Web/API/DOMException#exception-QuotaExceededError\n if (error.name === 'QuotaExceededError') {\n await executeQuotaErrorCallbacks();\n }\n throw error;\n }\n }\n for (const callback of this.iterateCallbacks('cacheDidUpdate')) {\n await callback({\n cacheName,\n oldResponse,\n newResponse: responseToCache.clone(),\n request: effectiveRequest,\n event: this.event,\n });\n }\n return true;\n }\n /**\n * Checks the list of plugins for the `cacheKeyWillBeUsed` callback, and\n * executes any of those callbacks found in sequence. The final `Request`\n * object returned by the last plugin is treated as the cache key for cache\n * reads and/or writes. If no `cacheKeyWillBeUsed` plugin callbacks have\n * been registered, the passed request is returned unmodified\n *\n * @param {Request} request\n * @param {string} mode\n * @return {Promise}\n */\n async getCacheKey(request, mode) {\n const key = `${request.url} | ${mode}`;\n if (!this._cacheKeys[key]) {\n let effectiveRequest = request;\n for (const callback of this.iterateCallbacks('cacheKeyWillBeUsed')) {\n effectiveRequest = toRequest(await callback({\n mode,\n request: effectiveRequest,\n event: this.event,\n // params has a type any can't change right now.\n params: this.params, // eslint-disable-line\n }));\n }\n this._cacheKeys[key] = effectiveRequest;\n }\n return this._cacheKeys[key];\n }\n /**\n * Returns true if the strategy has at least one plugin with the given\n * callback.\n *\n * @param {string} name The name of the callback to check for.\n * @return {boolean}\n */\n hasCallback(name) {\n for (const plugin of this._strategy.plugins) {\n if (name in plugin) {\n return true;\n }\n }\n return false;\n }\n /**\n * Runs all plugin callbacks matching the given name, in order, passing the\n * given param object (merged ith the current plugin state) as the only\n * argument.\n *\n * Note: since this method runs all plugins, it's not suitable for cases\n * where the return value of a callback needs to be applied prior to calling\n * the next callback. See\n * {@link workbox-strategies.StrategyHandler#iterateCallbacks}\n * below for how to handle that case.\n *\n * @param {string} name The name of the callback to run within each plugin.\n * @param {Object} param The object to pass as the first (and only) param\n * when executing each callback. This object will be merged with the\n * current plugin state prior to callback execution.\n */\n async runCallbacks(name, param) {\n for (const callback of this.iterateCallbacks(name)) {\n // TODO(philipwalton): not sure why `any` is needed. It seems like\n // this should work with `as WorkboxPluginCallbackParam[C]`.\n await callback(param);\n }\n }\n /**\n * Accepts a callback and returns an iterable of matching plugin callbacks,\n * where each callback is wrapped with the current handler state (i.e. when\n * you call each callback, whatever object parameter you pass it will\n * be merged with the plugin's current state).\n *\n * @param {string} name The name fo the callback to run\n * @return {Array}\n */\n *iterateCallbacks(name) {\n for (const plugin of this._strategy.plugins) {\n if (typeof plugin[name] === 'function') {\n const state = this._pluginStateMap.get(plugin);\n const statefulCallback = (param) => {\n const statefulParam = Object.assign(Object.assign({}, param), { state });\n // TODO(philipwalton): not sure why `any` is needed. It seems like\n // this should work with `as WorkboxPluginCallbackParam[C]`.\n return plugin[name](statefulParam);\n };\n yield statefulCallback;\n }\n }\n }\n /**\n * Adds a promise to the\n * [extend lifetime promises]{@link https://w3c.github.io/ServiceWorker/#extendableevent-extend-lifetime-promises}\n * of the event event associated with the request being handled (usually a\n * `FetchEvent`).\n *\n * Note: you can await\n * {@link workbox-strategies.StrategyHandler~doneWaiting}\n * to know when all added promises have settled.\n *\n * @param {Promise} promise A promise to add to the extend lifetime promises\n * of the event that triggered the request.\n */\n waitUntil(promise) {\n this._extendLifetimePromises.push(promise);\n return promise;\n }\n /**\n * Returns a promise that resolves once all promises passed to\n * {@link workbox-strategies.StrategyHandler~waitUntil}\n * have settled.\n *\n * Note: any work done after `doneWaiting()` settles should be manually\n * passed to an event's `waitUntil()` method (not this handler's\n * `waitUntil()` method), otherwise the service worker thread my be killed\n * prior to your work completing.\n */\n async doneWaiting() {\n let promise;\n while ((promise = this._extendLifetimePromises.shift())) {\n await promise;\n }\n }\n /**\n * Stops running the strategy and immediately resolves any pending\n * `waitUntil()` promises.\n */\n destroy() {\n this._handlerDeferred.resolve(null);\n }\n /**\n * This method will call cacheWillUpdate on the available plugins (or use\n * status === 200) to determine if the Response is safe and valid to cache.\n *\n * @param {Request} options.request\n * @param {Response} options.response\n * @return {Promise}\n *\n * @private\n */\n async _ensureResponseSafeToCache(response) {\n let responseToCache = response;\n let pluginsUsed = false;\n for (const callback of this.iterateCallbacks('cacheWillUpdate')) {\n responseToCache =\n (await callback({\n request: this.request,\n response: responseToCache,\n event: this.event,\n })) || undefined;\n pluginsUsed = true;\n if (!responseToCache) {\n break;\n }\n }\n if (!pluginsUsed) {\n if (responseToCache && responseToCache.status !== 200) {\n responseToCache = undefined;\n }\n if (process.env.NODE_ENV !== 'production') {\n if (responseToCache) {\n if (responseToCache.status !== 200) {\n if (responseToCache.status === 0) {\n logger.warn(`The response for '${this.request.url}' ` +\n `is an opaque response. The caching strategy that you're ` +\n `using will not cache opaque responses by default.`);\n }\n else {\n logger.debug(`The response for '${this.request.url}' ` +\n `returned a status code of '${response.status}' and won't ` +\n `be cached as a result.`);\n }\n }\n }\n }\n }\n return responseToCache;\n }\n}\nexport { StrategyHandler };\n","/*\n Copyright 2019 Google LLC\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n/**\n * Returns a promise that resolves and the passed number of milliseconds.\n * This utility is an async/await-friendly version of `setTimeout`.\n *\n * @param {number} ms\n * @return {Promise}\n * @private\n */\nexport function timeout(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\nconst getFriendlyURL = (url) => {\n const urlObj = new URL(String(url), location.href);\n // See https://github.com/GoogleChrome/workbox/issues/2323\n // We want to include everything, except for the origin if it's same-origin.\n return urlObj.href.replace(new RegExp(`^${location.origin}`), '');\n};\nexport { getFriendlyURL };\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { logger } from '../_private/logger.js';\nimport { quotaErrorCallbacks } from '../models/quotaErrorCallbacks.js';\nimport '../_version.js';\n/**\n * Runs all of the callback functions, one at a time sequentially, in the order\n * in which they were registered.\n *\n * @memberof workbox-core\n * @private\n */\nasync function executeQuotaErrorCallbacks() {\n if (process.env.NODE_ENV !== 'production') {\n logger.log(`About to run ${quotaErrorCallbacks.size} ` +\n `callbacks to clean up caches.`);\n }\n for (const callback of quotaErrorCallbacks) {\n await callback();\n if (process.env.NODE_ENV !== 'production') {\n logger.log(callback, 'is complete.');\n }\n }\n if (process.env.NODE_ENV !== 'production') {\n logger.log('Finished running callbacks.');\n }\n}\nexport { executeQuotaErrorCallbacks };\n","/*\n Copyright 2020 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { cacheNames } from 'workbox-core/_private/cacheNames.js';\nimport { WorkboxError } from 'workbox-core/_private/WorkboxError.js';\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { getFriendlyURL } from 'workbox-core/_private/getFriendlyURL.js';\nimport { StrategyHandler } from './StrategyHandler.js';\nimport './_version.js';\n/**\n * An abstract base class that all other strategy classes must extend from:\n *\n * @memberof workbox-strategies\n */\nclass Strategy {\n /**\n * Creates a new instance of the strategy and sets all documented option\n * properties as public instance properties.\n *\n * Note: if a custom strategy class extends the base Strategy class and does\n * not need more than these properties, it does not need to define its own\n * constructor.\n *\n * @param {Object} [options]\n * @param {string} [options.cacheName] Cache name to store and retrieve\n * requests. Defaults to the cache names provided by\n * {@link workbox-core.cacheNames}.\n * @param {Array