Skip to content

Commit

Permalink
Merge pull request #10 from voinmerk/master
Browse files Browse the repository at this point in the history
fix: Исправлено удаление мусорных тегов для больших шаблонов
  • Loading branch information
bingo-soft authored Aug 17, 2022
2 parents 29e5e72 + 4019ca1 commit 76f94d9
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 67 deletions.
2 changes: 1 addition & 1 deletion .phpunit.result.cache
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"version":1,"defects":{"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testTable":3,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testImages":4,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testSections":3},"times":{"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testTable":0.008,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testXmlToString":0.005,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testGetDocx":0.002,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testGetXml":0.002,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testPatchXml":0.002,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testRenderXml":0.014,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testRender":0.007,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testLineBreak":0.003,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testCyrillic":0.002,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testForLoop":0.006,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testImages":0.788,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testSections":0.009}}
{"version":1,"defects":{"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testTable":3,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testImages":4,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testSections":3,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testTemplate":4,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testRenderXml":3,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testPatchXml":4},"times":{"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testTable":0.057,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testXmlToString":0.029,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testGetDocx":0.02,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testGetXml":0.025,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testPatchXml":0.021,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testRenderXml":0.083,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testRender":0.065,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testLineBreak":0.056,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testCyrillic":0.074,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testForLoop":0.057,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testImages":0.124,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testSections":0.09,"Doctrine\\Tests\\DBAL\\Query\\PhpDocxTemplateTest::testTemplate":0.111}}
39 changes: 33 additions & 6 deletions src/PhpDocxTemplate.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
namespace PhpDocxTemplate;

use DOMDocument;
use DOMElement;
use Twig\Loader\ArrayLoader;
use Twig\Environment;
use PhpDocxTemplate\Twig\Impl\{
Expand Down Expand Up @@ -99,16 +98,44 @@ private function updateXml(DOMDocument $xml): void
$this->docx->updateDOMDocument($xml);
}

public function patchXml(string $xml): string
{
$matches = [];

preg_match('/^.*?(<w:body>)/s', $xml, $matches);

$beforeXml = $matches[0];

preg_match('/(<\/w:body>).*?$/s', $xml, $matches);

$afterXml = $matches[0];

$dom = new DOMDocument();
$dom->loadXML($xml);

$elBody = $dom->getElementsByTagName('body')->item(0);

$chunkXml = '';

for ($itemIdx = 0; $itemIdx < $elBody->childNodes->count(); $itemIdx++) {
$el = $elBody->childNodes->item($itemIdx);

$chunkXml .= $this->patchXmlChunk($el->ownerDocument->saveXML($el));
}

return sprintf('%s%s%s', $beforeXml, $chunkXml, $afterXml);
}

/**
* Patch initial xml
*
* @param string $xml - initial xml
*/
public function patchXml(string $xml): string
public function patchXmlChunk(string $xml): string
{
$xml = preg_replace('/(?<={)(<[^>]*>)+(?=[\{%])|(?<=[%\}])(<[^>]*>)+(?=\})/mu', '', $xml);
$xml = preg_replace('/(?<={)(<[^>]*>)+(?=[\{%\#])|(?<=[%\}\#])(<[^>]*>)+(?=\})/mu', '', $xml);
$xml = preg_replace_callback(
'/{%(?:(?!%}).)*|{{(?:(?!}}).)*/mu',
'/{%(?:(?!%}).)*|{#(?:(?!#}).)*|{{(?:(?!}}).)*/mu',
array(get_class($this), 'stripTags'),
$xml
);
Expand Down Expand Up @@ -262,7 +289,7 @@ private function resolveText(string $paragraphProperties, string $runProperties,
*
* @return string
*/
private function stripTags(array $matches): string
private static function stripTags(array $matches): string
{
return preg_replace('/<\/w:t>.*?(<w:t>|<w:t [^>]*>)/mu', '', $matches[0]);
}
Expand All @@ -274,7 +301,7 @@ private function stripTags(array $matches): string
*
* @return string
*/
private function colspan(array $matches): string
private static function colspan(array $matches): string
{
$cellXml = $matches[1] . $matches[3];
$cellXml = preg_replace('/<w:r[ >](?:(?!<w:r[ >]).)*<w:t><\/w:t>.*?<\/w:r>/mu', '', $cellXml);
Expand Down
120 changes: 60 additions & 60 deletions tests/PhpDocxTemplateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class PhpDocxTemplateTest extends TestCase
public function testXmlToString(): void
{
$xml = new DOMDocument('1.0');
$root = $xml->createElement('book');
$root = $xml->createElement('w:body');
$root = $xml->appendChild($root);
$title = $xml->createElement('title');
$title = $root->appendChild($title);
Expand All @@ -33,7 +33,7 @@ public function testXmlToString(): void

$this->assertEquals(
$reporter->xmlToString($xml),
"<?xml version=\"1.0\"?>\n<book><title>Title</title></book>\n"
"<?xml version=\"1.0\"?>\n<w:body><title>Title</title></w:body>\n"
);
$reporter->close();
}
Expand Down Expand Up @@ -99,64 +99,64 @@ public function testPatchXml(): void
//test stripTags
$xml = "{<tag>%Hello</w:t><w:t>\nworld%<tag>}\n{<tag>{Hi</w:t><w:t>\nthere}<tag>}\n";
$this->assertEquals(
$reporter->patchXml($xml),
$reporter->patchXmlChunk($xml),
"{%Hello\nworld%}\n{{Hi\nthere}}\n"
);

//test colspan
$xml = "<w:tc xeLLm[t6;cT&!Z_#KI8cniins[)UX>TAnAaqg_a}sePvK.OO#Q=B-]cBDFM8UL]8m@i" .
"Ct{% colspan val%}TkuSd<w:r meg+PYSJWO}~k<w:t></w:t></w:r>" .
"<w:gridSpan88MJ@1bX/><w:tcPrL4><w:gridSpan@1bY/>?Nl`z:^kY@FXeJ@P{8WhCt0__/,8woI2." .
"8#[r_Cqig!5Qt{8gl5ls<9Ci|^QN2IK#L[cB9@:XclVQQIxe</w:tc>";
"Ct{% colspan val%}TkuSd<w:r meg+PYSJWO}~k<w:t></w:t></w:r>" .
"<w:gridSpan88MJ@1bX/><w:tcPrL4><w:gridSpan@1bY/>?Nl`z:^kY@FXeJ@P{8WhCt0__/,8woI2." .
"8#[r_Cqig!5Qt{8gl5ls<9Ci|^QN2IK#L[cB9@:XclVQQIxe</w:tc>";
$this->assertEquals(
$reporter->patchXml($xml),
$reporter->patchXmlChunk($xml),
'<w:tc xeLLm[t6;cT&!Z_#KI8cniins[)UX>TAnAaqg_a}sePvK.OO#Q=B-]cBDFM8UL]8m@iCtTkuSd<w:tcPrL4>' .
'<w:gridSpan w:val="{{val}}"/><w:gridSpan@1bY/>?Nl`z:^kY@FXeJ@P{8WhCt0__/,8woI2.8#[r_Cqig!5Qt' .
'{8gl5ls<9Ci|^QN2IK#L[cB9@:XclVQQIxe</w:tc>'
);

//test cellbg
$xml = "<w:tc xeLLm[t6;cT&!Z_#KI8cniins[)UX>TAnAaqg_a}sePvK.OO#Q=B-]cBDFM8UL]8m@i" .
"Ct{% cellbg val%}TkuSd<w:r meg+PYSJWO}~k<w:t></w:t></w:r>" .
"<w:shd88MJ@1bX/><w:tcPrL4><w:shd@1bY/>?Nl`z:^kY@FXeJ@P{8WhCt0__/,8woI2." .
"8#[r_Cqig!5Qt{8gl5ls<9Ci|^QN2IK#L[cB9@:XclVQQIxe</w:tc>";
"Ct{% cellbg val%}TkuSd<w:r meg+PYSJWO}~k<w:t></w:t></w:r>" .
"<w:shd88MJ@1bX/><w:tcPrL4><w:shd@1bY/>?Nl`z:^kY@FXeJ@P{8WhCt0__/,8woI2." .
"8#[r_Cqig!5Qt{8gl5ls<9Ci|^QN2IK#L[cB9@:XclVQQIxe</w:tc>";
$this->assertEquals(
$reporter->patchXml($xml),
$reporter->patchXmlChunk($xml),
'<w:tc xeLLm[t6;cT&!Z_#KI8cniins[)UX>TAnAaqg_a}sePvK.OO#Q=B-]cBDFM8UL]8m@iCtTkuSd<w:tcPrL4>' .
'<w:shd w:val="clear" w:color="auto" w:fill="{{val}}"/><w:shd@1bY/>?Nl`z:^kY@FXeJ@P{8WhCt0__/,' .
'8woI2.8#[r_Cqig!5Qt{8gl5ls<9Ci|^QN2IK#L[cB9@:XclVQQIxe</w:tc>'
);

$xml = "{%r _Rom{X=aC3/s#W#~o<#d:tH^>DTAz;s<}O0RJ#V!wW:]%kR@wzLf*\iu^zAGrr!3]v<SUc|B)o>kA.:*1?,0%}";
$this->assertEquals(
$reporter->patchXml($xml),
$reporter->patchXmlChunk($xml),
'</w:t></w:r><w:r><w:t xml:space="preserve">{%r _Rom{X=aC3/s#W#~o<#d:tH^>DTAz;s<}O0RJ#V!wW:]%kR' .
'@wzLf*\iu^zAGrr!3]v<SUc|B)o>kA.:*1?,0%}</w:t></w:r><w:r><w:t xml:space="preserve">'
);

// test vMerge
$xml = "<w:tc></w:tcPr>t/H-Q.X)jC_sI6(J7w-;QI&JpDG}:>f02Zls<8(7&SEyc>" .
"`@P/<Ero^KEbL`EX^<w:t>{% vm %}</w:t></w:tc>";
"`@P/<Ero^KEbL`EX^<w:t>{% vm %}</w:t></w:tc>";
$this->assertEquals(
$reporter->patchXml($xml),
$reporter->patchXmlChunk($xml),
'<w:tc><w:vMerge w:val="{% if loop.first %}restart{% else %}continue' .
'{% endif %}"/></w:tcPr>t/H-Q.X)jC_sI6(J7w-;QI&JpDG}:>f02Zls<8(7&SEyc>`' .
'@P/<Ero^KEbL`EX^<w:t>{% if loop.first %}{% endif %}</w:t></w:tc>'
);

// test hMerge
$xml = "<w:tc></w:tcPr>t/H-Q.X)jC_sI6(J7w-;QI&JpDG}:>f02Zls<8(7&SEyc>" .
"`@P/<Ero^KEbL`EX^<w:t>{% hm %}</w:t></w:tc>";
"`@P/<Ero^KEbL`EX^<w:t>{% hm %}</w:t></w:tc>";
$this->assertEquals(
$reporter->patchXml($xml),
$reporter->patchXmlChunk($xml),
'{% if loop.first %}<w:tc><w:gridSpan w:val="{{ loop.length }}"/></w:tcPr>t/H-Q.X)' .
'jC_sI6(J7w-;QI&JpDG}:>f02Zls<8(7&SEyc>`@P/<Ero^KEbL`EX^<w:t></w:t></w:tc>{% endif %}'
);

// test cleanTags
$xml = '{%&#8216;&lt;&gt;“”‘’%}';
$this->assertEquals(
$reporter->patchXml($xml),
$reporter->patchXmlChunk($xml),
"{%'<>\"\"''%}"
);
$reporter->close();
Expand Down Expand Up @@ -754,48 +754,48 @@ public function testImages(): void
public function testSections(): void
{
$reporter = new PhpDocxTemplate(self::TEMPLATE9);
/* $this->assertEquals(
$reporter->buildXml(["object" => "world"]),
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" .
"<w:document xmlns:wpc=\"http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas\" " .
"xmlns:cx=\"http://schemas.microsoft.com/office/drawing/2014/chartex\" " .
"xmlns:cx1=\"http://schemas.microsoft.com/office/drawing/2015/9/8/chartex\" " .
"xmlns:cx2=\"http://schemas.microsoft.com/office/drawing/2015/10/21/chartex\" " .
"xmlns:cx3=\"http://schemas.microsoft.com/office/drawing/2016/5/9/chartex\" " .
"xmlns:cx4=\"http://schemas.microsoft.com/office/drawing/2016/5/10/chartex\" " .
"xmlns:cx5=\"http://schemas.microsoft.com/office/drawing/2016/5/11/chartex\" " .
"xmlns:cx6=\"http://schemas.microsoft.com/office/drawing/2016/5/12/chartex\" " .
"xmlns:cx7=\"http://schemas.microsoft.com/office/drawing/2016/5/13/chartex\" " .
"xmlns:cx8=\"http://schemas.microsoft.com/office/drawing/2016/5/14/chartex\" " .
"xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" " .
"xmlns:aink=\"http://schemas.microsoft.com/office/drawing/2016/ink\" " .
"xmlns:am3d=\"http://schemas.microsoft.com/office/drawing/2017/model3d\" " .
"xmlns:o=\"urn:schemas-microsoft-com:office:office\" " .
"xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" " .
"xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\" " .
"xmlns:v=\"urn:schemas-microsoft-com:vml\" " .
"xmlns:wp14=\"http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing\" " .
"xmlns:wp=\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\" " .
"xmlns:w10=\"urn:schemas-microsoft-com:office:word\" " .
"xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" " .
"xmlns:w14=\"http://schemas.microsoft.com/office/word/2010/wordml\" " .
"xmlns:w15=\"http://schemas.microsoft.com/office/word/2012/wordml\" " .
"xmlns:w16cid=\"http://schemas.microsoft.com/office/word/2016/wordml/cid\" " .
"xmlns:w16se=\"http://schemas.microsoft.com/office/word/2015/wordml/symex\" " .
"xmlns:wpg=\"http://schemas.microsoft.com/office/word/2010/wordprocessingGroup\" " .
"xmlns:wpi=\"http://schemas.microsoft.com/office/word/2010/wordprocessingInk\" " .
"xmlns:wne=\"http://schemas.microsoft.com/office/word/2006/wordml\" " .
"xmlns:wps=\"http://schemas.microsoft.com/office/word/2010/wordprocessingShape\" " .
"mc:Ignorable=\"w14 w15 w16se w16cid wp14\"><w:body><w:p w14:paraId=\"504F2588\" " .
"w14:textId=\"54DF26C8\" w:rsidR=\"0090657C\" w:rsidRPr=\"00FA3F61\" " .
"w:rsidRDefault=\"00FA3F61\" w:rsidP=\"00C13DD6\"><w:pPr><w:rPr><w:lang w:val=\"en-US\"/>" .
"</w:rPr></w:pPr><w:r><w:rPr><w:lang w:val=\"en-US\"/></w:rPr><w:t>Hello world!</w:t>" .
"</w:r><w:bookmarkStart w:id=\"0\" w:name=\"_GoBack\"/><w:bookmarkEnd w:id=\"0\"/></w:p>" .
"<w:sectPr w:rsidR=\"0090657C\" w:rsidRPr=\"00FA3F61\"><w:pgSz w:w=\"11906\" w:h=\"16838\"/>" .
"<w:pgMar w:top=\"1134\" w:right=\"850\" w:bottom=\"1134\" w:left=\"1701\" w:header=\"708\" " .
"w:footer=\"708\" w:gutter=\"0\"/><w:cols w:space=\"708\"/><w:docGrid w:linePitch=\"360\"/>" .
"</w:sectPr></w:body></w:document>\n"
);*/
/* $this->assertEquals(
$reporter->buildXml(["object" => "world"]),
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" .
"<w:document xmlns:wpc=\"http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas\" " .
"xmlns:cx=\"http://schemas.microsoft.com/office/drawing/2014/chartex\" " .
"xmlns:cx1=\"http://schemas.microsoft.com/office/drawing/2015/9/8/chartex\" " .
"xmlns:cx2=\"http://schemas.microsoft.com/office/drawing/2015/10/21/chartex\" " .
"xmlns:cx3=\"http://schemas.microsoft.com/office/drawing/2016/5/9/chartex\" " .
"xmlns:cx4=\"http://schemas.microsoft.com/office/drawing/2016/5/10/chartex\" " .
"xmlns:cx5=\"http://schemas.microsoft.com/office/drawing/2016/5/11/chartex\" " .
"xmlns:cx6=\"http://schemas.microsoft.com/office/drawing/2016/5/12/chartex\" " .
"xmlns:cx7=\"http://schemas.microsoft.com/office/drawing/2016/5/13/chartex\" " .
"xmlns:cx8=\"http://schemas.microsoft.com/office/drawing/2016/5/14/chartex\" " .
"xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" " .
"xmlns:aink=\"http://schemas.microsoft.com/office/drawing/2016/ink\" " .
"xmlns:am3d=\"http://schemas.microsoft.com/office/drawing/2017/model3d\" " .
"xmlns:o=\"urn:schemas-microsoft-com:office:office\" " .
"xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" " .
"xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\" " .
"xmlns:v=\"urn:schemas-microsoft-com:vml\" " .
"xmlns:wp14=\"http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing\" " .
"xmlns:wp=\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\" " .
"xmlns:w10=\"urn:schemas-microsoft-com:office:word\" " .
"xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" " .
"xmlns:w14=\"http://schemas.microsoft.com/office/word/2010/wordml\" " .
"xmlns:w15=\"http://schemas.microsoft.com/office/word/2012/wordml\" " .
"xmlns:w16cid=\"http://schemas.microsoft.com/office/word/2016/wordml/cid\" " .
"xmlns:w16se=\"http://schemas.microsoft.com/office/word/2015/wordml/symex\" " .
"xmlns:wpg=\"http://schemas.microsoft.com/office/word/2010/wordprocessingGroup\" " .
"xmlns:wpi=\"http://schemas.microsoft.com/office/word/2010/wordprocessingInk\" " .
"xmlns:wne=\"http://schemas.microsoft.com/office/word/2006/wordml\" " .
"xmlns:wps=\"http://schemas.microsoft.com/office/word/2010/wordprocessingShape\" " .
"mc:Ignorable=\"w14 w15 w16se w16cid wp14\"><w:body><w:p w14:paraId=\"504F2588\" " .
"w14:textId=\"54DF26C8\" w:rsidR=\"0090657C\" w:rsidRPr=\"00FA3F61\" " .
"w:rsidRDefault=\"00FA3F61\" w:rsidP=\"00C13DD6\"><w:pPr><w:rPr><w:lang w:val=\"en-US\"/>" .
"</w:rPr></w:pPr><w:r><w:rPr><w:lang w:val=\"en-US\"/></w:rPr><w:t>Hello world!</w:t>" .
"</w:r><w:bookmarkStart w:id=\"0\" w:name=\"_GoBack\"/><w:bookmarkEnd w:id=\"0\"/></w:p>" .
"<w:sectPr w:rsidR=\"0090657C\" w:rsidRPr=\"00FA3F61\"><w:pgSz w:w=\"11906\" w:h=\"16838\"/>" .
"<w:pgMar w:top=\"1134\" w:right=\"850\" w:bottom=\"1134\" w:left=\"1701\" w:header=\"708\" " .
"w:footer=\"708\" w:gutter=\"0\"/><w:cols w:space=\"708\"/><w:docGrid w:linePitch=\"360\"/>" .
"</w:sectPr></w:body></w:document>\n"
);*/
$docName = './doc9.docx';
$reporter->render(["object" => "test", "section" => [["id" => "test section"]]]);
$reporter->save($docName);
Expand All @@ -805,7 +805,7 @@ public function testSections(): void
$expectedDocumentZip->open($docName);
$header = $expectedDocumentZip->getFromName('word/header2.xml');
$this->assertEquals('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' . PHP_EOL .
'<w:hdr xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" ' .
'<w:hdr xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" ' .
'xmlns:cx="http://schemas.microsoft.com/office/drawing/2014/chartex" xmlns:cx1=' .
'"http://schemas.microsoft.com/office/drawing/2015/9/8/chartex" xmlns:cx2="http:' .
'//schemas.microsoft.com/office/drawing/2015/10/21/chartex" xmlns:cx3="http://sche' .
Expand Down
3 changes: 3 additions & 0 deletions tests/documents/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*

!.gitignore

0 comments on commit 76f94d9

Please sign in to comment.