From 0e0feed5daa8751b04bda7b4caac3854995cb0c8 Mon Sep 17 00:00:00 2001 From: Moonchild Date: Wed, 10 Jun 2020 01:19:37 +0000 Subject: Issue #1585 - Replace node.rootNode with node.getRootNode() This removes the (default disabled) node.rootNode readonly attribute and replaces it with a node.getRootNode() function per WhatWG spec discussion. Based on work by John Dai --- dom/tests/mochitest/webcomponents/mochitest.ini | 1 + .../mochitest/webcomponents/test_bug1269155.html | 89 ++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 dom/tests/mochitest/webcomponents/test_bug1269155.html (limited to 'dom/tests') diff --git a/dom/tests/mochitest/webcomponents/mochitest.ini b/dom/tests/mochitest/webcomponents/mochitest.ini index 496f7ea4d..f05140c57 100644 --- a/dom/tests/mochitest/webcomponents/mochitest.ini +++ b/dom/tests/mochitest/webcomponents/mochitest.ini @@ -46,3 +46,4 @@ support-files = [test_style_fallback_content.html] [test_unresolved_pseudo_class.html] [test_link_prefetch.html] +[test_bug1269155.html] diff --git a/dom/tests/mochitest/webcomponents/test_bug1269155.html b/dom/tests/mochitest/webcomponents/test_bug1269155.html new file mode 100644 index 000000000..f280ae1d2 --- /dev/null +++ b/dom/tests/mochitest/webcomponents/test_bug1269155.html @@ -0,0 +1,89 @@ + + + + + Test for Bug 1269155 + + + + + +Mozilla Bug 1269155 +

+ +
+
+
+ + + -- cgit v1.2.3 From 2b41c85019bd5fd7e62556b5d5bf6ace2a6d6963 Mon Sep 17 00:00:00 2001 From: Moonchild Date: Wed, 10 Jun 2020 21:08:58 +0000 Subject: Issue #1587 - Part 1: Implement FetchController/FetchSignal interface --- .../mochitest/fetch/file_fetch_controller.html | 40 ++++++++++++++++++++++ dom/tests/mochitest/fetch/mochitest.ini | 2 ++ .../mochitest/fetch/test_fetch_controller.html | 40 ++++++++++++++++++++++ 3 files changed, 82 insertions(+) create mode 100644 dom/tests/mochitest/fetch/file_fetch_controller.html create mode 100644 dom/tests/mochitest/fetch/test_fetch_controller.html (limited to 'dom/tests') diff --git a/dom/tests/mochitest/fetch/file_fetch_controller.html b/dom/tests/mochitest/fetch/file_fetch_controller.html new file mode 100644 index 000000000..6efa2fe0a --- /dev/null +++ b/dom/tests/mochitest/fetch/file_fetch_controller.html @@ -0,0 +1,40 @@ + diff --git a/dom/tests/mochitest/fetch/mochitest.ini b/dom/tests/mochitest/fetch/mochitest.ini index cf4477463..6dba08f98 100644 --- a/dom/tests/mochitest/fetch/mochitest.ini +++ b/dom/tests/mochitest/fetch/mochitest.ini @@ -1,6 +1,7 @@ [DEFAULT] support-files = fetch_test_framework.js + file_fetch_controller.html test_fetch_basic.js test_fetch_basic_http.js test_fetch_cors.js @@ -41,6 +42,7 @@ support-files = [test_fetch_basic_http.html] [test_fetch_basic_http_sw_reroute.html] [test_fetch_basic_http_sw_empty_reroute.html] +[test_fetch_controller.html] [test_fetch_cors.html] skip-if = toolkit == 'android' # Bug 1210282 [test_fetch_cors_sw_reroute.html] diff --git a/dom/tests/mochitest/fetch/test_fetch_controller.html b/dom/tests/mochitest/fetch/test_fetch_controller.html new file mode 100644 index 000000000..812fb9161 --- /dev/null +++ b/dom/tests/mochitest/fetch/test_fetch_controller.html @@ -0,0 +1,40 @@ + + + + + Test FetchController + + + + + + + + -- cgit v1.2.3 From 9e2da53a02356244c5dc0a3e7b7ec916740d3d51 Mon Sep 17 00:00:00 2001 From: Moonchild Date: Wed, 10 Jun 2020 21:33:28 +0000 Subject: Issue #1587 - Part 2: Implement controller follow/unfollow --- .../mochitest/fetch/file_fetch_controller.html | 68 ++++++++++++++++++++++ 1 file changed, 68 insertions(+) (limited to 'dom/tests') diff --git a/dom/tests/mochitest/fetch/file_fetch_controller.html b/dom/tests/mochitest/fetch/file_fetch_controller.html index 6efa2fe0a..791d21b2b 100644 --- a/dom/tests/mochitest/fetch/file_fetch_controller.html +++ b/dom/tests/mochitest/fetch/file_fetch_controller.html @@ -21,8 +21,76 @@ function testWebIDL() { next(); } +function testUpdateData() { + var fc = new FetchController(); + + is(fc.signal.aborted, false, "By default FetchSignal.aborted is false"); + + fc.abort(); + is(fc.signal.aborted, true, "Signal is aborted"); + + next(); +} + +function testFollowingOurself() { + // Let's follow ourself + var fc = new FetchController(); + fc.follow(fc.signal); + + fc.abort(); + is(fc.signal.aborted, true, "Signal is aborted"); + + next(); +} + +function testFollowingOther() { + // Let's follow another one + var fc1 = new FetchController(); + var fc2 = new FetchController(); + fc1.follow(fc2.signal); + + fc2.abort(); + + is(fc1.signal.aborted, true, "Signal is aborted"); + is(fc2.signal.aborted, true, "Signal is aborted"); + + next(); +} + +function testFollowingLoop() { + // fc1 -> fc2 -> fc3 -> fc1 + var fc1 = new FetchController(); + var fc2 = new FetchController(); + var fc3 = new FetchController(); + fc1.follow(fc2.signal); + fc2.follow(fc3.signal); + fc3.follow(fc1.signal); + + fc3.abort(); + + is(fc1.signal.aborted, true, "Signal is aborted"); + is(fc2.signal.aborted, true, "Signal is aborted"); + is(fc3.signal.aborted, true, "Signal is aborted"); + + next(); +} + +function testAbortEvent() { + var fc = new FetchController(); + fc.signal.onabort = function(e) { + is(e.type, "abort", "Abort received"); + next(); + } + fc.abort(); +} + var steps = [ testWebIDL, + testUpdateData, + testFollowingOurself, + testFollowingOther, + testFollowingLoop, + testAbortEvent, ]; function next() { -- cgit v1.2.3 From a04d67dd12d4999b28e74744150770482a3c5a3d Mon Sep 17 00:00:00 2001 From: Moonchild Date: Wed, 10 Jun 2020 21:51:44 +0000 Subject: Issue #1587 - Part 3: Hook FetchSignal up to the Fetch API --- .../mochitest/fetch/file_fetch_controller.html | 81 ++++++++++++++++++++++ 1 file changed, 81 insertions(+) (limited to 'dom/tests') diff --git a/dom/tests/mochitest/fetch/file_fetch_controller.html b/dom/tests/mochitest/fetch/file_fetch_controller.html index 791d21b2b..026ff16a8 100644 --- a/dom/tests/mochitest/fetch/file_fetch_controller.html +++ b/dom/tests/mochitest/fetch/file_fetch_controller.html @@ -84,13 +84,94 @@ function testAbortEvent() { fc.abort(); } +function testAbortedFetch() { + var fc = new FetchController(); + fc.abort(); + + fetch('data:,foo', { signal: fc.signal }).then(() => { + ok(false, "Fetch should not return a resolved promise"); + }, e => { + is(e.name, "AbortError", "We have an abort error"); + }).then(next); +} + +function testFetchAndAbort() { + var fc = new FetchController(); + + var p = fetch('data:,foo', { signal: fc.signal }); + fc.abort(); + + p.then(() => { + ok(false, "Fetch should not return a resolved promise"); + }, e => { + is(e.name, "AbortError", "We have an abort error"); + }).then(next); +} + +function testWorkerAbortedFetch() { + function worker() { + var fc = new FetchController(); + fc.abort(); + + fetch('data:,foo', { signal: fc.signal }).then(() => { + postMessage(false); + }, e => { + postMessage(e.name == "AbortError"); + }); + } + + var str = worker.toString(); + var content = str.substring(0, str.length - 1).split('\n').splice(1).join(' '); + var url = URL.createObjectURL(new Blob([content], { type: "application/javascript" })); + var w = new Worker(url); + w.onmessage = function(e) { + ok(e.data, "Abort + Fetch works in workers"); + next(); + } +} + +function testWorkerFetchAndAbort() { + function worker() { + var fc = new FetchController(); + + var p = fetch('data:,foo', { signal: fc.signal }); + fc.abort(); + + p.then(() => { + postMessage(false); + }, e => { + postMessage(e.name == "AbortError"); + }); + } + + var str = worker.toString(); + var content = str.substring(0, str.length - 1).split('\n').splice(1).join(' '); + var url = URL.createObjectURL(new Blob([content], { type: "application/javascript" })); + var w = new Worker(url); + w.onmessage = function(e) { + ok(e.data, "Abort + Fetch works in workers"); + next(); + } +} + var steps = [ + // Simple stuff testWebIDL, testUpdateData, + + // Following algorithm testFollowingOurself, testFollowingOther, testFollowingLoop, + + // Event propagation testAbortEvent, + + // fetch + signaling + testAbortedFetch, + testFetchAndAbort, + testWorkerAbortedFetch, + testWorkerFetchAndAbort, ]; function next() { -- cgit v1.2.3 From 3f3d626434b2533182ca0ee90adc92a1e7db373c Mon Sep 17 00:00:00 2001 From: Moonchild Date: Thu, 11 Jun 2020 08:22:04 +0000 Subject: Issue #1587 - Part 4: Implement FetchObserver --- dom/tests/mochitest/fetch/file_fetch_observer.html | 33 ++++++++++++++++++ dom/tests/mochitest/fetch/mochitest.ini | 2 ++ dom/tests/mochitest/fetch/test_fetch_observer.html | 40 ++++++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 dom/tests/mochitest/fetch/file_fetch_observer.html create mode 100644 dom/tests/mochitest/fetch/test_fetch_observer.html (limited to 'dom/tests') diff --git a/dom/tests/mochitest/fetch/file_fetch_observer.html b/dom/tests/mochitest/fetch/file_fetch_observer.html new file mode 100644 index 000000000..97af584ec --- /dev/null +++ b/dom/tests/mochitest/fetch/file_fetch_observer.html @@ -0,0 +1,33 @@ + diff --git a/dom/tests/mochitest/fetch/mochitest.ini b/dom/tests/mochitest/fetch/mochitest.ini index 6dba08f98..60fa454f4 100644 --- a/dom/tests/mochitest/fetch/mochitest.ini +++ b/dom/tests/mochitest/fetch/mochitest.ini @@ -5,6 +5,7 @@ support-files = test_fetch_basic.js test_fetch_basic_http.js test_fetch_cors.js + file_fetch_observer.html test_formdataparsing.js test_headers_common.js test_request.js @@ -49,6 +50,7 @@ skip-if = toolkit == 'android' # Bug 1210282 skip-if = toolkit == 'android' # Bug 1210282 [test_fetch_cors_sw_empty_reroute.html] skip-if = toolkit == 'android' # Bug 1210282 +[test_fetch_observer.html] [test_formdataparsing.html] [test_formdataparsing_sw_reroute.html] [test_request.html] diff --git a/dom/tests/mochitest/fetch/test_fetch_observer.html b/dom/tests/mochitest/fetch/test_fetch_observer.html new file mode 100644 index 000000000..2b6c0362d --- /dev/null +++ b/dom/tests/mochitest/fetch/test_fetch_observer.html @@ -0,0 +1,40 @@ + + + + + Test FetchObserver + + + + + + + + -- cgit v1.2.3 From bb7060582934f087b71702d1e83f762d5fd6f0af Mon Sep 17 00:00:00 2001 From: Moonchild Date: Thu, 11 Jun 2020 08:51:07 +0000 Subject: Issue #1587 - Part 5: Hook FetchObserver up to the Fetch API --- .../mochitest/fetch/file_fetch_controller.html | 40 ++----- dom/tests/mochitest/fetch/file_fetch_observer.html | 115 ++++++++++++++++++++- dom/tests/mochitest/fetch/mochitest.ini | 2 + dom/tests/mochitest/fetch/slow.sjs | 11 ++ dom/tests/mochitest/fetch/test_fetch_observer.html | 3 +- .../mochitest/fetch/worker_fetch_controller.js | 27 +++++ 6 files changed, 162 insertions(+), 36 deletions(-) create mode 100644 dom/tests/mochitest/fetch/slow.sjs create mode 100644 dom/tests/mochitest/fetch/worker_fetch_controller.js (limited to 'dom/tests') diff --git a/dom/tests/mochitest/fetch/file_fetch_controller.html b/dom/tests/mochitest/fetch/file_fetch_controller.html index 026ff16a8..e4137aac9 100644 --- a/dom/tests/mochitest/fetch/file_fetch_controller.html +++ b/dom/tests/mochitest/fetch/file_fetch_controller.html @@ -88,7 +88,7 @@ function testAbortedFetch() { var fc = new FetchController(); fc.abort(); - fetch('data:,foo', { signal: fc.signal }).then(() => { + fetch('slow.sjs', { signal: fc.signal }).then(() => { ok(false, "Fetch should not return a resolved promise"); }, e => { is(e.name, "AbortError", "We have an abort error"); @@ -98,7 +98,7 @@ function testAbortedFetch() { function testFetchAndAbort() { var fc = new FetchController(); - var p = fetch('data:,foo', { signal: fc.signal }); + var p = fetch('slow.sjs', { signal: fc.signal }); fc.abort(); p.then(() => { @@ -109,49 +109,21 @@ function testFetchAndAbort() { } function testWorkerAbortedFetch() { - function worker() { - var fc = new FetchController(); - fc.abort(); - - fetch('data:,foo', { signal: fc.signal }).then(() => { - postMessage(false); - }, e => { - postMessage(e.name == "AbortError"); - }); - } - - var str = worker.toString(); - var content = str.substring(0, str.length - 1).split('\n').splice(1).join(' '); - var url = URL.createObjectURL(new Blob([content], { type: "application/javascript" })); - var w = new Worker(url); + var w = new Worker('worker_fetch_controller.js'); w.onmessage = function(e) { ok(e.data, "Abort + Fetch works in workers"); next(); } + w.postMessage('testWorkerAbortedFetch'); } function testWorkerFetchAndAbort() { - function worker() { - var fc = new FetchController(); - - var p = fetch('data:,foo', { signal: fc.signal }); - fc.abort(); - - p.then(() => { - postMessage(false); - }, e => { - postMessage(e.name == "AbortError"); - }); - } - - var str = worker.toString(); - var content = str.substring(0, str.length - 1).split('\n').splice(1).join(' '); - var url = URL.createObjectURL(new Blob([content], { type: "application/javascript" })); - var w = new Worker(url); + var w = new Worker('worker_fetch_controller.js'); w.onmessage = function(e) { ok(e.data, "Abort + Fetch works in workers"); next(); } + w.postMessage('testWorkerFetchAndAbort'); } var steps = [ diff --git a/dom/tests/mochitest/fetch/file_fetch_observer.html b/dom/tests/mochitest/fetch/file_fetch_observer.html index 97af584ec..a172a18dc 100644 --- a/dom/tests/mochitest/fetch/file_fetch_observer.html +++ b/dom/tests/mochitest/fetch/file_fetch_observer.html @@ -10,12 +10,125 @@ function is(a, b, msg) { function testObserver() { ok("FetchObserver" in self, "We have a FetchObserver prototype"); - fetch('data:,foo', { observe: o => { + fetch('http://mochi.test:8888/tests/dom/tests/mochitest/fetch/slow.sjs', { observe: o => { + ok(!!o, "We have an observer"); + ok(o instanceof FetchObserver, "The correct object has been passed"); + is(o.state, "requesting", "By default the state is requesting"); + next(); }}); } +function testObserveAbort() { + var fc = new FetchController(); + + fetch('http://mochi.test:8888/tests/dom/tests/mochitest/fetch/slow.sjs', { + signal: fc.signal, + observe: o => { + o.onstatechange = () => { + ok(true, "StateChange event dispatched"); + if (o.state == "aborted") { + ok(true, "Aborted!"); + next(); + } + } + fc.abort(); + } + }); +} + +function testObserveComplete() { + var fc = new FetchController(); + + fetch('http://mochi.test:8888/tests/dom/tests/mochitest/fetch/slow.sjs', { + signal: fc.signal, + observe: o => { + o.onstatechange = () => { + ok(true, "StateChange event dispatched"); + if (o.state == "complete") { + ok(true, "Operation completed"); + next(); + } + } + } + }); +} + +function testObserveErrored() { + var fc = new FetchController(); + + fetch('foo: bar', { + signal: fc.signal, + observe: o => { + o.onstatechange = () => { + ok(true, "StateChange event dispatched"); + if (o.state == "errored") { + ok(true, "Operation completed"); + next(); + } + } + } + }); +} + +function testObserveResponding() { + var fc = new FetchController(); + + fetch('http://mochi.test:8888/tests/dom/tests/mochitest/fetch/slow.sjs', { + signal: fc.signal, + observe: o => { + o.onstatechange = () => { + if (o.state == "responding") { + ok(true, "We have responding events"); + next(); + } + } + } + }); +} + +function workify(worker) { + function methods() { + function ok(a, msg) { + postMessage( { type: 'check', state: !!a, message: msg }); + }; + function is(a, b, msg) { + postMessage( { type: 'check', state: a === b, message: msg }); + }; + function next() { + postMessage( { type: 'finish' }); + }; + } + + var str = methods.toString(); + var methodsContent = str.substring(0, str.length - 1).split('\n').splice(1).join('\n'); + + str = worker.toString(); + var workerContent = str.substring(0, str.length - 1).split('\n').splice(1).join('\n'); + + var content = methodsContent + workerContent; + var url = URL.createObjectURL(new Blob([content], { type: "application/javascript" })); + var w = new Worker(url); + w.onmessage = e => { + if (e.data.type == 'check') { + ok(e.data.state, "WORKER: " + e.data.message); + } else if (e.data.type == 'finish') { + next(); + } else { + ok(false, "Something went wrong"); + } + } +} + var steps = [ testObserver, + testObserveAbort, + function() { workify(testObserveAbort); }, + testObserveComplete, + function() { workify(testObserveComplete); }, + testObserveErrored, + function() { workify(testObserveErrored); }, + testObserveResponding, + function() { workify(testObserveResponding); }, ]; function next() { diff --git a/dom/tests/mochitest/fetch/mochitest.ini b/dom/tests/mochitest/fetch/mochitest.ini index 60fa454f4..7493ede50 100644 --- a/dom/tests/mochitest/fetch/mochitest.ini +++ b/dom/tests/mochitest/fetch/mochitest.ini @@ -17,11 +17,13 @@ support-files = reroute.html reroute.js reroute.js^headers^ + slow.sjs sw_reroute.js empty.js empty.js^headers^ worker_temporaryFileBlob.js common_temporaryFileBlob.js + worker_fetch_controller.js !/dom/xhr/tests/file_XHR_binary1.bin !/dom/xhr/tests/file_XHR_binary1.bin^headers^ !/dom/xhr/tests/file_XHR_binary2.bin diff --git a/dom/tests/mochitest/fetch/slow.sjs b/dom/tests/mochitest/fetch/slow.sjs new file mode 100644 index 000000000..feab0f1fc --- /dev/null +++ b/dom/tests/mochitest/fetch/slow.sjs @@ -0,0 +1,11 @@ +function handleRequest(request, response) +{ + response.processAsync(); + + timer = Components.classes["@mozilla.org/timer;1"]. + createInstance(Components.interfaces.nsITimer); + timer.init(function() { + response.write("Here the content. But slowly."); + response.finish(); + }, 1000, Components.interfaces.nsITimer.TYPE_ONE_SHOT); +} diff --git a/dom/tests/mochitest/fetch/test_fetch_observer.html b/dom/tests/mochitest/fetch/test_fetch_observer.html index 2b6c0362d..2af86977c 100644 --- a/dom/tests/mochitest/fetch/test_fetch_observer.html +++ b/dom/tests/mochitest/fetch/test_fetch_observer.html @@ -12,7 +12,8 @@ diff --git a/dom/tests/mochitest/fetch/mochitest.ini b/dom/tests/mochitest/fetch/mochitest.ini index 7493ede50..a9447d0d9 100644 --- a/dom/tests/mochitest/fetch/mochitest.ini +++ b/dom/tests/mochitest/fetch/mochitest.ini @@ -1,7 +1,6 @@ [DEFAULT] support-files = fetch_test_framework.js - file_fetch_controller.html test_fetch_basic.js test_fetch_basic_http.js test_fetch_cors.js @@ -23,7 +22,6 @@ support-files = empty.js^headers^ worker_temporaryFileBlob.js common_temporaryFileBlob.js - worker_fetch_controller.js !/dom/xhr/tests/file_XHR_binary1.bin !/dom/xhr/tests/file_XHR_binary1.bin^headers^ !/dom/xhr/tests/file_XHR_binary2.bin @@ -45,7 +43,6 @@ support-files = [test_fetch_basic_http.html] [test_fetch_basic_http_sw_reroute.html] [test_fetch_basic_http_sw_empty_reroute.html] -[test_fetch_controller.html] [test_fetch_cors.html] skip-if = toolkit == 'android' # Bug 1210282 [test_fetch_cors_sw_reroute.html] diff --git a/dom/tests/mochitest/fetch/test_fetch_controller.html b/dom/tests/mochitest/fetch/test_fetch_controller.html deleted file mode 100644 index 812fb9161..000000000 --- a/dom/tests/mochitest/fetch/test_fetch_controller.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - - Test FetchController - - - - - - - - diff --git a/dom/tests/mochitest/fetch/worker_fetch_controller.js b/dom/tests/mochitest/fetch/worker_fetch_controller.js deleted file mode 100644 index 6b008fea8..000000000 --- a/dom/tests/mochitest/fetch/worker_fetch_controller.js +++ /dev/null @@ -1,27 +0,0 @@ -function testWorkerAbortedFetch() { - var fc = new FetchController(); - fc.abort(); - - fetch('slow.sjs', { signal: fc.signal }).then(() => { - postMessage(false); - }, e => { - postMessage(e.name == "AbortError"); - }); -} - -function testWorkerFetchAndAbort() { - var fc = new FetchController(); - - var p = fetch('slow.sjs', { signal: fc.signal }); - fc.abort(); - - p.then(() => { - postMessage(false); - }, e => { - postMessage(e.name == "AbortError"); - }); -} - -onmessage = function(e) { - self[e.data](); -} -- cgit v1.2.3 From 21403c31e0288ad3c1921019f6f6185a0019a9a4 Mon Sep 17 00:00:00 2001 From: Moonchild Date: Thu, 11 Jun 2020 23:20:52 +0000 Subject: Issue #1587 - Part 7: Rename FetchController to AbortController Also renames FetchSignal to AbortSignal. Includes renaming the various controlling prefs to enable. --- dom/tests/mochitest/fetch/file_fetch_observer.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'dom/tests') diff --git a/dom/tests/mochitest/fetch/file_fetch_observer.html b/dom/tests/mochitest/fetch/file_fetch_observer.html index a172a18dc..668e609ec 100644 --- a/dom/tests/mochitest/fetch/file_fetch_observer.html +++ b/dom/tests/mochitest/fetch/file_fetch_observer.html @@ -19,7 +19,7 @@ function testObserver() { } function testObserveAbort() { - var fc = new FetchController(); + var fc = new AbortController(); fetch('http://mochi.test:8888/tests/dom/tests/mochitest/fetch/slow.sjs', { signal: fc.signal, @@ -37,7 +37,7 @@ function testObserveAbort() { } function testObserveComplete() { - var fc = new FetchController(); + var fc = new AbortController(); fetch('http://mochi.test:8888/tests/dom/tests/mochitest/fetch/slow.sjs', { signal: fc.signal, @@ -54,7 +54,7 @@ function testObserveComplete() { } function testObserveErrored() { - var fc = new FetchController(); + var fc = new AbortController(); fetch('foo: bar', { signal: fc.signal, @@ -71,7 +71,7 @@ function testObserveErrored() { } function testObserveResponding() { - var fc = new FetchController(); + var fc = new AbortController(); fetch('http://mochi.test:8888/tests/dom/tests/mochitest/fetch/slow.sjs', { signal: fc.signal, -- cgit v1.2.3