run:R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
23.8 KB
2026-03-11 16:18:51
R W Run
7.8 KB
2026-03-11 16:18:52
R W Run
36.1 KB
2026-03-11 16:18:51
R W Run
11.9 KB
2026-03-11 16:18:52
R W Run
18.94 KB
2026-03-11 16:18:52
R W Run
7.35 KB
2026-03-11 16:18:52
R W Run
28.6 KB
2026-03-11 16:18:51
R W Run
316 By
2026-03-11 16:18:51
R W Run
12.9 KB
2026-03-11 16:18:51
R W Run
61.02 KB
2026-03-11 16:18:52
R W Run
15 KB
2026-03-11 16:18:51
R W Run
112.05 KB
2026-03-11 16:18:51
R W Run
12.47 KB
2026-03-11 16:18:51
R W Run
15.07 KB
2026-03-11 16:18:52
R W Run
9.84 KB
2026-03-11 16:18:52
R W Run
13.17 KB
2026-03-11 16:18:52
R W Run
33.83 KB
2026-03-11 16:18:51
R W Run
42.63 KB
2026-03-11 16:18:51
R W Run
55.71 KB
2026-03-11 16:18:52
R W Run
12.53 KB
2026-03-11 16:18:51
R W Run
2.55 KB
2026-03-11 16:18:52
R W Run
28.92 KB
2026-03-11 16:18:52
R W Run
539 By
2026-03-11 16:18:51
R W Run
367 By
2026-03-11 16:18:52
R W Run
42.65 KB
2026-03-11 16:18:51
R W Run
401 By
2026-03-11 16:18:51
R W Run
6.61 KB
2026-03-11 16:18:51
R W Run
664 By
2026-03-11 16:18:52
R W Run
20.63 KB
2026-03-11 16:18:51
R W Run
2.18 KB
2026-03-11 16:18:52
R W Run
453 By
2026-03-11 16:18:52
R W Run
457 By
2026-03-11 16:18:51
R W Run
36.83 KB
2026-03-11 16:18:52
R W Run
2.41 KB
2026-03-11 16:18:52
R W Run
8.28 KB
2026-03-11 16:18:51
R W Run
13.89 KB
2026-03-11 16:18:51
R W Run
11.76 KB
2026-03-11 16:18:51
R W Run
2.65 KB
2026-03-11 16:18:51
R W Run
7.43 KB
2026-03-11 16:18:51
R W Run
17.46 KB
2026-03-11 16:18:51
R W Run
5.14 KB
2026-03-11 16:18:52
R W Run
16.7 KB
2026-03-11 16:18:51
R W Run
8.28 KB
2026-03-11 16:18:52
R W Run
2.92 KB
2026-03-11 16:18:52
R W Run
1.32 KB
2026-03-11 16:18:51
R W Run
4.6 KB
2026-03-11 16:18:52
R W Run
11.62 KB
2026-03-11 16:18:52
R W Run
2.5 KB
2026-03-11 16:18:51
R W Run
1.97 KB
2026-03-11 16:18:51
R W Run
11.25 KB
2026-03-11 16:18:52
R W Run
5.32 KB
2026-03-11 16:18:51
R W Run
10.99 KB
2026-03-11 16:18:52
R W Run
68.32 KB
2026-03-11 16:18:51
R W Run
6.34 KB
2026-03-11 16:18:51
R W Run
5.49 KB
2026-03-11 16:18:51
R W Run
1.99 KB
2026-03-11 16:18:52
R W Run
7.02 KB
2026-03-11 16:18:51
R W Run
4.91 KB
2026-03-11 16:18:52
R W Run
16.86 KB
2026-03-11 16:18:51
R W Run
24.23 KB
2026-03-11 16:18:51
R W Run
3.97 KB
2026-03-11 16:18:51
R W Run
47.66 KB
2026-03-11 16:18:51
R W Run
9.22 KB
2026-03-11 16:18:51
R W Run
25.51 KB
2026-03-11 16:18:51
R W Run
198.38 KB
2026-03-11 16:18:52
R W Run
56.65 KB
2026-03-11 16:18:51
R W Run
10.46 KB
2026-03-11 16:18:51
R W Run
10.95 KB
2026-03-11 16:18:52
R W Run
29.26 KB
2026-03-11 16:18:51
R W Run
70.91 KB
2026-03-11 16:18:52
R W Run
35.3 KB
2026-03-11 16:18:52
R W Run
16.61 KB
2026-03-11 16:18:52
R W Run
2.57 KB
2026-03-11 16:18:52
R W Run
39.83 KB
2026-03-11 16:18:51
R W Run
70.64 KB
2026-03-11 16:18:51
R W Run
15.56 KB
2026-03-11 16:18:52
R W Run
7.33 KB
2026-03-11 16:18:52
R W Run
253 By
2026-03-11 16:18:51
R W Run
7.96 KB
2026-03-11 16:18:52
R W Run
3.23 KB
2026-03-11 16:18:52
R W Run
969 By
2026-03-11 16:18:52
R W Run
16.28 KB
2026-03-11 16:18:51
R W Run
7.22 KB
2026-03-11 16:18:51
R W Run
12.95 KB
2026-03-11 16:18:51
R W Run
6.53 KB
2026-03-11 16:18:51
R W Run
3.42 KB
2026-03-11 16:18:52
R W Run
5.84 KB
2026-03-11 16:18:51
R W Run
1.97 KB
2026-03-11 16:18:51
R W Run
4.3 KB
2026-03-11 16:18:52
R W Run
2.91 KB
2026-03-11 16:18:51
R W Run
16.46 KB
2026-03-11 16:18:52
R W Run
40.6 KB
2026-03-11 16:18:51
R W Run
20.22 KB
2026-03-11 16:18:51
R W Run
36.11 KB
2026-03-11 16:18:52
R W Run
17.01 KB
2026-03-11 16:18:51
R W Run
7.27 KB
2026-03-11 16:18:52
R W Run
6.62 KB
2026-03-11 16:18:52
R W Run
16.49 KB
2026-03-11 16:18:52
R W Run
1.79 KB
2026-03-11 16:18:52
R W Run
29.82 KB
2026-03-11 16:18:51
R W Run
6.67 KB
2026-03-11 16:18:52
R W Run
8.98 KB
2026-03-11 16:18:52
R W Run
19.42 KB
2026-03-11 16:18:51
R W Run
12.01 KB
2026-03-11 16:18:51
R W Run
17.11 KB
2026-03-11 16:18:51
R W Run
6.74 KB
2026-03-11 16:18:52
R W Run
30.93 KB
2026-03-11 16:18:51
R W Run
4.99 KB
2026-03-11 16:18:51
R W Run
4.25 KB
2026-03-11 16:18:51
R W Run
24.72 KB
2026-03-11 16:18:51
R W Run
29.96 KB
2026-03-11 16:18:52
R W Run
6.41 KB
2026-03-11 16:18:51
R W Run
160 KB
2026-03-11 16:18:51
R W Run
6.72 KB
2026-03-11 16:18:52
R W Run
10.92 KB
2026-03-11 16:18:51
R W Run
4.77 KB
2026-03-11 16:18:51
R W Run
3.38 KB
2026-03-11 16:18:51
R W Run
11.18 KB
2026-03-11 16:18:51
R W Run
62.19 KB
2026-03-11 16:18:51
R W Run
2.46 KB
2026-03-11 16:18:51
R W Run
9.17 KB
2026-03-11 16:18:51
R W Run
32.15 KB
2026-03-11 16:18:51
R W Run
34.05 KB
2026-03-11 16:18:52
R W Run
7.15 KB
2026-03-11 16:18:51
R W Run
3.47 KB
2026-03-11 16:18:52
R W Run
1.87 KB
2026-03-11 16:18:52
R W Run
30.91 KB
2026-03-11 16:18:51
R W Run
7.29 KB
2026-03-11 16:18:52
R W Run
7.35 KB
2026-03-11 16:18:51
R W Run
12.54 KB
2026-03-11 16:18:51
R W Run
19.12 KB
2026-03-11 16:18:51
R W Run
18.12 KB
2026-03-11 16:18:52
R W Run
39.99 KB
2026-03-11 16:18:52
R W Run
5.17 KB
2026-03-11 16:18:52
R W Run
979 By
2026-03-11 16:18:51
R W Run
18.44 KB
2026-03-11 16:18:52
R W Run
10.24 KB
2026-03-11 16:18:51
R W Run
1.77 KB
2026-03-11 16:18:52
R W Run
34.9 KB
2026-03-11 16:18:51
R W Run
7.19 KB
2026-03-11 16:18:52
R W Run
160.5 KB
2026-03-11 16:18:51
R W Run
64.27 KB
2026-03-11 16:18:51
R W Run
27.95 KB
2026-03-11 16:18:51
R W Run
4.69 KB
2026-03-11 16:18:51
R W Run
2.94 KB
2026-03-11 16:18:51
R W Run
43.13 KB
2026-03-11 16:18:52
R W Run
2.25 KB
2026-03-11 16:18:52
R W Run
22.5 KB
2026-03-11 16:18:51
R W Run
13.01 KB
2026-03-11 16:18:52
R W Run
3.27 KB
2026-03-11 16:18:51
R W Run
18 KB
2026-03-11 16:18:51
R W Run
210.4 KB
2026-03-11 16:18:52
R W Run
25.86 KB
2026-03-11 16:18:52
R W Run
115.85 KB
2026-03-11 16:18:51
R W Run
373 By
2026-03-11 16:18:52
R W Run
343 By
2026-03-11 16:18:52
R W Run
338 By
2026-03-11 16:18:51
R W Run
100.73 KB
2026-03-11 16:18:52
R W Run
130.93 KB
2026-03-11 16:18:51
R W Run
19.1 KB
2026-03-11 16:18:51
R W Run
17.41 KB
2026-03-11 16:18:52
R W Run
41.98 KB
2026-03-11 16:18:52
R W Run
400 By
2026-03-11 16:18:52
R W Run
11.1 KB
2026-03-11 16:18:52
R W Run
37.02 KB
2026-03-11 16:18:51
R W Run
2.24 KB
2026-03-11 16:18:51
R W Run
188.13 KB
2026-03-11 16:18:51
R W Run
338 By
2026-03-11 16:18:51
R W Run
38 KB
2026-03-11 16:18:51
R W Run
4.02 KB
2026-03-11 16:18:52
R W Run
5.38 KB
2026-03-11 16:18:51
R W Run
3.05 KB
2026-03-11 16:18:52
R W Run
2.61 KB
2026-03-11 16:18:51
R W Run
1.16 KB
2026-03-11 16:18:52
R W Run
4.04 KB
2026-03-11 16:18:51
R W Run
3.71 KB
2026-03-11 16:18:51
R W Run
24.6 KB
2026-03-11 16:18:51
R W Run
9.56 KB
2026-03-11 16:18:51
R W Run
346.43 KB
2026-03-11 16:18:52
R W Run
281.84 KB
2026-03-11 16:18:52
R W Run
14.95 KB
2026-03-11 16:18:51
R W Run
8.44 KB
2026-03-11 16:18:52
R W Run
168.95 KB
2026-03-11 16:18:52
R W Run
20.71 KB
2026-03-11 16:18:52
R W Run
25.27 KB
2026-03-11 16:18:51
R W Run
5.72 KB
2026-03-11 16:18:51
R W Run
4.63 KB
2026-03-11 16:18:52
R W Run
81.73 KB
2026-03-11 16:18:51
R W Run
67.18 KB
2026-03-11 16:18:51
R W Run
156.36 KB
2026-03-11 16:18:52
R W Run
55.19 KB
2026-03-11 16:18:51
R W Run
162 By
2026-03-11 16:18:51
R W Run
61.72 KB
2026-03-11 16:18:51
R W Run
216.06 KB
2026-03-11 16:18:52
R W Run
65.09 KB
2026-03-11 16:18:51
R W Run
25.24 KB
2026-03-11 16:18:52
R W Run
4.81 KB
2026-03-11 16:18:51
R W Run
6.48 KB
2026-03-11 16:18:52
R W Run
21.25 KB
2026-03-11 16:18:51
R W Run
2.79 KB
2026-03-11 16:18:52
R W Run
89.69 KB
2026-03-11 16:18:52
R W Run
19.42 KB
2026-03-11 16:18:52
R W Run
3.69 KB
2026-03-11 16:18:52
R W Run
4.11 KB
2026-03-11 16:18:51
R W Run
40.74 KB
2026-03-11 16:18:51
R W Run
25.38 KB
2026-03-11 16:18:51
R W Run
43.31 KB
2026-03-11 16:18:52
R W Run
102.57 KB
2026-03-11 16:18:52
R W Run
6.18 KB
2026-03-11 16:18:51
R W Run
124.47 KB
2026-03-11 16:18:52
R W Run
35.65 KB
2026-03-11 16:18:52
R W Run
6.94 KB
2026-03-11 16:18:52
R W Run
67.04 KB
2026-03-11 16:18:52
R W Run
10.62 KB
2026-03-11 16:18:51
R W Run
289.35 KB
2026-03-11 16:18:52
R W Run
36.23 KB
2026-03-11 16:18:51
R W Run
200 By
2026-03-11 16:18:52
R W Run
200 By
2026-03-11 16:18:52
R W Run
98.29 KB
2026-03-11 16:18:52
R W Run
30.02 KB
2026-03-11 16:18:52
R W Run
19.03 KB
2026-03-11 16:18:52
R W Run
5.06 KB
2026-03-11 16:18:52
R W Run
255 By
2026-03-11 16:18:51
R W Run
22.66 KB
2026-03-11 16:18:52
R W Run
154.63 KB
2026-03-11 16:18:51
R W Run
9.68 KB
2026-03-11 16:18:51
R W Run
258 By
2026-03-11 16:18:51
R W Run
23.49 KB
2026-03-11 16:18:51
R W Run
3.16 KB
2026-03-11 16:18:51
R W Run
8.4 KB
2026-03-11 16:18:52
R W Run
441 By
2026-03-11 16:18:51
R W Run
7.39 KB
2026-03-11 16:18:51
R W Run
173 KB
2026-03-11 16:18:52
R W Run
544 By
2026-03-11 16:18:52
R W Run
4.17 KB
2026-03-11 16:18:51
R W Run
35.97 KB
2026-03-11 16:18:52
R W Run
1.69 KB
2026-03-11 16:18:51
R W Run
2.84 KB
2026-03-11 16:18:52
R W Run
6.09 KB
2026-03-11 16:18:51
R W Run
8.71 KB
2026-03-11 16:18:51
R W Run
131.84 KB
2026-03-11 16:18:51
R W Run
37.45 KB
2026-03-11 16:18:51
R W Run
173.89 KB
2026-03-11 16:18:51
R W Run
7.09 KB
2026-03-11 16:18:51
R W Run
6.41 KB
2026-03-11 16:18:51
R W Run
1.08 KB
2026-03-11 16:18:51
R W Run
69.46 KB
2026-03-11 16:18:52
R W Run
445 By
2026-03-11 16:18:51
R W Run
799 By
2026-03-11 16:18:52
R W Run
error_log
📄class-avif-info.php
1<?php
2/**
3 * Copyright (c) 2021, Alliance for Open Media. All rights reserved
4 *
5 * This source code is subject to the terms of the BSD 2 Clause License and
6 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
7 * was not distributed with this source code in the LICENSE file, you can
8 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
9 * Media Patent License 1.0 was not distributed with this source code in the
10 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
11 *
12 * Note: this class is from libavifinfo - https://aomedia.googlesource.com/libavifinfo/+/refs/heads/main/avifinfo.php at f509487.
13 * It is used as a fallback to parse AVIF files when the server doesn't support AVIF,
14 * primarily to identify the width and height of the image.
15 *
16 * Note PHP 8.2 added native support for AVIF, so this class can be removed when WordPress requires PHP 8.2.
17 */
18
19namespace Avifinfo;
20
21const FOUND = 0; // Input correctly parsed and information retrieved.
22const NOT_FOUND = 1; // Input correctly parsed but information is missing or elsewhere.
23const TRUNCATED = 2; // Input correctly parsed until missing bytes to continue.
24const ABORTED = 3; // Input correctly parsed until stopped to avoid timeout or crash.
25const INVALID = 4; // Input incorrectly parsed.
26
27const MAX_SIZE = 4294967295; // Unlikely to be insufficient to parse AVIF headers.
28const MAX_NUM_BOXES = 4096; // Be reasonable. Avoid timeouts and out-of-memory.
29const MAX_VALUE = 255;
30const MAX_TILES = 16;
31const MAX_PROPS = 32;
32const MAX_FEATURES = 8;
33const UNDEFINED = 0; // Value was not yet parsed.
34
35/**
36 * Reads an unsigned integer with most significant bits first.
37 *
38 * @param binary string $input Must be at least $num_bytes-long.
39 * @param int $num_bytes Number of parsed bytes.
40 * @return int Value.
41 */
42function read_big_endian( $input, $num_bytes ) {
43 if ( $num_bytes == 1 ) {
44 return unpack( 'C', $input ) [1];
45 } else if ( $num_bytes == 2 ) {
46 return unpack( 'n', $input ) [1];
47 } else if ( $num_bytes == 3 ) {
48 $bytes = unpack( 'C3', $input );
49 return ( $bytes[1] << 16 ) | ( $bytes[2] << 8 ) | $bytes[3];
50 } else { // $num_bytes is 4
51 // This might fail to read unsigned values >= 2^31 on 32-bit systems.
52 // See https://www.php.net/manual/en/function.unpack.php#106041
53 return unpack( 'N', $input ) [1];
54 }
55}
56
57/**
58 * Reads bytes and advances the stream position by the same count.
59 *
60 * @param stream $handle Bytes will be read from this resource.
61 * @param int $num_bytes Number of bytes read. Must be greater than 0.
62 * @return binary string|false The raw bytes or false on failure.
63 */
64function read( $handle, $num_bytes ) {
65 $data = fread( $handle, $num_bytes );
66 return ( $data !== false && strlen( $data ) >= $num_bytes ) ? $data : false;
67}
68
69/**
70 * Advances the stream position by the given offset.
71 *
72 * @param stream $handle Bytes will be skipped from this resource.
73 * @param int $num_bytes Number of skipped bytes. Can be 0.
74 * @return bool True on success or false on failure.
75 */
76// Skips 'num_bytes' from the 'stream'. 'num_bytes' can be zero.
77function skip( $handle, $num_bytes ) {
78 return ( fseek( $handle, $num_bytes, SEEK_CUR ) == 0 );
79}
80
81//------------------------------------------------------------------------------
82// Features are parsed into temporary property associations.
83
84class Tile { // Tile item id <-> parent item id associations.
85 public $tile_item_id;
86 public $parent_item_id;
87}
88
89class Prop { // Property index <-> item id associations.
90 public $property_index;
91 public $item_id;
92}
93
94class Dim_Prop { // Property <-> features associations.
95 public $property_index;
96 public $width;
97 public $height;
98}
99
100class Chan_Prop { // Property <-> features associations.
101 public $property_index;
102 public $bit_depth;
103 public $num_channels;
104}
105
106class Features {
107 public $has_primary_item = false; // True if "pitm" was parsed.
108 public $has_alpha = false; // True if an alpha "auxC" was parsed.
109 public $primary_item_id;
110 public $primary_item_features = array( // Deduced from the data below.
111 'width' => UNDEFINED, // In number of pixels.
112 'height' => UNDEFINED, // Ignores mirror and rotation.
113 'bit_depth' => UNDEFINED, // Likely 8, 10 or 12 bits per channel per pixel.
114 'num_channels' => UNDEFINED // Likely 1, 2, 3 or 4 channels:
115 // (1 monochrome or 3 colors) + (0 or 1 alpha)
116 );
117
118 public $tiles = array(); // Tile[]
119 public $props = array(); // Prop[]
120 public $dim_props = array(); // Dim_Prop[]
121 public $chan_props = array(); // Chan_Prop[]
122
123 /**
124 * Binds the width, height, bit depth and number of channels from stored internal features.
125 *
126 * @param int $target_item_id Id of the item whose features will be bound.
127 * @param int $tile_depth Maximum recursion to search within tile-parent relations.
128 * @return Status FOUND on success or NOT_FOUND on failure.
129 */
130 private function get_item_features( $target_item_id, $tile_depth ) {
131 foreach ( $this->props as $prop ) {
132 if ( $prop->item_id != $target_item_id ) {
133 continue;
134 }
135
136 // Retrieve the width and height of the primary item if not already done.
137 if ( $target_item_id == $this->primary_item_id &&
138 ( $this->primary_item_features['width'] == UNDEFINED ||
139 $this->primary_item_features['height'] == UNDEFINED ) ) {
140 foreach ( $this->dim_props as $dim_prop ) {
141 if ( $dim_prop->property_index != $prop->property_index ) {
142 continue;
143 }
144 $this->primary_item_features['width'] = $dim_prop->width;
145 $this->primary_item_features['height'] = $dim_prop->height;
146 if ( $this->primary_item_features['bit_depth'] != UNDEFINED &&
147 $this->primary_item_features['num_channels'] != UNDEFINED ) {
148 return FOUND;
149 }
150 break;
151 }
152 }
153 // Retrieve the bit depth and number of channels of the target item if not
154 // already done.
155 if ( $this->primary_item_features['bit_depth'] == UNDEFINED ||
156 $this->primary_item_features['num_channels'] == UNDEFINED ) {
157 foreach ( $this->chan_props as $chan_prop ) {
158 if ( $chan_prop->property_index != $prop->property_index ) {
159 continue;
160 }
161 $this->primary_item_features['bit_depth'] = $chan_prop->bit_depth;
162 $this->primary_item_features['num_channels'] = $chan_prop->num_channels;
163 if ( $this->primary_item_features['width'] != UNDEFINED &&
164 $this->primary_item_features['height'] != UNDEFINED ) {
165 return FOUND;
166 }
167 break;
168 }
169 }
170 }
171
172 // Check for the bit_depth and num_channels in a tile if not yet found.
173 if ( $tile_depth < 3 ) {
174 foreach ( $this->tiles as $tile ) {
175 if ( $tile->parent_item_id != $target_item_id ) {
176 continue;
177 }
178 $status = $this->get_item_features( $tile->tile_item_id, $tile_depth + 1 );
179 if ( $status != NOT_FOUND ) {
180 return $status;
181 }
182 }
183 }
184 return NOT_FOUND;
185 }
186
187 /**
188 * Finds the width, height, bit depth and number of channels of the primary item.
189 *
190 * @return Status FOUND on success or NOT_FOUND on failure.
191 */
192 public function get_primary_item_features() {
193 // Nothing to do without the primary item ID.
194 if ( !$this->has_primary_item ) {
195 return NOT_FOUND;
196 }
197 // Early exit.
198 if ( empty( $this->dim_props ) || empty( $this->chan_props ) ) {
199 return NOT_FOUND;
200 }
201 $status = $this->get_item_features( $this->primary_item_id, /*tile_depth=*/ 0 );
202 if ( $status != FOUND ) {
203 return $status;
204 }
205
206 // "auxC" is parsed before the "ipma" properties so it is known now, if any.
207 if ( $this->has_alpha ) {
208 ++$this->primary_item_features['num_channels'];
209 }
210 return FOUND;
211 }
212}
213
214//------------------------------------------------------------------------------
215
216class Box {
217 public $size; // In bytes.
218 public $type; // Four characters.
219 public $version; // 0 or actual version if this is a full box.
220 public $flags; // 0 or actual value if this is a full box.
221 public $content_size; // 'size' minus the header size.
222
223 /**
224 * Reads the box header.
225 *
226 * @param stream $handle The resource the header will be parsed from.
227 * @param int $num_parsed_boxes The total number of parsed boxes. Prevents timeouts.
228 * @param int $num_remaining_bytes The number of bytes that should be available from the resource.
229 * @return Status FOUND on success or an error on failure.
230 */
231 public function parse( $handle, &$num_parsed_boxes, $num_remaining_bytes = MAX_SIZE ) {
232 // See ISO/IEC 14496-12:2012(E) 4.2
233 $header_size = 8; // box 32b size + 32b type (at least)
234 if ( $header_size > $num_remaining_bytes ) {
235 return INVALID;
236 }
237 if ( !( $data = read( $handle, 8 ) ) ) {
238 return TRUNCATED;
239 }
240 $this->size = read_big_endian( $data, 4 );
241 $this->type = substr( $data, 4, 4 );
242 // 'box->size==1' means 64-bit size should be read after the box type.
243 // 'box->size==0' means this box extends to all remaining bytes.
244 if ( $this->size == 1 ) {
245 $header_size += 8;
246 if ( $header_size > $num_remaining_bytes ) {
247 return INVALID;
248 }
249 if ( !( $data = read( $handle, 8 ) ) ) {
250 return TRUNCATED;
251 }
252 // Stop the parsing if any box has a size greater than 4GB.
253 if ( read_big_endian( $data, 4 ) != 0 ) {
254 return ABORTED;
255 }
256 // Read the 32 least-significant bits.
257 $this->size = read_big_endian( substr( $data, 4, 4 ), 4 );
258 } else if ( $this->size == 0 ) {
259 $this->size = $num_remaining_bytes;
260 }
261 if ( $this->size < $header_size ) {
262 return INVALID;
263 }
264 if ( $this->size > $num_remaining_bytes ) {
265 return INVALID;
266 }
267
268 $has_fullbox_header = $this->type == 'meta' || $this->type == 'pitm' ||
269 $this->type == 'ipma' || $this->type == 'ispe' ||
270 $this->type == 'pixi' || $this->type == 'iref' ||
271 $this->type == 'auxC';
272 if ( $has_fullbox_header ) {
273 $header_size += 4;
274 }
275 if ( $this->size < $header_size ) {
276 return INVALID;
277 }
278 $this->content_size = $this->size - $header_size;
279 // Avoid timeouts. The maximum number of parsed boxes is arbitrary.
280 ++$num_parsed_boxes;
281 if ( $num_parsed_boxes >= MAX_NUM_BOXES ) {
282 return ABORTED;
283 }
284
285 $this->version = 0;
286 $this->flags = 0;
287 if ( $has_fullbox_header ) {
288 if ( !( $data = read( $handle, 4 ) ) ) {
289 return TRUNCATED;
290 }
291 $this->version = read_big_endian( $data, 1 );
292 $this->flags = read_big_endian( substr( $data, 1, 3 ), 3 );
293 // See AV1 Image File Format (AVIF) 8.1
294 // at https://aomediacodec.github.io/av1-avif/#avif-boxes (available when
295 // https://github.com/AOMediaCodec/av1-avif/pull/170 is merged).
296 $is_parsable = ( $this->type == 'meta' && $this->version <= 0 ) ||
297 ( $this->type == 'pitm' && $this->version <= 1 ) ||
298 ( $this->type == 'ipma' && $this->version <= 1 ) ||
299 ( $this->type == 'ispe' && $this->version <= 0 ) ||
300 ( $this->type == 'pixi' && $this->version <= 0 ) ||
301 ( $this->type == 'iref' && $this->version <= 1 ) ||
302 ( $this->type == 'auxC' && $this->version <= 0 );
303 // Instead of considering this file as invalid, skip unparsable boxes.
304 if ( !$is_parsable ) {
305 $this->type = 'unknownversion';
306 }
307 }
308 // print_r( $this ); // Uncomment to print all boxes.
309 return FOUND;
310 }
311}
312
313//------------------------------------------------------------------------------
314
315class Parser {
316 private $handle; // Input stream.
317 private $num_parsed_boxes = 0;
318 private $data_was_skipped = false;
319 public $features;
320
321 function __construct( $handle ) {
322 $this->handle = $handle;
323 $this->features = new Features();
324 }
325
326 /**
327 * Parses an "ipco" box.
328 *
329 * "ispe" is used for width and height, "pixi" and "av1C" are used for bit depth
330 * and number of channels, and "auxC" is used for alpha.
331 *
332 * @param stream $handle The resource the box will be parsed from.
333 * @param int $num_remaining_bytes The number of bytes that should be available from the resource.
334 * @return Status FOUND on success or an error on failure.
335 */
336 private function parse_ipco( $num_remaining_bytes ) {
337 $box_index = 1; // 1-based index. Used for iterating over properties.
338 do {
339 $box = new Box();
340 $status = $box->parse( $this->handle, $this->num_parsed_boxes, $num_remaining_bytes );
341 if ( $status != FOUND ) {
342 return $status;
343 }
344
345 if ( $box->type == 'ispe' ) {
346 // See ISO/IEC 23008-12:2017(E) 6.5.3.2
347 if ( $box->content_size < 8 ) {
348 return INVALID;
349 }
350 if ( !( $data = read( $this->handle, 8 ) ) ) {
351 return TRUNCATED;
352 }
353 $width = read_big_endian( substr( $data, 0, 4 ), 4 );
354 $height = read_big_endian( substr( $data, 4, 4 ), 4 );
355 if ( $width == 0 || $height == 0 ) {
356 return INVALID;
357 }
358 if ( count( $this->features->dim_props ) <= MAX_FEATURES &&
359 $box_index <= MAX_VALUE ) {
360 $dim_prop_count = count( $this->features->dim_props );
361 $this->features->dim_props[$dim_prop_count] = new Dim_Prop();
362 $this->features->dim_props[$dim_prop_count]->property_index = $box_index;
363 $this->features->dim_props[$dim_prop_count]->width = $width;
364 $this->features->dim_props[$dim_prop_count]->height = $height;
365 } else {
366 $this->data_was_skipped = true;
367 }
368 if ( !skip( $this->handle, $box->content_size - 8 ) ) {
369 return TRUNCATED;
370 }
371 } else if ( $box->type == 'pixi' ) {
372 // See ISO/IEC 23008-12:2017(E) 6.5.6.2
373 if ( $box->content_size < 1 ) {
374 return INVALID;
375 }
376 if ( !( $data = read( $this->handle, 1 ) ) ) {
377 return TRUNCATED;
378 }
379 $num_channels = read_big_endian( $data, 1 );
380 if ( $num_channels < 1 ) {
381 return INVALID;
382 }
383 if ( $box->content_size < 1 + $num_channels ) {
384 return INVALID;
385 }
386 if ( !( $data = read( $this->handle, 1 ) ) ) {
387 return TRUNCATED;
388 }
389 $bit_depth = read_big_endian( $data, 1 );
390 if ( $bit_depth < 1 ) {
391 return INVALID;
392 }
393 for ( $i = 1; $i < $num_channels; ++$i ) {
394 if ( !( $data = read( $this->handle, 1 ) ) ) {
395 return TRUNCATED;
396 }
397 // Bit depth should be the same for all channels.
398 if ( read_big_endian( $data, 1 ) != $bit_depth ) {
399 return INVALID;
400 }
401 if ( $i > 32 ) {
402 return ABORTED; // Be reasonable.
403 }
404 }
405 if ( count( $this->features->chan_props ) <= MAX_FEATURES &&
406 $box_index <= MAX_VALUE && $bit_depth <= MAX_VALUE &&
407 $num_channels <= MAX_VALUE ) {
408 $chan_prop_count = count( $this->features->chan_props );
409 $this->features->chan_props[$chan_prop_count] = new Chan_Prop();
410 $this->features->chan_props[$chan_prop_count]->property_index = $box_index;
411 $this->features->chan_props[$chan_prop_count]->bit_depth = $bit_depth;
412 $this->features->chan_props[$chan_prop_count]->num_channels = $num_channels;
413 } else {
414 $this->data_was_skipped = true;
415 }
416 if ( !skip( $this->handle, $box->content_size - ( 1 + $num_channels ) ) ) {
417 return TRUNCATED;
418 }
419 } else if ( $box->type == 'av1C' ) {
420 // See AV1 Codec ISO Media File Format Binding 2.3.1
421 // at https://aomediacodec.github.io/av1-isobmff/#av1c
422 // Only parse the necessary third byte. Assume that the others are valid.
423 if ( $box->content_size < 3 ) {
424 return INVALID;
425 }
426 if ( !( $data = read( $this->handle, 3 ) ) ) {
427 return TRUNCATED;
428 }
429 $byte = read_big_endian( substr( $data, 2, 1 ), 1 );
430 $high_bitdepth = ( $byte & 0x40 ) != 0;
431 $twelve_bit = ( $byte & 0x20 ) != 0;
432 $monochrome = ( $byte & 0x10 ) != 0;
433 if ( $twelve_bit && !$high_bitdepth ) {
434 return INVALID;
435 }
436 if ( count( $this->features->chan_props ) <= MAX_FEATURES &&
437 $box_index <= MAX_VALUE ) {
438 $chan_prop_count = count( $this->features->chan_props );
439 $this->features->chan_props[$chan_prop_count] = new Chan_Prop();
440 $this->features->chan_props[$chan_prop_count]->property_index = $box_index;
441 $this->features->chan_props[$chan_prop_count]->bit_depth =
442 $high_bitdepth ? $twelve_bit ? 12 : 10 : 8;
443 $this->features->chan_props[$chan_prop_count]->num_channels = $monochrome ? 1 : 3;
444 } else {
445 $this->data_was_skipped = true;
446 }
447 if ( !skip( $this->handle, $box->content_size - 3 ) ) {
448 return TRUNCATED;
449 }
450 } else if ( $box->type == 'auxC' ) {
451 // See AV1 Image File Format (AVIF) 4
452 // at https://aomediacodec.github.io/av1-avif/#auxiliary-images
453 $kAlphaStr = "urn:mpeg:mpegB:cicp:systems:auxiliary:alpha\0";
454 $kAlphaStrLength = 44; // Includes terminating character.
455 if ( $box->content_size >= $kAlphaStrLength ) {
456 if ( !( $data = read( $this->handle, $kAlphaStrLength ) ) ) {
457 return TRUNCATED;
458 }
459 if ( substr( $data, 0, $kAlphaStrLength ) == $kAlphaStr ) {
460 // Note: It is unlikely but it is possible that this alpha plane does
461 // not belong to the primary item or a tile. Ignore this issue.
462 $this->features->has_alpha = true;
463 }
464 if ( !skip( $this->handle, $box->content_size - $kAlphaStrLength ) ) {
465 return TRUNCATED;
466 }
467 } else {
468 if ( !skip( $this->handle, $box->content_size ) ) {
469 return TRUNCATED;
470 }
471 }
472 } else {
473 if ( !skip( $this->handle, $box->content_size ) ) {
474 return TRUNCATED;
475 }
476 }
477 ++$box_index;
478 $num_remaining_bytes -= $box->size;
479 } while ( $num_remaining_bytes > 0 );
480 return NOT_FOUND;
481 }
482
483 /**
484 * Parses an "iprp" box.
485 *
486 * The "ipco" box contain the properties which are linked to items by the "ipma" box.
487 *
488 * @param stream $handle The resource the box will be parsed from.
489 * @param int $num_remaining_bytes The number of bytes that should be available from the resource.
490 * @return Status FOUND on success or an error on failure.
491 */
492 private function parse_iprp( $num_remaining_bytes ) {
493 do {
494 $box = new Box();
495 $status = $box->parse( $this->handle, $this->num_parsed_boxes, $num_remaining_bytes );
496 if ( $status != FOUND ) {
497 return $status;
498 }
499
500 if ( $box->type == 'ipco' ) {
501 $status = $this->parse_ipco( $box->content_size );
502 if ( $status != NOT_FOUND ) {
503 return $status;
504 }
505 } else if ( $box->type == 'ipma' ) {
506 // See ISO/IEC 23008-12:2017(E) 9.3.2
507 $num_read_bytes = 4;
508 if ( $box->content_size < $num_read_bytes ) {
509 return INVALID;
510 }
511 if ( !( $data = read( $this->handle, $num_read_bytes ) ) ) {
512 return TRUNCATED;
513 }
514 $entry_count = read_big_endian( $data, 4 );
515 $id_num_bytes = ( $box->version < 1 ) ? 2 : 4;
516 $index_num_bytes = ( $box->flags & 1 ) ? 2 : 1;
517 $essential_bit_mask = ( $box->flags & 1 ) ? 0x8000 : 0x80;
518
519 for ( $entry = 0; $entry < $entry_count; ++$entry ) {
520 if ( $entry >= MAX_PROPS ||
521 count( $this->features->props ) >= MAX_PROPS ) {
522 $this->data_was_skipped = true;
523 break;
524 }
525 $num_read_bytes += $id_num_bytes + 1;
526 if ( $box->content_size < $num_read_bytes ) {
527 return INVALID;
528 }
529 if ( !( $data = read( $this->handle, $id_num_bytes + 1 ) ) ) {
530 return TRUNCATED;
531 }
532 $item_id = read_big_endian(
533 substr( $data, 0, $id_num_bytes ), $id_num_bytes );
534 $association_count = read_big_endian(
535 substr( $data, $id_num_bytes, 1 ), 1 );
536
537 for ( $property = 0; $property < $association_count; ++$property ) {
538 if ( $property >= MAX_PROPS ||
539 count( $this->features->props ) >= MAX_PROPS ) {
540 $this->data_was_skipped = true;
541 break;
542 }
543 $num_read_bytes += $index_num_bytes;
544 if ( $box->content_size < $num_read_bytes ) {
545 return INVALID;
546 }
547 if ( !( $data = read( $this->handle, $index_num_bytes ) ) ) {
548 return TRUNCATED;
549 }
550 $value = read_big_endian( $data, $index_num_bytes );
551 // $essential = ($value & $essential_bit_mask); // Unused.
552 $property_index = ( $value & ~$essential_bit_mask );
553 if ( $property_index <= MAX_VALUE && $item_id <= MAX_VALUE ) {
554 $prop_count = count( $this->features->props );
555 $this->features->props[$prop_count] = new Prop();
556 $this->features->props[$prop_count]->property_index = $property_index;
557 $this->features->props[$prop_count]->item_id = $item_id;
558 } else {
559 $this->data_was_skipped = true;
560 }
561 }
562 if ( $property < $association_count ) {
563 break; // Do not read garbage.
564 }
565 }
566
567 // If all features are available now, do not look further.
568 $status = $this->features->get_primary_item_features();
569 if ( $status != NOT_FOUND ) {
570 return $status;
571 }
572
573 // Mostly if 'data_was_skipped'.
574 if ( !skip( $this->handle, $box->content_size - $num_read_bytes ) ) {
575 return TRUNCATED;
576 }
577 } else {
578 if ( !skip( $this->handle, $box->content_size ) ) {
579 return TRUNCATED;
580 }
581 }
582 $num_remaining_bytes -= $box->size;
583 } while ( $num_remaining_bytes > 0 );
584 return NOT_FOUND;
585 }
586
587 /**
588 * Parses an "iref" box.
589 *
590 * The "dimg" boxes contain links between tiles and their parent items, which
591 * can be used to infer bit depth and number of channels for the primary item
592 * when the latter does not have these properties.
593 *
594 * @param stream $handle The resource the box will be parsed from.
595 * @param int $num_remaining_bytes The number of bytes that should be available from the resource.
596 * @return Status FOUND on success or an error on failure.
597 */
598 private function parse_iref( $num_remaining_bytes ) {
599 do {
600 $box = new Box();
601 $status = $box->parse( $this->handle, $this->num_parsed_boxes, $num_remaining_bytes );
602 if ( $status != FOUND ) {
603 return $status;
604 }
605
606 if ( $box->type == 'dimg' ) {
607 // See ISO/IEC 14496-12:2015(E) 8.11.12.2
608 $num_bytes_per_id = ( $box->version == 0 ) ? 2 : 4;
609 $num_read_bytes = $num_bytes_per_id + 2;
610 if ( $box->content_size < $num_read_bytes ) {
611 return INVALID;
612 }
613 if ( !( $data = read( $this->handle, $num_read_bytes ) ) ) {
614 return TRUNCATED;
615 }
616 $from_item_id = read_big_endian( $data, $num_bytes_per_id );
617 $reference_count = read_big_endian( substr( $data, $num_bytes_per_id, 2 ), 2 );
618
619 for ( $i = 0; $i < $reference_count; ++$i ) {
620 if ( $i >= MAX_TILES ) {
621 $this->data_was_skipped = true;
622 break;
623 }
624 $num_read_bytes += $num_bytes_per_id;
625 if ( $box->content_size < $num_read_bytes ) {
626 return INVALID;
627 }
628 if ( !( $data = read( $this->handle, $num_bytes_per_id ) ) ) {
629 return TRUNCATED;
630 }
631 $to_item_id = read_big_endian( $data, $num_bytes_per_id );
632 $tile_count = count( $this->features->tiles );
633 if ( $from_item_id <= MAX_VALUE && $to_item_id <= MAX_VALUE &&
634 $tile_count < MAX_TILES ) {
635 $this->features->tiles[$tile_count] = new Tile();
636 $this->features->tiles[$tile_count]->tile_item_id = $to_item_id;
637 $this->features->tiles[$tile_count]->parent_item_id = $from_item_id;
638 } else {
639 $this->data_was_skipped = true;
640 }
641 }
642
643 // If all features are available now, do not look further.
644 $status = $this->features->get_primary_item_features();
645 if ( $status != NOT_FOUND ) {
646 return $status;
647 }
648
649 // Mostly if 'data_was_skipped'.
650 if ( !skip( $this->handle, $box->content_size - $num_read_bytes ) ) {
651 return TRUNCATED;
652 }
653 } else {
654 if ( !skip( $this->handle, $box->content_size ) ) {
655 return TRUNCATED;
656 }
657 }
658 $num_remaining_bytes -= $box->size;
659 } while ( $num_remaining_bytes > 0 );
660 return NOT_FOUND;
661 }
662
663 /**
664 * Parses a "meta" box.
665 *
666 * It looks for the primary item ID in the "pitm" box and recurses into other boxes
667 * to find its features.
668 *
669 * @param stream $handle The resource the box will be parsed from.
670 * @param int $num_remaining_bytes The number of bytes that should be available from the resource.
671 * @return Status FOUND on success or an error on failure.
672 */
673 private function parse_meta( $num_remaining_bytes ) {
674 do {
675 $box = new Box();
676 $status = $box->parse( $this->handle, $this->num_parsed_boxes, $num_remaining_bytes );
677 if ( $status != FOUND ) {
678 return $status;
679 }
680
681 if ( $box->type == 'pitm' ) {
682 // See ISO/IEC 14496-12:2015(E) 8.11.4.2
683 $num_bytes_per_id = ( $box->version == 0 ) ? 2 : 4;
684 if ( $num_bytes_per_id > $num_remaining_bytes ) {
685 return INVALID;
686 }
687 if ( !( $data = read( $this->handle, $num_bytes_per_id ) ) ) {
688 return TRUNCATED;
689 }
690 $primary_item_id = read_big_endian( $data, $num_bytes_per_id );
691 if ( $primary_item_id > MAX_VALUE ) {
692 return ABORTED;
693 }
694 $this->features->has_primary_item = true;
695 $this->features->primary_item_id = $primary_item_id;
696 if ( !skip( $this->handle, $box->content_size - $num_bytes_per_id ) ) {
697 return TRUNCATED;
698 }
699 } else if ( $box->type == 'iprp' ) {
700 $status = $this->parse_iprp( $box->content_size );
701 if ( $status != NOT_FOUND ) {
702 return $status;
703 }
704 } else if ( $box->type == 'iref' ) {
705 $status = $this->parse_iref( $box->content_size );
706 if ( $status != NOT_FOUND ) {
707 return $status;
708 }
709 } else {
710 if ( !skip( $this->handle, $box->content_size ) ) {
711 return TRUNCATED;
712 }
713 }
714 $num_remaining_bytes -= $box->size;
715 } while ( $num_remaining_bytes != 0 );
716 // According to ISO/IEC 14496-12:2012(E) 8.11.1.1 there is at most one "meta".
717 return INVALID;
718 }
719
720 /**
721 * Parses a file stream.
722 *
723 * The file type is checked through the "ftyp" box.
724 *
725 * @return bool True if the input stream is an AVIF bitstream or false.
726 */
727 public function parse_ftyp() {
728 $box = new Box();
729 $status = $box->parse( $this->handle, $this->num_parsed_boxes );
730 if ( $status != FOUND ) {
731 return false;
732 }
733
734 if ( $box->type != 'ftyp' ) {
735 return false;
736 }
737 // Iterate over brands. See ISO/IEC 14496-12:2012(E) 4.3.1
738 if ( $box->content_size < 8 ) {
739 return false;
740 }
741 for ( $i = 0; $i + 4 <= $box->content_size; $i += 4 ) {
742 if ( !( $data = read( $this->handle, 4 ) ) ) {
743 return false;
744 }
745 if ( $i == 4 ) {
746 continue; // Skip minor_version.
747 }
748 if ( substr( $data, 0, 4 ) == 'avif' || substr( $data, 0, 4 ) == 'avis' ) {
749 return skip( $this->handle, $box->content_size - ( $i + 4 ) );
750 }
751 if ( $i > 32 * 4 ) {
752 return false; // Be reasonable.
753 }
754
755 }
756 return false; // No AVIF brand no good.
757 }
758
759 /**
760 * Parses a file stream.
761 *
762 * Features are extracted from the "meta" box.
763 *
764 * @return bool True if the main features of the primary item were parsed or false.
765 */
766 public function parse_file() {
767 $box = new Box();
768 while ( $box->parse( $this->handle, $this->num_parsed_boxes ) == FOUND ) {
769 if ( $box->type === 'meta' ) {
770 if ( $this->parse_meta( $box->content_size ) != FOUND ) {
771 return false;
772 }
773 return true;
774 }
775 if ( !skip( $this->handle, $box->content_size ) ) {
776 return false;
777 }
778 }
779 return false; // No "meta" no good.
780 }
781}
782
Ui Ux Design – Teachers Night Out https://cardgames4educators.com Wed, 16 Oct 2024 22:24:18 +0000 en-US hourly 1 https://wordpress.org/?v=6.9.4 https://cardgames4educators.com/wp-content/uploads/2024/06/cropped-Card-4-Educators-logo-32x32.png Ui Ux Design – Teachers Night Out https://cardgames4educators.com 32 32 Masters In English How English Speaker https://cardgames4educators.com/masters-in-english-how-english-speaker/ https://cardgames4educators.com/masters-in-english-how-english-speaker/#comments Mon, 27 May 2024 08:54:45 +0000 https://themexriver.com/wp/kadu/?p=1

Erat himenaeos neque id sagittis massa. Hac suscipit pulvinar dignissim platea magnis eu. Don tellus a pharetra inceptos efficitur dui pulvinar. Feugiat facilisis penatibus pulvinar nunc dictumst donec odio platea habitasse. Lacus porta dolor purus elit ante bibendum tortor netus taciti nullam cubilia. Erat per suspendisse placerat morbi egestas pulvinar bibendum sollicitudin nec. Euismod cubilia eleifend velit himenaeos sodales lectus. Leo maximus cras ac porttitor aliquam torquent pulvinar odio volutpat parturient. Quisque risus finibus suspendisse mus purus magnis facilisi condimentum consectetur dui. Curae elit suspendisse cursus vehicula.

Turpis taciti class non vel pretium quis pulvinar tempor lobortis nunc. Libero phasellus parturient sapien volutpat malesuada ornare. Cubilia dignissim sollicitudin rhoncus lacinia maximus. Cras lorem fermentum bibendum pellentesque nisl etiam ligula enim cubilia. Vulputate pede sapien torquent montes tempus malesuada in mattis dis turpis vitae. Porta est tempor ex eget feugiat vulputate ipsum. Justo nec iaculis habitant diam arcu fermentum.

We offer comprehen sive emplo ment services such as assistance wit employer compliance.Our company is your strategic HR partner as instead of HR. john smithson

Cubilia dignissim sollicitudin rhoncus lacinia maximus. Cras lorem fermentum bibendum pellentesque nisl etiam ligula enim cubilia. Vulputate pede sapien torquent montes tempus malesuada in mattis dis turpis vitae.

Exploring Learning Landscapes in Academic

Feugiat facilisis penatibus pulvinar nunc dictumst donec odio platea habitasse. Lacus porta dolor purus elit ante bibendum tortor netus taciti nullam cubilia. Erat per suspendisse placerat morbi egestas pulvinar bibendum sollicitudin nec. Euismod cubilia eleifend velit himenaeos sodales lectus. Leo maximus cras ac porttitor aliquam torquent.

]]>
https://cardgames4educators.com/masters-in-english-how-english-speaker/feed/ 1