1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* This file is part of PHPPresentation - A pure PHP library for reading and writing |
4
|
|
|
* presentations documents. |
5
|
|
|
* |
6
|
|
|
* PHPPresentation is free software distributed under the terms of the GNU Lesser |
7
|
|
|
* General Public License version 3 as published by the Free Software Foundation. |
8
|
|
|
* |
9
|
|
|
* For the full copyright and license information, please read the LICENSE |
10
|
|
|
* file that was distributed with this source code. For the full list of |
11
|
|
|
* contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. |
12
|
|
|
* |
13
|
|
|
* @link https://github.com/PHPOffice/PHPPresentation |
14
|
|
|
* @copyright 2009-2015 PHPPresentation contributors |
15
|
|
|
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 |
16
|
|
|
*/ |
17
|
|
|
|
18
|
|
|
namespace PhpOffice\PhpPresentation\Writer\ODPresentation; |
19
|
|
|
|
20
|
|
|
use PhpOffice\Common\Drawing as CommonDrawing; |
21
|
|
|
use PhpOffice\Common\Text; |
22
|
|
|
use PhpOffice\Common\XMLWriter; |
23
|
|
|
use PhpOffice\PhpPresentation\PhpPresentation; |
24
|
|
|
use PhpOffice\PhpPresentation\Shape\Group; |
25
|
|
|
use PhpOffice\PhpPresentation\Shape\Table; |
26
|
|
|
use PhpOffice\PhpPresentation\Slide\Background\Image; |
27
|
|
|
use PhpOffice\PhpPresentation\Style\Fill; |
28
|
|
|
use PhpOffice\PhpPresentation\Shape\RichText; |
29
|
|
|
use PhpOffice\PhpPresentation\Style\Border; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* \PhpOffice\PhpPresentation\Writer\ODPresentation\Styles |
33
|
|
|
*/ |
34
|
|
|
class Styles extends AbstractPart |
35
|
|
|
{ |
36
|
|
|
/** |
37
|
|
|
* Stores font styles draw:gradient nodes |
38
|
|
|
* |
39
|
|
|
* @var array |
40
|
|
|
*/ |
41
|
|
|
private $arrayGradient = array(); |
42
|
|
|
/** |
43
|
|
|
* Stores font styles draw:stroke-dash nodes |
44
|
|
|
* |
45
|
|
|
* @var array |
46
|
|
|
*/ |
47
|
|
|
private $arrayStrokeDash = array(); |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* Write Meta file to XML format |
51
|
|
|
* |
52
|
|
|
* @param PhpPresentation $pPhpPresentation |
53
|
|
|
* @return string XML Output |
54
|
|
|
* @throws \Exception |
55
|
|
|
*/ |
56
|
41 |
|
public function writePart(PhpPresentation $pPhpPresentation) |
57
|
|
|
{ |
58
|
|
|
// Create XML writer |
59
|
41 |
|
$objWriter = $this->getXMLWriter(); |
60
|
|
|
|
61
|
|
|
// XML header |
62
|
41 |
|
$objWriter->startDocument('1.0', 'UTF-8'); |
63
|
|
|
|
64
|
|
|
// office:document-meta |
65
|
41 |
|
$objWriter->startElement('office:document-styles'); |
66
|
41 |
|
$objWriter->writeAttribute('xmlns:office', 'urn:oasis:names:tc:opendocument:xmlns:office:1.0'); |
67
|
41 |
|
$objWriter->writeAttribute('xmlns:style', 'urn:oasis:names:tc:opendocument:xmlns:style:1.0'); |
68
|
41 |
|
$objWriter->writeAttribute('xmlns:text', 'urn:oasis:names:tc:opendocument:xmlns:text:1.0'); |
69
|
41 |
|
$objWriter->writeAttribute('xmlns:table', 'urn:oasis:names:tc:opendocument:xmlns:table:1.0'); |
70
|
41 |
|
$objWriter->writeAttribute('xmlns:draw', 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0'); |
71
|
41 |
|
$objWriter->writeAttribute('xmlns:fo', 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0'); |
72
|
41 |
|
$objWriter->writeAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink'); |
73
|
41 |
|
$objWriter->writeAttribute('xmlns:dc', 'http://purl.org/dc/elements/1.1/'); |
74
|
41 |
|
$objWriter->writeAttribute('xmlns:meta', 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0'); |
75
|
41 |
|
$objWriter->writeAttribute('xmlns:number', 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0'); |
76
|
41 |
|
$objWriter->writeAttribute('xmlns:presentation', 'urn:oasis:names:tc:opendocument:xmlns:presentation:1.0'); |
77
|
41 |
|
$objWriter->writeAttribute('xmlns:svg', 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0'); |
78
|
41 |
|
$objWriter->writeAttribute('xmlns:chart', 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0'); |
79
|
41 |
|
$objWriter->writeAttribute('xmlns:dr3d', 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0'); |
80
|
41 |
|
$objWriter->writeAttribute('xmlns:math', 'http://www.w3.org/1998/Math/MathML'); |
81
|
41 |
|
$objWriter->writeAttribute('xmlns:form', 'urn:oasis:names:tc:opendocument:xmlns:form:1.0'); |
82
|
41 |
|
$objWriter->writeAttribute('xmlns:script', 'urn:oasis:names:tc:opendocument:xmlns:script:1.0'); |
83
|
41 |
|
$objWriter->writeAttribute('xmlns:ooo', 'http://openoffice.org/2004/office'); |
84
|
41 |
|
$objWriter->writeAttribute('xmlns:ooow', 'http://openoffice.org/2004/writer'); |
85
|
41 |
|
$objWriter->writeAttribute('xmlns:oooc', 'http://openoffice.org/2004/calc'); |
86
|
41 |
|
$objWriter->writeAttribute('xmlns:dom', 'http://www.w3.org/2001/xml-events'); |
87
|
41 |
|
$objWriter->writeAttribute('xmlns:smil', 'urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0'); |
88
|
41 |
|
$objWriter->writeAttribute('xmlns:anim', 'urn:oasis:names:tc:opendocument:xmlns:animation:1.0'); |
89
|
41 |
|
$objWriter->writeAttribute('xmlns:rpt', 'http://openoffice.org/2005/report'); |
90
|
41 |
|
$objWriter->writeAttribute('xmlns:of', 'urn:oasis:names:tc:opendocument:xmlns:of:1.2'); |
91
|
41 |
|
$objWriter->writeAttribute('xmlns:xhtml', 'http://www.w3.org/1999/xhtml'); |
92
|
41 |
|
$objWriter->writeAttribute('xmlns:grddl', 'http://www.w3.org/2003/g/data-view#'); |
93
|
41 |
|
$objWriter->writeAttribute('xmlns:officeooo', 'http://openoffice.org/2009/office'); |
94
|
41 |
|
$objWriter->writeAttribute('xmlns:tableooo', 'http://openoffice.org/2009/table'); |
95
|
41 |
|
$objWriter->writeAttribute('xmlns:drawooo', 'http://openoffice.org/2010/draw'); |
96
|
41 |
|
$objWriter->writeAttribute('xmlns:css3t', 'http://www.w3.org/TR/css3-text/'); |
97
|
41 |
|
$objWriter->writeAttribute('office:version', '1.2'); |
98
|
|
|
|
99
|
|
|
// Variables |
100
|
41 |
|
$stylePageLayout = $pPhpPresentation->getLayout()->getDocumentLayout(); |
101
|
|
|
|
102
|
|
|
// office:styles |
103
|
41 |
|
$objWriter->startElement('office:styles'); |
104
|
|
|
// style:style |
105
|
41 |
|
$objWriter->startElement('style:style'); |
106
|
41 |
|
$objWriter->writeAttribute('style:name', 'sPres0'); |
107
|
41 |
|
$objWriter->writeAttribute('style:display-name', 'sPres0'); |
108
|
41 |
|
$objWriter->writeAttribute('style:family', 'presentation'); |
109
|
|
|
// style:graphic-properties |
110
|
41 |
|
$objWriter->startElement('style:graphic-properties'); |
111
|
41 |
|
$objWriter->writeAttribute('draw:fill-color', '#ffffff'); |
112
|
|
|
// > style:graphic-properties |
113
|
41 |
|
$objWriter->endElement(); |
114
|
|
|
// > style:style |
115
|
41 |
|
$objWriter->endElement(); |
116
|
|
|
|
117
|
41 |
|
foreach ($pPhpPresentation->getAllSlides() as $keySlide => $oSlide) { |
118
|
41 |
|
foreach ($oSlide->getShapeCollection() as $shape) { |
119
|
36 |
|
if ($shape instanceof Table) { |
120
|
7 |
|
$this->writeTableStyle($objWriter, $shape); |
121
|
36 |
|
} elseif ($shape instanceof Group) { |
122
|
1 |
|
$this->writeGroupStyle($objWriter, $shape); |
123
|
30 |
|
} elseif ($shape instanceof RichText) { |
124
|
13 |
|
$this->writeRichTextStyle($objWriter, $shape); |
125
|
13 |
|
} |
126
|
41 |
|
} |
127
|
41 |
|
$oBkgImage = $oSlide->getBackground(); |
128
|
41 |
|
if ($oBkgImage instanceof Image) { |
129
|
|
|
$this->writeBackgroundStyle($objWriter, $oBkgImage, $keySlide); |
130
|
|
|
} |
131
|
41 |
|
} |
132
|
|
|
// > office:styles |
133
|
41 |
|
$objWriter->endElement(); |
134
|
|
|
|
135
|
|
|
// office:automatic-styles |
136
|
41 |
|
$objWriter->startElement('office:automatic-styles'); |
137
|
|
|
// style:page-layout |
138
|
41 |
|
$objWriter->startElement('style:page-layout'); |
139
|
41 |
|
if (empty($stylePageLayout)) { |
140
|
1 |
|
$objWriter->writeAttribute('style:name', 'sPL0'); |
141
|
1 |
|
} else { |
142
|
40 |
|
$objWriter->writeAttribute('style:name', $stylePageLayout); |
143
|
|
|
} |
144
|
|
|
// style:page-layout-properties |
145
|
41 |
|
$objWriter->startElement('style:page-layout-properties'); |
146
|
41 |
|
$objWriter->writeAttribute('fo:margin-top', '0cm'); |
147
|
41 |
|
$objWriter->writeAttribute('fo:margin-bottom', '0cm'); |
148
|
41 |
|
$objWriter->writeAttribute('fo:margin-left', '0cm'); |
149
|
41 |
|
$objWriter->writeAttribute('fo:margin-right', '0cm'); |
150
|
41 |
|
$objWriter->writeAttribute('fo:page-width', Text::numberFormat(CommonDrawing::pixelsToCentimeters(CommonDrawing::emuToPixels($pPhpPresentation->getLayout()->getCX())), 1) . 'cm'); |
151
|
41 |
|
$objWriter->writeAttribute('fo:page-height', Text::numberFormat(CommonDrawing::pixelsToCentimeters(CommonDrawing::emuToPixels($pPhpPresentation->getLayout()->getCY())), 1) . 'cm'); |
152
|
41 |
|
if ($pPhpPresentation->getLayout()->getCX() > $pPhpPresentation->getLayout()->getCY()) { |
153
|
40 |
|
$objWriter->writeAttribute('style:print-orientation', 'landscape'); |
154
|
40 |
|
} else { |
155
|
2 |
|
$objWriter->writeAttribute('style:print-orientation', 'portrait'); |
156
|
|
|
} |
157
|
41 |
|
$objWriter->endElement(); |
158
|
41 |
|
$objWriter->endElement(); |
159
|
41 |
|
$objWriter->endElement(); |
160
|
|
|
|
161
|
|
|
// office:master-styles |
162
|
41 |
|
$objWriter->startElement('office:master-styles'); |
163
|
|
|
// style:master-page |
164
|
41 |
|
$objWriter->startElement('style:master-page'); |
165
|
41 |
|
$objWriter->writeAttribute('style:name', 'Standard'); |
166
|
41 |
|
$objWriter->writeAttribute('style:display-name', 'Standard'); |
167
|
41 |
|
if (empty($stylePageLayout)) { |
168
|
1 |
|
$objWriter->writeAttribute('style:page-layout-name', 'sPL0'); |
169
|
1 |
|
} else { |
170
|
40 |
|
$objWriter->writeAttribute('style:page-layout-name', $stylePageLayout); |
171
|
|
|
} |
172
|
41 |
|
$objWriter->writeAttribute('draw:style-name', 'sPres0'); |
173
|
41 |
|
$objWriter->endElement(); |
174
|
41 |
|
$objWriter->endElement(); |
175
|
|
|
|
176
|
41 |
|
$objWriter->endElement(); |
177
|
|
|
|
178
|
|
|
// Return |
179
|
41 |
|
return $objWriter->getData(); |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
/** |
183
|
|
|
* Write the default style information for a RichText shape |
184
|
|
|
* |
185
|
|
|
* @param XMLWriter $objWriter |
186
|
|
|
* @param RichText $shape |
187
|
|
|
*/ |
188
|
13 |
|
public function writeRichTextStyle(XMLWriter $objWriter, RichText $shape) |
189
|
|
|
{ |
190
|
13 |
|
if ($shape->getFill()->getFillType() == Fill::FILL_GRADIENT_LINEAR || $shape->getFill()->getFillType() == Fill::FILL_GRADIENT_PATH) { |
191
|
1 |
|
if (!in_array($shape->getFill()->getHashCode(), $this->arrayGradient)) { |
192
|
1 |
|
$this->writeGradientFill($objWriter, $shape->getFill()); |
193
|
1 |
|
} |
194
|
1 |
|
} |
195
|
13 |
|
if ($shape->getBorder()->getDashStyle() != Border::DASH_SOLID) { |
196
|
2 |
|
if (!in_array($shape->getBorder()->getDashStyle(), $this->arrayStrokeDash)) { |
197
|
2 |
|
$objWriter->startElement('draw:stroke-dash'); |
198
|
2 |
|
$objWriter->writeAttribute('draw:name', 'strokeDash_'.$shape->getBorder()->getDashStyle()); |
199
|
2 |
|
$objWriter->writeAttribute('draw:style', 'rect'); |
200
|
2 |
|
switch ($shape->getBorder()->getDashStyle()) { |
201
|
2 |
|
case Border::DASH_DASH: |
202
|
2 |
|
$objWriter->writeAttribute('draw:distance', '0.105cm'); |
203
|
2 |
|
$objWriter->writeAttribute('draw:dots2', '1'); |
204
|
2 |
|
$objWriter->writeAttribute('draw:dots2-length', '0.14cm'); |
205
|
2 |
|
break; |
206
|
1 |
|
case Border::DASH_DASHDOT: |
207
|
1 |
|
$objWriter->writeAttribute('draw:distance', '0.105cm'); |
208
|
1 |
|
$objWriter->writeAttribute('draw:dots1', '1'); |
209
|
1 |
|
$objWriter->writeAttribute('draw:dots1-length', '0.035cm'); |
210
|
1 |
|
$objWriter->writeAttribute('draw:dots2', '1'); |
211
|
1 |
|
$objWriter->writeAttribute('draw:dots2-length', '0.14cm'); |
212
|
1 |
|
break; |
213
|
1 |
|
case Border::DASH_DOT: |
214
|
1 |
|
$objWriter->writeAttribute('draw:distance', '0.105cm'); |
215
|
1 |
|
$objWriter->writeAttribute('draw:dots1', '1'); |
216
|
1 |
|
$objWriter->writeAttribute('draw:dots1-length', '0.035cm'); |
217
|
1 |
|
break; |
218
|
1 |
|
case Border::DASH_LARGEDASH: |
219
|
1 |
|
$objWriter->writeAttribute('draw:distance', '0.105cm'); |
220
|
1 |
|
$objWriter->writeAttribute('draw:dots2', '1'); |
221
|
1 |
|
$objWriter->writeAttribute('draw:dots2-length', '0.28cm'); |
222
|
1 |
|
break; |
223
|
1 |
|
case Border::DASH_LARGEDASHDOT: |
224
|
1 |
|
$objWriter->writeAttribute('draw:distance', '0.105cm'); |
225
|
1 |
|
$objWriter->writeAttribute('draw:dots1', '1'); |
226
|
1 |
|
$objWriter->writeAttribute('draw:dots1-length', '0.035cm'); |
227
|
1 |
|
$objWriter->writeAttribute('draw:dots2', '1'); |
228
|
1 |
|
$objWriter->writeAttribute('draw:dots2-length', '0.28cm'); |
229
|
1 |
|
break; |
230
|
1 |
|
case Border::DASH_LARGEDASHDOTDOT: |
231
|
1 |
|
$objWriter->writeAttribute('draw:distance', '0.105cm'); |
232
|
1 |
|
$objWriter->writeAttribute('draw:dots1', '2'); |
233
|
1 |
|
$objWriter->writeAttribute('draw:dots1-length', '0.035cm'); |
234
|
1 |
|
$objWriter->writeAttribute('draw:dots2', '1'); |
235
|
1 |
|
$objWriter->writeAttribute('draw:dots2-length', '0.28cm'); |
236
|
1 |
|
break; |
237
|
1 |
|
case Border::DASH_SYSDASH: |
238
|
1 |
|
$objWriter->writeAttribute('draw:distance', '0.035cm'); |
239
|
1 |
|
$objWriter->writeAttribute('draw:dots2', '1'); |
240
|
1 |
|
$objWriter->writeAttribute('draw:dots2-length', '0.105cm'); |
241
|
1 |
|
break; |
242
|
1 |
|
case Border::DASH_SYSDASHDOT: |
243
|
1 |
|
$objWriter->writeAttribute('draw:distance', '0.035cm'); |
244
|
1 |
|
$objWriter->writeAttribute('draw:dots1', '1'); |
245
|
1 |
|
$objWriter->writeAttribute('draw:dots1-length', '0.035cm'); |
246
|
1 |
|
$objWriter->writeAttribute('draw:dots2', '1'); |
247
|
1 |
|
$objWriter->writeAttribute('draw:dots2-length', '0.105cm'); |
248
|
1 |
|
break; |
249
|
1 |
|
case Border::DASH_SYSDASHDOTDOT: |
250
|
1 |
|
$objWriter->writeAttribute('draw:distance', '0.035cm'); |
251
|
1 |
|
$objWriter->writeAttribute('draw:dots1', '2'); |
252
|
1 |
|
$objWriter->writeAttribute('draw:dots1-length', '0.035cm'); |
253
|
1 |
|
$objWriter->writeAttribute('draw:dots2', '1'); |
254
|
1 |
|
$objWriter->writeAttribute('draw:dots2-length', '0.105cm'); |
255
|
1 |
|
break; |
256
|
1 |
|
case Border::DASH_SYSDOT: |
257
|
1 |
|
$objWriter->writeAttribute('draw:distance', '0.035cm'); |
258
|
1 |
|
$objWriter->writeAttribute('draw:dots1', '1'); |
259
|
1 |
|
$objWriter->writeAttribute('draw:dots1-length', '0.035cm'); |
260
|
1 |
|
break; |
261
|
2 |
|
} |
262
|
2 |
|
$objWriter->endElement(); |
263
|
2 |
|
$this->arrayStrokeDash[] = $shape->getBorder()->getDashStyle(); |
264
|
2 |
|
} |
265
|
2 |
|
} |
266
|
13 |
|
} |
267
|
|
|
|
268
|
|
|
/** |
269
|
|
|
* Write the default style information for a Table shape |
270
|
|
|
* |
271
|
|
|
* @param XMLWriter $objWriter |
272
|
|
|
* @param Table $shape |
273
|
|
|
*/ |
274
|
7 |
|
public function writeTableStyle(XMLWriter $objWriter, Table $shape) |
275
|
|
|
{ |
276
|
7 |
|
foreach ($shape->getRows() as $row) { |
277
|
6 |
|
foreach ($row->getCells() as $cell) { |
278
|
6 |
|
if ($cell->getFill()->getFillType() == Fill::FILL_GRADIENT_LINEAR) { |
279
|
1 |
|
if (!in_array($cell->getFill()->getHashCode(), $this->arrayGradient)) { |
280
|
1 |
|
$this->writeGradientFill($objWriter, $cell->getFill()); |
281
|
1 |
|
} |
282
|
1 |
|
} |
283
|
6 |
|
} |
284
|
7 |
|
} |
285
|
7 |
|
} |
286
|
|
|
|
287
|
|
|
/** |
288
|
|
|
* Writes the style information for a group of shapes |
289
|
|
|
* |
290
|
|
|
* @param XMLWriter $objWriter |
291
|
|
|
* @param Group $group |
292
|
|
|
*/ |
293
|
1 |
|
public function writeGroupStyle(XMLWriter $objWriter, Group $group) |
294
|
|
|
{ |
295
|
1 |
|
$shapes = $group->getShapeCollection(); |
296
|
1 |
|
foreach ($shapes as $shape) { |
297
|
1 |
|
if ($shape instanceof Table) { |
298
|
|
|
$this->writeTableStyle($objWriter, $shape); |
299
|
1 |
|
} elseif ($shape instanceof Group) { |
300
|
|
|
$this->writeGroupStyle($objWriter, $shape); |
301
|
|
|
} |
302
|
1 |
|
} |
303
|
1 |
|
} |
304
|
|
|
|
305
|
|
|
/** |
306
|
|
|
* Write the gradient style |
307
|
|
|
* @param XMLWriter $objWriter |
308
|
|
|
* @param Fill $oFill |
309
|
|
|
*/ |
310
|
2 |
|
protected function writeGradientFill(XMLWriter $objWriter, Fill $oFill) |
311
|
|
|
{ |
312
|
2 |
|
$objWriter->startElement('draw:gradient'); |
313
|
2 |
|
$objWriter->writeAttribute('draw:name', 'gradient_'.$oFill->getHashCode()); |
314
|
2 |
|
$objWriter->writeAttribute('draw:display-name', 'gradient_'.$oFill->getHashCode()); |
315
|
2 |
|
$objWriter->writeAttribute('draw:style', 'linear'); |
316
|
2 |
|
$objWriter->writeAttribute('draw:start-intensity', '100%'); |
317
|
2 |
|
$objWriter->writeAttribute('draw:end-intensity', '100%'); |
318
|
2 |
|
$objWriter->writeAttribute('draw:start-color', '#'.$oFill->getStartColor()->getRGB()); |
319
|
2 |
|
$objWriter->writeAttribute('draw:end-color', '#'.$oFill->getEndColor()->getRGB()); |
320
|
2 |
|
$objWriter->writeAttribute('draw:border', '0%'); |
321
|
2 |
|
$objWriter->writeAttribute('draw:angle', $oFill->getRotation() - 90); |
322
|
2 |
|
$objWriter->endElement(); |
323
|
2 |
|
$this->arrayGradient[] = $oFill->getHashCode(); |
324
|
2 |
|
} |
325
|
|
|
|
326
|
|
|
/** |
327
|
|
|
* Write the background image style |
328
|
|
|
* @param XMLWriter $objWriter |
329
|
|
|
* @param Image $oBkgImage |
330
|
|
|
*/ |
331
|
|
|
protected function writeBackgroundStyle(XMLWriter $objWriter, Image $oBkgImage, $numSlide) |
332
|
|
|
{ |
333
|
|
|
$objWriter->startElement('draw:fill-image'); |
334
|
|
|
$objWriter->writeAttribute('draw:name', 'background_'.$numSlide); |
335
|
|
|
$objWriter->writeAttribute('xlink:href', 'Pictures/'.str_replace(' ', '_', $oBkgImage->getIndexedFilename($numSlide))); |
336
|
|
|
$objWriter->writeAttribute('xlink:type', 'simple'); |
337
|
|
|
$objWriter->writeAttribute('xlink:show', 'embed'); |
338
|
|
|
$objWriter->writeAttribute('xlink:actuate', 'onLoad'); |
339
|
|
|
$objWriter->endElement(); |
340
|
|
|
} |
341
|
|
|
} |
342
|
|
|
|