Initial import: WebAisMap

Closes TG-4

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-04 07:56:45 +03:00
commit 03075f1ef1
1460 changed files with 16334 additions and 0 deletions
+1359
View File
File diff suppressed because it is too large Load Diff
+6077
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -0,0 +1 @@
{"273":"RU","275":"LV","277":"LT","276":"EE","272":"UA","261":"PL","211":"DE","218":"DE","226":"FR","227":"FR","228":"FR","247":"IT","257":"NO","258":"NO","259":"NO","265":"SE","266":"SE","230":"FI","219":"DK","220":"DK","244":"NL","245":"NL","246":"NL","205":"BE","224":"ES","225":"ES","237":"GR","239":"GR","240":"GR","241":"GR","271":"TR","264":"RO","207":"BG","238":"HR","232":"GB","233":"GB","234":"GB","235":"GB","250":"IE","251":"IS","215":"MT","229":"MT","248":"MT","249":"MT","256":"MT","209":"CY","210":"CY","212":"CY","338":"US","366":"US","367":"US","368":"US","369":"US","316":"CA","412":"CN","413":"CN","414":"CN","431":"JP","432":"JP","440":"KR","441":"KR","563":"SG","564":"SG","565":"SG","566":"SG","419":"IN","503":"AU","710":"BR","701":"AR","351":"PA","352":"PA","353":"PA","354":"PA","355":"PA","356":"PA","357":"PA","370":"PA","371":"PA","372":"PA","373":"PA","374":"PA","636":"LR","637":"LR","538":"MH","308":"BS","309":"BS","311":"BS","477":"HK","416":"TW","574":"VN","525":"ID","533":"MY","548":"PH","567":"TH","403":"SA","470":"AE","471":"AE","428":"IL","622":"EG","601":"ZA","512":"NZ","345":"MX","725":"CL","263":"PT","269":"CH","203":"AT","270":"CZ","243":"HU","279":"RS","278":"SI","267":"SK","262":"ME","201":"AL","213":"GE","436":"KZ","422":"IR"}
+473
View File
@@ -0,0 +1,473 @@
/**
* Редактор габаритов (ITU Fig. 38).
* Корма — L, правый борт — W (доли A/L и C/W фиксируются на время жеста); точка GPS — перетаскивание.
* Для роста L/W координаты могут выходить за контур корпуса (опорный масштаб wPxRef/hPxRef с pointerdown).
*/
(function () {
'use strict';
var NS = 'http://www.w3.org/2000/svg';
var MIN_LEN = 20;
var MIN_BEAM = 6;
var MAX_AB = 511;
var MAX_CD = 63;
var MAX_L = MAX_AB + MAX_AB;
var MAX_W = MAX_CD + MAX_CD;
/** Макс. размер корпуса в пикселях (пропорции сохраняются) */
var MAX_DRAW_W = 175;
var MAX_DRAW_H = 210;
/** Минимум по меньшей стороне корпуса в px — иначе ручки и клампы «схлопываются» */
var MIN_HULL_PX = 48;
var PAD_L = 12;
var PAD_T = 48;
var PAD_R = 78;
var PAD_B = 42;
var svg, inner, hull, marker, handles;
var gridH, gridV, lblBow, lblStern, dimBeam, dimLength;
var drag = null;
/** Текущая геометрия (обновляется в refresh) */
var layout = {
wPx: 100,
hPx: 160,
dispL: MIN_LEN,
dispW: MIN_BEAM,
};
function clamp(n, lo, hi) {
return Math.max(lo, Math.min(hi, n));
}
function el(name, attrs) {
var e = document.createElementNS(NS, name);
if (attrs) {
Object.keys(attrs).forEach(function (k) {
e.setAttribute(k, attrs[k]);
});
}
return e;
}
function readDims() {
var A = parseInt(document.getElementById('tp-to-bow').value, 10) || 0;
var B = parseInt(document.getElementById('tp-to-stern').value, 10) || 0;
var C = parseInt(document.getElementById('tp-to-port').value, 10) || 0;
var D = parseInt(document.getElementById('tp-to-starboard').value, 10) || 0;
A = clamp(A, 0, MAX_AB);
B = clamp(B, 0, MAX_AB);
C = clamp(C, 0, MAX_CD);
D = clamp(D, 0, MAX_CD);
return { A: A, B: B, C: C, D: D, L: A + B, W: C + D };
}
function writeDims(A, B, C, D) {
A = clamp(Math.round(A), 0, MAX_AB);
B = clamp(Math.round(B), 0, MAX_AB);
C = clamp(Math.round(C), 0, MAX_CD);
D = clamp(Math.round(D), 0, MAX_CD);
document.getElementById('tp-to-bow').value = A;
document.getElementById('tp-to-stern').value = B;
document.getElementById('tp-to-port').value = C;
document.getElementById('tp-to-starboard').value = D;
}
function displayLW(d) {
var L = d.L > 0 ? d.L : MIN_LEN;
var W = d.W > 0 ? d.W : MIN_BEAM;
return { L: L, W: W, template: d.L === 0 && d.W === 0 };
}
function hullPath(w, h) {
var bow = Math.min(20, h * 0.11);
var tipX = w / 2;
return (
'M ' + tipX + ',0 L ' + w + ',' + bow + ' L ' + w + ',' + h + ' L 0,' + h + ' L 0,' + bow + ' Z'
);
}
function computeLayout(d, disp) {
var scale = Math.min(MAX_DRAW_W / disp.W, MAX_DRAW_H / disp.L);
if (!isFinite(scale) || scale <= 0) scale = 1;
var wPx0 = disp.W * scale;
var hPx0 = disp.L * scale;
var bump = 1;
if (wPx0 < MIN_HULL_PX) bump = Math.max(bump, MIN_HULL_PX / Math.max(wPx0, 1e-6));
if (hPx0 < MIN_HULL_PX) bump = Math.max(bump, MIN_HULL_PX / Math.max(hPx0, 1e-6));
scale *= bump;
var wPx = disp.W * scale;
var hPx = disp.L * scale;
layout.wPx = wPx;
layout.hPx = hPx;
layout.dispL = disp.L;
layout.dispW = disp.W;
layout.scale = scale;
return { sx: scale, sy: scale, wPx: wPx, hPx: hPx };
}
function scales(d, disp, geo) {
var wPx = geo.wPx;
var hPx = geo.hPx;
var padX = Math.max(1, Math.min(8, wPx * 0.1));
var padY = Math.max(1, Math.min(8, hPx * 0.1));
var aVis = d.L > 0 ? d.A : disp.L / 2;
var cVis = d.W > 0 ? d.C : disp.W / 2;
var mx = clamp(cVis * geo.sx, padX, wPx - padX);
var my = clamp(aVis * geo.sy, padY, hPx - padY);
return { mx: mx, my: my };
}
function ensureNonZeroDims() {
var d = readDims();
if (d.L === 0 && d.W === 0) {
writeDims(MIN_LEN / 2, MIN_LEN / 2, MIN_BEAM / 2, MIN_BEAM / 2);
}
}
function clearG(g) {
while (g.firstChild) g.removeChild(g.firstChild);
}
function rebuildBeamDimension(g, wPx, hPx, Wm) {
clearG(g);
var bow = Math.min(20, hPx * 0.11);
var off = 24;
var y = -off;
var yPast = y - 1.5;
g.appendChild(
el('line', { class: 'ship-dim-ext', x1: 0, y1: bow, x2: 0, y2: yPast })
);
g.appendChild(
el('line', { class: 'ship-dim-ext', x1: wPx, y1: bow, x2: wPx, y2: yPast })
);
g.appendChild(
el('line', {
class: 'ship-dim-main',
x1: 0,
y1: y,
x2: wPx,
y2: y,
'marker-start': 'url(#ship-dim-arrow)',
'marker-end': 'url(#ship-dim-arrow)',
})
);
var t = el('text', {
class: 'ship-dim-txt',
x: wPx / 2,
y: y - 8,
'text-anchor': 'middle',
});
t.textContent = 'W = ' + Wm + ' м';
g.appendChild(t);
}
function rebuildLengthDimension(g, wPx, hPx, Lm) {
clearG(g);
var bow = Math.min(20, hPx * 0.11);
var off = 22;
var x = wPx + off;
var xPast = x + 1.5;
g.appendChild(
el('line', { class: 'ship-dim-ext', x1: wPx, y1: bow, x2: x, y2: bow })
);
g.appendChild(
el('line', { class: 'ship-dim-ext', x1: x, y1: bow, x2: x, y2: 0 })
);
g.appendChild(
el('line', { class: 'ship-dim-ext', x1: wPx, y1: hPx, x2: xPast, y2: hPx })
);
g.appendChild(
el('line', {
class: 'ship-dim-main',
x1: x,
y1: 0,
x2: x,
y2: hPx,
'marker-start': 'url(#ship-dim-arrow)',
'marker-end': 'url(#ship-dim-arrow)',
})
);
var t = el('text', {
class: 'ship-dim-txt',
x: x + 14,
y: hPx / 2,
'text-anchor': 'middle',
transform: 'rotate(-90 ' + (x + 14) + ' ' + hPx / 2 + ')',
});
t.textContent = 'L = ' + Lm + ' м';
g.appendChild(t);
}
function positionHandles(wPx, hPx) {
if (!handles) return;
var stern = handles.querySelector('[data-ship-edge="stern"]');
var sb = handles.querySelector('[data-ship-edge="starboard"]');
if (stern) stern.setAttribute('transform', 'translate(' + wPx / 2 + ',' + hPx + ')');
if (sb) sb.setAttribute('transform', 'translate(' + wPx + ',' + hPx / 2 + ')');
}
function refreshFromInputs() {
if (!svg || !inner || !hull || !marker) return;
var d = readDims();
var disp = displayLW(d);
var geo = computeLayout(d, disp);
var sc = scales(d, disp, geo);
var wPx = geo.wPx;
var hPx = geo.hPx;
inner.setAttribute('transform', 'translate(' + PAD_L + ',' + PAD_T + ')');
var vbW = PAD_L + wPx + PAD_R;
var vbH = PAD_T + hPx + PAD_B;
svg.setAttribute('viewBox', '0 0 ' + vbW + ' ' + vbH);
rebuildBeamDimension(dimBeam, wPx, hPx, disp.W);
rebuildLengthDimension(dimLength, wPx, hPx, disp.L);
hull.setAttribute('d', hullPath(wPx, hPx));
if (gridH && gridV) {
gridH.setAttribute('x1', 0);
gridH.setAttribute('y1', sc.my);
gridH.setAttribute('x2', wPx);
gridH.setAttribute('y2', sc.my);
gridV.setAttribute('x1', sc.mx);
gridV.setAttribute('y1', 0);
gridV.setAttribute('x2', sc.mx);
gridV.setAttribute('y2', hPx);
}
if (lblBow) {
lblBow.setAttribute('x', wPx / 2);
lblBow.setAttribute('y', -38);
}
if (lblStern) {
lblStern.setAttribute('x', wPx / 2);
lblStern.setAttribute('y', hPx + 22);
}
marker.setAttribute('transform', 'translate(' + sc.mx + ',' + sc.my + ')');
marker.setAttribute('class', 'ship-gps-group' + (disp.template ? ' ship-gps-group--template' : ''));
positionHandles(wPx, hPx);
}
function svgPointFromClient(clientX, clientY) {
var pt = svg.createSVGPoint();
pt.x = clientX;
pt.y = clientY;
var ctm = inner.getScreenCTM();
if (!ctm) return null;
var p = pt.matrixTransform(ctm.inverse());
return { x: p.x, y: p.y };
}
function splitLength(u, Ls) {
u = clamp(u, 0, 1);
var A = Math.round(u * Ls);
A = clamp(A, 0, MAX_AB);
var B = Ls - A;
if (B > MAX_AB) {
B = MAX_AB;
A = clamp(Ls - B, 0, MAX_AB);
}
if (B < 0) {
B = 0;
A = clamp(Ls, 0, MAX_AB);
}
return { A: A, B: B };
}
function splitBeam(v, Ws) {
v = clamp(v, 0, 1);
var C = Math.round(v * Ws);
C = clamp(C, 0, MAX_CD);
var D = Ws - C;
if (D > MAX_CD) {
D = MAX_CD;
C = clamp(Ws - D, 0, MAX_CD);
}
if (D < 0) {
D = 0;
C = clamp(Ws, 0, MAX_CD);
}
return { C: C, D: D };
}
/** Новая длина L; сохраняем долю носа A/L ≈ rA. */
function abFromLength(Ln, rA) {
Ln = clamp(Math.round(Ln), 1, MAX_L);
var r = clamp(isFinite(rA) ? rA : 0.5, 0, 1);
var A = Math.round(r * Ln);
A = clamp(A, 0, MAX_AB);
var B = Ln - A;
if (B > MAX_AB) {
B = MAX_AB;
A = clamp(Ln - B, 0, MAX_AB);
}
if (B < 0) {
B = 0;
A = clamp(Ln, 0, MAX_AB);
}
return { A: A, B: B };
}
/** Новая ширина W; сохраняем долю порта C/W ≈ rC. */
function cdFromWidth(Wn, rC) {
Wn = clamp(Math.round(Wn), 1, MAX_W);
var r = clamp(isFinite(rC) ? rC : 0.5, 0, 1);
var C = Math.round(r * Wn);
C = clamp(C, 0, MAX_CD);
var D = Wn - C;
if (D > MAX_CD) {
D = MAX_CD;
C = clamp(Wn - D, 0, MAX_CD);
}
if (D < 0) {
D = 0;
C = clamp(Wn, 0, MAX_CD);
}
return { C: C, D: D };
}
function startDrag(ev, kind, captureEl) {
ev.preventDefault();
captureEl.setPointerCapture(ev.pointerId);
document.body.classList.add('ship-editor-dragging');
document.addEventListener('pointermove', onDocumentPointerMove);
document.addEventListener('pointerup', onDocumentPointerEnd);
document.addEventListener('pointercancel', onDocumentPointerEnd);
return { kind: kind, pid: ev.pointerId, el: captureEl };
}
function stopDragListeners() {
document.removeEventListener('pointermove', onDocumentPointerMove);
document.removeEventListener('pointerup', onDocumentPointerEnd);
document.removeEventListener('pointercancel', onDocumentPointerEnd);
}
function onInnerPointerDown(ev) {
if (!inner) return;
var edgeG = ev.target.closest ? ev.target.closest('[data-ship-edge]') : null;
if (edgeG) {
ensureNonZeroDims();
var d0 = readDims();
var disp0 = displayLW(d0);
var geo0 = computeLayout(d0, disp0);
var kind = edgeG.getAttribute('data-ship-edge');
drag = startDrag(ev, kind, edgeG);
drag.L0 = d0.L;
drag.W0 = d0.W;
drag.rA = d0.L > 0 ? d0.A / d0.L : 0.5;
drag.rC = d0.W > 0 ? d0.C / d0.W : 0.5;
drag.wPxRef = geo0.wPx;
drag.hPxRef = geo0.hPx;
return;
}
if (marker && marker.contains(ev.target)) {
ensureNonZeroDims();
var dg = readDims();
var Ls = dg.L > 0 ? Math.min(dg.L, MAX_L) : MIN_LEN;
var Ws = dg.W > 0 ? Math.min(dg.W, MAX_W) : MIN_BEAM;
Ls = clamp(Ls, 1, MAX_L);
Ws = clamp(Ws, 1, MAX_W);
drag = startDrag(ev, 'gps', marker);
drag.Ls = Ls;
drag.Ws = Ws;
}
}
function onDocumentPointerMove(ev) {
if (!drag || ev.pointerId !== drag.pid) return;
var p = svgPointFromClient(ev.clientX, ev.clientY);
if (!p) return;
var d = readDims();
var disp = displayLW(d);
var geo = computeLayout(d, disp);
var wPx = geo.wPx;
var hPx = geo.hPx;
if (drag.kind === 'gps') {
var u = p.y / hPx;
var v = p.x / wPx;
var ab = splitLength(u, drag.Ls);
var cd = splitBeam(v, drag.Ws);
writeDims(ab.A, ab.B, cd.C, cd.D);
refreshFromInputs();
return;
}
var wRef = drag.wPxRef;
var hRef = drag.hPxRef;
if (drag.kind === 'stern' && wRef > 0 && hRef > 0) {
var yMin = (hRef * 1) / Math.max(drag.L0, 1);
var yMax = (hRef * MAX_L) / Math.max(drag.L0, 1);
var yS = clamp(p.y, yMin, yMax);
var L1 = Math.round((drag.L0 * yS) / hRef);
L1 = clamp(L1, 1, MAX_L);
var abS = abFromLength(L1, drag.rA);
writeDims(abS.A, abS.B, d.C, d.D);
} else if (drag.kind === 'starboard' && wRef > 0 && hRef > 0) {
var xMin = (wRef * 1) / Math.max(drag.W0, 1);
var xMax = (wRef * MAX_W) / Math.max(drag.W0, 1);
var xSb = clamp(p.x, xMin, xMax);
var W1s = Math.round((drag.W0 * xSb) / wRef);
W1s = clamp(W1s, 1, MAX_W);
var cd2 = cdFromWidth(W1s, drag.rC);
writeDims(d.A, d.B, cd2.C, cd2.D);
}
refreshFromInputs();
}
function onDocumentPointerEnd(ev) {
if (!drag || ev.pointerId !== drag.pid) return;
stopDragListeners();
try {
drag.el.releasePointerCapture(ev.pointerId);
} catch (e) { /* ignore */ }
drag = null;
document.body.classList.remove('ship-editor-dragging');
}
function bindInputs() {
['tp-to-bow', 'tp-to-stern', 'tp-to-port', 'tp-to-starboard'].forEach(function (id) {
var eln = document.getElementById(id);
if (eln) {
eln.addEventListener('input', refreshFromInputs);
eln.addEventListener('change', refreshFromInputs);
}
});
}
function boot() {
svg = document.getElementById('ship-editor-svg');
inner = document.getElementById('ship-editor-inner');
hull = document.getElementById('ship-hull');
marker = document.getElementById('ship-gps-marker');
handles = document.getElementById('ship-edge-handles');
gridH = document.getElementById('ship-grid-h');
gridV = document.getElementById('ship-grid-v');
lblBow = document.getElementById('ship-lbl-bow');
lblStern = document.getElementById('ship-lbl-stern');
dimBeam = document.getElementById('ship-dim-beam');
dimLength = document.getElementById('ship-dim-length');
if (!svg || !inner || !hull || !marker) return;
inner.addEventListener('pointerdown', onInnerPointerDown);
bindInputs();
refreshFromInputs();
}
window.shipDimsEditorRefresh = refreshFromInputs;
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', boot);
} else {
boot();
}
})();
+179
View File
@@ -0,0 +1,179 @@
/**
* ITU-R M.1371-6, табл. 51 — тип судна (идентификатор 0–99).
* Подписи на русском по официальным формулировкам (сокращ.: ОПГ — опасные грузы;
* ОН — опасные только насыпью; ВВ — вредные вещества; МЗ — морские загрязнители).
*/
(function () {
'use strict';
var LABELS = [
'Не указано',
'Научно-исследовательское судно',
'Учебное судно',
'Судно, принадлежащее или эксплуатируемое государственным органом',
'Ледокол',
'Судно обслуживания буёв (навигационных знаков)',
'Кабелеукладчик',
'Трубоукладчик',
'Зарезервировано (на будущее)',
'Судно специального назначения, дополнительные сведения не указаны',
'Зарезервировано (на будущее)',
'Судно FPSO (добыча, хранение и отгрузка нефти на месторождении)',
'Рыбозавод (плавучий рыбоперерабатывающий завод)',
'Судно обеспечения рыбоводческого хозяйства',
'Судно оффшорного обеспечения и т. п.',
'Зарезервировано (на будущее)',
'Зарезервировано (на будущее)',
'Судно для строительных работ',
'Катер доставки экипажа (crew boat)',
'Судно обеспечения, дополнительные сведения не указаны',
'Судно на воздушной подушке (WIG), все суда этого типа',
'WIG с ОПГ и/или ОН, ВВ или МЗ, категория опасности X (ИМО)',
'WIG с ОПГ и/или ОН, ВВ или МЗ, категория опасности Y (ИМО)',
'WIG с ОПГ и/или ОН, ВВ или МЗ, категория опасности Z (ИМО)',
'WIG с ОПГ и/или ОН, ВВ или МЗ, категория OS (ИМО)',
'Зарезервировано (на будущее)',
'Зарезервировано (на будущее)',
'Зарезервировано (на будущее)',
'Зарезервировано (на будущее)',
'WIG, дополнительные сведения не указаны',
'Рыболовное судно',
'Буксир',
'Буксир; длина буксира >200 м или ширина >25 м',
'Земснаряд',
'Водолазное судно',
'Военный корабль или вспомогательное судно ВМС',
'Парусное судно',
'Прогулочное моторное судно',
'Тральщик',
'Патрульное судно',
'Высокоскоростное судно (ВСС), все суда этого типа',
'ВСС с ОПГ и/или ОН, ВВ или МЗ, категория X (ИМО)',
'ВСС с ОПГ и/или ОН, ВВ или МЗ, категория Y (ИМО)',
'ВСС с ОПГ и/или ОН, ВВ или МЗ, категория Z (ИМО)',
'ВСС с ОПГ и/или ОН, ВВ или МЗ, категория OS (ИМО)',
'ВСС, перевозка пассажиров',
'ВСС Ro-Ro (автомобили / ж/д)',
'Зарезервировано (на будущее)',
'Зарезервировано (на будущее)',
'ВСС, дополнительные сведения не указаны',
'Лоцманское судно',
'Поисково-спасательное судно',
'Буксиры',
'Портовое или рыболовное вспомогательное судно',
'Противозагрязнение или пожарный резерв',
'Судно правоохранительных органов',
'Резерв 1 — для назначений местным судам',
'Резерв 2 — для назначений местным судам',
'Медицинский транспорт (Женевские конвенции 1949 г. и Доп. протоколы)',
'Судна государств, не участвующих в вооружённом конфликте',
'Пассажирское судно, все суда этого типа',
'Пассажирское с ОПГ и/или ОН, ВВ или МЗ, категория X (ИМО)',
'Пассажирское с ОПГ и/или ОН, ВВ или МЗ, категория Y (ИМО)',
'Пассажирское с ОПГ и/или ОН, ВВ или МЗ, категория Z (ИМО)',
'Пассажирское с ОПГ и/или ОН, ВВ или МЗ, категория OS (ИМО)',
'Пассажирский лайнер (круизное судно)',
'Пассажирский паром',
'Пассажирское прогулочное (напр. по гавани, наблюдение за китами)',
'Зарезервировано (на будущее)',
'Пассажирское судно, дополнительные сведения не указаны',
'Грузовое судно, все суда этого типа',
'Грузовое с ОПГ и/или ОН, ВВ или МЗ, категория X (ИМО)',
'Грузовое с ОПГ и/или ОН, ВВ или МЗ, категория Y (ИМО)',
'Грузовое с ОПГ и/или ОН, ВВ или МЗ, категория Z (ИМО)',
'Грузовое с ОПГ и/или ОН, ВВ или МЗ, категория OS (ИМО)',
'Грузовое судно, балкер',
'Грузовое судно, контейнеровоз',
'Грузовое судно, Ro-Ro',
'Грузовое судно, десантная баржа',
'Грузовое судно, дополнительные сведения не указаны',
'Танкер, все суда этого типа',
'Танкер с ОПГ и/или ОН, ВВ или МЗ, категория X (ИМО)',
'Танкер с ОПГ и/или ОН, ВВ или МЗ, категория Y (ИМО)',
'Танкер с ОПГ и/или ОН, ВВ или МЗ, категория Z (ИМО)',
'Танкер с ОПГ и/или ОН, ВВ или МЗ, категория OS (ИМО)',
'Танкер, неопасный груз / не загрязняющий',
'Составной буксир и танкерная баржа (A–D — буксир и баржа)',
'Зарезервировано (на будущее)',
'Зарезервировано (на будущее)',
'Танкер, дополнительные сведения не указаны',
'Прочий тип судна',
'Прочий тип с ОПГ и/или ОН, ВВ или МЗ, категория X (ИМО)',
'Прочий тип с ОПГ и/или ОН, ВВ или МЗ, категория Y (ИМО)',
'Прочий тип с ОПГ и/или ОН, ВВ или МЗ, категория Z (ИМО)',
'Прочий тип с ОПГ и/или ОН, ВВ или МЗ, категория OS (ИМО)',
'Зарезервировано (на будущее)',
'Зарезервировано (на будущее)',
'Зарезервировано (на будущее)',
'Зарезервировано (на будущее)',
'Прочий тип судна, дополнительные сведения не указаны',
];
var GROUPS = [
{ from: 1, to: 9, title: '01–09 Судно специального назначения' },
{ from: 10, to: 19, title: '10–19 Судно обеспечения' },
{ from: 20, to: 29, title: '20–29 Судно на воздушной подушке (WIG)' },
{ from: 30, to: 39, title: '3039 Особое судно' },
{ from: 40, to: 49, title: '40–49 Высокоскоростное судно (ВСС)' },
{ from: 50, to: 59, title: '5059 Особое судно' },
{ from: 60, to: 69, title: '60–69 Пассажирское судно' },
{ from: 70, to: 79, title: '70–79 Грузовое судно' },
{ from: 80, to: 89, title: '8089 Танкер' },
{ from: 90, to: 99, title: '9099 Прочие типы' },
];
function addOption(sel, value, text) {
var o = document.createElement('option');
o.value = String(value);
o.textContent = String(value) + ' — ' + text;
sel.appendChild(o);
}
function fillShipTypeSelect() {
var sel = document.getElementById('tp-ship-type');
if (!sel || sel.getAttribute('data-table51') === '1') return;
sel.setAttribute('data-table51', '1');
sel.innerHTML = '';
addOption(sel, 0, LABELS[0]);
GROUPS.forEach(function (g) {
var og = document.createElement('optgroup');
og.label = g.title;
for (var c = g.from; c <= g.to; c++) {
var o = document.createElement('option');
o.value = String(c);
var pad = c < 10 ? '0' + c : String(c);
o.textContent = pad + ' — ' + LABELS[c];
og.appendChild(o);
}
sel.appendChild(og);
});
}
function ensureShipTypeOption(value) {
var sel = document.getElementById('tp-ship-type');
if (!sel) return;
var v = Math.max(0, Math.min(255, parseInt(value, 10) || 0));
var s = String(v);
for (var i = 0; i < sel.options.length; i++) {
if (sel.options[i].value === s) return;
}
var o = document.createElement('option');
o.value = s;
o.textContent = s + ' — (из конфигурации, вне табл. 51 / 099)';
sel.appendChild(o);
}
window.fillShipTypeSelect = fillShipTypeSelect;
window.ensureShipTypeOption = ensureShipTypeOption;
window.AIS_TABLE51_SHIP_TYPE_LABEL = function (code) {
var c = parseInt(code, 10);
if (isNaN(c) || c < 0 || c > 99) return null;
return LABELS[c] || null;
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', fillShipTypeSelect);
} else {
fillShipTypeSelect();
}
})();
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 696 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 618 B

File diff suppressed because it is too large Load Diff
+661
View File
@@ -0,0 +1,661 @@
/* required styles */
.leaflet-pane,
.leaflet-tile,
.leaflet-marker-icon,
.leaflet-marker-shadow,
.leaflet-tile-container,
.leaflet-pane > svg,
.leaflet-pane > canvas,
.leaflet-zoom-box,
.leaflet-image-layer,
.leaflet-layer {
position: absolute;
left: 0;
top: 0;
}
.leaflet-container {
overflow: hidden;
}
.leaflet-tile,
.leaflet-marker-icon,
.leaflet-marker-shadow {
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
-webkit-user-drag: none;
}
/* Prevents IE11 from highlighting tiles in blue */
.leaflet-tile::selection {
background: transparent;
}
/* Safari renders non-retina tile on retina better with this, but Chrome is worse */
.leaflet-safari .leaflet-tile {
image-rendering: -webkit-optimize-contrast;
}
/* hack that prevents hw layers "stretching" when loading new tiles */
.leaflet-safari .leaflet-tile-container {
width: 1600px;
height: 1600px;
-webkit-transform-origin: 0 0;
}
.leaflet-marker-icon,
.leaflet-marker-shadow {
display: block;
}
/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */
/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */
.leaflet-container .leaflet-overlay-pane svg {
max-width: none !important;
max-height: none !important;
}
.leaflet-container .leaflet-marker-pane img,
.leaflet-container .leaflet-shadow-pane img,
.leaflet-container .leaflet-tile-pane img,
.leaflet-container img.leaflet-image-layer,
.leaflet-container .leaflet-tile {
max-width: none !important;
max-height: none !important;
width: auto;
padding: 0;
}
.leaflet-container img.leaflet-tile {
/* See: https://bugs.chromium.org/p/chromium/issues/detail?id=600120 */
mix-blend-mode: plus-lighter;
}
.leaflet-container.leaflet-touch-zoom {
-ms-touch-action: pan-x pan-y;
touch-action: pan-x pan-y;
}
.leaflet-container.leaflet-touch-drag {
-ms-touch-action: pinch-zoom;
/* Fallback for FF which doesn't support pinch-zoom */
touch-action: none;
touch-action: pinch-zoom;
}
.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom {
-ms-touch-action: none;
touch-action: none;
}
.leaflet-container {
-webkit-tap-highlight-color: transparent;
}
.leaflet-container a {
-webkit-tap-highlight-color: rgba(51, 181, 229, 0.4);
}
.leaflet-tile {
filter: inherit;
visibility: hidden;
}
.leaflet-tile-loaded {
visibility: inherit;
}
.leaflet-zoom-box {
width: 0;
height: 0;
-moz-box-sizing: border-box;
box-sizing: border-box;
z-index: 800;
}
/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
.leaflet-overlay-pane svg {
-moz-user-select: none;
}
.leaflet-pane { z-index: 400; }
.leaflet-tile-pane { z-index: 200; }
.leaflet-overlay-pane { z-index: 400; }
.leaflet-shadow-pane { z-index: 500; }
.leaflet-marker-pane { z-index: 600; }
.leaflet-tooltip-pane { z-index: 650; }
.leaflet-popup-pane { z-index: 700; }
.leaflet-map-pane canvas { z-index: 100; }
.leaflet-map-pane svg { z-index: 200; }
.leaflet-vml-shape {
width: 1px;
height: 1px;
}
.lvml {
behavior: url(#default#VML);
display: inline-block;
position: absolute;
}
/* control positioning */
.leaflet-control {
position: relative;
z-index: 800;
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
pointer-events: auto;
}
.leaflet-top,
.leaflet-bottom {
position: absolute;
z-index: 1000;
pointer-events: none;
}
.leaflet-top {
top: 0;
}
.leaflet-right {
right: 0;
}
.leaflet-bottom {
bottom: 0;
}
.leaflet-left {
left: 0;
}
.leaflet-control {
float: left;
clear: both;
}
.leaflet-right .leaflet-control {
float: right;
}
.leaflet-top .leaflet-control {
margin-top: 10px;
}
.leaflet-bottom .leaflet-control {
margin-bottom: 10px;
}
.leaflet-left .leaflet-control {
margin-left: 10px;
}
.leaflet-right .leaflet-control {
margin-right: 10px;
}
/* zoom and fade animations */
.leaflet-fade-anim .leaflet-popup {
opacity: 0;
-webkit-transition: opacity 0.2s linear;
-moz-transition: opacity 0.2s linear;
transition: opacity 0.2s linear;
}
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
opacity: 1;
}
.leaflet-zoom-animated {
-webkit-transform-origin: 0 0;
-ms-transform-origin: 0 0;
transform-origin: 0 0;
}
svg.leaflet-zoom-animated {
will-change: transform;
}
.leaflet-zoom-anim .leaflet-zoom-animated {
-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
-moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
transition: transform 0.25s cubic-bezier(0,0,0.25,1);
}
.leaflet-zoom-anim .leaflet-tile,
.leaflet-pan-anim .leaflet-tile {
-webkit-transition: none;
-moz-transition: none;
transition: none;
}
.leaflet-zoom-anim .leaflet-zoom-hide {
visibility: hidden;
}
/* cursors */
.leaflet-interactive {
cursor: pointer;
}
.leaflet-grab {
cursor: -webkit-grab;
cursor: -moz-grab;
cursor: grab;
}
.leaflet-crosshair,
.leaflet-crosshair .leaflet-interactive {
cursor: crosshair;
}
.leaflet-popup-pane,
.leaflet-control {
cursor: auto;
}
.leaflet-dragging .leaflet-grab,
.leaflet-dragging .leaflet-grab .leaflet-interactive,
.leaflet-dragging .leaflet-marker-draggable {
cursor: move;
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
cursor: grabbing;
}
/* marker & overlays interactivity */
.leaflet-marker-icon,
.leaflet-marker-shadow,
.leaflet-image-layer,
.leaflet-pane > svg path,
.leaflet-tile-container {
pointer-events: none;
}
.leaflet-marker-icon.leaflet-interactive,
.leaflet-image-layer.leaflet-interactive,
.leaflet-pane > svg path.leaflet-interactive,
svg.leaflet-image-layer.leaflet-interactive path {
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
pointer-events: auto;
}
/* visual tweaks */
.leaflet-container {
background: #ddd;
outline-offset: 1px;
}
.leaflet-container a {
color: #0078A8;
}
.leaflet-zoom-box {
border: 2px dotted #38f;
background: rgba(255,255,255,0.5);
}
/* general typography */
.leaflet-container {
font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
font-size: 12px;
font-size: 0.75rem;
line-height: 1.5;
}
/* general toolbar styles */
.leaflet-bar {
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
border-radius: 4px;
}
.leaflet-bar a {
background-color: #fff;
border-bottom: 1px solid #ccc;
width: 26px;
height: 26px;
line-height: 26px;
display: block;
text-align: center;
text-decoration: none;
color: black;
}
.leaflet-bar a,
.leaflet-control-layers-toggle {
background-position: 50% 50%;
background-repeat: no-repeat;
display: block;
}
.leaflet-bar a:hover,
.leaflet-bar a:focus {
background-color: #f4f4f4;
}
.leaflet-bar a:first-child {
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
.leaflet-bar a:last-child {
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
border-bottom: none;
}
.leaflet-bar a.leaflet-disabled {
cursor: default;
background-color: #f4f4f4;
color: #bbb;
}
.leaflet-touch .leaflet-bar a {
width: 30px;
height: 30px;
line-height: 30px;
}
.leaflet-touch .leaflet-bar a:first-child {
border-top-left-radius: 2px;
border-top-right-radius: 2px;
}
.leaflet-touch .leaflet-bar a:last-child {
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
}
/* zoom control */
.leaflet-control-zoom-in,
.leaflet-control-zoom-out {
font: bold 18px 'Lucida Console', Monaco, monospace;
text-indent: 1px;
}
.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out {
font-size: 22px;
}
/* layers control */
.leaflet-control-layers {
box-shadow: 0 1px 5px rgba(0,0,0,0.4);
background: #fff;
border-radius: 5px;
}
.leaflet-control-layers-toggle {
background-image: url(images/layers.png);
width: 36px;
height: 36px;
}
.leaflet-retina .leaflet-control-layers-toggle {
background-image: url(images/layers-2x.png);
background-size: 26px 26px;
}
.leaflet-touch .leaflet-control-layers-toggle {
width: 44px;
height: 44px;
}
.leaflet-control-layers .leaflet-control-layers-list,
.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
display: none;
}
.leaflet-control-layers-expanded .leaflet-control-layers-list {
display: block;
position: relative;
}
.leaflet-control-layers-expanded {
padding: 6px 10px 6px 6px;
color: #333;
background: #fff;
}
.leaflet-control-layers-scrollbar {
overflow-y: scroll;
overflow-x: hidden;
padding-right: 5px;
}
.leaflet-control-layers-selector {
margin-top: 2px;
position: relative;
top: 1px;
}
.leaflet-control-layers label {
display: block;
font-size: 13px;
font-size: 1.08333em;
}
.leaflet-control-layers-separator {
height: 0;
border-top: 1px solid #ddd;
margin: 5px -10px 5px -6px;
}
/* Default icon URLs */
.leaflet-default-icon-path { /* used only in path-guessing heuristic, see L.Icon.Default */
background-image: url(images/marker-icon.png);
}
/* attribution and scale controls */
.leaflet-container .leaflet-control-attribution {
background: #fff;
background: rgba(255, 255, 255, 0.8);
margin: 0;
}
.leaflet-control-attribution,
.leaflet-control-scale-line {
padding: 0 5px;
color: #333;
line-height: 1.4;
}
.leaflet-control-attribution a {
text-decoration: none;
}
.leaflet-control-attribution a:hover,
.leaflet-control-attribution a:focus {
text-decoration: underline;
}
.leaflet-attribution-flag {
display: inline !important;
vertical-align: baseline !important;
width: 1em;
height: 0.6669em;
}
.leaflet-left .leaflet-control-scale {
margin-left: 5px;
}
.leaflet-bottom .leaflet-control-scale {
margin-bottom: 5px;
}
.leaflet-control-scale-line {
border: 2px solid #777;
border-top: none;
line-height: 1.1;
padding: 2px 5px 1px;
white-space: nowrap;
-moz-box-sizing: border-box;
box-sizing: border-box;
background: rgba(255, 255, 255, 0.8);
text-shadow: 1px 1px #fff;
}
.leaflet-control-scale-line:not(:first-child) {
border-top: 2px solid #777;
border-bottom: none;
margin-top: -2px;
}
.leaflet-control-scale-line:not(:first-child):not(:last-child) {
border-bottom: 2px solid #777;
}
.leaflet-touch .leaflet-control-attribution,
.leaflet-touch .leaflet-control-layers,
.leaflet-touch .leaflet-bar {
box-shadow: none;
}
.leaflet-touch .leaflet-control-layers,
.leaflet-touch .leaflet-bar {
border: 2px solid rgba(0,0,0,0.2);
background-clip: padding-box;
}
/* popup */
.leaflet-popup {
position: absolute;
text-align: center;
margin-bottom: 20px;
}
.leaflet-popup-content-wrapper {
padding: 1px;
text-align: left;
border-radius: 12px;
}
.leaflet-popup-content {
margin: 13px 24px 13px 20px;
line-height: 1.3;
font-size: 13px;
font-size: 1.08333em;
min-height: 1px;
}
.leaflet-popup-content p {
margin: 17px 0;
margin: 1.3em 0;
}
.leaflet-popup-tip-container {
width: 40px;
height: 20px;
position: absolute;
left: 50%;
margin-top: -1px;
margin-left: -20px;
overflow: hidden;
pointer-events: none;
}
.leaflet-popup-tip {
width: 17px;
height: 17px;
padding: 1px;
margin: -10px auto 0;
pointer-events: auto;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
}
.leaflet-popup-content-wrapper,
.leaflet-popup-tip {
background: white;
color: #333;
box-shadow: 0 3px 14px rgba(0,0,0,0.4);
}
.leaflet-container a.leaflet-popup-close-button {
position: absolute;
top: 0;
right: 0;
border: none;
text-align: center;
width: 24px;
height: 24px;
font: 16px/24px Tahoma, Verdana, sans-serif;
color: #757575;
text-decoration: none;
background: transparent;
}
.leaflet-container a.leaflet-popup-close-button:hover,
.leaflet-container a.leaflet-popup-close-button:focus {
color: #585858;
}
.leaflet-popup-scrolled {
overflow: auto;
}
.leaflet-oldie .leaflet-popup-content-wrapper {
-ms-zoom: 1;
}
.leaflet-oldie .leaflet-popup-tip {
width: 24px;
margin: 0 auto;
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
}
.leaflet-oldie .leaflet-control-zoom,
.leaflet-oldie .leaflet-control-layers,
.leaflet-oldie .leaflet-popup-content-wrapper,
.leaflet-oldie .leaflet-popup-tip {
border: 1px solid #999;
}
/* div icon */
.leaflet-div-icon {
background: #fff;
border: 1px solid #666;
}
/* Tooltip */
/* Base styles for the element that has a tooltip */
.leaflet-tooltip {
position: absolute;
padding: 6px;
background-color: #fff;
border: 1px solid #fff;
border-radius: 3px;
color: #222;
white-space: nowrap;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
pointer-events: none;
box-shadow: 0 1px 3px rgba(0,0,0,0.4);
}
.leaflet-tooltip.leaflet-interactive {
cursor: pointer;
pointer-events: auto;
}
.leaflet-tooltip-top:before,
.leaflet-tooltip-bottom:before,
.leaflet-tooltip-left:before,
.leaflet-tooltip-right:before {
position: absolute;
pointer-events: none;
border: 6px solid transparent;
background: transparent;
content: "";
}
/* Directions */
.leaflet-tooltip-bottom {
margin-top: 6px;
}
.leaflet-tooltip-top {
margin-top: -6px;
}
.leaflet-tooltip-bottom:before,
.leaflet-tooltip-top:before {
left: 50%;
margin-left: -6px;
}
.leaflet-tooltip-top:before {
bottom: 0;
margin-bottom: -12px;
border-top-color: #fff;
}
.leaflet-tooltip-bottom:before {
top: 0;
margin-top: -12px;
margin-left: -6px;
border-bottom-color: #fff;
}
.leaflet-tooltip-left {
margin-left: -6px;
}
.leaflet-tooltip-right {
margin-left: 6px;
}
.leaflet-tooltip-left:before,
.leaflet-tooltip-right:before {
top: 50%;
margin-top: -6px;
}
.leaflet-tooltip-left:before {
right: 0;
margin-right: -12px;
border-left-color: #fff;
}
.leaflet-tooltip-right:before {
left: 0;
margin-left: -12px;
border-right-color: #fff;
}
/* Printing */
@media print {
/* Prevent printers from removing background-images of controls. */
.leaflet-control {
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
}
File diff suppressed because one or more lines are too long
+151
View File
@@ -0,0 +1,151 @@
// AIS Map Service Worker — кеширование тайлов и ассетов.
// Цели: моментальная отрисовка карты после первой загрузки, офлайн-доступ к ранее
// просмотренным тайлам, минимум сетевых запросов в slow-networks и при pan/zoom.
const CACHE_VERSION = 'v2';
const TILE_CACHE = 'aismap-tiles-' + CACHE_VERSION;
const ASSET_CACHE = 'aismap-assets-' + CACHE_VERSION;
const APP_CACHE = 'aismap-app-' + CACHE_VERSION;
// Ограничиваем, сколько тайлов держим на устройстве, чтобы не забить storage на телефоне.
const TILE_CACHE_MAX = 4000;
self.addEventListener('install', (event) => {
self.skipWaiting();
});
self.addEventListener('activate', (event) => {
event.waitUntil((async () => {
const keys = await caches.keys();
await Promise.all(
keys
.filter((k) => ![TILE_CACHE, ASSET_CACHE, APP_CACHE].includes(k))
.map((k) => caches.delete(k))
);
await self.clients.claim();
})());
});
function isTileRequest(url) {
return url.pathname.startsWith('/tiles/') || url.pathname.startsWith('/vtiles/');
}
function isLongLivedAsset(url) {
if (url.pathname.startsWith('/static/leaflet/')) return true;
if (url.pathname.startsWith('/static/xterm/')) return true;
if (url.pathname.startsWith('/svg/')) return true;
return false;
}
function isAppShell(url) {
if (url.pathname === '/' || url.pathname === '/cert') return true;
if (url.pathname.startsWith('/static/js/')) return true;
if (url.pathname.startsWith('/static/css/')) return true;
return false;
}
function isApiRequest(url) {
return url.pathname.startsWith('/api/') || url.pathname === '/ws' || url.pathname.startsWith('/ws/');
}
async function trimCache(cacheName, max) {
try {
const cache = await caches.open(cacheName);
const keys = await cache.keys();
if (keys.length <= max) return;
const excess = keys.length - max;
for (let i = 0; i < excess; i += 1) {
await cache.delete(keys[i]);
}
} catch (e) {}
}
// Cache-first с фоновым обновлением: отдаём из кеша если есть, в фоне освежаем.
async function cacheFirstWithRefresh(request, cacheName) {
const cache = await caches.open(cacheName);
const cached = await cache.match(request);
const fetchAndUpdate = fetch(request)
.then((resp) => {
if (resp && resp.ok) {
cache.put(request, resp.clone()).catch(() => {});
if (cacheName === TILE_CACHE) {
trimCache(TILE_CACHE, TILE_CACHE_MAX);
}
}
return resp;
})
.catch(() => null);
if (cached) {
// Обновление в фоне, клиенту отдаём кеш немедленно.
fetchAndUpdate.catch(() => {});
return cached;
}
const fresh = await fetchAndUpdate;
if (fresh) return fresh;
return new Response('', { status: 504, statusText: 'Gateway Timeout (offline)' });
}
// Stale-while-revalidate: мгновенно из кеша, параллельно обновляем кеш.
async function staleWhileRevalidate(request, cacheName) {
const cache = await caches.open(cacheName);
const cached = await cache.match(request);
const networkFetch = fetch(request)
.then((resp) => {
if (resp && resp.ok) {
cache.put(request, resp.clone()).catch(() => {});
}
return resp;
})
.catch(() => null);
if (cached) {
networkFetch.catch(() => {});
return cached;
}
const fresh = await networkFetch;
if (fresh) return fresh;
return new Response('', { status: 504, statusText: 'Gateway Timeout (offline)' });
}
self.addEventListener('fetch', (event) => {
const req = event.request;
if (req.method !== 'GET') return;
let url;
try {
url = new URL(req.url);
} catch (e) {
return;
}
// Не трогаем кросс-оригинальные запросы (OSM, CARTO и т.п.) — пусть идут напрямую.
if (url.origin !== self.location.origin) return;
// API и WebSocket — без кеша. WebSocket вообще не проходит через fetch, но на всякий случай.
if (isApiRequest(url)) return;
if (isTileRequest(url)) {
event.respondWith(cacheFirstWithRefresh(req, TILE_CACHE));
return;
}
if (isLongLivedAsset(url)) {
event.respondWith(cacheFirstWithRefresh(req, ASSET_CACHE));
return;
}
if (isAppShell(url)) {
event.respondWith(staleWhileRevalidate(req, APP_CACHE));
return;
}
});
// Принудительный сброс кешей по команде со страницы.
self.addEventListener('message', (event) => {
if (!event.data || typeof event.data !== 'object') return;
if (event.data.type === 'aismap:clear-caches') {
event.waitUntil((async () => {
const keys = await caches.keys();
await Promise.all(keys.map((k) => caches.delete(k)));
})());
}
});
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Some files were not shown because too many files have changed in this diff Show More