PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 16.0-beta
Jetpack – WP Security, Backup, Speed, & Growth v16.0-beta
16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / _inc / lib / admin-pages / class-akismet-admin-chrome.php
jetpack / _inc / lib / admin-pages Last commit date
class-akismet-admin-chrome.php 2 weeks ago class-jetpack-about-page.php 1 month ago class-jetpack-ai-page.php 1 month ago class-jetpack-redux-state-helper.php 2 weeks ago class.jetpack-admin-page.php 1 month ago class.jetpack-landing-page.php 2 years ago class.jetpack-react-page.php 6 months ago class.jetpack-settings-page.php 7 months ago
class-akismet-admin-chrome.php
353 lines
1 <?php
2 /**
3 * Renders the unified Jetpack admin header and footer chrome on Akismet's admin pages.
4 *
5 * Akismet (5.7+) exposes two action hooks in its admin views:
6 * - `akismet_header`: when an action is registered, it REPLACES Akismet's default masthead.
7 * - `akismet_footer`: rendered at the bottom of every admin view; empty by default.
8 *
9 * This integration consumes those hooks from the Jetpack plugin so that Akismet's pages
10 * share the same branded header bar, standardized footer AND contained layout as the rest
11 * of the unified Jetpack admin (the `@wordpress/admin-ui` page header + `JetpackFooter` look
12 * used by My Jetpack, Protect, Social, etc.): a fixed header, an internally-scrolling middle
13 * and a footer pinned to the bottom of the viewport.
14 *
15 * The markup mirrors the admin-ui page header and `.jetpack-footer` component, and the
16 * styling is a small self-contained stylesheet (no external CSS, no JS, no build step) that
17 * reproduces the measured computed styles of those components plus the
18 * `jetpack-admin-page-layout` mixin, adapted to Akismet's markup
19 * (`#wpbody-content > #akismet-plugin-container > header / .akismet-lower / footer`). This
20 * keeps the integration resilient to the CSS-Module class hashing used by the real React
21 * components.
22 *
23 * NOTE: This class does not modify the Akismet plugin in any way. It only registers
24 * callbacks on Akismet's own action hooks.
25 *
26 * @package automattic/jetpack
27 */
28
29 use Automattic\Jetpack\Redirect;
30 use Automattic\Jetpack\Status;
31 use Automattic\Jetpack\Status\Host;
32
33 if ( ! defined( 'ABSPATH' ) ) {
34 exit( 0 );
35 }
36
37 /**
38 * Wires the unified Jetpack header, footer and contained layout onto Akismet's admin pages.
39 */
40 class Akismet_Admin_Chrome {
41
42 /**
43 * The green Jetpack logo mark, sized via the `height` attribute by callers.
44 *
45 * @param int $height Pixel height of the logo.
46 * @return string SVG markup.
47 */
48 private function jetpack_logo( $height ) {
49 return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" height="' . (int) $height . '" class="jp-akismet-logo" aria-hidden="true"><path fill="#069e08" d="M16,0C7.2,0,0,7.2,0,16s7.2,16,16,16s16-7.2,16-16S24.8,0,16,0z M15,19H7l8-16V19z M17,29V13h8L17,29z"></path></svg>';
50 }
51
52 /**
53 * The Akismet logo mark — the green rounded square with the white "A", taken from
54 * Akismet's own `akismet-refresh-logo.svg`. Sized via the `height` attribute by callers.
55 *
56 * @param int $height Pixel height of the logo.
57 * @return string SVG markup.
58 */
59 private function akismet_logo( $height ) {
60 return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 44 44" height="' . (int) $height . '" class="jp-akismet-mark" aria-hidden="true"><rect width="44" height="44" fill="#357B49" rx="6"/><path fill="#fff" fill-rule="evenodd" d="m29.746 28.31-6.392-16.797c-.152-.397-.305-.672-.789-.675-.673 0-1.408.611-1.746 1.316l-7.378 16.154c-.072.16-.143.311-.214.454-.5.995-1.045 1.546-2.357 1.626a.399.399 0 0 0-.16.033l-.01.004a.399.399 0 0 0-.23.392v.01c0 .054.01.106.03.155l.004.01a.416.416 0 0 0 .394.252h6.212a.417.417 0 0 0 .307-.12.416.416 0 0 0 .124-.305.398.398 0 0 0-.105-.302.399.399 0 0 0-.294-.127c-.757 0-2.197-.062-2.197-1.164.02-.318.103-.63.245-.916l1.399-3.152c.52-1.163 1.654-1.163 2.572-1.163h5.843c.023 0 .044 0 .062.003.13.014.16.081.214.242l1.534 4.07a2.857 2.857 0 0 1 .216 1.04c0 .054-.003.104-.01.153-.09.726-.831.887-1.49.887a.4.4 0 0 0-.294.127l-.007.008-.007.008a.401.401 0 0 0-.092.286v.01c0 .054.01.106.03.155l.005.01a.42.42 0 0 0 .395.252h7.011a.413.413 0 0 0 .279-.13.412.412 0 0 0 .11-.297.387.387 0 0 0-.09-.294.388.388 0 0 0-.277-.135c-1.448-.122-2.295-.643-2.847-2.08Zm-11.985-5.844 2.847-6.304c.361-.728.659-1.486.889-2.265 0-.06.03-.092.06-.092s.061.032.061.091c.02.122.045.247.073.374.197.888.584 1.878.914 2.723l.176.453 1.684 4.529a.927.927 0 0 1 .092.4.473.473 0 0 1-.009.094c-.041.202-.228.272-.602.272h-6.063c-.122 0-.184-.03-.184-.092a.36.36 0 0 1 .062-.183Zm17.107-.721c0 .786-.446 1.231-1.25 1.231-.806 0-1.125-.409-1.125-1.034 0-.786.465-1.231 1.25-1.231.785 0 1.125.427 1.125 1.034ZM9.629 23.002c.803 0 1.25-.447 1.25-1.231 0-.607-.343-1.036-1.128-1.036-.785 0-1.25.447-1.25 1.231 0 .625.325 1.036 1.128 1.036Z" clip-rule="evenodd"/></svg>';
61 }
62
63 /**
64 * Register the hooks that drive the chrome.
65 *
66 * Safe to call unconditionally: the header/footer callbacks are only ever fired by
67 * Akismet's own admin views, and the inline stylesheet is printed alongside the header.
68 *
69 * Idempotent: this can be wired from more than one place depending on the platform —
70 * `Jetpack_Admin` on Atomic/self-hosted, and `Akismet_Admin_WPCOM` on WordPress.com
71 * Simple sites (the two run under different load orders). The static guard ensures the
72 * `akismet_header` / `akismet_footer` callbacks are only ever registered once, so the
73 * chrome can never render twice regardless of how many call sites fire.
74 */
75 public function init_hooks() {
76 static $registered = false;
77 if ( $registered ) {
78 return;
79 }
80 $registered = true;
81
82 add_action( 'akismet_header', array( $this, 'render_header' ) );
83 add_action( 'akismet_footer', array( $this, 'render_footer' ) );
84 }
85
86 /**
87 * The self-contained stylesheet reproducing the admin-ui page header + `.jetpack-footer`
88 * computed styles. Printed once, alongside the header.
89 */
90 private function print_styles() {
91 static $printed = false;
92 if ( $printed ) {
93 return;
94 }
95 $printed = true;
96 ?>
97 <style id="jp-akismet-chrome-css">
98 /* ── Header (admin-ui page header look) ── */
99 .jp-akismet-header {
100 display: flex;
101 align-items: center;
102 box-sizing: border-box;
103 min-height: 72px;
104 padding: 16px 24px;
105 background: #fff;
106 /* `box-shadow` (not `border-bottom`) so the hairline never adds to the
107 box and nudges the logo/title off the admin-ui header's vertical center. */
108 box-shadow: inset 0 -1px 0 #e4e4e4;
109 }
110 .jp-akismet-header__title {
111 display: flex;
112 align-items: center;
113 gap: 8px;
114 }
115 /* 24×24 visual slot centering the 20px logo, matching My Jetpack/Boost. */
116 .jp-akismet-header__visual {
117 display: flex;
118 align-items: center;
119 justify-content: center;
120 flex-shrink: 0;
121 width: 24px;
122 height: 24px;
123 }
124 .jp-akismet-header__title h1 {
125 margin: 0;
126 padding: 0;
127 font-size: 15px;
128 font-weight: 500;
129 line-height: 20px;
130 color: #1e1e1e;
131 }
132 /* ── Footer (.jetpack-footer look) ── */
133 .jp-akismet-footer {
134 display: flex;
135 align-items: center;
136 flex-wrap: wrap;
137 gap: 24px;
138 box-sizing: border-box;
139 padding: 20px 24px;
140 border-top: 1px solid #e4e4e4;
141 background: #fff;
142 color: #1e1e1e;
143 font-size: 13px;
144 }
145 .jp-akismet-footer__logo {
146 display: flex;
147 align-items: center;
148 gap: 8px;
149 font-weight: 500;
150 }
151 .jp-akismet-footer__menu {
152 display: flex;
153 gap: 16px;
154 }
155 /* `#akismet-plugin-container a` is green in Akismet's own CSS; this scoped
156 selector outranks it so the footer links read as neutral grey (#707070,
157 matching My Jetpack's footer links). */
158 #akismet-plugin-container .jp-akismet-footer__menu a {
159 color: #707070;
160 text-decoration: none;
161 }
162 #akismet-plugin-container .jp-akismet-footer__menu a:hover {
163 color: #1e1e1e;
164 text-decoration: underline;
165 }
166 .jp-akismet-footer__a8c {
167 margin-inline-start: auto;
168 display: inline-flex;
169 align-items: center;
170 }
171 /* Mobile: the byline drops its right-push and wraps to its own full-width
172 row, left-aligned — matching how JetpackFooter stacks on other pages. */
173 @media (max-width: 782px) {
174 .jp-akismet-footer__a8c {
175 margin-inline-start: 0;
176 flex-basis: 100%;
177 }
178 }
179 .jp-akismet-footer__a8c svg path {
180 fill: #707070;
181 }
182
183 /* ── Hello Dolly ──
184 The `.jetpack-admin-page #dolly` treatment (right-aligned, italic,
185 WPDS colors) ships in the jetpack-components / My Jetpack admin CSS,
186 which doesn't load on Akismet's page — so without this, Dolly's lyric
187 falls back to left-aligned here. Re-declare it so Dolly lands top-right
188 exactly like every other unified Jetpack admin page. */
189 .jetpack-admin-page #dolly {
190 float: none;
191 text-align: end;
192 background: var(--wpds-color-bg-surface-neutral-strong, #fff);
193 font-style: italic;
194 color: var(--wpds-color-fg-content-neutral-weak, #87a6bc);
195 border-bottom: none;
196 }
197 @media (max-width: 659px) {
198 .jetpack-admin-page #dolly {
199 display: none;
200 }
201 }
202
203 /* ── Contained layout: fixed header, scrolling middle, pinned footer ──
204 Mirrors the jetpack-admin-page-layout mixin, adapted to Akismet's
205 markup (#wpbody-content > #akismet-plugin-container > header/.akismet-lower/footer).
206 Scoped to both menu locations: jetpack_page_… and settings_page_…
207
208 The mixin uses physical `left`/`right` because its SCSS is compiled
209 through rtlcss, which emits a flipped stylesheet. This inline `<style>`
210 has no such build step, so it uses CSS logical properties
211 (`inset-inline-*`, `padding-inline-*`, `margin-inline`) to flip with the
212 admin menu under RTL locales. */
213 body[class*="_page_akismet-key-config"] #wpcontent {
214 padding-inline-start: 0;
215 }
216 body[class*="_page_akismet-key-config"] #wpfooter {
217 display: none;
218 }
219 /* `#screen-meta-links` (the Screen Options / Help tabs container) is always
220 emitted by core's admin header even when empty, and core gives it
221 `margin: 0 10px 20px 0`. On wp.com Simple sites its contents are hidden
222 but the element — and its 20px bottom margin — remain, reserving a blank
223 slot at the very top of the page above the Jetpack header. The
224 `jetpack-admin-page-layout` mixin hides it for the same reason; do it here
225 too. Left UNSCOPED (not under `_page_akismet-key-config`) on purpose: the
226 inline stylesheet is only ever printed on Akismet admin views, and Simple
227 renders its stats UI under a different slug (`dashboard_page_akismet-stats`),
228 so an unscoped rule covers every page this chrome appears on. */
229 #screen-meta-links {
230 display: none;
231 }
232 body[class*="_page_akismet-key-config"] #wpbody-content {
233 box-sizing: border-box;
234 position: fixed;
235 top: var(--wp-admin-bar-height, 32px);
236 inset-inline-start: 160px;
237 inset-inline-end: 0;
238 bottom: 0;
239 width: auto;
240 padding-bottom: 0;
241 overflow: hidden;
242 display: flex;
243 flex-direction: column;
244 }
245 body[class*="_page_akismet-key-config"].folded #wpbody-content {
246 inset-inline-start: 36px;
247 }
248 @media (max-width: 960px) {
249 body[class*="_page_akismet-key-config"].auto-fold #wpbody-content {
250 inset-inline-start: 36px;
251 }
252 }
253 @media (min-width: 961px) {
254 body[class*="_page_akismet-key-config"].is-nav-unification:not(.folded) #wpbody-content {
255 inset-inline-start: 272px;
256 }
257 }
258 body[class*="_page_akismet-key-config"] #akismet-plugin-container {
259 flex: 1 1 auto;
260 min-height: 0;
261 min-width: 0;
262 display: flex;
263 flex-direction: column;
264 /* Drop Akismet's 1px container border: it insets the whole column by 1px,
265 pushing the header logo/title off the admin-ui alignment grid. */
266 border: 0;
267 }
268 body[class*="_page_akismet-key-config"] .jp-akismet-header {
269 flex-shrink: 0;
270 }
271 /* The scrollable middle. Target the generic child between header and
272 footer (not `.akismet-lower` specifically) so the config, start AND
273 stats (bare iframe) views all get a full-width scroll surface. The
274 `#wpbody-content` id keeps these rules ahead of Akismet's own
275 `.akismet-lower { width: 720px }`. */
276 body[class*="_page_akismet-key-config"] #wpbody-content > #akismet-plugin-container > :not(.jp-akismet-header):not(.jp-akismet-footer) {
277 flex: 1 1 auto;
278 min-height: 0;
279 min-width: 0;
280 width: auto;
281 max-width: none;
282 margin: 0;
283 overflow: auto;
284 }
285 /* Move the readable-width restriction onto the content blocks so the
286 scroll surface itself spans the full width (scrolling works wherever
287 the pointer is), while the cards stay a comfortable column, left-
288 aligned with the header. 45rem ≈ Akismet's original 720px column. */
289 body[class*="_page_akismet-key-config"] .akismet-lower > * {
290 box-sizing: border-box;
291 max-width: 45rem;
292 margin-inline: auto;
293 }
294 body[class*="_page_akismet-key-config"] .jp-akismet-footer {
295 flex-shrink: 0;
296 }
297 @media (max-width: 782px) {
298 body[class*="_page_akismet-key-config"] #wpbody-content,
299 body[class*="_page_akismet-key-config"].folded #wpbody-content,
300 body[class*="_page_akismet-key-config"].auto-fold #wpbody-content {
301 top: var(--wp-admin-bar-height, 46px);
302 inset-inline-start: 0;
303 }
304 }
305 </style>
306 <?php
307 }
308
309 /**
310 * Render the admin-ui-style header (Akismet logo + title) that replaces Akismet's default masthead.
311 */
312 public function render_header() {
313 $this->print_styles();
314 ?>
315 <header class="jp-akismet-header">
316 <div class="jp-akismet-header__title">
317 <span class="jp-akismet-header__visual" aria-hidden="true"><?php echo $this->akismet_logo( 20 ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- static SVG. ?></span>
318 <h1><?php esc_html_e( 'Akismet Anti-spam', 'jetpack' ); ?></h1>
319 </div>
320 </header>
321 <?php
322 }
323
324 /**
325 * Render the unified Jetpack footer (`.jetpack-footer` look) at the bottom of the page.
326 */
327 public function render_footer() {
328 // Match wrap_ui(): link the byline to the local About page when Jetpack isn't connectable,
329 // otherwise to the external jetpack.com redirect.
330 $connectable = ! Jetpack::is_connection_ready() && ! ( new Status() )->is_offline_mode();
331 $a8c_url = ! $connectable
332 ? admin_url( 'admin.php?page=jetpack_about' )
333 : Redirect::get_url( 'jetpack' );
334 ?>
335 <footer class="jp-akismet-footer jetpack-footer" aria-label="<?php esc_attr_e( 'Jetpack', 'jetpack' ); ?>" role="contentinfo">
336 <div class="jp-akismet-footer__logo">
337 <?php echo $this->jetpack_logo( 16 ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- static SVG. ?>
338 <span><?php esc_html_e( 'Jetpack', 'jetpack' ); ?></span>
339 </div>
340 <?php if ( ! ( new Host() )->is_wpcom_platform() ) : ?>
341 <nav class="jp-akismet-footer__menu">
342 <a href="<?php echo esc_url( admin_url( 'admin.php?page=my-jetpack#/products' ) ); ?>"><?php echo esc_html_x( 'Products', 'Navigation item', 'jetpack' ); ?></a>
343 <a href="<?php echo esc_url( admin_url( 'admin.php?page=my-jetpack#/help' ) ); ?>"><?php echo esc_html_x( 'Help', 'Navigation item', 'jetpack' ); ?></a>
344 </nav>
345 <?php endif; ?>
346 <a class="jp-akismet-footer__a8c" href="<?php echo esc_url( $a8c_url ); ?>" aria-label="<?php esc_attr_e( 'An Automattic Airline', 'jetpack' ); ?>">
347 <svg role="img" x="0" y="0" viewBox="0 0 935 38.2" height="7" aria-hidden="true"><path d="M317.1 38.2c-12.6 0-20.7-9.1-20.7-18.5v-1.2c0-9.6 8.2-18.5 20.7-18.5 12.6 0 20.8 8.9 20.8 18.5v1.2C337.9 29.1 329.7 38.2 317.1 38.2zM331.2 18.6c0-6.9-5-13-14.1-13s-14 6.1-14 13v0.9c0 6.9 5 13.1 14 13.1s14.1-6.2 14.1-13.1V18.6zM175 36.8l-4.7-8.8h-20.9l-4.5 8.8h-7L157 1.3h5.5L182 36.8H175zM159.7 8.2L152 23.1h15.7L159.7 8.2zM212.4 38.2c-12.7 0-18.7-6.9-18.7-16.2V1.3h6.6v20.9c0 6.6 4.3 10.5 12.5 10.5 8.4 0 11.9-3.9 11.9-10.5V1.3h6.7V22C231.4 30.8 225.8 38.2 212.4 38.2zM268.6 6.8v30h-6.7v-30h-15.5V1.3h37.7v5.5H268.6zM397.3 36.8V8.7l-1.8 3.1 -14.9 25h-3.3l-14.7-25 -1.8-3.1v28.1h-6.5V1.3h9.2l14 24.4 1.7 3 1.7-3 13.9-24.4h9.1v35.5H397.3zM454.4 36.8l-4.7-8.8h-20.9l-4.5 8.8h-7l19.2-35.5h5.5l19.5 35.5H454.4zM439.1 8.2l-7.7 14.9h15.7L439.1 8.2zM488.4 6.8v30h-6.7v-30h-15.5V1.3h37.7v5.5H488.4zM537.3 6.8v30h-6.7v-30h-15.5V1.3h37.7v5.5H537.3zM569.3 36.8V4.6c2.7 0 3.7-1.4 3.7-3.4h2.8v35.5L569.3 36.8 569.3 36.8zM628 11.3c-3.2-2.9-7.9-5.7-14.2-5.7 -9.5 0-14.8 6.5-14.8 13.3v0.7c0 6.7 5.4 13 15.3 13 5.9 0 10.8-2.8 13.9-5.7l4 4.2c-3.9 3.8-10.5 7.1-18.3 7.1 -13.4 0-21.6-8.7-21.6-18.3v-1.2c0-9.6 8.9-18.7 21.9-18.7 7.5 0 14.3 3.1 18 7.1L628 11.3zM321.5 12.4c1.2 0.8 1.5 2.4 0.8 3.6l-6.1 9.4c-0.8 1.2-2.4 1.6-3.6 0.8l0 0c-1.2-0.8-1.5-2.4-0.8-3.6l6.1-9.4C318.7 11.9 320.3 11.6 321.5 12.4L321.5 12.4z"></path><path d="M37.5 36.7l-4.7-8.9H11.7l-4.6 8.9H0L19.4 0.8H25l19.7 35.9H37.5zM22 7.8l-7.8 15.1h15.9L22 7.8zM82.8 36.7l-23.3-24 -2.3-2.5v26.6h-6.7v-36H57l22.6 24 2.3 2.6V0.8h6.7v35.9H82.8z"></path><path d="M719.9 37l-4.8-8.9H694l-4.6 8.9h-7.1l19.5-36h5.6l19.8 36H719.9zM704.4 8l-7.8 15.1h15.9L704.4 8zM733 37V1h6.8v36H733zM781 37c-1.8 0-2.6-2.5-2.9-5.8l-0.2-3.7c-0.2-3.6-1.7-5.1-8.4-5.1h-12.8V37H750V1h19.6c10.8 0 15.7 4.3 15.7 9.9 0 3.9-2 7.7-9 9 7 0.5 8.5 3.7 8.6 7.9l0.1 3c0.1 2.5 0.5 4.3 2.2 6.1V37H781zM778.5 11.8c0-2.6-2.1-5.1-7.9-5.1h-13.8v10.8h14.4c5 0 7.3-2.4 7.3-5.2V11.8zM794.8 37V1h6.8v30.4h28.2V37H794.8zM836.7 37V1h6.8v36H836.7zM886.2 37l-23.4-24.1 -2.3-2.5V37h-6.8V1h6.5l22.7 24.1 2.3 2.6V1h6.8v36H886.2zM902.3 37V1H935v5.6h-26v9.2h20v5.5h-20v10.1h26V37H902.3z"></path></svg>
348 </a>
349 </footer>
350 <?php
351 }
352 }
353