Add error catching, viewing and reporting via sentry

This commit is contained in:
Ilya Ig. Petrov 2016-12-02 10:52:11 -08:00
parent 6750872ea5
commit 38ac7450a6
13 changed files with 607 additions and 234 deletions

View File

@ -4,7 +4,6 @@
const handlersState = function(key, value) { const handlersState = function(key, value) {
console.log(key, value, '!');
key = 'handlers-' + key; key = 'handlers-' + key;
if (value === null) { if (value === null) {
return localStorage.removeItem(key); return localStorage.removeItem(key);
@ -21,6 +20,7 @@
}; };
const ifPrefix = 'if-on-'; const ifPrefix = 'if-on-';
const extName = chrome.runtime.getManifest().name;
window.apis.errorHandlers = { window.apis.errorHandlers = {
@ -67,29 +67,19 @@
}, },
}; idToErr: {},
} mayNotify(
id, title, errOrMessage,
// INIT
chrome.proxy.settings.get(
{},
(details) => window.apis.errorHandlers.isNotControlled(details)
);
{
const extName = chrome.runtime.getManifest().name;
const mayNotify = function(
id, title, message,
icon = 'default-128.png', icon = 'default-128.png',
context = extName context = extName
) { ) {
if ( !window.apis.errorHandlers.isOn(id) ) { if ( !this.isOn(id) ) {
return; return;
} }
this.idToErr[id] = errOrMessage;
const message = errOrMessage.message || errOrMessage.toString();
chrome.notifications.create( chrome.notifications.create(
id, id,
{ {
@ -103,31 +93,66 @@ chrome.proxy.settings.get(
} }
); );
}; },
window.addEventListener('error', (err) => { installListenersOn(win, name, cb) {
console.warn('GLOBAL ERROR', err); win.addEventListener('error', (errEvent) => {
mayNotify('ext-error', 'Unhandled error', JSON.stringify(err),
console.warn(name + ':GLOBAL ERROR', errEvent);
this.mayNotify('ext-error', 'Ошибка расширения', errEvent,
'ext-error-128.png'); 'ext-error-128.png');
}); });
window.addEventListener('unhandledrejection', (event) => { win.addEventListener('unhandledrejection', (event) => {
console.warn('Unhandled rejection. Throwing error.'); console.warn(name + ':Unhandled rejection. Throwing error.');
event.preventDefault(); event.preventDefault();
throw event.reason; throw event.reason;
}); });
if (cb) {
// setTimeout changes error context.
setTimeout(cb, 0);
}
},
};
}
{
const handlers = window.apis.errorHandlers;
// INIT
chrome.proxy.settings.get(
{},
(details) => handlers.isNotControlled(details)
);
chrome.notifications.onClicked.addListener( function(notId) {
chrome.notifications.clear(notId);
if(notId === 'no-control') {
return chrome.tabs.create({active: true, url: 'chrome://settings/#proxy'});
}
chrome.tabs.create({active: true, url: './pages/view-error/index.html#' + notId});
});
handlers.installListenersOn(window, 'BG');
chrome.proxy.onProxyError.addListener((details) => { chrome.proxy.onProxyError.addListener((details) => {
if (window.apis.errorHandlers.ifNoControl) { if (handlers.ifNoControl) {
return; return;
} }
console.warn('PAC ERROR', details); console.warn('PAC ERROR', details);
mayNotify('pac-error', ' PAC !', JSON.stringify(details), handlers.mayNotify('pac-error', 'Ошибка PAC!', details,
'pac-error-128.png' ); 'pac-error-128.png' );
}); });
@ -136,8 +161,9 @@ chrome.proxy.settings.get(
console.log('Proxy settings changed.', details); console.log('Proxy settings changed.', details);
const noCon = 'no-control'; const noCon = 'no-control';
if ( window.apis.errorHandlers.isNotControlled(details) ) { if ( handlers.isNotControlled(details) ) {
mayNotify(noCon, 'Proxy changed', JSON.stringify(details), console.log(details);
handlers.mayNotify(noCon, 'Прокси контролирует другое расширение', details,
'no-control-128.png'); 'no-control-128.png');
} else { } else {
chrome.notifications.clear( noCon ); chrome.notifications.clear( noCon );

View File

@ -99,7 +99,7 @@
_periodicUpdateAlarmReason: 'Периодичное обновление PAC-скрипта Антизапрет', _periodicUpdateAlarmReason: 'Периодичное обновление PAC-скрипта Антизапрет',
pushToStorage(cb) { pushToStorageAsync(cb) {
console.log('Pushing to storage...'); console.log('Pushing to storage...');
@ -143,7 +143,7 @@
}, },
*/ */
syncWithPacProvider(key, cb) { syncWithPacProviderAsync(key, cb) {
if( !key || typeof(key) === 'function' ) { if( !key || typeof(key) === 'function' ) {
cb = key; cb = key;
@ -200,7 +200,7 @@
if (pacErr && ipsErr) { if (pacErr && ipsErr) {
return cb(pacErr, pacRes); return cb(pacErr, pacRes);
} }
this.pushToStorage( this.pushToStorageAsync(
(pushErr) => cb(pacErr || ipsErr || pushErr, pacRes) (pushErr) => cb(pacErr || ipsErr || pushErr, pacRes)
); );
@ -239,21 +239,21 @@
}, },
installPac(key, cb) { installPacAsync(key, cb) {
console.log('Installing PAC...'); console.log('Installing PAC...');
if (!key) { if (!key) {
throw new Error('Key must be defined.'); throw new Error('Key must be defined.');
} }
if (this.currentProviderKey !== key) { if (this.currentProviderKey !== key) {
return this.syncWithPacProvider(key, cb); return this.syncWithPacProviderAsync(key, cb);
} }
console.log(key + ' already installed.'); console.log(key + ' already installed.');
cb(); cb();
}, },
clearPac(cb) { clearPacAsync(cb) {
cb = asyncLogGroup('Cearing alarms and PAC...', cb); cb = asyncLogGroup('Cearing alarms and PAC...', cb);
chrome.alarms.clearAll( chrome.alarms.clearAll(
@ -266,7 +266,7 @@
return cb(err); return cb(err);
} }
this.currentPacProviderKey = null; this.currentPacProviderKey = null;
this.pushToStorage(cb); this.pushToStorageAsync(cb);
} }
) )
@ -296,7 +296,7 @@
'Periodic PAC update triggered:', 'Periodic PAC update triggered:',
new Date().toLocaleString('ru-RU') new Date().toLocaleString('ru-RU')
); );
antiCensorRu.syncWithPacProvider(/* Swallows errors. */); antiCensorRu.syncWithPacProviderAsync(/* Swallows errors. */);
} }
} }
@ -358,7 +358,7 @@
// UPDATE & MIGRATION // UPDATE & MIGRATION
console.log('Extension updated.'); console.log('Extension updated.');
if (!ifAlarmTriggered) { if (!ifAlarmTriggered) {
antiCensorRu.pushToStorage(/* Swallows errors. */); antiCensorRu.pushToStorageAsync(/* Swallows errors. */);
} }
/* /*
@ -414,7 +414,9 @@
args = replaceArgs; args = replaceArgs;
} }
const err = checkChromeError(stack); const err = checkChromeError(stack);
cb && cb.call(null, err, ...args); if (cb) {
setTimeout( cb.bind(null, err, ...args), 0 );
}
}; };

View File

@ -4,20 +4,23 @@
(e.g. popup) to background window, so we may catch errors (e.g. popup) to background window, so we may catch errors
in bg error handlers. in bg error handlers.
More: https://bugs.chromium.org/p/chromium/issues/detail?id=357568 More: https://bugs.chromium.org/p/chromium/issues/detail?id=357568
setTimeout is applied to Async methods only (name ends with Async)
*/ */
// Fix error context of methods of all APIs. // Fix error context of methods of all APIs.
for(const api of Object.keys(window.apis)) { /*
for(const apiName of Object.keys(window.apis)) {
const api = window.apis[apiName];
for(const prop of Object.keys(api)) { for(const prop of Object.keys(api)) {
if ( typeof(api[prop]) !== 'function' ) { const method = api[prop];
if ( !(typeof(api[prop]) === 'function'
&& method.name.endsWith('Async')) ) {
continue; continue;
} }
const method = api[prop];
api[prop] = function(...args) { api[prop] = function(...args) {
setTimeout(method.bind(this, ...args), 0); setTimeout(method.bind(this, ...args), 0);
}; };
} }
} }*/

View File

@ -20,6 +20,7 @@
"contextMenus", "contextMenus",
"notifications" "notifications"
], ],
"background": { "background": {
"scripts": ["00-init-apis.js", "11-api-error-handlers.js", "12-api-sync-pac-script-with-pac-provider.js", "20-api-fixes.js", "30-block-informer.js", "40-context-menus.js"] "scripts": ["00-init-apis.js", "11-api-error-handlers.js", "12-api-sync-pac-script-with-pac-provider.js", "20-api-fixes.js", "30-block-informer.js", "40-context-menus.js"]
}, },

View File

@ -1,6 +1,7 @@
'use strict'; 'use strict';
chrome.runtime.getBackgroundPage( (backgroundPage) => { chrome.runtime.getBackgroundPage( (backgroundPage) =>
backgroundPage.apis.errorHandlers.installListenersOn(window, 'POPUP', () => {
const getStatus = () => document.querySelector('#status'); const getStatus = () => document.querySelector('#status');
@ -83,24 +84,23 @@ chrome.runtime.getBackgroundPage( (backgroundPage) => {
} }
message = message.trim(); message = message.trim();
setStatusTo( setStatusTo(
`<span style="color:red"> `<span style="color:red">
${ifNotCritical ? 'Некритичная ошибка.' : 'Ошибка!'} ${ifNotCritical ? 'Некритичная ошибка.' : 'Ошибка!'}
</span> </span>
<br/> <br/>
<span style="font-size: 0.9em; color: darkred">${message}</span> <span style="font-size: 0.9em; color: darkred">${message}</span>
<a href class="link-button">[Ещё&nbsp;подробнее]</a>` <a href class="link-button">[Ещё&nbsp;подробнее]</a>`
); );
getStatus().querySelector('.link-button').onclick = function() { getStatus().querySelector('.link-button').onclick = function() {
const div = document.createElement('div'); const div = document.createElement('div');
div.innerHTML = ` div.innerHTML = `
Более подробную информацию можно узнать из логов фоновой страницы:<br/> Более подробную информацию можно узнать из логов фоновой страницы:<br/>
<a href="chrome://extensions?id=${chrome.runtime.id}" data-in-bg="true"> <a href="chrome://extensions?id=${chrome.runtime.id}" data-in-bg="true">
chrome://extensions</a> chrome://extensions</a>
Это расширение Отладка страниц: фоновая страница Console (DevTools) Это расширение Отладка страниц: фоновая страница Console (DevTools)
<br> <br>
Ещё: ${JSON.stringify({err: err, stack: err.stack})} Ещё: ` + JSON.stringify({err: err, stack: err.stack});
`;
getStatus().replaceChild(div, this); getStatus().replaceChild(div, this);
return false; return false;
@ -144,7 +144,7 @@ chrome://extensions</a>
li.querySelector('.link-button').onclick = li.querySelector('.link-button').onclick =
() => { () => {
conduct( conduct(
'Обновляем...', (cb) => antiCensorRu.syncWithPacProvider(cb), 'Обновляем...', (cb) => antiCensorRu.syncWithPacProviderAsync(cb),
'Обновлено.' 'Обновлено.'
); );
return false; return false;
@ -166,14 +166,14 @@ chrome://extensions</a>
if (pacKey === 'none') { if (pacKey === 'none') {
conduct( conduct(
'Отключение...', 'Отключение...',
(cb) => antiCensorRu.clearPac(cb), (cb) => antiCensorRu.clearPacAsync(cb),
'Отключено.', 'Отключено.',
checkChosenProvider checkChosenProvider
); );
} else { } else {
conduct( conduct(
'Установка...', 'Установка...',
(cb) => antiCensorRu.installPac(pacKey, cb), (cb) => antiCensorRu.installPacAsync(pacKey, cb),
'PAC-скрипт установлен.', 'PAC-скрипт установлен.',
checkChosenProvider checkChosenProvider
); );
@ -207,4 +207,5 @@ chrome://extensions</a>
document.querySelector('#update-' + id).click(); document.querySelector('#update-' + id).click();
} }
}); })
);

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

View File

@ -0,0 +1,75 @@
<!DOCTYPE html>
<html>
<head>
<title>Ошибка</title>
<style type="text/css" media="screen">
html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
html {
background: black url('./err.jpg') repeat;
background-position: left;
color: white;
}
body {
background: linear-gradient(to bottom, black 45em, transparent);
}
header {
padding-top: 1em;
}
h2 {
margin-top: 0;
}
main {
color: #999999;
font-size: 1.5em;
}
pre {
margin: 0 !important;
padding: 1em !important;
width: 100% !important;
border-radius: 0 !important;
box-sizing: border-box !important;
background-color: transparent !important;
}
header {
padding-left: 2em;
}
ol, ul {
list-style-type: none;
}
textarea {
width: 40em;
height: 10em;
font: inherit;
}
#output {
background-color: black;
}
</style>
</head>
<body>
<header>
<h2>Информация об ошибке</h2>
</header>
<main>
<ol>
<li>Тип: <span>ext-error</span></li>
<li><pre><code id="output" class='hljs'></code></pre></li>
<li><textarea placeholder='Ваш комментарий (опционально)' id="comment"></textarea></li>
<li>
<button id="raven-report">Отправить автору</button>
<button id="github-search">Искать на GitHub</button>
<button id="github-report">Написать на GitHub</button>
</li>
</ol>
</main>
<script src="./vendor/raven3.8.1.min.js" crossorigin="anonymous"></script>
<link rel="stylesheet" href="./vendor/highlight.js/styles/atom-one-dark.css">
<script src="./vendor/highlight.js/highlight9.8.0.min.js"></script>
<script src="./index.js" charset="utf-8"></script>
</body>
</html>

View File

@ -0,0 +1,100 @@
'use strict';
function errorJsonReplacer(key, value) {
if ( !['Error', 'ErrorEvent'].includes( value.constructor.name ) ) {
return value;
}
const alt = {};
Object.getOwnPropertyNames(value).forEach(function (key) {
alt[key] = value[key];
}, value);
for(const prop in value) {
if (/^[A-Z]/.test(prop)) {
continue;
}
alt[prop] = value[prop];
}
// fooWindow.ErrorEvent !== barWindow.ErrorEvent
if (value.constructor.name === 'ErrorEvent') {
for(const circularProp of
[ // First line are circular props.
'target', 'srcElement', 'path', 'currentTarget',
'bubbles', 'cancelBubble', 'cancelable', 'composed',
'defaultPrevented', 'eventPhase', 'isTrusted', 'returnValue',
'timeStamp']) {
delete alt[circularProp];
}
}
return alt;
}
chrome.runtime.getBackgroundPage( (backgroundPage) =>
backgroundPage.apis.errorHandlers.installListenersOn(window, 'ErrView', () => {
Raven.config('https://bc534321358f455b9ae861740c2d3af8@sentry.io/116007', {
release: chrome.runtime.getManifest().version,
autoBreadcrumbs: false,
}).install();
const errId = window.location.hash.slice(1);
const err = backgroundPage.apis.errorHandlers.idToErr[errId];
const json = JSON.stringify(err, errorJsonReplacer, 2);
document.getElementById('output').innerHTML = hljs.highlight('json', json).value;
document.addEventListener('ravenSuccess', () => alert('Готово'));
document.addEventListener('ravenFailure', () => alert('Ошибка sentry.io! (подробности недоступны)'));
document.getElementById('raven-report').onclick = () => {
const e = err.error || err;
const extra = JSON.parse(json);
const comment = document.getElementById('comment').value;
if (comment.trim()) {
extra.comment = comment;
}
Raven.captureException(e, {
extra: extra,
onSuccess: () => alert('Готово'),
onError: (err) => { throw err; }
});
};
document.getElementById('github-search').onclick = () => {
const title = err.message || err;
chrome.tabs.create({
active: true,
url: 'https://rebrand.ly/ac-search-issues?q=' + encodeURIComponent(title)
});
};
document.getElementById('github-report').onclick = () => {
const comment = document.getElementById('comment').value;
const title = err.message || err;
const body = (comment || 'Ваш текст') + `
### Ошибка
\`\`\`json
${json}
\`\`\`
Версия: ${chrome.runtime.getManifest().version}
`;
chrome.tabs.create({
active: true,
url: `https://rebrand.ly/ac-new-issue?title=${encodeURIComponent(title)}&body=${encodeURIComponent(body)}`
});
};
})
);

View File

@ -0,0 +1,63 @@
!function(){/*
Copyright (C) 2013 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Copyright (C) 2006 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
(function(){function ba(g){function k(){try{M.doScroll("left")}catch(g){t.setTimeout(k,50);return}z("poll")}function z(k){if("readystatechange"!=k.type||"complete"==A.readyState)("load"==k.type?t:A)[B](p+k.type,z,!1),!q&&(q=!0)&&g.call(t,k.type||k)}var Y=A.addEventListener,q=!1,C=!0,x=Y?"addEventListener":"attachEvent",B=Y?"removeEventListener":"detachEvent",p=Y?"":"on";if("complete"==A.readyState)g.call(t,"lazy");else{if(A.createEventObject&&M.doScroll){try{C=!t.frameElement}catch(da){}C&&k()}A[x](p+
"DOMContentLoaded",z,!1);A[x](p+"readystatechange",z,!1);t[x](p+"load",z,!1)}}function U(){V&&ba(function(){var g=N.length;ca(g?function(){for(var k=0;k<g;++k)(function(g){t.setTimeout(function(){t.exports[N[g]].apply(t,arguments)},0)})(k)}:void 0)})}for(var t=window,A=document,M=A.documentElement,O=A.head||A.getElementsByTagName("head")[0]||M,B="",F=A.getElementsByTagName("script"),q=F.length;0<=--q;){var P=F[q],Z=P.src.match(/^[^?#]*\/run_prettify\.js(\?[^#]*)?(?:#.*)?$/);if(Z){B=Z[1]||"";P.parentNode.removeChild(P);
break}}var V=!0,H=[],Q=[],N=[];B.replace(/[?&]([^&=]+)=([^&]+)/g,function(g,k,z){z=decodeURIComponent(z);k=decodeURIComponent(k);"autorun"==k?V=!/^[0fn]/i.test(z):"lang"==k?H.push(z):"skin"==k?Q.push(z):"callback"==k&&N.push(z)});q=0;for(B=H.length;q<B;++q)(function(){var g=A.createElement("script");g.onload=g.onerror=g.onreadystatechange=function(){!g||g.readyState&&!/loaded|complete/.test(g.readyState)||(g.onerror=g.onload=g.onreadystatechange=null,--T,T||t.setTimeout(U,0),g.parentNode&&g.parentNode.removeChild(g),
g=null)};g.type="text/javascript";g.src="https://cdn.rawgit.com/google/code-prettify/master/loader/lang-"+encodeURIComponent(H[q])+".js";O.insertBefore(g,O.firstChild)})(H[q]);for(var T=H.length,F=[],q=0,B=Q.length;q<B;++q)F.push("./vendor/code-prettify/skins/"+encodeURIComponent(Q[q])+".css");F.push("https://cdn.rawgit.com/google/code-prettify/master/loader/prettify.css");(function(g){function k(q){if(q!==z){var t=A.createElement("link");t.rel="stylesheet";t.type=
"text/css";q+1<z&&(t.error=t.onerror=function(){k(q+1)});t.href=g[q];O.appendChild(t)}}var z=g.length;k(0)})(F);var ca=function(){window.PR_SHOULD_USE_CONTINUATION=!0;var g;(function(){function k(a){function d(e){var b=e.charCodeAt(0);if(92!==b)return b;var a=e.charAt(1);return(b=W[a])?b:"0"<=a&&"7">=a?parseInt(e.substring(1),8):"u"===a||"x"===a?parseInt(e.substring(2),16):e.charCodeAt(1)}function f(e){if(32>e)return(16>e?"\\x0":"\\x")+e.toString(16);e=String.fromCharCode(e);return"\\"===e||"-"===
e||"]"===e||"^"===e?"\\"+e:e}function b(e){var b=e.substring(1,e.length-1).match(/\\u[0-9A-Fa-f]{4}|\\x[0-9A-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\s\S]|-|[^-\\]/g);e=[];var a="^"===b[0],c=["["];a&&c.push("^");for(var a=a?1:0,h=b.length;a<h;++a){var l=b[a];if(/\\[bdsw]/i.test(l))c.push(l);else{var l=d(l),n;a+2<h&&"-"===b[a+1]?(n=d(b[a+2]),a+=2):n=l;e.push([l,n]);65>n||122<l||(65>n||90<l||e.push([Math.max(65,l)|32,Math.min(n,90)|32]),97>n||122<l||e.push([Math.max(97,l)&-33,Math.min(n,122)&-33]))}}e.sort(function(e,
a){return e[0]-a[0]||a[1]-e[1]});b=[];h=[];for(a=0;a<e.length;++a)l=e[a],l[0]<=h[1]+1?h[1]=Math.max(h[1],l[1]):b.push(h=l);for(a=0;a<b.length;++a)l=b[a],c.push(f(l[0])),l[1]>l[0]&&(l[1]+1>l[0]&&c.push("-"),c.push(f(l[1])));c.push("]");return c.join("")}function g(e){for(var a=e.source.match(/(?:\[(?:[^\x5C\x5D]|\\[\s\S])*\]|\\u[A-Fa-f0-9]{4}|\\x[A-Fa-f0-9]{2}|\\[0-9]+|\\[^ux0-9]|\(\?[:!=]|[\(\)\^]|[^\x5B\x5C\(\)\^]+)/g),c=a.length,d=[],h=0,l=0;h<c;++h){var n=a[h];"("===n?++l:"\\"===n.charAt(0)&&(n=
+n.substring(1))&&(n<=l?d[n]=-1:a[h]=f(n))}for(h=1;h<d.length;++h)-1===d[h]&&(d[h]=++k);for(l=h=0;h<c;++h)n=a[h],"("===n?(++l,d[l]||(a[h]="(?:")):"\\"===n.charAt(0)&&(n=+n.substring(1))&&n<=l&&(a[h]="\\"+d[n]);for(h=0;h<c;++h)"^"===a[h]&&"^"!==a[h+1]&&(a[h]="");if(e.ignoreCase&&I)for(h=0;h<c;++h)n=a[h],e=n.charAt(0),2<=n.length&&"["===e?a[h]=b(n):"\\"!==e&&(a[h]=n.replace(/[a-zA-Z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return a.join("")}for(var k=0,I=!1,
m=!1,J=0,c=a.length;J<c;++J){var r=a[J];if(r.ignoreCase)m=!0;else if(/[a-z]/i.test(r.source.replace(/\\u[0-9a-f]{4}|\\x[0-9a-f]{2}|\\[^ux]/gi,""))){I=!0;m=!1;break}}for(var W={b:8,t:9,n:10,v:11,f:12,r:13},u=[],J=0,c=a.length;J<c;++J){r=a[J];if(r.global||r.multiline)throw Error(""+r);u.push("(?:"+g(r)+")")}return new RegExp(u.join("|"),m?"gi":"g")}function q(a,d){function f(a){var c=a.nodeType;if(1==c){if(!b.test(a.className)){for(c=a.firstChild;c;c=c.nextSibling)f(c);c=a.nodeName.toLowerCase();if("br"===
c||"li"===c)g[m]="\n",I[m<<1]=k++,I[m++<<1|1]=a}}else if(3==c||4==c)c=a.nodeValue,c.length&&(c=d?c.replace(/\r\n?/g,"\n"):c.replace(/[ \t\r\n]+/g," "),g[m]=c,I[m<<1]=k,k+=c.length,I[m++<<1|1]=a)}var b=/(?:^|\s)nocode(?:\s|$)/,g=[],k=0,I=[],m=0;f(a);return{a:g.join("").replace(/\n$/,""),c:I}}function t(a,d,f,b,g){f&&(a={h:a,l:1,j:null,m:null,a:f,c:null,i:d,g:null},b(a),g.push.apply(g,a.g))}function A(a){for(var d=void 0,f=a.firstChild;f;f=f.nextSibling)var b=f.nodeType,d=1===b?d?a:f:3===b?T.test(f.nodeValue)?
a:d:d;return d===a?void 0:d}function C(a,d){function f(a){for(var m=a.i,k=a.h,c=[m,"pln"],r=0,W=a.a.match(g)||[],u={},e=0,q=W.length;e<q;++e){var D=W[e],w=u[D],h=void 0,l;if("string"===typeof w)l=!1;else{var n=b[D.charAt(0)];if(n)h=D.match(n[1]),w=n[0];else{for(l=0;l<p;++l)if(n=d[l],h=D.match(n[1])){w=n[0];break}h||(w="pln")}!(l=5<=w.length&&"lang-"===w.substring(0,5))||h&&"string"===typeof h[1]||(l=!1,w="src");l||(u[D]=w)}n=r;r+=D.length;if(l){l=h[1];var E=D.indexOf(l),G=E+l.length;h[2]&&(G=D.length-
h[2].length,E=G-l.length);w=w.substring(5);t(k,m+n,D.substring(0,E),f,c);t(k,m+n+E,l,F(w,l),c);t(k,m+n+G,D.substring(G),f,c)}else c.push(m+n,w)}a.g=c}var b={},g;(function(){for(var f=a.concat(d),m=[],p={},c=0,r=f.length;c<r;++c){var q=f[c],u=q[3];if(u)for(var e=u.length;0<=--e;)b[u.charAt(e)]=q;q=q[1];u=""+q;p.hasOwnProperty(u)||(m.push(q),p[u]=null)}m.push(/[\0-\uffff]/);g=k(m)})();var p=d.length;return f}function x(a){var d=[],f=[];a.tripleQuotedStrings?d.push(["str",/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,
null,"'\""]):a.multiLineStrings?d.push(["str",/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"]):d.push(["str",/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"]);a.verbatimStrings&&f.push(["str",/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null]);var b=a.hashComments;b&&(a.cStyleComments?(1<b?d.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"]):d.push(["com",/^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\b|[^\r\n]*)/,
null,"#"]),f.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/,null])):d.push(["com",/^#[^\r\n]*/,null,"#"]));a.cStyleComments&&(f.push(["com",/^\/\/[^\r\n]*/,null]),f.push(["com",/^\/\*[\s\S]*?(?:\*\/|$)/,null]));if(b=a.regexLiterals){var g=(b=1<b?"":"\n\r")?".":"[\\S\\s]";f.push(["lang-regex",RegExp("^(?:^^\\.?|[+-]|[!=]=?=?|\\#|%=?|&&?=?|\\(|\\*=?|[+\\-]=|->|\\/=?|::?|<<?=?|>>?>?=?|,|;|\\?|@|\\[|~|{|\\^\\^?=?|\\|\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*("+
("/(?=[^/*"+b+"])(?:[^/\\x5B\\x5C"+b+"]|\\x5C"+g+"|\\x5B(?:[^\\x5C\\x5D"+b+"]|\\x5C"+g+")*(?:\\x5D|$))+/")+")")])}(b=a.types)&&f.push(["typ",b]);b=(""+a.keywords).replace(/^ | $/g,"");b.length&&f.push(["kwd",new RegExp("^(?:"+b.replace(/[\s,]+/g,"|")+")\\b"),null]);d.push(["pln",/^\s+/,null," \r\n\t\u00a0"]);b="^.[^\\s\\w.$@'\"`/\\\\]*";a.regexLiterals&&(b+="(?!s*/)");f.push(["lit",/^@[a-z_$][a-z_$@0-9]*/i,null],["typ",/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],["pln",/^[a-z_$][a-z_$@0-9]*/i,
null],["lit",/^(?:0x[a-f0-9]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+\-]?\d+)?)[a-z]*/i,null,"0123456789"],["pln",/^\\[\s\S]?/,null],["pun",new RegExp(b),null]);return C(d,f)}function B(a,d,f){function b(a){var c=a.nodeType;if(1==c&&!k.test(a.className))if("br"===a.nodeName)g(a),a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)b(a);else if((3==c||4==c)&&f){var d=a.nodeValue,p=d.match(q);p&&(c=d.substring(0,p.index),a.nodeValue=c,(d=d.substring(p.index+p[0].length))&&
a.parentNode.insertBefore(m.createTextNode(d),a.nextSibling),g(a),c||a.parentNode.removeChild(a))}}function g(a){function b(a,c){var d=c?a.cloneNode(!1):a,n=a.parentNode;if(n){var n=b(n,1),e=a.nextSibling;n.appendChild(d);for(var f=e;f;f=e)e=f.nextSibling,n.appendChild(f)}return d}for(;!a.nextSibling;)if(a=a.parentNode,!a)return;a=b(a.nextSibling,0);for(var d;(d=a.parentNode)&&1===d.nodeType;)a=d;c.push(a)}for(var k=/(?:^|\s)nocode(?:\s|$)/,q=/\r\n?|\n/,m=a.ownerDocument,p=m.createElement("li");a.firstChild;)p.appendChild(a.firstChild);
for(var c=[p],r=0;r<c.length;++r)b(c[r]);d===(d|0)&&c[0].setAttribute("value",d);var t=m.createElement("ol");t.className="linenums";d=Math.max(0,d-1|0)||0;for(var r=0,u=c.length;r<u;++r)p=c[r],p.className="L"+(r+d)%10,p.firstChild||p.appendChild(m.createTextNode("\u00a0")),t.appendChild(p);a.appendChild(t)}function p(a,d){for(var f=d.length;0<=--f;){var b=d[f];X.hasOwnProperty(b)?R.console&&console.warn("cannot override language handler %s",b):X[b]=a}}function F(a,d){a&&X.hasOwnProperty(a)||(a=/^\s*</.test(d)?
"default-markup":"default-code");return X[a]}function H(a){var d=a.j;try{var f=q(a.h,a.l),b=f.a;a.a=b;a.c=f.c;a.i=0;F(d,b)(a);var g=/\bMSIE\s(\d+)/.exec(navigator.userAgent),g=g&&8>=+g[1],d=/\n/g,p=a.a,k=p.length,f=0,m=a.c,t=m.length,b=0,c=a.g,r=c.length,x=0;c[r]=k;var u,e;for(e=u=0;e<r;)c[e]!==c[e+2]?(c[u++]=c[e++],c[u++]=c[e++]):e+=2;r=u;for(e=u=0;e<r;){for(var A=c[e],D=c[e+1],w=e+2;w+2<=r&&c[w+1]===D;)w+=2;c[u++]=A;c[u++]=D;e=w}c.length=u;var h=a.h;a="";h&&(a=h.style.display,h.style.display="none");
try{for(;b<t;){var l=m[b+2]||k,n=c[x+2]||k,w=Math.min(l,n),E=m[b+1],G;if(1!==E.nodeType&&(G=p.substring(f,w))){g&&(G=G.replace(d,"\r"));E.nodeValue=G;var aa=E.ownerDocument,v=aa.createElement("span");v.className=c[x+1];var B=E.parentNode;B.replaceChild(v,E);v.appendChild(E);f<l&&(m[b+1]=E=aa.createTextNode(p.substring(w,l)),B.insertBefore(E,v.nextSibling))}f=w;f>=l&&(b+=2);f>=n&&(x+=2)}}finally{h&&(h.style.display=a)}}catch(y){R.console&&console.log(y&&y.stack||y)}}var R=window,K=["break,continue,do,else,for,if,return,while"],
L=[[K,"auto,case,char,const,default,double,enum,extern,float,goto,inline,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],S=[L,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,delegate,dynamic_cast,explicit,export,friend,generic,late_check,mutable,namespace,nullptr,property,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],
M=[L,"abstract,assert,boolean,byte,extends,finally,final,implements,import,instanceof,interface,null,native,package,strictfp,super,synchronized,throws,transient"],N=[L,"abstract,as,base,bool,by,byte,checked,decimal,delegate,descending,dynamic,event,finally,fixed,foreach,from,group,implicit,in,interface,internal,into,is,let,lock,null,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var,virtual,where"],L=[L,"debugger,eval,export,function,get,instanceof,null,set,undefined,var,with,Infinity,NaN"],
O=[K,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],P=[K,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],K=[K,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],Q=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)\b/,
T=/\S/,U=x({keywords:[S,N,M,L,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",O,P,K],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),X={};p(U,["default-code"]);p(C([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",
/^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),"default-markup htm html mxml xhtml xml xsl".split(" "));p(C([["pln",/^[\s]+/,null," \t\r\n"],["atv",/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],
["pun",/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);p(C([],[["atv",/^[\s\S]+/]]),["uq.val"]);p(x({keywords:S,hashComments:!0,cStyleComments:!0,types:Q}),"c cc cpp cxx cyc m".split(" "));p(x({keywords:"null,true,false"}),["json"]);p(x({keywords:N,hashComments:!0,cStyleComments:!0,
verbatimStrings:!0,types:Q}),["cs"]);p(x({keywords:M,cStyleComments:!0}),["java"]);p(x({keywords:K,hashComments:!0,multiLineStrings:!0}),["bash","bsh","csh","sh"]);p(x({keywords:O,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),["cv","py","python"]);p(x({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:2}),
["perl","pl","pm"]);p(x({keywords:P,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb","ruby"]);p(x({keywords:L,cStyleComments:!0,regexLiterals:!0}),["javascript","js"]);p(x({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,throw,true,try,unless,until,when,while,yes",hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);p(C([],[["str",/^[\s\S]+/]]),["regex"]);
var V=R.PR={createSimpleLexer:C,registerLangHandler:p,sourceDecorator:x,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ",prettyPrintOne:function(a,d,f){f=f||!1;d=d||null;var b=document.createElement("div");b.innerHTML="<pre>"+a+"</pre>";b=b.firstChild;f&&B(b,f,!0);H({j:d,m:f,h:b,l:1,a:null,i:null,c:null,g:null});return b.innerHTML},
prettyPrint:g=g=function(a,d){function f(){for(var b=R.PR_SHOULD_USE_CONTINUATION?c.now()+250:Infinity;r<p.length&&c.now()<b;r++){for(var d=p[r],k=h,q=d;q=q.previousSibling;){var m=q.nodeType,v=(7===m||8===m)&&q.nodeValue;if(v?!/^\??prettify\b/.test(v):3!==m||/\S/.test(q.nodeValue))break;if(v){k={};v.replace(/\b(\w+)=([\w:.%+-]+)/g,function(a,b,c){k[b]=c});break}}q=d.className;if((k!==h||u.test(q))&&!e.test(q)){m=!1;for(v=d.parentNode;v;v=v.parentNode)if(w.test(v.tagName)&&v.className&&u.test(v.className)){m=
!0;break}if(!m){d.className+=" prettyprinted";m=k.lang;if(!m){var m=q.match(t),C;!m&&(C=A(d))&&z.test(C.tagName)&&(m=C.className.match(t));m&&(m=m[1])}if(x.test(d.tagName))v=1;else var v=d.currentStyle,y=g.defaultView,v=(v=v?v.whiteSpace:y&&y.getComputedStyle?y.getComputedStyle(d,null).getPropertyValue("white-space"):0)&&"pre"===v.substring(0,3);y=k.linenums;(y="true"===y||+y)||(y=(y=q.match(/\blinenums\b(?::(\d+))?/))?y[1]&&y[1].length?+y[1]:!0:!1);y&&B(d,y,v);H({j:m,h:d,m:y,l:v,a:null,i:null,c:null,
g:null})}}}r<p.length?R.setTimeout(f,250):"function"===typeof a&&a()}for(var b=d||document.body,g=b.ownerDocument||document,b=[b.getElementsByTagName("pre"),b.getElementsByTagName("code"),b.getElementsByTagName("xmp")],p=[],k=0;k<b.length;++k)for(var m=0,q=b[k].length;m<q;++m)p.push(b[k][m]);var b=null,c=Date;c.now||(c={now:function(){return+new Date}});var r=0,t=/\blang(?:uage)?-([\w.]+)(?!\S)/,u=/\bprettyprint\b/,e=/\bprettyprinted\b/,x=/pre|xmp/i,z=/^code$/i,w=/^(?:pre|code|xmp)$/i,h={};f()}},
S=R.define;"function"===typeof S&&S.amd&&S("google-code-prettify",[],function(){return V})})();return g}();T||t.setTimeout(U,0)})();}()

View File

@ -0,0 +1 @@
pre .str,code .str{color:#65b042}pre .kwd,code .kwd{color:#e28964}pre .com,code .com{color:#aeaeae;font-style:italic}pre .typ,code .typ{color:#89bdff}pre .lit,code .lit{color:#3387cc}pre .pun,code .pun{color:#fff}pre .pln,code .pln{color:#fff}pre .tag,code .tag{color:#89bdff}pre .atn,code .atn{color:#bdb76b}pre .atv,code .atv{color:#65b042}pre .dec,code .dec{color:#3387cc}pre.prettyprint,code.prettyprint{background-color:#000;-moz-border-radius:8px;-webkit-border-radius:8px;-o-border-radius:8px;-ms-border-radius:8px;-khtml-border-radius:8px;border-radius:8px}pre.prettyprint{width:95%;margin:1em auto;padding:1em;white-space:pre-wrap}ol.linenums{margin-top:0;margin-bottom:0;color:#aeaeae}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}@media print{pre .str,code .str{color:#060}pre .kwd,code .kwd{color:#006;font-weight:bold}pre .com,code .com{color:#600;font-style:italic}pre .typ,code .typ{color:#404;font-weight:bold}pre .lit,code .lit{color:#044}pre .pun,code .pun{color:#440}pre .pln,code .pln{color:#000}pre .tag,code .tag{color:#006;font-weight:bold}pre .atn,code .atn{color:#404}pre .atv,code .atv{color:#060}}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,96 @@
/*
Atom One Dark by Daniel Gamage
Original One Dark Syntax theme from https://github.com/atom/one-dark-syntax
base: #282c34
mono-1: #abb2bf
mono-2: #818896
mono-3: #5c6370
hue-1: #56b6c2
hue-2: #61aeee
hue-3: #c678dd
hue-4: #98c379
hue-5: #e06c75
hue-5-2: #be5046
hue-6: #d19a66
hue-6-2: #e6c07b
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
color: #abb2bf;
background: #282c34;
}
.hljs-comment,
.hljs-quote {
color: #5c6370;
font-style: italic;
}
.hljs-doctag,
.hljs-keyword,
.hljs-formula {
color: #c678dd;
}
.hljs-section,
.hljs-name,
.hljs-selector-tag,
.hljs-deletion,
.hljs-subst {
color: #e06c75;
}
.hljs-literal {
color: #56b6c2;
}
.hljs-string,
.hljs-regexp,
.hljs-addition,
.hljs-attr,
.hljs-meta-string {
color: #98c379;
}
.hljs-built_in,
.hljs-class .hljs-title {
color: #e6c07b;
}
.hljs-attr,
.hljs-variable,
.hljs-template-variable,
.hljs-type,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo,
.hljs-number {
color: #d19a66;
}
.hljs-symbol,
.hljs-bullet,
.hljs-link,
.hljs-meta,
.hljs-selector-id,
.hljs-title {
color: #61aeee;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}
.hljs-link {
text-decoration: underline;
}

File diff suppressed because one or more lines are too long