|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
<html>
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
https://bugzilla.mozilla.org/show_bug.cgi?id=421640
|
|
Packit |
f0b94e |
-->
|
|
Packit |
f0b94e |
<head>
|
|
Packit |
f0b94e |
<title>Test for Bug 396392</title>
|
|
Packit |
f0b94e |
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
|
Packit |
f0b94e |
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
|
Packit |
f0b94e |
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
|
Packit |
f0b94e |
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
|
Packit |
f0b94e |
</head>
|
|
Packit |
f0b94e |
<body>
|
|
Packit |
f0b94e |
Mozilla Bug Range getClientRects and getBoundingClientRect
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
0000000 000000 000000000000 000000000000 00000000000000 000000 000000000000 00000000000003 100305
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
english <bdo id="bdo" dir="rtl">rtl-overide english</bdo> word
|
|
Packit |
f0b94e |
english <bdo id="bdo2" dir="rtl">rtl-override english</bdo> word
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
<script class="testbody" type="text/javascript">
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
var isLTR = true;
|
|
Packit |
f0b94e |
var isTransformed = false;
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
function annotateName(name) {
|
|
Packit |
f0b94e |
return (isLTR ? 'isLTR ' : 'isRTL ') +
|
|
Packit |
f0b94e |
(isTransformed ? 'transformed ' : '') + name;
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
function isEmptyRect(rect, name) {
|
|
Packit |
f0b94e |
name = annotateName(name);
|
|
Packit |
f0b94e |
is(rect.left, 0, name+'empty rect should have left = 0');
|
|
Packit |
f0b94e |
is(rect.right, 0, name+'empty rect should have right = 0');
|
|
Packit |
f0b94e |
is(rect.top, 0, name+'empty rect should have top = 0');
|
|
Packit |
f0b94e |
is(rect.bottom, 0, name+'empty rect should have bottom = 0');
|
|
Packit |
f0b94e |
is(rect.width, 0, name+'empty rect should have width = 0');
|
|
Packit |
f0b94e |
is(rect.height, 0, name+'empty rect should have height = 0');
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
function isEmptyRectList(rectlist, name) {
|
|
Packit |
f0b94e |
name = annotateName(name);
|
|
Packit |
f0b94e |
is(rectlist.length, 0, name + 'empty rectlist should have zero rects');
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
// round coordinates to the nearest 1/256 of a pixel
|
|
Packit |
f0b94e |
function roundCoord(x) {
|
|
Packit |
f0b94e |
return Math.round(x * 256) / 256;
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
function _getRect(r) {
|
|
Packit |
f0b94e |
if (r.length) //array
|
|
Packit |
f0b94e |
return "{left:"+roundCoord(r[0])+",right:"+roundCoord(r[1])+
|
|
Packit |
f0b94e |
",top:" +roundCoord(r[2])+",bottom:"+roundCoord(r[3])+
|
|
Packit |
f0b94e |
",width:"+roundCoord(r[4])+",height:"+roundCoord(r[5])+"}";
|
|
Packit |
f0b94e |
else
|
|
Packit |
f0b94e |
return "{left:"+roundCoord(r.left)+",right:"+roundCoord(r.right)+
|
|
Packit |
f0b94e |
",top:"+roundCoord(r.top)+",bottom:"+roundCoord(r.bottom)+
|
|
Packit |
f0b94e |
",width:"+roundCoord(r.width)+",height:"+roundCoord(r.height)+"}";
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
function runATest(obj) {
|
|
Packit |
f0b94e |
var range = document.createRange();
|
|
Packit |
f0b94e |
try {
|
|
Packit |
f0b94e |
range.setStart(obj.range[0],obj.range[1]);
|
|
Packit |
f0b94e |
if (obj.range.length>2) {
|
|
Packit |
f0b94e |
range.setEnd(obj.range[2]||obj.range[0], obj.range[3]);
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
//test getBoundingClientRect()
|
|
Packit |
f0b94e |
var rect = range.getBoundingClientRect();
|
|
Packit |
f0b94e |
var testname = 'range.getBoundingClientRect for ' + obj.name;
|
|
Packit |
f0b94e |
if (obj.rect) {
|
|
Packit |
f0b94e |
is(_getRect(rect),_getRect(obj.rect), annotateName(testname));
|
|
Packit |
f0b94e |
} else {
|
|
Packit |
f0b94e |
isEmptyRect(rect,testname+": ");
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
//test getClientRects()
|
|
Packit |
f0b94e |
var rectlist = range.getClientRects();
|
|
Packit |
f0b94e |
testname = 'range.getClientRects for ' + obj.name;
|
|
Packit |
f0b94e |
if (!obj.rectList) {
|
|
Packit |
f0b94e |
//rectList is not specified, use obj.rect to figure out rectList
|
|
Packit |
f0b94e |
obj.rectList = obj.rect?[obj.rect]:[];
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
if (!obj.rectList.length) {
|
|
Packit |
f0b94e |
isEmptyRectList(rectlist, testname+": ");
|
|
Packit |
f0b94e |
} else {
|
|
Packit |
f0b94e |
is(rectlist.length, obj.rectList.length,
|
|
Packit |
f0b94e |
annotateName(testname+' should return '+obj.rectList.length+' rects.'));
|
|
Packit |
f0b94e |
if(!obj.rectList.forEach){
|
|
Packit |
f0b94e |
//convert RectList to a real array
|
|
Packit |
f0b94e |
obj.rectList=Array.prototype.slice.call(obj.rectList, 0);
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
obj.rectList.forEach(function(rect,i) {
|
|
Packit |
f0b94e |
is(_getRect(rectlist[i]),_getRect(rect),
|
|
Packit |
f0b94e |
annotateName(testname+": item at "+i));
|
|
Packit |
f0b94e |
});
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
} finally {
|
|
Packit |
f0b94e |
range.detach();
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
/** Test for Bug 396392 **/
|
|
Packit |
f0b94e |
function doTest(){
|
|
Packit |
f0b94e |
var root = document.getElementById('content');
|
|
Packit |
f0b94e |
var firstP = root.firstElementChild, spanInFirstP = firstP.childNodes[1],
|
|
Packit |
f0b94e |
firstDiv = root.childNodes[2], spanInFirstDiv = firstDiv.childNodes[1],
|
|
Packit |
f0b94e |
secondP = root.childNodes[3], spanInSecondP = secondP.childNodes[1],
|
|
Packit |
f0b94e |
secondDiv = root.childNodes[4], spanInSecondDiv = secondDiv.firstChild,
|
|
Packit |
f0b94e |
thirdDiv = root.childNodes[5];
|
|
Packit |
f0b94e |
var firstPRect = firstP.getBoundingClientRect(),
|
|
Packit |
f0b94e |
spanInFirstPRect = spanInFirstP.getBoundingClientRect(),
|
|
Packit |
f0b94e |
firstDivRect = firstDiv.getBoundingClientRect(),
|
|
Packit |
f0b94e |
spanInFirstDivRect = spanInFirstDiv.getBoundingClientRect(),
|
|
Packit |
f0b94e |
secondPRect = secondP.getBoundingClientRect(),
|
|
Packit |
f0b94e |
secondDivRect = secondDiv.getBoundingClientRect(),
|
|
Packit |
f0b94e |
spanInSecondPRect = spanInSecondP.getBoundingClientRect(),
|
|
Packit |
f0b94e |
spanInSecondDivRect = spanInSecondDiv.getBoundingClientRect(),
|
|
Packit |
f0b94e |
spanInSecondDivRectList = spanInSecondDiv.getClientRects();
|
|
Packit |
f0b94e |
var widthPerchar = spanInSecondPRect.width / spanInSecondP.firstChild.length;
|
|
Packit |
f0b94e |
var testcases = [
|
|
Packit |
f0b94e |
{name:'nodesNotInDocument', range:[document.createTextNode('abc'), 1],
|
|
Packit |
f0b94e |
rect:null},
|
|
Packit |
f0b94e |
{name:'collapsedInBlockNode', range:[firstP, 2], rect:null},
|
|
Packit |
f0b94e |
{name:'collapsedAtBeginningOfTextNode', range:[firstP.firstChild, 0],
|
|
Packit |
f0b94e |
rect:[spanInFirstPRect.left - 6 * widthPerchar,
|
|
Packit |
f0b94e |
spanInFirstPRect.left - 6 * widthPerchar, spanInFirstPRect.top,
|
|
Packit |
f0b94e |
spanInFirstPRect.bottom, 0, spanInFirstPRect.height]},
|
|
Packit |
f0b94e |
{name:'collapsedWithinTextNode', range:[firstP.firstChild, 1],
|
|
Packit |
f0b94e |
rect:[spanInFirstPRect.left - 5 * widthPerchar,
|
|
Packit |
f0b94e |
spanInFirstPRect.left - 5 * widthPerchar,
|
|
Packit |
f0b94e |
spanInFirstPRect.top, spanInFirstPRect.bottom, 0, spanInFirstPRect.height]},
|
|
Packit |
f0b94e |
{name:'collapsedAtEndOfTextNode', range:[firstP.firstChild, 6],
|
|
Packit |
f0b94e |
rect:[spanInFirstPRect.left, spanInFirstPRect.left,
|
|
Packit |
f0b94e |
spanInFirstPRect.top, spanInFirstPRect.bottom, 0, spanInFirstPRect.height]},
|
|
Packit |
f0b94e |
{name:'singleBlockNode', range:[root, 1, root, 2], rect:firstPRect},
|
|
Packit |
f0b94e |
{name:'twoBlockNodes', range:[root, 1, root, 3],
|
|
Packit |
f0b94e |
rect:[firstPRect.left, firstPRect.right, firstPRect.top,
|
|
Packit |
f0b94e |
firstDivRect.bottom, firstPRect.width,
|
|
Packit |
f0b94e |
firstDivRect.bottom - firstPRect.top],
|
|
Packit |
f0b94e |
rectList:[firstPRect, firstDivRect]},
|
|
Packit |
f0b94e |
{name:'endOfTextNodeToEndOfAnotherTextNodeInAnotherBlock',
|
|
Packit |
f0b94e |
range:[spanInFirstP.firstChild, 1, firstDiv.firstChild, 5],
|
|
Packit |
f0b94e |
rect:[spanInFirstDivRect.left - 5*widthPerchar, spanInFirstDivRect.left,
|
|
Packit |
f0b94e |
spanInFirstDivRect.top, spanInFirstDivRect.bottom, 5 * widthPerchar,
|
|
Packit |
f0b94e |
spanInFirstDivRect.height]},
|
|
Packit |
f0b94e |
{name:'startOfTextNodeToStartOfAnotherTextNodeInAnotherBlock',
|
|
Packit |
f0b94e |
range:[spanInFirstP.firstChild, 0, firstDiv.firstChild, 0],
|
|
Packit |
f0b94e |
rect:[spanInFirstPRect.left, spanInFirstPRect.left + widthPerchar, spanInFirstPRect.top,
|
|
Packit |
f0b94e |
spanInFirstPRect.bottom, widthPerchar, spanInFirstPRect.height]},
|
|
Packit |
f0b94e |
{name:'endPortionOfATextNode', range:[firstP.firstChild, 3,
|
|
Packit |
f0b94e |
firstP.firstChild, 6],
|
|
Packit |
f0b94e |
rect:[spanInFirstPRect.left - 3*widthPerchar, spanInFirstPRect.left,
|
|
Packit |
f0b94e |
spanInFirstPRect.top, spanInFirstPRect.bottom, 3*widthPerchar, spanInFirstPRect.height]},
|
|
Packit |
f0b94e |
{name:'startPortionOfATextNode', range:[firstP.firstChild, 0,
|
|
Packit |
f0b94e |
firstP.firstChild, 3],
|
|
Packit |
f0b94e |
rect:[spanInFirstPRect.left - 6*widthPerchar,
|
|
Packit |
f0b94e |
spanInFirstPRect.left - 3*widthPerchar, spanInFirstPRect.top,
|
|
Packit |
f0b94e |
spanInFirstPRect.bottom, 3 * widthPerchar, spanInFirstPRect.height]},
|
|
Packit |
f0b94e |
{name:'spanTextNodes', range:[secondP.firstChild, 1, secondP.lastChild, 1],
|
|
Packit |
f0b94e |
rect:[spanInSecondPRect.left - 3*widthPerchar, spanInSecondPRect.right +
|
|
Packit |
f0b94e |
widthPerchar, spanInSecondPRect.top, spanInSecondPRect.bottom,
|
|
Packit |
f0b94e |
spanInSecondPRect.width + 4*widthPerchar, spanInSecondPRect.height],
|
|
Packit |
f0b94e |
rectList:[[spanInSecondPRect.left - 3*widthPerchar, spanInSecondPRect.left,
|
|
Packit |
f0b94e |
spanInSecondPRect.top, spanInSecondPRect.bottom, 3 * widthPerchar,
|
|
Packit |
f0b94e |
spanInSecondPRect.height],
|
|
Packit |
f0b94e |
spanInSecondPRect,
|
|
Packit |
f0b94e |
[spanInSecondPRect.right, spanInSecondPRect.right + widthPerchar,
|
|
Packit |
f0b94e |
spanInSecondPRect.top, spanInSecondPRect.bottom, widthPerchar,
|
|
Packit |
f0b94e |
spanInSecondPRect.height]]}
|
|
Packit |
f0b94e |
];
|
|
Packit |
f0b94e |
testcases.forEach(runATest);
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
// testcases that have different ranges in LTR and RTL
|
|
Packit |
f0b94e |
var directionDependentTestcases;
|
|
Packit |
f0b94e |
if (isLTR) {
|
|
Packit |
f0b94e |
directionDependentTestcases = [
|
|
Packit |
f0b94e |
{name:'spanAcrossLines',range:[spanInSecondDiv.firstChild, 1, spanInSecondDiv.firstChild, 30],
|
|
Packit |
f0b94e |
rect: spanInSecondDivRect,
|
|
Packit |
f0b94e |
rectList:[[spanInSecondDivRectList[0].left+widthPerchar,
|
|
Packit |
f0b94e |
spanInSecondDivRectList[0].right, spanInSecondDivRectList[0].top,
|
|
Packit |
f0b94e |
spanInSecondDivRectList[0].bottom, spanInSecondDivRectList[0].width - widthPerchar,
|
|
Packit |
f0b94e |
spanInSecondDivRectList[0].height],
|
|
Packit |
f0b94e |
spanInSecondDivRectList[1],
|
|
Packit |
f0b94e |
[spanInSecondDivRectList[2].left,
|
|
Packit |
f0b94e |
spanInSecondDivRectList[2].right - 4 * widthPerchar, spanInSecondDivRectList[2].top,
|
|
Packit |
f0b94e |
spanInSecondDivRectList[2].bottom,
|
|
Packit |
f0b94e |
spanInSecondDivRectList[2].width - 4 * widthPerchar,
|
|
Packit |
f0b94e |
spanInSecondDivRectList[2].height]]},
|
|
Packit |
f0b94e |
{name:'textAcrossLines',range:[thirdDiv.firstChild, 13, thirdDiv.firstChild, 28],
|
|
Packit |
f0b94e |
rect: [spanInSecondDivRectList[1].left, spanInSecondDivRectList[1].right,
|
|
Packit |
f0b94e |
spanInSecondDivRectList[1].top + secondDivRect.height,
|
|
Packit |
f0b94e |
spanInSecondDivRectList[1].bottom + secondDivRect.height,
|
|
Packit |
f0b94e |
spanInSecondDivRectList[1].width, spanInSecondDivRectList[1].height]}
|
|
Packit |
f0b94e |
];
|
|
Packit |
f0b94e |
} else {
|
|
Packit |
f0b94e |
directionDependentTestcases = [
|
|
Packit |
f0b94e |
{name:'spanAcrossLines',range:[spanInSecondDiv.firstChild, 1, spanInSecondDiv.firstChild, 30],
|
|
Packit |
f0b94e |
rect: spanInSecondDivRect,
|
|
Packit |
f0b94e |
rectList:[[spanInSecondDivRectList[0].left+widthPerchar,
|
|
Packit |
f0b94e |
spanInSecondDivRectList[0].right, spanInSecondDivRectList[0].top,
|
|
Packit |
f0b94e |
spanInSecondDivRectList[0].bottom, spanInSecondDivRectList[0].width - widthPerchar,
|
|
Packit |
f0b94e |
spanInSecondDivRectList[0].height],
|
|
Packit |
f0b94e |
spanInSecondDivRectList[1],
|
|
Packit |
f0b94e |
spanInSecondDivRectList[2],
|
|
Packit |
f0b94e |
spanInSecondDivRectList[3],
|
|
Packit |
f0b94e |
[spanInSecondDivRectList[4].left,
|
|
Packit |
f0b94e |
spanInSecondDivRectList[4].right - 4 * widthPerchar,
|
|
Packit |
f0b94e |
spanInSecondDivRectList[4].top,
|
|
Packit |
f0b94e |
spanInSecondDivRectList[4].bottom,
|
|
Packit |
f0b94e |
spanInSecondDivRectList[4].width - 4 * widthPerchar,
|
|
Packit |
f0b94e |
spanInSecondDivRectList[4].height]]},
|
|
Packit |
f0b94e |
{name:'textAcrossLines',range:[thirdDiv.firstChild, 13, thirdDiv.firstChild, 28],
|
|
Packit |
f0b94e |
rect: [spanInSecondDivRectList[2].left, spanInSecondDivRectList[2].right,
|
|
Packit |
f0b94e |
spanInSecondDivRectList[2].top + secondDivRect.height,
|
|
Packit |
f0b94e |
spanInSecondDivRectList[2].bottom + secondDivRect.height,
|
|
Packit |
f0b94e |
spanInSecondDivRectList[2].width, spanInSecondDivRectList[2].height],
|
|
Packit |
f0b94e |
rectList:[[spanInSecondDivRectList[2].left, spanInSecondDivRectList[2].right,
|
|
Packit |
f0b94e |
spanInSecondDivRectList[2].top + secondDivRect.height,
|
|
Packit |
f0b94e |
spanInSecondDivRectList[2].bottom + secondDivRect.height,
|
|
Packit |
f0b94e |
spanInSecondDivRectList[2].width, spanInSecondDivRectList[2].height],
|
|
Packit |
f0b94e |
[spanInSecondDivRectList[2].left, spanInSecondDivRectList[2].left,
|
|
Packit |
f0b94e |
spanInSecondDivRectList[2].top + secondDivRect.height,
|
|
Packit |
f0b94e |
spanInSecondDivRectList[2].bottom + secondDivRect.height,
|
|
Packit |
f0b94e |
0, spanInSecondDivRectList[2].height]]}
|
|
Packit |
f0b94e |
];
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
directionDependentTestcases.forEach(runATest);
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
function testMixedDir(){
|
|
Packit |
f0b94e |
var root = document.getElementById('mixeddir');
|
|
Packit |
f0b94e |
var firstSpan = root.firstElementChild, firstSpanRect=firstSpan.getBoundingClientRect(),
|
|
Packit |
f0b94e |
firstSpanRectList = firstSpan.getClientRects();
|
|
Packit |
f0b94e |
runATest({name:'mixeddir',range:[firstSpan.firstChild,0,firstSpan.lastChild,firstSpan.lastChild.length],
|
|
Packit |
f0b94e |
rect: firstSpanRect, rectList:firstSpanRectList});
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
root = document.getElementById('mixeddir2');
|
|
Packit |
f0b94e |
firstSpan = root.firstElementChild;
|
|
Packit |
f0b94e |
firstSpanRect = firstSpan.getBoundingClientRect();
|
|
Packit |
f0b94e |
bdo = document.getElementById('bdo2');
|
|
Packit |
f0b94e |
bdoRect=bdo.getBoundingClientRect();
|
|
Packit |
f0b94e |
var widthPerChar = bdoRect.width / bdo.firstChild.length;
|
|
Packit |
f0b94e |
runATest({name:'mixeddirPartial', range:[firstSpan.firstChild, 3,
|
|
Packit |
f0b94e |
bdo.firstChild, 7],
|
|
Packit |
f0b94e |
rect: [firstSpanRect.left + 3*widthPerChar, bdoRect.right,
|
|
Packit |
f0b94e |
bdoRect.top, bdoRect.bottom,
|
|
Packit |
f0b94e |
(firstSpan.firstChild.length + bdo.firstChild.length - 3) *
|
|
Packit |
f0b94e |
widthPerChar,
|
|
Packit |
f0b94e |
bdoRect.height],
|
|
Packit |
f0b94e |
rectList:[[firstSpanRect.left + 3*widthPerChar,
|
|
Packit |
f0b94e |
bdoRect.left,
|
|
Packit |
f0b94e |
firstSpanRect.top, firstSpanRect.bottom,
|
|
Packit |
f0b94e |
(firstSpan.firstChild.length - 3) * widthPerChar,
|
|
Packit |
f0b94e |
firstSpanRect.height],
|
|
Packit |
f0b94e |
[bdoRect.right - 7 * widthPerChar, bdoRect.right,
|
|
Packit |
f0b94e |
bdoRect.top, bdoRect.bottom,
|
|
Packit |
f0b94e |
7*widthPerChar, bdoRect.height]]});
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
function test(){
|
|
Packit |
f0b94e |
//test ltr
|
|
Packit |
f0b94e |
doTest();
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
//test rtl
|
|
Packit |
f0b94e |
isLTR = false;
|
|
Packit |
f0b94e |
var root = document.getElementById('content');
|
|
Packit |
f0b94e |
root.dir = 'rtl';
|
|
Packit |
f0b94e |
doTest();
|
|
Packit |
f0b94e |
isLTR = true;
|
|
Packit |
f0b94e |
root.dir = 'ltr';
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
testMixedDir();
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
//test transforms
|
|
Packit |
f0b94e |
isTransformed = true;
|
|
Packit |
f0b94e |
root.style.transform = "translate(30px,50px)";
|
|
Packit |
f0b94e |
doTest();
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
SimpleTest.finish();
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
window.onload = function() {
|
|
Packit |
f0b94e |
SimpleTest.waitForExplicitFinish();
|
|
Packit |
f0b94e |
setTimeout(test, 0);
|
|
Packit |
f0b94e |
};
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
</script>
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
</body>
|
|
Packit |
f0b94e |
</html>
|