PluginProbe
GiveWP – Donation Plugin and Fundraising Platform / 4.16.6.1
GiveWP – Donation Plugin and Fundraising Platform v4.16.6.1
4.18.0.1 4.18.0 4.17.0 4.16.9 4.16.8.1 4.16.8 4.16.7.2 4.16.7.1 4.16.7 4.16.6.1 4.16.6 4.16.5.1 4.16.5 4.16.4 4.16.3 4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 All 258 releases
give / includes / misc-functions.php

misc-functions.php in GiveWP – Donation Plugin and Fundraising Platform 4.16.6.1, at includes/misc-functions.php

2,698 lines 114.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Misc Functions
4 *
5 * @package Give
6 * @subpackage Functions
7 * @copyright Copyright (c) 2016, GiveWP
8 * @license https://opensource.org/licenses/gpl-license GNU Public License
9 * @since 1.0
10 */
11
12 use Give\License\PremiumAddonsListManager;
13 use Give\License\Repositories\LicenseRepository;
14 use Give\License\ValueObjects\LicenseOptionKeys;
15
16 // Exit if accessed directly.
17 if ( ! defined( 'ABSPATH' ) ) {
18 exit;
19 }
20
21 /**
22 * Is Test Mode Enabled.
23 *
24 * @return bool $ret True if return mode is enabled, false otherwise
25 * @since 1.0
26 */
27 function give_is_test_mode() {
28
29 $ret = give_is_setting_enabled( give_get_option( 'test_mode' ) );
30
31 return (bool) apply_filters( 'give_is_test_mode', $ret );
32
33 }
34
35 /**
36 * Get the current page URL.
37 *
38 * @return string $current_url Current page URL.
39 * @since 1.0
40 */
41 function give_get_current_page_url() {
42
43 global $wp;
44
45 if ( get_option( 'permalink_structure' ) ) {
46 $base = trailingslashit( home_url( $wp->request ) );
47 } else {
48 $base = add_query_arg( $wp->query_string, '', trailingslashit( home_url( $wp->request ) ) );
49 $base = remove_query_arg( [ 'post_type', 'name' ], $base );
50 }
51
52 $scheme = is_ssl() ? 'https' : 'http';
53 $current_uri = set_url_scheme( $base, $scheme );
54
55 if ( is_front_page() ) {
56 $current_uri = home_url( '/' );
57 }
58
59 /**
60 * Filter the current page url
61 *
62 * @param string $current_uri
63 *
64 * @since 1.0
65 */
66 return esc_url_raw( apply_filters( 'give_get_current_page_url', $current_uri ) );
67
68 }
69
70
71 /**
72 * Verify credit card numbers live?
73 *
74 * @return bool $ret True is verify credit cards is live
75 * @since 1.0
76 */
77 function give_is_cc_verify_enabled() {
78
79 $ret = true;
80
81 /**
82 * Enable if use a single gateway other than PayPal or Manual. We have to assume it accepts credit cards.
83 * Enable if using more than one gateway if they are not both PayPal and manual, again assuming credit card usage.
84 */
85 $gateways = give_get_enabled_payment_gateways();
86
87 if ( count( $gateways ) == 1 && ! isset( $gateways['paypal'] ) && ! isset( $gateways['manual'] ) ) {
88 $ret = true;
89 } elseif ( count( $gateways ) == 1 ) {
90 $ret = false;
91 } elseif ( count( $gateways ) == 2 && isset( $gateways['paypal'] ) && isset( $gateways['manual'] ) ) {
92 $ret = false;
93 }
94
95 /**
96 * Fire the filter
97 *
98 * @param bool $ret
99 *
100 * @since 1.0
101 */
102 return (bool) apply_filters( 'give_is_cc_verify_enabled', $ret );
103 }
104
105 /**
106 * Retrieve timezone.
107 *
108 * @return string $timezone The timezone ID.
109 * @since 1.0
110 */
111 function give_get_timezone_id() {
112
113 // if site timezone string exists, return it.
114 if ( $timezone = get_option( 'timezone_string' ) ) {
115 return $timezone;
116 }
117
118 // get UTC offset, if it isn't set return UTC.
119 if ( ! ( $utc_offset = 3600 * get_option( 'gmt_offset', 0 ) ) ) {
120 return 'UTC';
121 }
122
123 // attempt to guess the timezone string from the UTC offset.
124 $timezone = timezone_name_from_abbr( '', $utc_offset );
125
126 // last try, guess timezone string manually.
127 if ( $timezone === false ) {
128
129 $is_dst = date( 'I' );
130
131 foreach ( timezone_abbreviations_list() as $abbr ) {
132 foreach ( $abbr as $city ) {
133 if ( $city['dst'] == $is_dst && $city['offset'] == $utc_offset ) {
134 return $city['timezone_id'];
135 }
136 }
137 }
138 }
139
140 // Fallback.
141 return 'UTC';
142 }
143
144
145 /**
146 * Get User IP
147 *
148 * Returns the IP address of the current visitor
149 *
150 * @since 2.33.5 Add $single param.
151 * @since 1.0
152 *
153 * @return string $ip User's IP address
154 */
155 function give_get_ip($single = true)
156 {
157 $ip_addresses = '127.0.0.1';
158 $header_type = '';
159
160 if ( ! empty( $_SERVER['HTTP_CLIENT_IP'] ) ) {
161 // check ip from share internet
162 $ip_addresses = $_SERVER['HTTP_CLIENT_IP'];
163 $header_type = 'HTTP_CLIENT_IP';
164 } elseif ( ! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
165 // to check ip is pass from proxy
166 $ip_addresses = $_SERVER['HTTP_X_FORWARDED_FOR'];
167 $header_type = 'HTTP_X_FORWARDED_FOR';
168 } elseif ( ! empty( $_SERVER['REMOTE_ADDR'] ) ) {
169 $ip_addresses = $_SERVER['REMOTE_ADDR'];
170 $header_type = 'REMOTE_ADDR';
171 }
172
173 /**
174 * Filter the IP
175 *
176 * @since 2.33.5 Add $single and $header_type params.
177 * @since 1.0
178 */
179 $ip_addresses = apply_filters('give_get_ip', $ip_addresses, $single, $header_type);
180
181 // Filter empty values.
182 if (false !== strpos($ip_addresses, ',')) {
183 $ip_addresses = give_clean(explode(',', $ip_addresses));
184 $ip_addresses = array_filter($ip_addresses);
185 $ip_addresses = implode(',', $ip_addresses);
186 } else {
187 $ip_addresses = give_clean($ip_addresses);
188 }
189
190 if ($single && false !== strpos($ip_addresses, ',')) {
191 return explode(',', $ip_addresses)[0];
192 }
193
194 return $ip_addresses;
195 }
196
197
198 /**
199 * Store Donation Data in Sessions
200 *
201 * Used for storing info about donation
202 *
203 * @param $purchase_data
204 *
205 * @since 1.0
206 *
207 * @uses Give()->session->set()
208 */
209 function give_set_purchase_session( $purchase_data = [] ) {
210 Give()->session->set( 'give_purchase', $purchase_data );
211 Give()->session->set( 'give_email', $purchase_data['user_email'] );
212 }
213
214 /**
215 * Retrieve Donation Data from Session
216 *
217 * Used for retrieving info about donation
218 * after completing a donation
219 *
220 * @return mixed array | false
221 * @uses Give()->session->get()
222 * @since 1.0
223 */
224 function give_get_purchase_session() {
225 return Give()->session->get( 'give_purchase' );
226 }
227
228 /**
229 * Retrieve Payment Key of the Receipt Access Session.
230 *
231 * @return array|string
232 * @since 1.8.17
233 */
234 function give_get_receipt_session() {
235 return Give()->session->get( 'receipt_access' );
236 }
237
238 /**
239 * Retrieve Payment Key of the History Access Session.
240 *
241 * @return array|string
242 * @since 1.8.17
243 */
244 function give_get_history_session() {
245 return (bool) Give()->session->get( 'history_access' );
246 }
247
248 /**
249 * Generate Item Title for Payment Gateway.
250 *
251 * @since 1.8.14
252 * @since 2.9.6 Function will return form title with selected form level if price id set to zero. Added second param to return result with requested character length.
253 *
254 * @param array $payment_data Payment Data.
255 *
256 * @param string|null $length
257 *
258 * @return string By default, the name of the form. Then the price level text if any is found.
259 */
260 function give_payment_gateway_item_title( $payment_data, $length = null ) {
261
262 $form_id = intval( $payment_data['post_data']['give-form-id'] );
263 $item_name = isset( $payment_data['post_data']['give-form-title'] ) ? $payment_data['post_data']['give-form-title'] : '';
264 $price_id = isset( $payment_data['post_data']['give-price-id'] ) ? $payment_data['post_data']['give-price-id'] : '';
265
266 // Verify has variable prices.
267 if ( give_has_variable_prices( $form_id ) ) {
268
269 $item_price_level_text = give_get_price_option_name( $form_id, $price_id, 0, false );
270
271 /**
272 * Output donation level text if:
273 *
274 * 1. It's not a custom amount
275 * 2. The level field has actual text and isn't the amount (which is already displayed on the receipt).
276 */
277 if ( 'custom' !== $price_id && ! empty( $item_price_level_text ) ) {
278 // Matches a donation level - append level text.
279 $item_name .= ' - ' . $item_price_level_text;
280 }
281 }
282
283 /**
284 * Filter the Item Title of Payment Gateway.
285 *
286 * @param string $item_name Item Title of Payment Gateway.
287 * @param int $form_id Donation Form ID.
288 * @param array $payment_data Payment Data.
289 *
290 * @return string
291 * @since 1.8.14
292 */
293 $item_name = apply_filters( 'give_payment_gateway_item_title', $item_name, $form_id, $payment_data );
294
295 // Cut the length
296 if ( $length ) {
297 $item_name = substr( $item_name, 0, $length );
298 }
299
300 return $item_name;
301 }
302
303 /**
304 * Get Donation Summary
305 *
306 * Creates a donation summary for payment gateways from the donation data before the payment is created in the database.
307 *
308 * @param array $donation_data
309 * @param bool $name_and_email
310 * @param int $length
311 *
312 * @return string
313 * @since 1.8.12
314 */
315 function give_payment_gateway_donation_summary( $donation_data, $name_and_email = true, $length = 255 ) {
316
317 $form_id = isset( $donation_data['post_data']['give-form-id'] ) ? $donation_data['post_data']['give-form-id'] : '';
318 $price_id = isset( $donation_data['post_data']['give-price-id'] ) ? $donation_data['post_data']['give-price-id'] : '';
319
320 // Form title.
321 $summary = ( ! empty( $donation_data['post_data']['give-form-title'] ) ? $donation_data['post_data']['give-form-title'] : ( ! empty( $form_id ) ? wp_sprintf( __( 'Donation Form ID: %d', 'give' ), $form_id ) : __( 'Untitled donation form', 'give' ) ) );
322
323 // Form multilevel if applicable.
324 if ( ! empty( $price_id ) && 'custom' !== $price_id ) {
325 $summary .= ': ' . give_get_price_option_name( $form_id, $donation_data['post_data']['give-price-id'] );
326 }
327
328 // Add Donor's name + email if requested.
329 if ( $name_and_email ) {
330
331 // First name
332 if ( isset( $donation_data['user_info']['first_name'] ) && ! empty( $donation_data['user_info']['first_name'] ) ) {
333 $summary .= ' - ' . $donation_data['user_info']['first_name'];
334 }
335
336 if ( isset( $donation_data['user_info']['last_name'] ) && ! empty( $donation_data['user_info']['last_name'] ) ) {
337 $summary .= ' ' . $donation_data['user_info']['last_name'];
338 }
339
340 $summary .= ' (' . $donation_data['user_email'] . ')';
341 }
342
343 // Cut the length
344 $summary = substr( $summary, 0, $length );
345
346 return apply_filters( 'give_payment_gateway_donation_summary', $summary );
347 }
348
349
350 /**
351 * Get user host
352 *
353 * Returns the webhost this site is using if possible
354 *
355 * @return string $host if detected, false otherwise
356 * @since 1.0
357 */
358 function give_get_host() {
359 $find_host = gethostname();
360
361 if ( strpos( $find_host, 'sgvps.net' ) ) {
362 $host = 'Siteground';
363 } elseif ( defined( 'WPE_APIKEY' ) ) {
364 $host = 'WP Engine';
365 } elseif ( defined( 'PAGELYBIN' ) || strpos( $find_host, 'pagelyhosting.com' ) ) {
366 $host = 'Pagely';
367 } elseif ( strpos( $find_host, 'secureserver.net' ) ) {
368 $host = 'GoDaddy/Media Temple';
369 } elseif ( DB_HOST == 'localhost:/tmp/mysql5.sock' ) {
370 $host = 'ICDSoft';
371 } elseif ( DB_HOST == 'mysqlv5' ) {
372 $host = 'NetworkSolutions';
373 } elseif ( strpos( DB_HOST, 'ipagemysql.com' ) !== false ) {
374 $host = 'iPage';
375 } elseif ( strpos( DB_HOST, 'ipowermysql.com' ) !== false ) {
376 $host = 'IPower';
377 } elseif ( strpos( DB_HOST, '.gridserver.com' ) !== false ) {
378 $host = 'MediaTemple Grid';
379 } elseif ( strpos( DB_HOST, '.pair.com' ) !== false ) {
380 $host = 'pair Networks';
381 } elseif ( strpos( DB_HOST, '.stabletransit.com' ) !== false ) {
382 $host = 'Rackspace Cloud';
383 } elseif ( strpos( DB_HOST, '.sysfix.eu' ) !== false ) {
384 $host = 'SysFix.eu Power Hosting';
385 } elseif ( strpos( $_SERVER['SERVER_NAME'], 'Flywheel' ) !== false || strpos( $find_host, 'fw' ) ) {
386 $host = 'Flywheel';
387 } else {
388 // Adding a general fallback for data gathering
389 $host = 'DBH: ' . DB_HOST . ', SRV: ' . $_SERVER['SERVER_NAME'];
390 }
391
392 return $host;
393 }
394
395 /**
396 * Marks a function as deprecated and informs when it has been used.
397 *
398 * There is a hook give_deprecated_function_run that will be called that can be used
399 * to get the backtrace up to what file and function called the deprecated
400 * function.
401 *
402 * The current behavior is to trigger a user error if WP_DEBUG is true.
403 *
404 * This function is to be used in every function that is deprecated.
405 *
406 * @param string $function The function that was called.
407 * @param string $version The plugin version that deprecated the function.
408 * @param string $replacement Optional. The function that should have been called.
409 * @param array $backtrace Optional. Contains stack backtrace of deprecated function.
410 *
411 * @uses do_action() Calls 'give_deprecated_function_run' and passes the function name, what to use instead,
412 * and the version the function was deprecated in.
413 * @uses apply_filters() Calls 'give_deprecated_function_trigger_error' and expects boolean value of true to do
414 * trigger or false to not trigger error.
415 */
416 function _give_deprecated_function( $function, $version, $replacement = null, $backtrace = null ) {
417
418 /**
419 * Fires while give deprecated function call occurs.
420 *
421 * Allow you to hook to deprecated function call.
422 *
423 * @param string $function The function that was called.
424 * @param string $replacement Optional. The function that should have been called.
425 * @param string $version The plugin version that deprecated the function.
426 *
427 * @since 1.0
428 */
429 do_action( 'give_deprecated_function_run', $function, $replacement, $version );
430
431 $show_errors = current_user_can( 'manage_options' );
432
433 // Allow plugin to filter the output error trigger.
434 if ( WP_DEBUG && apply_filters( 'give_deprecated_function_trigger_error', $show_errors ) ) {
435 if ( ! is_null( $replacement ) ) {
436 trigger_error( sprintf( __( '%1$s is <strong>deprecated</strong> since GiveWP version %2$s! Use %3$s instead.', 'give' ), $function, $version, $replacement ) );
437 trigger_error( print_r( $backtrace, 1 ) ); // Limited to previous 1028 characters, but since we only need to move back 1 in stack that should be fine.
438 // Alternatively we could dump this to a file.
439 } else {
440 trigger_error( sprintf( __( '%1$s is <strong>deprecated</strong> since GiveWP version %2$s with no alternative available.', 'give' ), $function, $version ) );
441 trigger_error( print_r( $backtrace, 1 ) );// Limited to previous 1028 characters, but since we only need to move back 1 in stack that should be fine.
442 // Alternatively we could dump this to a file.
443 }
444 }
445 }
446
447 /**
448 * Give Get Admin ID
449 *
450 * Helper function to return the ID of the post for admin usage
451 *
452 * @return string $post_id
453 */
454 function give_get_admin_post_id() {
455 $post_id = isset( $_REQUEST['post'] ) ? absint( $_REQUEST['post'] ) : null;
456
457 $post_id = ! empty( $post_id ) ? $post_id : ( isset( $_REQUEST['post_id'] ) ? absint( $_REQUEST['post_id'] ) : null );
458
459 $post_id = ! empty( $post_id ) ? $post_id : ( isset( $_REQUEST['post_ID'] ) ? absint( $_REQUEST['post_ID'] ) : null );
460
461 return $post_id;
462 }
463
464 /**
465 * Get PHP Arg Separator Output
466 *
467 * @return string Arg separator output
468 * @since 1.0
469 */
470 function give_get_php_arg_separator_output() {
471 return ini_get( 'arg_separator.output' );
472 }
473
474
475 /**
476 * Month Num To Name
477 *
478 * Takes a month number and returns the name three letter name of it.
479 *
480 * @param int $n
481 *
482 * @return string Short month name
483 * @since 1.0
484 */
485 function give_month_num_to_name( $n ) {
486 $timestamp = mktime( 0, 0, 0, $n, 1, 2005 );
487
488 return date_i18n( 'M', $timestamp );
489 }
490
491 /**
492 * Checks whether function is disabled.
493 *
494 * @param string $function Name of the function.
495 *
496 * @return bool Whether or not function is disabled.
497 * @since 1.0
498 */
499 function give_is_func_disabled( $function ) {
500 $disabled = explode( ',', ini_get( 'disable_functions' ) );
501
502 return in_array( $function, $disabled );
503 }
504
505
506 /**
507 * Create SVG library function
508 *
509 * @param string $icon
510 *
511 * @return string
512 */
513 function give_svg_icons( $icon ) {
514
515 // Store your SVGs in an associative array
516 $svgs = [
517 'microphone' => 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pg0KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE2LjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPg0KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgd2lkdGg9IjY0cHgiIGhlaWdodD0iMTAwcHgiIHZpZXdCb3g9IjAgLTIwIDY0IDEyMCIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNjQgMTAwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8Zz4NCgk8Zz4NCgkJPHBhdGggZD0iTTYyLDM2LjIxNWgtM2MtMS4xLDAtMiwwLjktMiwyVjUyYzAsNi42ODYtNS4yNjYsMTgtMjUsMThTNyw1OC42ODYsNyw1MlYzOC4yMTVjMC0xLjEtMC45LTItMi0ySDJjLTEuMSwwLTIsMC45LTIsMlY1Mg0KCQkJYzAsMTEuMTg0LDguMjE1LDIzLjE1MiwyNywyNC44MDFWOTBIMTRjLTEuMSwwLTIsMC44OTgtMiwydjZjMCwxLjEsMC45LDIsMiwyaDM2YzEuMSwwLDItMC45LDItMnYtNmMwLTEuMTAyLTAuOS0yLTItMkgzN1Y3Ni44MDENCgkJCUM1NS43ODUsNzUuMTUyLDY0LDYzLjE4NCw2NCw1MlYzOC4yMTVDNjQsMzcuMTE1LDYzLjEsMzYuMjE1LDYyLDM2LjIxNXoiLz4NCgkJPHBhdGggZD0iTTMyLDYwYzExLjczMiwwLDE1LTQuODE4LDE1LThWMzYuMjE1SDE3VjUyQzE3LDU1LjE4MiwyMC4yNjYsNjAsMzIsNjB6Ii8+DQoJCTxwYXRoIGQ9Ik00Nyw4YzAtMy4xODQtMy4yNjgtOC0xNS04QzIwLjI2NiwwLDE3LDQuODE2LDE3LDh2MjEuMjE1aDMwVjh6Ii8+DQoJPC9nPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPC9zdmc+DQo=',
518 'alert' => 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pg0KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE2LjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPg0KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgd2lkdGg9IjI4LjkzOHB4IiBoZWlnaHQ9IjI1LjAwNXB4IiB2aWV3Qm94PSIwIDAgMjguOTM4IDI1LjAwNSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMjguOTM4IDI1LjAwNTsiDQoJIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPHBhdGggc3R5bGU9ImZpbGw6IzAwMDAwMDsiIGQ9Ik0yOC44NTksMjQuMTU4TDE0Ljk1NywwLjI3OUMxNC44NTYsMC4xMDYsMTQuNjcsMCwxNC40NjgsMGMtMC4xOTgsMC0wLjM4MywwLjEwNi0wLjQ4MSwwLjI3OQ0KCUwwLjA3OSwyNC4xNThjLTAuMTAyLDAuMTc1LTAuMTA2LDAuMzg5LTAuMDA2LDAuNTY1YzAuMTAzLDAuMTc0LDAuMjg3LDAuMjgyLDAuNDg4LDAuMjgyaDI3LjgxNGMwLjIwMSwwLDAuMzg5LTAuMTA4LDAuNDg4LTAuMjgyDQoJYzAuMDQ3LTAuMDg4LDAuMDc0LTAuMTg2LDAuMDc0LTAuMjgxQzI4LjkzOCwyNC4zNDMsMjguOTExLDI0LjI0NSwyOC44NTksMjQuMTU4eiBNMTYuMzY5LDguNDc1bC0wLjQ2Miw5LjQ5M2gtMi4zODlsLTAuNDYxLTkuNDkzDQoJSDE2LjM2OXogTTE0LjcxMSwyMi44MjhoLTAuMDQyYy0xLjA4OSwwLTEuODQzLTAuODE3LTEuODQzLTEuOTA3YzAtMS4xMzEsMC43NzQtMS45MDcsMS44ODUtMS45MDdzMS44NDYsMC43NzUsMS44NjcsMS45MDcNCglDMTYuNTc5LDIyLjAxMSwxNS44NDQsMjIuODI4LDE0LjcxMSwyMi44Mjh6Ii8+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8L3N2Zz4NCg==',
519 'placemark' => 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxNi4wLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB3aWR0aD0iMTAwcHgiIGhlaWdodD0iMTAwcHgiIHZpZXdCb3g9IjAgMCAxMDAgMTAwIiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAxMDAgMTAwIiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxnPg0KCTxwYXRoIGQ9Ik01MC40MzQsMjAuMjcxYy0xMi40OTksMC0yMi42NjgsMTAuMTY5LTIyLjY2OCwyMi42NjhjMCwxMS44MTQsMTguODE1LDMyLjE1NSwyMC45NiwzNC40MzdsMS43MDgsMS44MTZsMS43MDgtMS44MTYNCgkJYzIuMTQ1LTIuMjgxLDIwLjk2LTIyLjYyMywyMC45Ni0zNC40MzdDNzMuMTAzLDMwLjQ0LDYyLjkzNCwyMC4yNzEsNTAuNDM0LDIwLjI3MXogTTUwLjQzNCw1Mi4zMmMtNS4xNzIsMC05LjM4LTQuMjA4LTkuMzgtOS4zOA0KCQlzNC4yMDgtOS4zOCw5LjM4LTkuMzhjNS4xNzMsMCw5LjM4LDQuMjA4LDkuMzgsOS4zOFM1NS42MDcsNTIuMzIsNTAuNDM0LDUyLjMyeiIvPg0KPC9nPg0KPC9zdmc+DQo=',
520 'give_grey' => 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiIHZpZXdCb3g9IjEwMC4xIDAgNDAwIDQwMCIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAxMDAuMSAwIDQwMCA0MDAiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxnIGlkPSJMYXllcl8xXzFfIj48Y2lyY2xlIGZpbGw9IiM2NkJCNkEiIGN4PSItNDA3LjMiIGN5PSIzNDYuMyIgcj0iNDIuMiIvPjxnPjxnPjxwYXRoIGZpbGw9IiM1NDZFN0EiIGQ9Ik0tNzg2LjQsMTMzLjh2LTEyLjVoNC44YzMuOCwwLDYuNiwyLjUsNi42LDYuNHMtMi44LDYuNC02LjYsNi40aC00LjhWMTMzLjh6IE0tNzc3LjUsMTI3LjVjMC0yLjMtMS4zLTMuOC0zLjgtMy44aC0yLjN2Ny45aDIuM0MtNzc5LDEzMS42LTc3Ny41LDEyOS44LTc3Ny41LDEyNy41eiIvPjxwYXRoIGZpbGw9IiM1NDZFN0EiIGQ9Ik0tNzcxLjYsMTMzLjh2LTEyLjVoOC45djIuM2gtNi4xdjIuNWg2LjF2Mi4zaC02LjF2Mi44aDYuMXYyLjNoLTguOVYxMzMuOHoiLz48cGF0aCBmaWxsPSIjNTQ2RTdBIiBkPSJNLTc0OC41LDEzMy44di04LjdsLTMuNiw4LjdoLTEuM2wtMy42LTguN3Y4LjdoLTIuNXYtMTIuNWgzLjhsMy4xLDcuNmwzLjEtNy42aDMuOHYxMi41SC03NDguNXoiLz48cGF0aCBmaWxsPSIjNTQ2RTdBIiBkPSJNLTc0Mi40LDEyNy41YzAtMy44LDIuOC02LjQsNi42LTYuNHM2LjYsMi44LDYuNiw2LjRjMCwzLjgtMi44LDYuNC02LjYsNi40Qy03MzkuOCwxMzQuMS03NDIuNCwxMzEuMy03NDIuNCwxMjcuNXogTS03MzIuMiwxMjcuNWMwLTIuMy0xLjUtNC4xLTMuOC00LjFjLTIuMywwLTMuOCwxLjgtMy44LDQuMWMwLDIuMywxLjUsNC4xLDMuOCw0LjFDLTczMy43LDEzMS42LTczMi4yLDEyOS44LTczMi4yLDEyNy41eiIvPjxwYXRoIGZpbGw9IiM1NDZFN0EiIGQ9Ik0tNzI2LjgsMTI3LjVjMC0zLjgsMi44LTYuNCw2LjYtNi40YzIuOCwwLDQuMywxLjUsNS4zLDMuMWwtMi4zLDFjLTAuNS0xLTEuNS0xLjgtMy4xLTEuOGMtMi4zLDAtMy44LDEuOC0zLjgsNC4xYzAsMi4zLDEuNSw0LjEsMy44LDQuMWMxLjMsMCwyLjMtMC44LDMuMS0xLjhsMi4zLDFjLTEsMS41LTIuNSwzLjEtNS4zLDMuMUMtNzIzLjgsMTM0LjEtNzI2LjgsMTMxLjMtNzI2LjgsMTI3LjV6Ii8+PHBhdGggZmlsbD0iIzU0NkU3QSIgZD0iTS03MDQuNywxMzMuOGwtMi41LTQuM2gtMnY0LjNoLTIuNXYtMTIuNWg1LjljMi41LDAsNC4xLDEuOCw0LjEsNC4xYzAsMi4zLTEuMywzLjMtMi44LDMuOGwyLjgsNC44aC0yLjhWMTMzLjh6IE0tNzA0LjUsMTI1LjJjMC0xLTAuOC0xLjgtMS44LTEuOGgtMi44djMuM2gyLjhDLTcwNS41LDEyNy03MDQuNSwxMjYuNS03MDQuNSwxMjUuMnoiLz48cGF0aCBmaWxsPSIjNTQ2RTdBIiBkPSJNLTY4OS43LDEzMy44bC0wLjgtMmgtNS4zbC0wLjgsMmgtMy4xbDQuOC0xMi41aDMuM2w0LjgsMTIuNUgtNjg5Ljd6IE0tNjkzLjMsMTIzLjlsLTIsNS4zaDMuOEwtNjkzLjMsMTIzLjl6Ii8+PHBhdGggZmlsbD0iIzU0NkU3QSIgZD0iTS02ODIuNiwxMzMuOHYtMTAuMmgtMy42di0yLjNoOS45djIuM2gtMy42djEwLjJILTY4Mi42eiIvPjxwYXRoIGZpbGw9IiM1NDZFN0EiIGQ9Ik0tNjczLjIsMTMzLjh2LTEyLjVoMi41djEyLjVILTY3My4yeiIvPjxwYXRoIGZpbGw9IiM1NDZFN0EiIGQ9Ik0tNjY3LDEzMy44di0ybDUuOS03LjloLTUuOXYtMi4zaDkuNHYybC01LjksOC4xaDYuMXYyLjNoLTkuN1YxMzMuOHoiLz48cGF0aCBmaWxsPSIjNTQ2RTdBIiBkPSJNLTY1NC4xLDEzMy44di0xMi41aDIuNXYxMi41SC02NTQuMXoiLz48cGF0aCBmaWxsPSIjNTQ2RTdBIiBkPSJNLTYzOS4xLDEzMy44bC01LjktOC4xdjguMWgtMi41di0xMi41aDIuOGw1LjksNy45di03LjloMi41djEyLjVILTYzOS4xeiIvPjxwYXRoIGZpbGw9IiM1NDZFN0EiIGQ9Ik0tNjMzLjIsMTI3LjVjMC00LjEsMy4xLTYuNCw2LjYtNi40YzIuNSwwLDQuMywxLjMsNS4xLDIuOGwtMi4zLDEuM2MtMC41LTAuOC0xLjUtMS41LTMuMS0xLjVjLTIuMywwLTMuOCwxLjgtMy44LDQuMWMwLDIuMywxLjUsNC4xLDMuOCw0LjFjMSwwLDItMC41LDIuNS0xdi0xLjVoLTMuM1YxMjdoNS45djQuOGMtMS4zLDEuNS0zLjEsMi4zLTUuMywyLjNDLTYzMC4yLDEzNC4xLTYzMy4yLDEzMS42LTYzMy4yLDEyNy41eiIvPjxwYXRoIGZpbGw9IiM1NDZFN0EiIGQ9Ik0tNjEyLjEsMTI3LjVjMC00LjEsMy4xLTYuNCw2LjYtNi40YzIuNSwwLDQuMywxLjMsNS4xLDIuOGwtMi4zLDEuM2MtMC41LTAuOC0xLjUtMS41LTMuMS0xLjVjLTIuMywwLTMuOCwxLjgtMy44LDQuMWMwLDIuMywxLjUsNC4xLDMuOCw0LjFjMSwwLDItMC41LDIuNS0xdi0xLjVoLTMuM1YxMjdoNS45djQuOGMtMS4zLDEuNS0zLjEsMi4zLTUuMywyLjNDLTYwOSwxMzQuMS02MTIuMSwxMzEuNi02MTIuMSwxMjcuNXoiLz48cGF0aCBmaWxsPSIjNTQ2RTdBIiBkPSJNLTU5Ni42LDEzMy44di0xMi41aDguOXYyLjNoLTYuMXYyLjVoNi4xdjIuM2gtNi4xdjIuOGg2LjF2Mi4zaC04LjlWMTMzLjh6Ii8+PHBhdGggZmlsbD0iIzU0NkU3QSIgZD0iTS01NzUuNywxMzMuOGwtNS45LTguMXY4LjFoLTIuNXYtMTIuNWgyLjhsNS45LDcuOXYtNy45aDIuNXYxMi41SC01NzUuN3oiLz48cGF0aCBmaWxsPSIjNTQ2RTdBIiBkPSJNLTU2OS4xLDEzMy44di0xMi41aDguOXYyLjNoLTYuMXYyLjVoNi4xdjIuM2gtNi4xdjIuOGg2LjF2Mi4zaC04LjlWMTMzLjh6Ii8+PHBhdGggZmlsbD0iIzU0NkU3QSIgZD0iTS01NDkuNywxMzMuOGwtMi41LTQuM2gtMnY0LjNoLTIuNXYtMTIuNWg1LjljMi41LDAsNC4xLDEuOCw0LjEsNC4xYzAsMi4zLTEuMywzLjMtMi44LDMuOGwyLjgsNC44aC0yLjhWMTMzLjh6IE0tNTQ5LjUsMTI1LjJjMC0xLTAuOC0xLjgtMS44LTEuOGgtMi44djMuM2gyLjhDLTU1MC4zLDEyNy01NDkuNSwxMjYuNS01NDkuNSwxMjUuMnoiLz48cGF0aCBmaWxsPSIjNTQ2RTdBIiBkPSJNLTU0My45LDEyNy41YzAtMy44LDIuOC02LjQsNi42LTYuNHM2LjYsMi44LDYuNiw2LjRjMCwzLjgtMi44LDYuNC02LjYsNi40Qy01NDEuMywxMzQuMS01NDMuOSwxMzEuMy01NDMuOSwxMjcuNXogTS01MzMuNywxMjcuNWMwLTIuMy0xLjUtNC4xLTMuOC00LjFzLTMuOCwxLjgtMy44LDQuMWMwLDIuMywxLjUsNC4xLDMuOCw0LjFDLTUzNS4yLDEzMS42LTUzMy43LDEyOS44LTUzMy43LDEyNy41eiIvPjxwYXRoIGZpbGw9IiM1NDZFN0EiIGQ9Ik0tNTI4LjYsMTMyLjFsMS41LTJjMC44LDEsMi4zLDEuOCw0LjEsMS44YzEuNSwwLDIuMy0wLjgsMi4zLTEuM2MwLTIuMy03LjEtMC44LTcuMS01LjNjMC0yLDEuOC0zLjgsNC44LTMuOGMyLDAsMy42LDAuNSw0LjgsMS44bC0xLjUsMmMtMS0xLTIuMy0xLjMtMy42LTEuM2MtMSwwLTEuOCwwLjUtMS44LDEuM2MwLDIsNy4xLDAuOCw3LjEsNS4zYzAsMi4zLTEuNSw0LjEtNS4xLDQuMUMtNTI1LjYsMTM0LjEtNTI3LjQsMTMzLjEtNTI4LjYsMTMyLjF6Ii8+PHBhdGggZmlsbD0iIzU0NkU3QSIgZD0iTS01MTUuMSwxMzMuOHYtMTIuNWgyLjV2MTIuNUgtNTE1LjF6Ii8+PHBhdGggZmlsbD0iIzU0NkU3QSIgZD0iTS01MDUuNywxMzMuOHYtMTAuMmgtMy42di0yLjNoOS45djIuM2gtMy42djEwLjJILTUwNS43eiIvPjxwYXRoIGZpbGw9IiM1NDZFN0EiIGQ9Ik0tNDkyLjcsMTMzLjh2LTUuMWwtNC44LTcuNGgzLjFsMy4xLDUuMWwzLjEtNS4xaDMuMWwtNC44LDcuNHY1LjFILTQ5Mi43eiIvPjwvZz48Zz48Zz48cGF0aCBmaWxsPSIjNjZCQjZBIiBkPSJNLTQ4NS45LDQ0LjNoLTEuM2wwLjMsMS4zYzIsOS45LDAuMywyNC43LTcuNCwzMy44Yy00LjMsNS4zLTkuOSw4LjEtMTYuOCw4LjFjLTEwLjksMC0xNS0xMy0xNS41LTI3LjdjMTcuOC00LjMsMjkuOC0xNS41LDI5LjgtMjguNWMwLTkuNC0yLjgtMjQuOS0yMS40LTI0LjljLTE3LjYsMC0yNi41LDI2LjItMjguMiw0NC41Yy04LjktMC4zLTE1LjUtNC4zLTE5LjYtOC4xYzEuNS02LjQsMi4zLTEyLjIsMi4zLTE3LjZjMC03LjQtNS4xLTEwLjctOS45LTEwLjdjLTYuOSwwLTE0LDYuNi0xNCwxOS4zYzAsNy42LDIuOCwxNCw4LjcsMTguNmMtNS4xLDEyLTEzLjcsMjIuMS0xNi41LDI1LjRjLTIuMy00LjgtOS43LTIyLjQtMTItNDEuNWMyLjgtNy42LDQuMy0xNCw0LjMtMTdjMC00LjgtMy4xLTcuNi04LjEtNy42Yy02LjksMC0xNy44LDQuMy0xOC4xLDQuNmwtMC41LDAuM3YwLjhjMCwwLjMsMy4zLDE1LjUsNi42LDMyLjNjLTYuNCwxMC40LTE3LjYsMjcuNy0yMy4yLDI3LjdjLTEwLjIsMCw2LjYtNTIuMi0wLjgtNTMuOWMtMC4zLDAtMC41LDAtMC44LDAuM2MtMy42LDIuMy00My41LDI0LjQtOTYuNywyNC40YzAsMCwwLDEsMC41LDJjMC4zLDAuOCwxLDEuNSwxLDEuNWMxNSwxLjgsMzYuNC0wLjMsNTIuNy0yLjVjLTkuNCwyMC4xLTI2LDMzLjMtNDEuMiwzMy4zYy0yOC44LDAtNTAuOS0zNC45LTUwLjktMzQuOWM4LjktNy45LDIzLjQtMzMuMyw0NC44LTMzLjNjMjEuMSwwLDMwLjMsMTEuNywzMC4zLDExLjdsMi4zLTMuOGMwLDAtOS45LTM0LjYtMzcuOS0zNC42cy01Ny44LDQ1LjgtNzUuMSw1Ni41YzAsMCwyMy45LDU2LjUsNzYuMSw1Ni41YzQzLjgsMCw1NS00Miw1Ny01Mi4yYzEwLjctMS41LDE4LjEtMy4xLDE4LjEtMy4xcy0yLjgsMjEuNC0yLjgsMzAuM3M5LjksMTguMywxOC4xLDE4LjNjNi45LDAsMjAuOS0xNC4yLDMxLTMxLjZsMC41LDJjNS4zLDE5LjYsMTIsMjkuOCwxOS44LDI5LjhjNy45LDAsMjAuOS0xNi4zLDI5LjMtMzYuOWM4LjQsMy42LDE4LjMsNC42LDI0LjIsNC44YzIuMywzNS40LDMxLjgsMzYuNCwzNS40LDM2LjRjMjEuOSwwLDQwLjUtMTUuOCw0MC41LTM0LjRDLTQ3MC42LDQ0LjUtNDg1LjYsNDQuMy00ODUuOSw0NC4zeiBNLTUxMi42LDI5LjVjMCwwLTAuMywxMS43LTEzLjUsMTcuNmMxLjMtMTUuNSw1LjEtMjkuNSw3LjYtMjkuNUMtNTE1LjYsMTcuOC01MTIuNiwyMi4xLTUxMi42LDI5LjV6Ii8+PHBhdGggZmlsbD0iIzY2QkI2QSIgZD0iTS02NjUsMTUuNWMwLDAuNSwwLjMsMC44LDAuOCwxYzEwLjQsMS41LDE3LjMtMS44LDE3LjMtMTguNmMwLTE1LjgtMTYuMy0zLjMtMTkuMy0xYy0wLjMsMC4zLTAuMywwLjUtMC4zLDFDLTY2My43LDQuMS02NjQuOCwxMy02NjUsMTUuNXoiLz48L2c+PGxpbmVhckdyYWRpZW50IGlkPSJTVkdJRF8xXyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIHgxPSItMjg5LjU4NjQiIHkxPSIzNzMuMjM3OSIgeDI9Ii0yODIuODg0MiIgeTI9IjM3NS40NzE5IiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDIuNTQ0NSAwIDAgLTIuNTQ0NSAxMDAuMTI3MiAxMDE3LjgxMTcpIj48c3RvcCAgb2Zmc2V0PSIwIiBzdHlsZT0ic3RvcC1jb2xvcjojNjZCQjZBIi8+PHN0b3AgIG9mZnNldD0iMSIgc3R5bGU9InN0b3AtY29sb3I6IzM3OEY0MyIvPjwvbGluZWFyR3JhZGllbnQ+PHBhdGggZmlsbD0idXJsKCNTVkdJRF8xXykiIGQ9Ik0tNjIzLDQ5LjRjLTQuMSw2LjktMTAuMiwxNi4zLTE1LjUsMjIuMWMxLjMsMy4xLDIuOCw2LjksNC4zLDkuOWM0LjgtNS4zLDkuNy0xMi4yLDE0LTE5LjNMLTYyMyw0OS40eiIvPjxsaW5lYXJHcmFkaWVudCBpZD0iU1ZHSURfMl8iIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iLTI2OS4wNTc3IiB5MT0iMzcxLjU0NDEiIHgyPSItMjY1LjE3MDUiIHkyPSIzNzguMzgwMiIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgyLjU0NDUgMCAwIC0yLjU0NDUgMTAwLjEyNzIgMTAxNy44MTE3KSI+PHN0b3AgIG9mZnNldD0iMCIgc3R5bGU9InN0b3AtY29sb3I6IzY2QkI2QSIvPjxzdG9wICBvZmZzZXQ9IjEiIHN0eWxlPSJzdG9wLWNvbG9yOiMzNzhGNDMiLz48L2xpbmVhckdyYWRpZW50PjxwYXRoIGZpbGw9InVybCgjU1ZHSURfMl8pIiBkPSJNLTU3NC43LDU0LjdjLTItMS0zLjgtMi41LTMuOC0yLjVjLTMuNiw3LjktOC40LDE1LjMtMTIuMiwyMC4xYzEuOCwyLjUsNC44LDUuOSw3LjEsOC40YzQuNi02LjQsOS40LTE0LjgsMTMtMjMuN0MtNTcwLjQsNTYuNy01NzIuNiw1Ni01NzQuNyw1NC43eiIvPjxsaW5lYXJHcmFkaWVudCBpZD0iU1ZHSURfM18iIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iLTI0OC42NDE2IiB5MT0iMzY4LjM4MzUiIHgyPSItMjQ5LjQ0NTkiIHkyPSIzNzUuNTMyMyIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgyLjU0NDUgMCAwIC0yLjU0NDUgMTAwLjEyNzIgMTAxNy44MTE3KSI+PHN0b3AgIG9mZnNldD0iMCIgc3R5bGU9InN0b3AtY29sb3I6IzY2QkI2QSIvPjxzdG9wICBvZmZzZXQ9IjEiIHN0eWxlPSJzdG9wLWNvbG9yOiMzNzhGNDMiLz48L2xpbmVhckdyYWRpZW50PjxwYXRoIGZpbGw9InVybCgjU1ZHSURfM18pIiBkPSJNLTUyNi4zLDU5LjhjMCwwLTUuMSwxLTEwLjIsMS41cy05LjksMC4zLTkuOSwwLjNjMC44LDEwLjIsMy42LDE3LjMsNy40LDIyLjZsMTguNi0xLjVDLTUyNC4zLDc3LjYtNTI2LjEsNjktNTI2LjMsNTkuOHoiLz48bGluZWFyR3JhZGllbnQgaWQ9IlNWR0lEXzRfIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9Ii0yNDkuOCIgeTE9IjM4My41ODEiIHgyPSItMjQ5LjgiIHkyPSIzNzYuMzc2MyIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgyLjU0NDUgMCAwIC0yLjU0NDUgMTAwLjEyNzIgMTAxNy44MTE3KSI+PHN0b3AgIG9mZnNldD0iMCIgc3R5bGU9InN0b3AtY29sb3I6IzY2QkI2QSIvPjxzdG9wICBvZmZzZXQ9IjEiIHN0eWxlPSJzdG9wLWNvbG9yOiMzNzhGNDMiLz48L2xpbmVhckdyYWRpZW50PjxwYXRoIGZpbGw9InVybCgjU1ZHSURfNF8pIiBkPSJNLTU0MS4xLDI4LjhMLTU0MS4xLDI4LjhjLTAuNSwxLjUtMS4zLDMuMy0xLjgsNS4xYzAsMC41LTAuMywwLjgtMC4zLDEuM2MtMSwzLjMtMS44LDYuNi0yLjMsOS45YzAsMC41LTAuMywwLjgtMC4zLDEuM2MtMC4zLDEuNS0wLjUsMy4xLTAuNSw0LjZjMTIsMCwyMC4xLTMuNiwyMC4xLTMuNmMwLTEuMywwLjMtMi4zLDAuMy0zLjZjMC0wLjMsMC0wLjUsMC0wLjhjMC0xLDAuMy0xLjgsMC4zLTIuOGMwLTAuMywwLTAuNSwwLTAuOGMwLjMtMi4zLDAuOC00LjYsMS02LjZMLTU0MS4xLDI4Ljh6IE0tNTQ2LjQsNTAuNkwtNTQ2LjQsNTAuNkwtNTQ2LjQsNTAuNkwtNTQ2LjQsNTAuNnoiLz48bGluZWFyR3JhZGllbnQgaWQ9IlNWR0lEXzVfIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9Ii0zMTMiIHkxPSIzNzEuNzcyMiIgeDI9Ii0zMTMiIHkyPSIzODAuNzA4MyIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgyLjU0NDUgMCAwIC0yLjU0NDUgMTAwLjEyNzIgMTAxNy44MTE3KSI+PHN0b3AgIG9mZnNldD0iMCIgc3R5bGU9InN0b3AtY29sb3I6IzY2QkI2QSIvPjxzdG9wICBvZmZzZXQ9IjEiIHN0eWxlPSJzdG9wLWNvbG9yOiMzNzhGNDMiLz48L2xpbmVhckdyYWRpZW50PjxwYXRoIGZpbGw9InVybCgjU1ZHSURfNV8pIiBkPSJNLTcwOC4zLDcyLjhsMTEuMiw0LjhjNS4zLTcuNiw4LjctMTUuNSwxMC43LTIxLjZsMi04LjFsLTUuMywwLjhDLTY5NC41LDU4LjgtNzAxLjEsNjYuOS03MDguMyw3Mi44eiIvPjxsaW5lYXJHcmFkaWVudCBpZD0iU1ZHSURfNl8iIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iLTI3Ny41MjU1IiB5MT0iMzkwLjIxMyIgeDI9Ii0yNzguNjQ3OSIgeTI9IjM4OC40MjU0IiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDIuNTQ0NSAwIDAgLTIuNTQ0NSAxMDAuMTI3MiAxMDE3LjgxMTcpIj48c3RvcCAgb2Zmc2V0PSIwIiBzdHlsZT0ic3RvcC1jb2xvcjojNjZCQjZBIi8+PHN0b3AgIG9mZnNldD0iMSIgc3R5bGU9InN0b3AtY29sb3I6IzM3OEY0MyIvPjwvbGluZWFyR3JhZGllbnQ+PHBhdGggZmlsbD0idXJsKCNTVkdJRF82XykiIGQ9Ik0tNjA3LDM2LjFjMi44LTcuNiw0LjMtMTQsNC4zLTE3YzAtMC4zLDAtMC41LDAtMC44bC02LjYsMkMtNjA5LjMsMjAuNC02MDksMjQuNy02MDcsMzYuMXoiLz48bGluZWFyR3JhZGllbnQgaWQ9IlNWR0lEXzdfIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9Ii0yNjIuNTgxMyIgeTE9IjM4Ni40ODI3IiB4Mj0iLTI2My4yMTUiIHkyPSIzODQuMDc0OSIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgyLjU0NDUgMCAwIC0yLjU0NDUgMTAwLjEyNzIgMTAxNy44MTE3KSI+PHN0b3AgIG9mZnNldD0iMCIgc3R5bGU9InN0b3AtY29sb3I6IzY2QkI2QSIvPjxzdG9wICBvZmZzZXQ9IjEiIHN0eWxlPSJzdG9wLWNvbG9yOiMzNzhGNDMiLz48L2xpbmVhckdyYWRpZW50PjxwYXRoIGZpbGw9InVybCgjU1ZHSURfN18pIiBkPSJNLTU3MS40LDMwLjVjMCwwLTEuOCw1LjMsNS42LDEyYzEuMy01LjMsMi0xMC43LDIuMy0xNS4zTC01NzEuNCwzMC41eiIvPjwvZz48L2c+PGc+PGc+PHBhdGggZmlsbD0iIzY2QkI2QSIgZD0iTS04MDcuOCwzNDYuNmgtMC41djAuNWMwLjgsNC4zLDAsMTAuNC0zLjEsMTQuNWMtMS44LDIuMy00LjMsMy42LTcuMSwzLjZjLTQuNiwwLTYuNC01LjYtNi42LTExLjdjNy42LTEuOCwxMi43LTYuNiwxMi43LTEyLjJjMC00LjEtMS4zLTEwLjctOS4yLTEwLjdjLTcuNCwwLTExLjIsMTEuMi0xMiwxOC44Yy0zLjgsMC02LjYtMS44LTguNC0zLjZjMC44LTIuOCwxLTUuMSwxLTcuNGMwLTMuMS0yLjMtNC42LTQuMS00LjZjLTMuMSwwLTUuOSwyLjgtNS45LDguMWMwLDMuMywxLjMsNS45LDMuOCw3LjljLTIuMyw1LjEtNS45LDkuNC03LjEsMTAuN2MtMS0yLTQuMS05LjctNS4xLTE3LjZjMS4zLTMuMywxLjgtNS45LDEuOC03LjFjMC0yLTEuMy0zLjMtMy42LTMuM2MtMy4xLDAtNy42LDEuOC03LjYsMmwtMC4zLDAuM3YwLjNjMCwwLDEuMyw2LjYsMi44LDEzLjdjLTIuOCw0LjMtNy40LDExLjctOS45LDExLjdjLTQuMywwLDIuOC0yMi4xLTAuMy0yMi45aC0wLjNjLTEuNSwxLTE4LjYsMTAuNC00MSwxMC40YzAsMCwwLDAuNSwwLjMsMC44YzAuMywwLjMsMC41LDAuNSwwLjUsMC41YzYuNCwwLjgsMTUuNSwwLDIyLjQtMWMtNC4xLDguNC0xMC45LDE0LjItMTcuNiwxNC4yYy0xMi4yLDAtMjEuNi0xNC44LTIxLjYtMTQuOGMzLjgtMy4zLDkuOS0xNC4yLDE5LjEtMTQuMmM4LjksMCwxMyw0LjgsMTMsNC44bDEtMS41YzAsMC00LjMtMTQuOC0xNi0xNC44cy0yNC40LDE5LjYtMzEuOCwyMy45YzAsMCwxMC4yLDI0LjIsMzIuMywyNC4yYzE4LjYsMCwyMy40LTE3LjgsMjQuMi0yMi4xYzQuNi0wLjgsNy42LTEuMyw3LjYtMS4zcy0xLDkuMi0xLDEzYzAsMy44LDQuMSw3LjksNy42LDcuOWMzLjEsMCw4LjktNi4xLDEzLjItMTMuNWwwLjMsMC44YzIuMyw4LjQsNS4xLDEyLjcsOC40LDEyLjdzOC45LTYuOSwxMi41LTE1LjVjMy42LDEuNSw3LjksMiwxMC4yLDJjMSwxNSwxMy41LDE1LjUsMTUsMTUuNWM5LjQsMCwxNy4zLTYuNiwxNy4zLTE0LjVDLTgwMS40LDM0Ni44LTgwNy44LDM0Ni42LTgwNy44LDM0Ni42eiBNLTgxOSwzNDAuMmMwLDAsMCw1LjEtNS45LDcuNmMwLjUtNi42LDItMTIuNSwzLjMtMTIuNUMtODIwLjUsMzM1LjQtODE5LDMzNy4yLTgxOSwzNDAuMnoiLz48cGF0aCBmaWxsPSIjNjZCQjZBIiBkPSJNLTg4My44LDMzNC40YzAsMC4zLDAsMC4zLDAuMywwLjVjNC4zLDAuNSw3LjQtMC44LDcuNC03LjljMC02LjYtNi45LTEuNS04LjEtMC41YzAsMC0wLjMsMC4zLDAsMC41Qy04ODMuMywzMjkuNS04ODMuOCwzMzMuMS04ODMuOCwzMzQuNHoiLz48L2c+PGxpbmVhckdyYWRpZW50IGlkPSJTVkdJRF84XyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIHgxPSItMzgyLjAwNzQiIHkxPSIyNTkuODQ3NSIgeDI9Ii0zNzkuMTU4NSIgeTI9IjI2MC43OTcyIiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDIuNTQ0NSAwIDAgLTIuNTQ0NSAxMDAuMTI3MiAxMDE3LjgxMTcpIj48c3RvcCAgb2Zmc2V0PSIwIiBzdHlsZT0ic3RvcC1jb2xvcjojNjZCQjZBIi8+PHN0b3AgIG9mZnNldD0iMSIgc3R5bGU9InN0b3AtY29sb3I6IzM3OEY0MyIvPjwvbGluZWFyR3JhZGllbnQ+PHBhdGggZmlsbD0idXJsKCNTVkdJRF84XykiIGQ9Ik0tODY2LDM0OC42Yy0xLjgsMi44LTQuMyw2LjktNi42LDkuNGMwLjUsMS4zLDEuMywyLjgsMS44LDQuM2MyLTIuMyw0LjEtNS4xLDYuMS04LjFMLTg2NiwzNDguNnoiLz48bGluZWFyR3JhZGllbnQgaWQ9IlNWR0lEXzlfIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9Ii0zNzMuMTYyNiIgeTE9IjI1OS4wNDIzIiB4Mj0iLTM3MS41MTAyIiB5Mj0iMjYxLjk0ODIiIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMi41NDQ1IDAgMCAtMi41NDQ1IDEwMC4xMjcyIDEwMTcuODExNykiPjxzdG9wICBvZmZzZXQ9IjAiIHN0eWxlPSJzdG9wLWNvbG9yOiM2NkJCNkEiLz48c3RvcCAgb2Zmc2V0PSIxIiBzdHlsZT0ic3RvcC1jb2xvcjojMzc4RjQzIi8+PC9saW5lYXJHcmFkaWVudD48cGF0aCBmaWxsPSJ1cmwoI1NWR0lEXzlfKSIgZD0iTS04NDUuNCwzNTAuOWMtMC44LTAuNS0xLjUtMS0xLjUtMWMtMS41LDMuMy0zLjYsNi40LTUuMSw4LjdjMC44LDEsMiwyLjUsMy4xLDMuNmMyLTIuOCw0LjEtNi4xLDUuNi0xMC4yQy04NDMuNiwzNTEuOS04NDQuNywzNTEuNC04NDUuNCwzNTAuOXoiLz48bGluZWFyR3JhZGllbnQgaWQ9IlNWR0lEXzEwXyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIHgxPSItMzY0LjY5OTYiIHkxPSIyNTcuNzUwMyIgeDI9Ii0zNjUuMDQxNCIgeTI9IjI2MC43ODkyIiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDIuNTQ0NSAwIDAgLTIuNTQ0NSAxMDAuMTI3MiAxMDE3LjgxMTcpIj48c3RvcCAgb2Zmc2V0PSIwIiBzdHlsZT0ic3RvcC1jb2xvcjojNjZCQjZBIi8+PHN0b3AgIG9mZnNldD0iMSIgc3R5bGU9InN0b3AtY29sb3I6IzM3OEY0MyIvPjwvbGluZWFyR3JhZGllbnQ+PHBhdGggZmlsbD0idXJsKCNTVkdJRF8xMF8pIiBkPSJNLTgyNS4xLDM1My4yYzAsMC0yLDAuNS00LjMsMC44Yy0yLDAuMy00LjMsMC00LjMsMGMwLjMsNC4zLDEuNSw3LjQsMy4xLDkuN2w3LjktMC44Qy04MjQsMzYwLjgtODI0LjgsMzU3LTgyNS4xLDM1My4yeiIvPjxsaW5lYXJHcmFkaWVudCBpZD0iU1ZHSURfMTFfIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9Ii0zNjUiIHkxPSIyNjQuMjIyMyIgeDI9Ii0zNjUiIHkyPSIyNjEuMTU5NyIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgyLjU0NDUgMCAwIC0yLjU0NDUgMTAwLjEyNzIgMTAxNy44MTE3KSI+PHN0b3AgIG9mZnNldD0iMCIgc3R5bGU9InN0b3AtY29sb3I6IzY2QkI2QSIvPjxzdG9wICBvZmZzZXQ9IjEiIHN0eWxlPSJzdG9wLWNvbG9yOiMzNzhGNDMiLz48L2xpbmVhckdyYWRpZW50PjxwYXRoIGZpbGw9InVybCgjU1ZHSURfMTFfKSIgZD0iTS04MzEuMiwzMzkuOUwtODMxLjIsMzM5LjljLTAuMywwLjgtMC41LDEuNS0wLjgsMmMwLDAuMywwLDAuMy0wLjMsMC41Yy0wLjUsMS41LTAuOCwyLjgtMSw0LjNjMCwwLjMsMCwwLjMsMCwwLjVjMCwwLjgtMC4zLDEuMy0wLjMsMmM1LjEsMCw4LjctMS41LDguNy0xLjVjMC0wLjUsMC0xLDAuMy0xLjV2LTAuM2MwLTAuNSwwLTAuOCwwLjMtMXYtMC4zYzAuMy0xLDAuMy0yLDAuNS0yLjhMLTgzMS4yLDMzOS45eiBNLTgzMy41LDM0OS40TC04MzMuNSwzNDkuNEwtODMzLjUsMzQ5LjRMLTgzMy41LDM0OS40eiIvPjxsaW5lYXJHcmFkaWVudCBpZD0iU1ZHSURfMTJfIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9Ii0zOTIiIHkxPSIyNTkuMjAyNSIgeDI9Ii0zOTIiIHkyPSIyNjMuMDAxMSIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgyLjU0NDUgMCAwIC0yLjU0NDUgMTAwLjEyNzIgMTAxNy44MTE3KSI+PHN0b3AgIG9mZnNldD0iMCIgc3R5bGU9InN0b3AtY29sb3I6IzY2QkI2QSIvPjxzdG9wICBvZmZzZXQ9IjEiIHN0eWxlPSJzdG9wLWNvbG9yOiMzNzhGNDMiLz48L2xpbmVhckdyYWRpZW50PjxwYXRoIGZpbGw9InVybCgjU1ZHSURfMTJfKSIgZD0iTS05MDIuNCwzNTguOGw0LjgsMmMyLjMtMy4zLDMuNi02LjYsNC42LTkuMmwwLjgtMy42bC0yLjMsMC4zQy04OTYuNiwzNTIuNy04OTkuMSwzNTYuMi05MDIuNCwzNTguOHoiLz48bGluZWFyR3JhZGllbnQgaWQ9IlNWR0lEXzEzXyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIHgxPSItMzc2Ljg2MzciIHkxPSIyNjcuMDM1NSIgeDI9Ii0zNzcuMzQwOSIgeTI9IjI2Ni4yNzU1IiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDIuNTQ0NSAwIDAgLTIuNTQ0NSAxMDAuMTI3MiAxMDE3LjgxMTcpIj48c3RvcCAgb2Zmc2V0PSIwIiBzdHlsZT0ic3RvcC1jb2xvcjojNjZCQjZBIi8+PHN0b3AgIG9mZnNldD0iMSIgc3R5bGU9InN0b3AtY29sb3I6IzM3OEY0MyIvPjwvbGluZWFyR3JhZGllbnQ+PHBhdGggZmlsbD0idXJsKCNTVkdJRF8xM18pIiBkPSJNLTg1OS4yLDM0M2MxLjMtMy4zLDEuOC01LjksMS44LTcuMXYtMC4zbC0yLjgsMC44Qy04NjAuMiwzMzYuNC04NjAuMiwzMzguMi04NTkuMiwzNDN6Ii8+PGxpbmVhckdyYWRpZW50IGlkPSJTVkdJRF8xNF8iIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iLTM3MC41NTQzIiB5MT0iMjY1LjQ2NDUiIHgyPSItMzcwLjgyMzYiIHkyPSIyNjQuNDQxIiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDIuNTQ0NSAwIDAgLTIuNTQ0NSAxMDAuMTI3MiAxMDE3LjgxMTcpIj48c3RvcCAgb2Zmc2V0PSIwIiBzdHlsZT0ic3RvcC1jb2xvcjojNjZCQjZBIi8+PHN0b3AgIG9mZnNldD0iMSIgc3R5bGU9InN0b3AtY29sb3I6IzM3OEY0MyIvPjwvbGluZWFyR3JhZGllbnQ+PHBhdGggZmlsbD0idXJsKCNTVkdJRF8xNF8pIiBkPSJNLTg0NC4xLDM0MC43YzAsMC0wLjgsMi4zLDIuMyw1LjFjMC41LTIuMywxLTQuNiwxLTYuNkwtODQ0LjEsMzQwLjd6Ii8+PC9nPjxnPjxyZWN0IHg9Ii02OTcuMyIgeT0iMjkyLjkiIGZpbGw9IiNGRkZGRkYiIHdpZHRoPSIxMDYuOSIgaGVpZ2h0PSIxMDYuOSIvPjxnPjxwYXRoIGZpbGw9IiM2NkJCNkEiIGQ9Ik0tNjQ0LjQsMzQ5LjljMC4zLDAuNSwwLjUsMC44LDAuNSwwLjhjOC43LDEsMjEuMSwwLDMwLjUtMS41Yy01LjMsMTEuNy0xNSwxOS4zLTIzLjksMTkuM2MtMTYuNSwwLTI5LjUtMjAuMS0yOS41LTIwLjFjNS4xLTQuNiwxMy43LTE5LjMsMjYtMTkuM2MxMi4yLDAsMTcuNiw2LjYsMTcuNiw2LjZsMS4zLTIuM2MwLDAtNS45LTIwLjEtMjEuOS0yMC4xYy0xNi4zLDAtMzMuMywyNi41LTQzLjUsMzIuNmMwLDAsMTMuNywzMi44LDQ0LDMyLjhjMjUuNCwwLDMxLjgtMjQuMiwzMy4xLTMwLjNjMy4zLTAuNSw2LjEtMSw4LjEtMS4zYzAuNS0xLjMsMS4zLTMuOCwwLjgtNy4xYy0xMC4yLDMuOC0yNS40LDguNC00My41LDguNEMtNjQ0LjcsMzQ4LjYtNjQ0LjcsMzQ5LjEtNjQ0LjQsMzQ5Ljl6Ii8+PGxpbmVhckdyYWRpZW50IGlkPSJTVkdJRF8xNV8iIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iLTI4MS44NSIgeTE9IjI1Ny41MTg3IiB4Mj0iLTI4MS44NSIgeTI9IjI2Mi42NTExIiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDIuNTQ0NSAwIDAgLTIuNTQ0NSAxMDAuMTI3MiAxMDE3LjgxMTcpIj48c3RvcCAgb2Zmc2V0PSIwIiBzdHlsZT0ic3RvcC1jb2xvcjojNjZCQjZBIi8+PHN0b3AgIG9mZnNldD0iMSIgc3R5bGU9InN0b3AtY29sb3I6IzM3OEY0MyIvPjwvbGluZWFyR3JhZGllbnQ+PHBhdGggZmlsbD0idXJsKCNTVkdJRF8xNV8pIiBkPSJNLTYxMC4xLDM0OC45bC0zLjEsMC4zYzAsMC4zLTAuMywwLjUtMC41LDAuOGMtMC41LDEtMSwxLjgtMS41LDIuOGMtMC4zLDAuNS0wLjUsMC44LTAuOCwxLjNjLTAuNSwxLTEuMywyLTIsMi44Yy0wLjMsMC4zLTAuMywwLjMtMC41LDAuNWMtMS44LDIuMy0zLjYsNC4zLTUuNiw1LjlsNi40LDIuOEMtNjEyLjYsMzU5LjMtNjEwLjYsMzUxLjctNjEwLjEsMzQ4Ljl6Ii8+PC9nPjwvZz48Zz48Zz48ZGVmcz48Y2lyY2xlIGlkPSJTVkdJRF8xNl8iIGN4PSItNDA3LjMiIGN5PSIzNDYuMyIgcj0iNDIuMiIvPjwvZGVmcz48Y2xpcFBhdGggaWQ9IlNWR0lEXzE3XyI+PHVzZSB4bGluazpocmVmPSIjU1ZHSURfMTZfIiAgb3ZlcmZsb3c9InZpc2libGUiLz48L2NsaXBQYXRoPjxwYXRoIGNsaXAtcGF0aD0idXJsKCNTVkdJRF8xN18pIiBmaWxsPSIjRkZGRkZGIiBkPSJNLTQwMS4xLDM0OS40YzAuMywwLjMsMC41LDAuOCwwLjUsMC44YzcuNCwxLDE4LjEsMCwyNi4yLTEuM2MtNC42LDkuOS0xMywxNi41LTIwLjQsMTYuNWMtMTQuMiwwLTI1LjItMTcuMy0yNS4yLTE3LjNjNC4zLTMuOCwxMS43LTE2LjUsMjIuMS0xNi41czE1LDUuOSwxNSw1LjlsMS4zLTEuOGMwLDAtNC44LTE3LTE4LjgtMTdzLTI4LjUsMjIuNi0zNy4yLDI4YzAsMCwxMiwyOCwzNy43LDI4YzIxLjYsMCwyNy4yLTIwLjksMjguMi0yNmMyLjgtMC41LDUuMy0wLjgsNi45LTFjMC41LTEuMywxLTMuMywwLjgtNi4xYy04LjcsMy4zLTIxLjYsNy4xLTM3LjIsNy4xQy00MDEuNCwzNDguMy00MDEuNCwzNDguOS00MDEuMSwzNDkuNHoiLz48L2c+PC9nPjwvZz48ZyBpZD0iTGF5ZXJfMiI+PHBhdGggZmlsbD0iIzg4ODg4OCIgZD0iTTQ2Ny4zLDIwOS45Yy00LjgsMjQuNC0zMC44LDEyMi42LTEzMy42LDEyMi42Yy0xMjIuNiwwLTE3OC42LTEzMi44LTE3OC42LTEzMi44YzQxLTI0LjksMTEwLjQtMTMyLjMsMTc2LjEtMTMyLjNzODguOCw4MS4yLDg4LjgsODEuMmwtNS42LDguOWMwLDAtMjEuNi0yNy4yLTcxLjItMjcuMnMtODMuNyw1OS44LTEwNC42LDc4LjRjMCwwLDUyLjIsODEuNywxMTkuMyw4MS43YzM2LjEsMCw3NS4xLTMxLjMsOTYuOS03OC40Yy0zOC4yLDUuMy04OC4zLDEwLjItMTIzLjcsNS42YzAsMC0xLjgtMS41LTIuNS0zLjNjLTEtMi4zLTEuMy00LjYtMS4zLTQuNmM3MC4yLDAsMTMwLjUtMTYuNSwxNzEuNS0zMS44QzQ4Ny43LDc3LjYsNDAyLjksMCwzMDAuMSwwYy0xMTAuNCwwLTIwMCw4OS42LTIwMCwyMDBzODkuNiwyMDAsMjAwLDIwMGMxMDguOSwwLDE5Ny41LTg3LDIwMC0xOTUuNEM0OTIuNSwyMDUuOSw0ODEsMjA3LjksNDY3LjMsMjA5Ljl6Ii8+PC9nPjwvc3ZnPg==',
521 'give_cpt_icon' => 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxOC4wLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHZpZXdCb3g9IjAgMCAxNTcuMSAxNTcuMiIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMTU3LjEgMTU3LjI7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoJLnN0MHtmaWxsOiM2NkJCNkE7fQ0KCS5zdDF7ZmlsbDojNTQ2RTdBO30NCgkuc3Qye2ZpbGw6dXJsKCNTVkdJRF8xXyk7fQ0KCS5zdDN7ZmlsbDp1cmwoI1NWR0lEXzJfKTt9DQoJLnN0NHtmaWxsOnVybCgjU1ZHSURfM18pO30NCgkuc3Q1e2ZpbGw6dXJsKCNTVkdJRF80Xyk7fQ0KCS5zdDZ7ZmlsbDp1cmwoI1NWR0lEXzVfKTt9DQoJLnN0N3tmaWxsOnVybCgjU1ZHSURfNl8pO30NCgkuc3Q4e2ZpbGw6dXJsKCNTVkdJRF83Xyk7fQ0KCS5zdDl7ZmlsbDp1cmwoI1NWR0lEXzhfKTt9DQoJLnN0MTB7ZmlsbDp1cmwoI1NWR0lEXzlfKTt9DQoJLnN0MTF7ZmlsbDp1cmwoI1NWR0lEXzEwXyk7fQ0KCS5zdDEye2ZpbGw6dXJsKCNTVkdJRF8xMV8pO30NCgkuc3QxM3tmaWxsOnVybCgjU1ZHSURfMTJfKTt9DQoJLnN0MTR7ZmlsbDp1cmwoI1NWR0lEXzEzXyk7fQ0KCS5zdDE1e2ZpbGw6dXJsKCNTVkdJRF8xNF8pO30NCgkuc3QxNntmaWxsOiNGRkZGRkY7fQ0KCS5zdDE3e2ZpbGw6dXJsKCNTVkdJRF8xNV8pO30NCgkuc3QxOHtjbGlwLXBhdGg6dXJsKCNTVkdJRF8xN18pO2ZpbGw6I0ZGRkZGRjt9DQoJLnN0MTl7ZmlsbDojRjFGMkYyO30NCjwvc3R5bGU+DQo8ZyBpZD0iTGF5ZXJfMSI+DQoJPGNpcmNsZSBjbGFzcz0ic3QwIiBjeD0iLTE5OS40IiBjeT0iMTM2LjEiIHI9IjE2LjYiLz4NCgk8Zz4NCgkJPGc+DQoJCQk8cGF0aCBjbGFzcz0ic3QxIiBkPSJNLTM0OC40LDUyLjZ2LTQuOWgxLjljMS41LDAsMi42LDEsMi42LDIuNWMwLDEuNS0xLjEsMi41LTIuNiwyLjVILTM0OC40eiBNLTM0NC45LDUwLjENCgkJCQljMC0wLjktMC41LTEuNS0xLjUtMS41aC0wLjl2My4xaDAuOUMtMzQ1LjUsNTEuNy0zNDQuOSw1MS0zNDQuOSw1MC4xeiIvPg0KCQkJPHBhdGggY2xhc3M9InN0MSIgZD0iTS0zNDIuNiw1Mi42di00LjloMy41djAuOWgtMi40djFoMi40djAuOWgtMi40djEuMWgyLjR2MC45SC0zNDIuNnoiLz4NCgkJCTxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0tMzMzLjUsNTIuNnYtMy40bC0xLjQsMy40aC0wLjVsLTEuNC0zLjR2My40aC0xdi00LjloMS41bDEuMiwzbDEuMi0zaDEuNXY0LjlILTMzMy41eiIvPg0KCQkJPHBhdGggY2xhc3M9InN0MSIgZD0iTS0zMzEuMSw1MC4xYzAtMS41LDEuMS0yLjUsMi42LTIuNWMxLjUsMCwyLjYsMS4xLDIuNiwyLjVjMCwxLjUtMS4xLDIuNS0yLjYsMi41DQoJCQkJQy0zMzAuMSw1Mi43LTMzMS4xLDUxLjYtMzMxLjEsNTAuMXogTS0zMjcuMSw1MC4xYzAtMC45LTAuNi0xLjYtMS41LTEuNnMtMS41LDAuNy0xLjUsMS42YzAsMC45LDAuNiwxLjYsMS41LDEuNg0KCQkJCVMtMzI3LjEsNTEtMzI3LjEsNTAuMXoiLz4NCgkJCTxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0tMzI1LDUwLjFjMC0xLjUsMS4xLTIuNSwyLjYtMi41YzEuMSwwLDEuNywwLjYsMi4xLDEuMmwtMC45LDAuNGMtMC4yLTAuNC0wLjYtMC43LTEuMi0wLjcNCgkJCQljLTAuOSwwLTEuNSwwLjctMS41LDEuNmMwLDAuOSwwLjYsMS42LDEuNSwxLjZjMC41LDAsMC45LTAuMywxLjItMC43bDAuOSwwLjRjLTAuNCwwLjYtMSwxLjItMi4xLDEuMg0KCQkJCUMtMzIzLjgsNTIuNy0zMjUsNTEuNi0zMjUsNTAuMXoiLz4NCgkJCTxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0tMzE2LjMsNTIuNmwtMS0xLjdoLTAuOHYxLjdoLTF2LTQuOWgyLjNjMSwwLDEuNiwwLjcsMS42LDEuNmMwLDAuOS0wLjUsMS4zLTEuMSwxLjVsMS4xLDEuOUgtMzE2LjN6DQoJCQkJIE0tMzE2LjIsNDkuMmMwLTAuNC0wLjMtMC43LTAuNy0wLjdoLTEuMXYxLjNoMS4xQy0zMTYuNiw0OS45LTMxNi4yLDQ5LjctMzE2LjIsNDkuMnoiLz4NCgkJCTxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0tMzEwLjQsNTIuNmwtMC4zLTAuOGgtMi4xbC0wLjMsMC44aC0xLjJsMS45LTQuOWgxLjNsMS45LDQuOUgtMzEwLjR6IE0tMzExLjgsNDguN2wtMC44LDIuMWgxLjUNCgkJCQlMLTMxMS44LDQ4Ljd6Ii8+DQoJCQk8cGF0aCBjbGFzcz0ic3QxIiBkPSJNLTMwNy42LDUyLjZ2LTRoLTEuNHYtMC45aDMuOXYwLjloLTEuNHY0SC0zMDcuNnoiLz4NCgkJCTxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0tMzAzLjksNTIuNnYtNC45aDF2NC45SC0zMDMuOXoiLz4NCgkJCTxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0tMzAxLjUsNTIuNnYtMC44bDIuMy0zLjFoLTIuM3YtMC45aDMuN3YwLjhsLTIuMywzLjJoMi40djAuOUgtMzAxLjV6Ii8+DQoJCQk8cGF0aCBjbGFzcz0ic3QxIiBkPSJNLTI5Ni40LDUyLjZ2LTQuOWgxdjQuOUgtMjk2LjR6Ii8+DQoJCQk8cGF0aCBjbGFzcz0ic3QxIiBkPSJNLTI5MC41LDUyLjZsLTIuMy0zLjJ2My4yaC0xdi00LjloMS4xbDIuMywzLjF2LTMuMWgxdjQuOUgtMjkwLjV6Ii8+DQoJCQk8cGF0aCBjbGFzcz0ic3QxIiBkPSJNLTI4OC4yLDUwLjFjMC0xLjYsMS4yLTIuNSwyLjYtMi41YzEsMCwxLjcsMC41LDIsMS4xbC0wLjksMC41Yy0wLjItMC4zLTAuNi0wLjYtMS4yLTAuNg0KCQkJCWMtMC45LDAtMS41LDAuNy0xLjUsMS42YzAsMC45LDAuNiwxLjYsMS41LDEuNmMwLjQsMCwwLjgtMC4yLDEtMC40di0wLjZoLTEuM3YtMC45aDIuM3YxLjljLTAuNSwwLjYtMS4yLDAuOS0yLjEsMC45DQoJCQkJQy0yODcsNTIuNy0yODguMiw1MS43LTI4OC4yLDUwLjF6Ii8+DQoJCQk8cGF0aCBjbGFzcz0ic3QxIiBkPSJNLTI3OS45LDUwLjFjMC0xLjYsMS4yLTIuNSwyLjYtMi41YzEsMCwxLjcsMC41LDIsMS4xbC0wLjksMC41Yy0wLjItMC4zLTAuNi0wLjYtMS4yLTAuNg0KCQkJCWMtMC45LDAtMS41LDAuNy0xLjUsMS42YzAsMC45LDAuNiwxLjYsMS41LDEuNmMwLjQsMCwwLjgtMC4yLDEtMC40di0wLjZoLTEuM3YtMC45aDIuM3YxLjljLTAuNSwwLjYtMS4yLDAuOS0yLjEsMC45DQoJCQkJQy0yNzguNyw1Mi43LTI3OS45LDUxLjctMjc5LjksNTAuMXoiLz4NCgkJCTxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0tMjczLjgsNTIuNnYtNC45aDMuNXYwLjloLTIuNHYxaDIuNHYwLjloLTIuNHYxLjFoMi40djAuOUgtMjczLjh6Ii8+DQoJCQk8cGF0aCBjbGFzcz0ic3QxIiBkPSJNLTI2NS42LDUyLjZsLTIuMy0zLjJ2My4yaC0xdi00LjloMS4xbDIuMywzLjF2LTMuMWgxdjQuOUgtMjY1LjZ6Ii8+DQoJCQk8cGF0aCBjbGFzcz0ic3QxIiBkPSJNLTI2Myw1Mi42di00LjloMy41djAuOWgtMi40djFoMi40djAuOWgtMi40djEuMWgyLjR2MC45SC0yNjN6Ii8+DQoJCQk8cGF0aCBjbGFzcz0ic3QxIiBkPSJNLTI1NS40LDUyLjZsLTEtMS43aC0wLjh2MS43aC0xdi00LjloMi4zYzEsMCwxLjYsMC43LDEuNiwxLjZjMCwwLjktMC41LDEuMy0xLjEsMS41bDEuMSwxLjlILTI1NS40eg0KCQkJCSBNLTI1NS4zLDQ5LjJjMC0wLjQtMC4zLTAuNy0wLjctMC43aC0xLjF2MS4zaDEuMUMtMjU1LjYsNDkuOS0yNTUuMyw0OS43LTI1NS4zLDQ5LjJ6Ii8+DQoJCQk8cGF0aCBjbGFzcz0ic3QxIiBkPSJNLTI1My4xLDUwLjFjMC0xLjUsMS4xLTIuNSwyLjYtMi41YzEuNSwwLDIuNiwxLjEsMi42LDIuNWMwLDEuNS0xLjEsMi41LTIuNiwyLjUNCgkJCQlDLTI1Mi4xLDUyLjctMjUzLjEsNTEuNi0yNTMuMSw1MC4xeiBNLTI0OS4xLDUwLjFjMC0wLjktMC42LTEuNi0xLjUtMS42Yy0wLjksMC0xLjUsMC43LTEuNSwxLjZjMCwwLjksMC42LDEuNiwxLjUsMS42DQoJCQkJQy0yNDkuNyw1MS43LTI0OS4xLDUxLTI0OS4xLDUwLjF6Ii8+DQoJCQk8cGF0aCBjbGFzcz0ic3QxIiBkPSJNLTI0Ny4xLDUxLjlsMC42LTAuOGMwLjMsMC40LDAuOSwwLjcsMS42LDAuN2MwLjYsMCwwLjktMC4zLDAuOS0wLjVjMC0wLjktMi44LTAuMy0yLjgtMi4xDQoJCQkJYzAtMC44LDAuNy0xLjUsMS45LTEuNWMwLjgsMCwxLjQsMC4yLDEuOSwwLjdsLTAuNiwwLjhjLTAuNC0wLjQtMC45LTAuNS0xLjQtMC41Yy0wLjQsMC0wLjcsMC4yLTAuNywwLjVjMCwwLjgsMi44LDAuMywyLjgsMi4xDQoJCQkJYzAsMC45LTAuNiwxLjYtMiwxLjZDLTI0NS45LDUyLjctMjQ2LjYsNTIuMy0yNDcuMSw1MS45eiIvPg0KCQkJPHBhdGggY2xhc3M9InN0MSIgZD0iTS0yNDEuOCw1Mi42di00LjloMXY0LjlILTI0MS44eiIvPg0KCQkJPHBhdGggY2xhc3M9InN0MSIgZD0iTS0yMzguMSw1Mi42di00aC0xLjR2LTAuOWgzLjl2MC45aC0xLjR2NEgtMjM4LjF6Ii8+DQoJCQk8cGF0aCBjbGFzcz0ic3QxIiBkPSJNLTIzMyw1Mi42di0ybC0xLjktMi45aDEuMmwxLjIsMmwxLjItMmgxLjJsLTEuOSwyLjl2MkgtMjMzeiIvPg0KCQk8L2c+DQoJCTxnPg0KCQkJPGc+DQoJCQkJPHBhdGggY2xhc3M9InN0MCIgZD0iTS0yMzAuMywxNy40bC0wLjUsMGwwLjEsMC41YzAuOCwzLjksMC4xLDkuNy0yLjksMTMuM2MtMS43LDIuMS0zLjksMy4yLTYuNiwzLjJjLTQuMywwLTUuOS01LjEtNi4xLTEwLjkNCgkJCQkJYzctMS43LDExLjctNi4xLDExLjctMTEuMmMwLTMuNy0xLjEtOS44LTguNC05LjhjLTYuOSwwLTEwLjQsMTAuMy0xMS4xLDE3LjVjLTMuNS0wLjEtNi4xLTEuNy03LjctMy4yYzAuNi0yLjUsMC45LTQuOCwwLjktNi45DQoJCQkJCWMwLTIuOS0yLTQuMi0zLjktNC4yYy0yLjcsMC01LjUsMi42LTUuNSw3LjZjMCwzLDEuMSw1LjUsMy40LDcuM2MtMiw0LjctNS40LDguNy02LjUsMTBjLTAuOS0xLjktMy44LTguOC00LjctMTYuMw0KCQkJCQljMS4xLTMsMS43LTUuNSwxLjctNi43YzAtMS45LTEuMi0zLTMuMi0zYy0yLjcsMC03LDEuNy03LjEsMS44bC0wLjIsMC4xbDAsMC4zYzAsMC4xLDEuMyw2LjEsMi42LDEyLjcNCgkJCQkJYy0yLjUsNC4xLTYuOSwxMC45LTkuMSwxMC45Yy00LDAsMi42LTIwLjUtMC4zLTIxLjJjLTAuMSwwLTAuMiwwLTAuMywwLjFjLTEuNCwwLjktMTcuMSw5LjYtMzgsOS42YzAsMCwwLDAuNCwwLjIsMC44DQoJCQkJCWMwLjEsMC4zLDAuNCwwLjYsMC40LDAuNmM1LjksMC43LDE0LjMtMC4xLDIwLjctMWMtMy43LDcuOS0xMC4yLDEzLjEtMTYuMiwxMy4xYy0xMS4zLDAtMjAtMTMuNy0yMC0xMy43DQoJCQkJCWMzLjUtMy4xLDkuMi0xMy4xLDE3LjYtMTMuMWM4LjMsMCwxMS45LDQuNiwxMS45LDQuNmwwLjktMS41YzAsMC0zLjktMTMuNi0xNC45LTEzLjZjLTExLDAtMjIuNywxOC0yOS41LDIyLjINCgkJCQkJYzAsMCw5LjQsMjIuMiwyOS45LDIyLjJjMTcuMiwwLDIxLjYtMTYuNSwyMi40LTIwLjVjNC4yLTAuNiw3LjEtMS4yLDcuMS0xLjJzLTEuMSw4LjQtMS4xLDExLjljMCwzLjUsMy45LDcuMiw3LjEsNy4yDQoJCQkJCWMyLjcsMCw4LjItNS42LDEyLjItMTIuNGwwLjIsMC44YzIuMSw3LjcsNC43LDExLjcsNy44LDExLjdjMy4xLDAsOC4yLTYuNCwxMS41LTE0LjVjMy4zLDEuNCw3LjIsMS44LDkuNSwxLjkNCgkJCQkJYzAuOSwxMy45LDEyLjUsMTQuMywxMy45LDE0LjNjOC42LDAsMTUuOS02LjIsMTUuOS0xMy41Qy0yMjQuMywxNy41LTIzMC4yLDE3LjQtMjMwLjMsMTcuNHogTS0yNDAuOCwxMS42YzAsMC0wLjEsNC42LTUuMyw2LjkNCgkJCQkJYzAuNS02LjEsMi0xMS42LDMtMTEuNkMtMjQyLDctMjQwLjgsOC43LTI0MC44LDExLjZ6Ii8+DQoJCQkJPHBhdGggY2xhc3M9InN0MCIgZD0iTS0zMDAuNyw2LjFjMCwwLjIsMC4xLDAuMywwLjMsMC40YzQuMSwwLjYsNi44LTAuNyw2LjgtNy4zYzAtNi4yLTYuNC0xLjMtNy42LTAuNA0KCQkJCQljLTAuMSwwLjEtMC4xLDAuMi0wLjEsMC40Qy0zMDAuMiwxLjYtMzAwLjYsNS4xLTMwMC43LDYuMXoiLz4NCgkJCTwvZz4NCgkJCTxsaW5lYXJHcmFkaWVudCBpZD0iU1ZHSURfMV8iIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iLTI4OS41ODQ0IiB5MT0iMjYuNzY4IiB4Mj0iLTI4Mi44ODIzIiB5Mj0iMjQuNTM0Ij4NCgkJCQk8c3RvcCAgb2Zmc2V0PSIwIiBzdHlsZT0ic3RvcC1jb2xvcjojNjZCQjZBIi8+DQoJCQkJPHN0b3AgIG9mZnNldD0iMSIgc3R5bGU9InN0b3AtY29sb3I6IzM3OEY0MyIvPg0KCQkJPC9saW5lYXJHcmFkaWVudD4NCgkJCTxwYXRoIGNsYXNzPSJzdDIiIGQ9Ik0tMjg0LjIsMTkuNGMtMS42LDIuNy00LDYuNC02LjEsOC43YzAuNSwxLjIsMS4xLDIuNywxLjcsMy45YzEuOS0yLjEsMy44LTQuOCw1LjUtNy42TC0yODQuMiwxOS40eiIvPg0KCQkJPGxpbmVhckdyYWRpZW50IGlkPSJTVkdJRF8yXyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIHgxPSItMjY5LjAxOTQiIHkxPSIyOC40Nzc3IiB4Mj0iLTI2NS4xMzIyIiB5Mj0iMjEuNjQxNiI+DQoJCQkJPHN0b3AgIG9mZnNldD0iMCIgc3R5bGU9InN0b3AtY29sb3I6IzY2QkI2QSIvPg0KCQkJCTxzdG9wICBvZmZzZXQ9IjEiIHN0eWxlPSJzdG9wLWNvbG9yOiMzNzhGNDMiLz4NCgkJCTwvbGluZWFyR3JhZGllbnQ+DQoJCQk8cGF0aCBjbGFzcz0ic3QzIiBkPSJNLTI2NS4yLDIxLjVjLTAuOC0wLjQtMS41LTEtMS41LTFjLTEuNCwzLjEtMy4zLDYtNC44LDcuOWMwLjcsMSwxLjksMi4zLDIuOCwzLjNjMS44LTIuNSwzLjctNS44LDUuMS05LjMNCgkJCQlDLTI2My41LDIyLjMtMjY0LjQsMjItMjY1LjIsMjEuNXoiLz4NCgkJCTxsaW5lYXJHcmFkaWVudCBpZD0iU1ZHSURfM18iIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iLTI0OC42MjU0IiB5MT0iMzEuNjE0NyIgeDI9Ii0yNDkuNDI5NyIgeTI9IjI0LjQ2NTkiPg0KCQkJCTxzdG9wICBvZmZzZXQ9IjAiIHN0eWxlPSJzdG9wLWNvbG9yOiM2NkJCNkEiLz4NCgkJCQk8c3RvcCAgb2Zmc2V0PSIxIiBzdHlsZT0ic3RvcC1jb2xvcjojMzc4RjQzIi8+DQoJCQk8L2xpbmVhckdyYWRpZW50Pg0KCQkJPHBhdGggY2xhc3M9InN0NCIgZD0iTS0yNDYuMiwyMy41YzAsMC0yLDAuNC00LDAuNmMtMiwwLjItMy45LDAuMS0zLjksMC4xYzAuMyw0LDEuNCw2LjgsMi45LDguOWw3LjMtMC42DQoJCQkJQy0yNDUuNCwzMC41LTI0Ni4xLDI3LjEtMjQ2LjIsMjMuNXoiLz4NCgkJCTxsaW5lYXJHcmFkaWVudCBpZD0iU1ZHSURfNF8iIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iLTI0OS43MjY3IiB5MT0iMTYuNDE5IiB4Mj0iLTI0OS43MjY3IiB5Mj0iMjMuNjIzNyI+DQoJCQkJPHN0b3AgIG9mZnNldD0iMCIgc3R5bGU9InN0b3AtY29sb3I6IzY2QkI2QSIvPg0KCQkJCTxzdG9wICBvZmZzZXQ9IjEiIHN0eWxlPSJzdG9wLWNvbG9yOiMzNzhGNDMiLz4NCgkJCTwvbGluZWFyR3JhZGllbnQ+DQoJCQk8cGF0aCBjbGFzcz0ic3Q1IiBkPSJNLTI1MiwxMS4zTC0yNTIsMTEuM2MtMC4yLDAuNi0wLjUsMS4zLTAuNywyYzAsMC4yLTAuMSwwLjMtMC4xLDAuNWMtMC40LDEuMy0wLjcsMi42LTAuOSwzLjkNCgkJCQljMCwwLjItMC4xLDAuMy0wLjEsMC41Yy0wLjEsMC42LTAuMiwxLjItMC4yLDEuOGM0LjcsMCw3LjktMS40LDcuOS0xLjRjMC0wLjUsMC4xLTAuOSwwLjEtMS40YzAtMC4xLDAtMC4yLDAtMC4zDQoJCQkJYzAtMC40LDAuMS0wLjcsMC4xLTEuMWMwLTAuMSwwLTAuMiwwLTAuM2MwLjEtMC45LDAuMy0xLjgsMC40LTIuNkwtMjUyLDExLjN6IE0tMjU0LjEsMTkuOUMtMjU0LjEsMTkuOS0yNTQuMSwxOS45LTI1NC4xLDE5LjkNCgkJCQlMLTI1NC4xLDE5LjlDLTI1NC4xLDE5LjktMjU0LjEsMTkuOS0yNTQuMSwxOS45eiIvPg0KCQkJPGxpbmVhckdyYWRpZW50IGlkPSJTVkdJRF81XyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIHgxPSItMzEzLjAyNzIiIHkxPSIyOC4yMjc4IiB4Mj0iLTMxMy4wMjcyIiB5Mj0iMTkuMjkxNyI+DQoJCQkJPHN0b3AgIG9mZnNldD0iMCIgc3R5bGU9InN0b3AtY29sb3I6IzY2QkI2QSIvPg0KCQkJCTxzdG9wICBvZmZzZXQ9IjEiIHN0eWxlPSJzdG9wLWNvbG9yOiMzNzhGNDMiLz4NCgkJCTwvbGluZWFyR3JhZGllbnQ+DQoJCQk8cGF0aCBjbGFzcz0ic3Q2IiBkPSJNLTMxNy43LDI4LjZsNC40LDEuOWMyLjEtMywzLjQtNi4xLDQuMi04LjVsMC44LTMuMmwtMi4xLDAuM0MtMzEyLjMsMjMuMS0zMTQuOSwyNi4zLTMxNy43LDI4LjZ6Ii8+DQoJCQk8bGluZWFyR3JhZGllbnQgaWQ9IlNWR0lEXzZfIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9Ii0yNzcuNTIzOSIgeTE9IjkuNzg4IiB4Mj0iLTI3OC42NDYzIiB5Mj0iMTEuNTc1NiI+DQoJCQkJPHN0b3AgIG9mZnNldD0iMCIgc3R5bGU9InN0b3AtY29sb3I6IzY2QkI2QSIvPg0KCQkJCTxzdG9wICBvZmZzZXQ9IjEiIHN0eWxlPSJzdG9wLWNvbG9yOiMzNzhGNDMiLz4NCgkJCTwvbGluZWFyR3JhZGllbnQ+DQoJCQk8cGF0aCBjbGFzcz0ic3Q3IiBkPSJNLTI3Ny45LDE0LjJjMS4xLTMsMS43LTUuNSwxLjctNi43YzAtMC4xLDAtMC4yLDAtMC4zbC0yLjYsMC44Qy0yNzguOCw4LTI3OC43LDkuNy0yNzcuOSwxNC4yeiIvPg0KCQkJPGxpbmVhckdyYWRpZW50IGlkPSJTVkdJRF83XyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIHgxPSItMjYyLjU1MjkiIHkxPSIxMy41MjQ4IiB4Mj0iLTI2My4xODY2IiB5Mj0iMTUuOTMyNiI+DQoJCQkJPHN0b3AgIG9mZnNldD0iMCIgc3R5bGU9InN0b3AtY29sb3I6IzY2QkI2QSIvPg0KCQkJCTxzdG9wICBvZmZzZXQ9IjEiIHN0eWxlPSJzdG9wLWNvbG9yOiMzNzhGNDMiLz4NCgkJCTwvbGluZWFyR3JhZGllbnQ+DQoJCQk8cGF0aCBjbGFzcz0ic3Q4IiBkPSJNLTI2My45LDEyYzAsMC0wLjcsMi4xLDIuMiw0LjdjMC41LTIuMSwwLjgtNC4yLDAuOS02TC0yNjMuOSwxMnoiLz4NCgkJPC9nPg0KCTwvZz4NCgk8Zz4NCgkJPGc+DQoJCQk8cGF0aCBjbGFzcz0ic3QwIiBkPSJNLTM1Ni44LDEzNi4ybC0wLjIsMGwwLDAuMmMwLjMsMS43LDAsNC4xLTEuMiw1LjdjLTAuNywwLjktMS43LDEuNC0yLjgsMS40Yy0xLjgsMC0yLjUtMi4yLTIuNi00LjYNCgkJCQljMy0wLjcsNS0yLjYsNS00LjhjMC0xLjYtMC41LTQuMi0zLjYtNC4yYy0yLjksMC00LjQsNC40LTQuNyw3LjRjLTEuNSwwLTIuNi0wLjctMy4zLTEuNGMwLjMtMS4xLDAuNC0yLDAuNC0yLjkNCgkJCQljMC0xLjItMC45LTEuOC0xLjYtMS44Yy0xLjIsMC0yLjMsMS4xLTIuMywzLjJjMCwxLjMsMC41LDIuMywxLjUsMy4xYy0wLjksMi0yLjMsMy43LTIuOCw0LjJjLTAuNC0wLjgtMS42LTMuOC0yLTYuOQ0KCQkJCWMwLjUtMS4zLDAuNy0yLjMsMC43LTIuOGMwLTAuOC0wLjUtMS4zLTEuNC0xLjNjLTEuMiwwLTMsMC43LTMsMC44bC0wLjEsMC4xbDAsMC4xYzAsMCwwLjUsMi42LDEuMSw1LjQNCgkJCQljLTEuMSwxLjctMi45LDQuNi0zLjksNC42Yy0xLjcsMCwxLjEtOC43LTAuMS05YzAsMC0wLjEsMC0wLjEsMGMtMC42LDAuNC03LjMsNC4xLTE2LjEsNC4xYzAsMCwwLDAuMiwwLjEsMC4zDQoJCQkJYzAuMSwwLjEsMC4yLDAuMiwwLjIsMC4yYzIuNSwwLjMsNi4xLDAsOC44LTAuNGMtMS42LDMuMy00LjMsNS42LTYuOSw1LjZjLTQuOCwwLTguNS01LjgtOC41LTUuOGMxLjUtMS4zLDMuOS01LjYsNy41LTUuNg0KCQkJCWMzLjUsMCw1LjEsMS45LDUuMSwxLjlsMC40LTAuNmMwLDAtMS43LTUuOC02LjMtNS44cy05LjYsNy43LTEyLjUsOS40YzAsMCw0LDkuNSwxMi43LDkuNWM3LjMsMCw5LjItNyw5LjUtOC43DQoJCQkJYzEuOC0wLjMsMy0wLjUsMy0wLjVzLTAuNCwzLjYtMC40LDUuMXMxLjYsMy4xLDMsMy4xYzEuMiwwLDMuNS0yLjQsNS4yLTUuM2wwLjEsMC4zYzAuOSwzLjMsMiw1LDMuMyw1YzEuMywwLDMuNS0yLjcsNC45LTYuMQ0KCQkJCWMxLjQsMC42LDMuMSwwLjgsNCwwLjhjMC40LDUuOSw1LjMsNi4xLDUuOSw2LjFjMy43LDAsNi44LTIuNiw2LjgtNS43Qy0zNTQuMywxMzYuMy0zNTYuOCwxMzYuMi0zNTYuOCwxMzYuMnogTS0zNjEuMiwxMzMuNw0KCQkJCWMwLDAsMCwyLTIuMywzYzAuMi0yLjYsMC44LTQuOSwxLjMtNC45Qy0zNjEuOCwxMzEuOC0zNjEuMiwxMzIuNS0zNjEuMiwxMzMuN3oiLz4NCgkJCTxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0tMzg2LjcsMTMxLjRjMCwwLjEsMCwwLjEsMC4xLDAuMmMxLjcsMC4yLDIuOS0wLjMsMi45LTMuMWMwLTIuNi0yLjctMC42LTMuMi0wLjJjMCwwLTAuMSwwLjEsMCwwLjINCgkJCQlDLTM4Ni41LDEyOS41LTM4Ni43LDEzMC45LTM4Ni43LDEzMS40eiIvPg0KCQk8L2c+DQoJCTxsaW5lYXJHcmFkaWVudCBpZD0iU1ZHSURfOF8iIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iLTM4MS45OTkzIiB5MT0iMTQwLjE3NjkiIHgyPSItMzc5LjE1MDQiIHkyPSIxMzkuMjI3MiI+DQoJCQk8c3RvcCAgb2Zmc2V0PSIwIiBzdHlsZT0ic3RvcC1jb2xvcjojNjZCQjZBIi8+DQoJCQk8c3RvcCAgb2Zmc2V0PSIxIiBzdHlsZT0ic3RvcC1jb2xvcjojMzc4RjQzIi8+DQoJCTwvbGluZWFyR3JhZGllbnQ+DQoJCTxwYXRoIGNsYXNzPSJzdDkiIGQ9Ik0tMzc5LjcsMTM3Yy0wLjcsMS4xLTEuNywyLjctMi42LDMuN2MwLjIsMC41LDAuNSwxLjEsMC43LDEuN2MwLjgtMC45LDEuNi0yLDIuNC0zLjJMLTM3OS43LDEzN3oiLz4NCgkJPGxpbmVhckdyYWRpZW50IGlkPSJTVkdJRF85XyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIHgxPSItMzczLjI1NzUiIHkxPSIxNDAuOTAzNyIgeDI9Ii0zNzEuNjA1MSIgeTI9IjEzNy45OTc4Ij4NCgkJCTxzdG9wICBvZmZzZXQ9IjAiIHN0eWxlPSJzdG9wLWNvbG9yOiM2NkJCNkEiLz4NCgkJCTxzdG9wICBvZmZzZXQ9IjEiIHN0eWxlPSJzdG9wLWNvbG9yOiMzNzhGNDMiLz4NCgkJPC9saW5lYXJHcmFkaWVudD4NCgkJPHBhdGggY2xhc3M9InN0MTAiIGQ9Ik0tMzcxLjYsMTM3LjljLTAuMy0wLjItMC42LTAuNC0wLjYtMC40Yy0wLjYsMS4zLTEuNCwyLjUtMiwzLjRjMC4zLDAuNCwwLjgsMSwxLjIsMS40DQoJCQljMC44LTEuMSwxLjYtMi40LDIuMi00Qy0zNzAuOSwxMzguMy0zNzEuMywxMzguMS0zNzEuNiwxMzcuOXoiLz4NCgkJPGxpbmVhckdyYWRpZW50IGlkPSJTVkdJRF8xMF8iIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iLTM2NC41ODg0IiB5MT0iMTQyLjIzNzIiIHgyPSItMzY0LjkzMDMiIHkyPSIxMzkuMTk4MyI+DQoJCQk8c3RvcCAgb2Zmc2V0PSIwIiBzdHlsZT0ic3RvcC1jb2xvcjojNjZCQjZBIi8+DQoJCQk8c3RvcCAgb2Zmc2V0PSIxIiBzdHlsZT0ic3RvcC1jb2xvcjojMzc4RjQzIi8+DQoJCTwvbGluZWFyR3JhZGllbnQ+DQoJCTxwYXRoIGNsYXNzPSJzdDExIiBkPSJNLTM2My42LDEzOC44YzAsMC0wLjgsMC4yLTEuNywwLjNjLTAuOCwwLjEtMS43LDAtMS43LDBjMC4xLDEuNywwLjYsMi45LDEuMiwzLjhsMy4xLTAuMw0KCQkJQy0zNjMuMiwxNDEuOC0zNjMuNSwxNDAuMy0zNjMuNiwxMzguOHoiLz4NCgkJPGxpbmVhckdyYWRpZW50IGlkPSJTVkdJRF8xMV8iIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iLTM2NS4wNTY2IiB5MT0iMTM1Ljc3NzciIHgyPSItMzY1LjA1NjYiIHkyPSIxMzguODQwMyI+DQoJCQk8c3RvcCAgb2Zmc2V0PSIwIiBzdHlsZT0ic3RvcC1jb2xvcjojNjZCQjZBIi8+DQoJCQk8c3RvcCAgb2Zmc2V0PSIxIiBzdHlsZT0ic3RvcC1jb2xvcjojMzc4RjQzIi8+DQoJCTwvbGluZWFyR3JhZGllbnQ+DQoJCTxwYXRoIGNsYXNzPSJzdDEyIiBkPSJNLTM2NiwxMzMuNkwtMzY2LDEzMy42Yy0wLjEsMC4zLTAuMiwwLjYtMC4zLDAuOGMwLDAuMSwwLDAuMS0wLjEsMC4yYy0wLjIsMC42LTAuMywxLjEtMC40LDEuNw0KCQkJYzAsMC4xLDAsMC4xLDAsMC4yYzAsMC4zLTAuMSwwLjUtMC4xLDAuOGMyLDAsMy40LTAuNiwzLjQtMC42YzAtMC4yLDAtMC40LDAuMS0wLjZjMCwwLDAtMC4xLDAtMC4xYzAtMC4yLDAtMC4zLDAuMS0wLjQNCgkJCWMwLDAsMC0wLjEsMC0wLjFjMC4xLTAuNCwwLjEtMC44LDAuMi0xLjFMLTM2NiwxMzMuNnogTS0zNjYuOSwxMzcuM0MtMzY2LjksMTM3LjMtMzY2LjksMTM3LjMtMzY2LjksMTM3LjNMLTM2Ni45LDEzNy4zDQoJCQlDLTM2Ni45LDEzNy4zLTM2Ni45LDEzNy4zLTM2Ni45LDEzNy4zeiIvPg0KCQk8bGluZWFyR3JhZGllbnQgaWQ9IlNWR0lEXzEyXyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIHgxPSItMzkxLjk2NDQiIHkxPSIxNDAuNzk3NSIgeDI9Ii0zOTEuOTY0NCIgeTI9IjEzNi45OTg5Ij4NCgkJCTxzdG9wICBvZmZzZXQ9IjAiIHN0eWxlPSJzdG9wLWNvbG9yOiM2NkJCNkEiLz4NCgkJCTxzdG9wICBvZmZzZXQ9IjEiIHN0eWxlPSJzdG9wLWNvbG9yOiMzNzhGNDMiLz4NCgkJPC9saW5lYXJHcmFkaWVudD4NCgkJPHBhdGggY2xhc3M9InN0MTMiIGQ9Ik0tMzk0LDE0MWwxLjksMC44YzAuOS0xLjMsMS40LTIuNiwxLjgtMy42bDAuMy0xLjRsLTAuOSwwLjFDLTM5MS43LDEzOC42LTM5Mi43LDE0MC0zOTQsMTQxeiIvPg0KCQk8bGluZWFyR3JhZGllbnQgaWQ9IlNWR0lEXzEzXyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIHgxPSItMzc2Ljg3MjYiIHkxPSIxMzIuOTU5IiB4Mj0iLTM3Ny4zNDk4IiB5Mj0iMTMzLjcxODkiPg0KCQkJPHN0b3AgIG9mZnNldD0iMCIgc3R5bGU9InN0b3AtY29sb3I6IzY2QkI2QSIvPg0KCQkJPHN0b3AgIG9mZnNldD0iMSIgc3R5bGU9InN0b3AtY29sb3I6IzM3OEY0MyIvPg0KCQk8L2xpbmVhckdyYWRpZW50Pg0KCQk8cGF0aCBjbGFzcz0ic3QxNCIgZD0iTS0zNzcsMTM0LjhjMC41LTEuMywwLjctMi4zLDAuNy0yLjhjMCwwLDAtMC4xLDAtMC4xbC0xLjEsMC4zQy0zNzcuNCwxMzIuMi0zNzcuNCwxMzIuOS0zNzcsMTM0Ljh6Ii8+DQoJCTxsaW5lYXJHcmFkaWVudCBpZD0iU1ZHSURfMTRfIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9Ii0zNzAuNTA4OCIgeTE9IjEzNC41NDc1IiB4Mj0iLTM3MC43NzgxIiB5Mj0iMTM1LjU3MSI+DQoJCQk8c3RvcCAgb2Zmc2V0PSIwIiBzdHlsZT0ic3RvcC1jb2xvcjojNjZCQjZBIi8+DQoJCQk8c3RvcCAgb2Zmc2V0PSIxIiBzdHlsZT0ic3RvcC1jb2xvcjojMzc4RjQzIi8+DQoJCTwvbGluZWFyR3JhZGllbnQ+DQoJCTxwYXRoIGNsYXNzPSJzdDE1IiBkPSJNLTM3MS4xLDEzMy45YzAsMC0wLjMsMC45LDAuOSwyYzAuMi0wLjksMC40LTEuOCwwLjQtMi42TC0zNzEuMSwxMzMuOXoiLz4NCgk8L2c+DQoJPGc+DQoJCTxyZWN0IHg9Ii0zMTMuNCIgeT0iMTE1LjEiIGNsYXNzPSJzdDE2IiB3aWR0aD0iNDIiIGhlaWdodD0iNDIiLz4NCgkJPGc+DQoJCQk8cGF0aCBjbGFzcz0ic3QwIiBkPSJNLTI5Mi42LDEzNy41YzAuMSwwLjIsMC4yLDAuMywwLjIsMC4zYzMuNCwwLjQsOC4zLDAsMTItMC42Yy0yLjEsNC42LTUuOSw3LjYtOS40LDcuNg0KCQkJCWMtNi41LDAtMTEuNi03LjktMTEuNi03LjljMi0xLjgsNS40LTcuNiwxMC4yLTcuNnM2LjksMi42LDYuOSwyLjZsMC41LTAuOWMwLDAtMi4zLTcuOS04LjYtNy45Yy02LjQsMC0xMy4xLDEwLjQtMTcuMSwxMi44DQoJCQkJYzAsMCw1LjQsMTIuOSwxNy4zLDEyLjljMTAsMCwxMi41LTkuNSwxMy0xMS45YzEuMy0wLjIsMi40LTAuNCwzLjItMC41YzAuMi0wLjUsMC41LTEuNSwwLjMtMi44Yy00LDEuNS0xMCwzLjMtMTcuMSwzLjMNCgkJCQlDLTI5Mi43LDEzNy0yOTIuNywxMzcuMi0yOTIuNiwxMzcuNXoiLz4NCgkJCTxsaW5lYXJHcmFkaWVudCBpZD0iU1ZHSURfMTVfIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9Ii0yODEuNzk2MiIgeTE9IjE0Mi40ODEzIiB4Mj0iLTI4MS43OTYyIiB5Mj0iMTM3LjM0ODkiPg0KCQkJCTxzdG9wICBvZmZzZXQ9IjAiIHN0eWxlPSJzdG9wLWNvbG9yOiM2NkJCNkEiLz4NCgkJCQk8c3RvcCAgb2Zmc2V0PSIxIiBzdHlsZT0ic3RvcC1jb2xvcjojMzc4RjQzIi8+DQoJCQk8L2xpbmVhckdyYWRpZW50Pg0KCQkJPHBhdGggY2xhc3M9InN0MTciIGQ9Ik0tMjc5LjEsMTM3LjFsLTEuMiwwLjFjMCwwLjEtMC4xLDAuMi0wLjIsMC4zYy0wLjIsMC40LTAuNCwwLjctMC42LDEuMWMtMC4xLDAuMi0wLjIsMC4zLTAuMywwLjUNCgkJCQljLTAuMiwwLjQtMC41LDAuOC0wLjgsMS4xYy0wLjEsMC4xLTAuMSwwLjEtMC4yLDAuMmMtMC43LDAuOS0xLjQsMS43LTIuMiwyLjNsMi41LDEuMUMtMjgwLjEsMTQxLjItMjc5LjMsMTM4LjItMjc5LjEsMTM3LjF6Ii8+DQoJCTwvZz4NCgk8L2c+DQoJPGc+DQoJCTxkZWZzPg0KCQkJPGNpcmNsZSBpZD0iU1ZHSURfMTZfIiBjeD0iLTE5OS40IiBjeT0iMTM2LjEiIHI9IjE2LjYiLz4NCgkJPC9kZWZzPg0KCQk8Y2xpcFBhdGggaWQ9IlNWR0lEXzE3XyI+DQoJCQk8dXNlIHhsaW5rOmhyZWY9IiNTVkdJRF8xNl8iICBzdHlsZT0ib3ZlcmZsb3c6dmlzaWJsZTsiLz4NCgkJPC9jbGlwUGF0aD4NCgkJPHBhdGggY2xhc3M9InN0MTgiIGQ9Ik0tMTk3LDEzNy4zYzAuMSwwLjEsMC4yLDAuMywwLjIsMC4zYzIuOSwwLjQsNy4xLDAsMTAuMy0wLjVjLTEuOCwzLjktNS4xLDYuNS04LDYuNWMtNS42LDAtOS45LTYuOC05LjktNi44DQoJCQljMS43LTEuNSw0LjYtNi41LDguNy02LjVzNS45LDIuMyw1LjksMi4zbDAuNS0wLjdjMCwwLTEuOS02LjctNy40LTYuN3MtMTEuMiw4LjktMTQuNiwxMWMwLDAsNC43LDExLDE0LjgsMTENCgkJCWM4LjUsMCwxMC43LTguMiwxMS4xLTEwLjJjMS4xLTAuMiwyLjEtMC4zLDIuNy0wLjRjMC4yLTAuNSwwLjQtMS4zLDAuMy0yLjRjLTMuNCwxLjMtOC41LDIuOC0xNC42LDIuOA0KCQkJQy0xOTcuMSwxMzYuOS0xOTcuMSwxMzcuMS0xOTcsMTM3LjN6Ii8+DQoJPC9nPg0KPC9nPg0KPGcgaWQ9IkxheWVyXzIiPg0KCTxwYXRoIGNsYXNzPSJzdDE5IiBkPSJNMTQ0LjMsODIuNWMtMS45LDkuNi0xMi4xLDQ4LjItNTIuNSw0OC4yYy00OC4yLDAtNzAuMi01Mi4yLTcwLjItNTIuMmMxNi4xLTkuOCw0My40LTUyLDY5LjItNTINCgkJczM0LjksMzEuOSwzNC45LDMxLjlsLTIuMiwzLjVjMCwwLTguNS0xMC43LTI4LTEwLjdTNjIuNiw3NC43LDU0LjQsODJjMCwwLDIwLjUsMzIuMSw0Ni45LDMyLjFjMTQuMiwwLDI5LjUtMTIuMywzOC4xLTMwLjgNCgkJYy0xNSwyLjEtMzQuNyw0LTQ4LjYsMi4yYzAsMC0wLjctMC42LTEtMS4zYy0wLjQtMC45LTAuNS0xLjgtMC41LTEuOGMyNy42LDAsNTEuMy02LjUsNjcuNC0xMi41QzE1Mi4zLDMwLjUsMTE5LDAsNzguNiwwDQoJCUMzNS4yLDAsMCwzNS4yLDAsNzguNmMwLDQzLjQsMzUuMiw3OC42LDc4LjYsNzguNmM0Mi44LDAsNzcuNi0zNC4yLDc4LjYtNzYuOEMxNTQuMiw4MC45LDE0OS43LDgxLjcsMTQ0LjMsODIuNXoiLz4NCjwvZz4NCjwvc3ZnPg0K',
522 ];
523
524 // Return the chosen icon's SVG string
525 return $svgs[ $icon ];
526 }
527
528 /**
529 * Modify Admin Nav Menu Label
530 *
531 * @param object $post_type The current object to add a menu items meta box for.
532 *
533 * @return mixed
534 * @since 1.3
535 */
536 function modify_nav_menu_meta_box_object( $post_type ) {
537 if ( isset( $post_type->name ) && $post_type->name == 'give_forms' ) {
538 $post_type->labels->name = esc_html__( 'Donation Forms', 'give' );
539 }
540
541 return $post_type;
542 }
543
544 add_filter( 'nav_menu_meta_box_object', 'modify_nav_menu_meta_box_object' );
545
546 /**
547 * Show Donation Forms Post Type in Appearance > Menus by default on fresh install.
548 *
549 * @return bool
550 * @todo Remove this, when WordPress Core ticket is resolved (https://core.trac.wordpress.org/ticket/16828).
551 *
552 * @since 1.8.14
553 */
554 function give_donation_metabox_menu() {
555
556 // Get Current Screen.
557 $screen = get_current_screen();
558
559 // Proceed, if current screen is navigation menus.
560 if ( 'nav-menus' === $screen->id && give_is_setting_enabled( give_get_option( 'forms_singular' ) ) && ! get_user_option( 'give_is_donation_forms_menu_updated' ) ) {
561
562 // Return false, if it fails to retrieve hidden meta box list and is not admin.
563 if ( ! is_admin() || ( ! $hidden_meta_boxes = get_user_option( 'metaboxhidden_nav-menus' ) ) ) {
564 return false;
565 }
566
567 // Return false, In case, we don't find 'Donation Form' in hidden meta box list.
568 if ( ! in_array( 'add-post-type-give_forms', $hidden_meta_boxes, true ) ) {
569 return false;
570 }
571
572 // Exclude 'Donation Form' value from hidden meta box's list.
573 $hidden_meta_boxes = array_diff( $hidden_meta_boxes, [ 'add-post-type-give_forms' ] );
574
575 // Get current user ID.
576 $user = wp_get_current_user();
577
578 update_user_option( $user->ID, 'metaboxhidden_nav-menus', $hidden_meta_boxes, true );
579 update_user_option( $user->ID, 'give_is_donation_forms_menu_updated', true, true );
580 }
581 }
582
583 add_action( 'current_screen', 'give_donation_metabox_menu' );
584
585 /**
586 * Array_column backup usage
587 *
588 * This file is part of the array_column library.
589 *
590 * @since : 1.3.0.1
591 *
592 * @copyright Copyright (c) Ben Ramsey (http://benramsey.com)
593 * @license https://opensource.org/licenses/MIT MIT
594 */
595
596 if ( ! function_exists( 'array_column' ) ) {
597 /**
598 * Returns the values from a single column of the input array, identified by
599 * the $columnKey.
600 *
601 * Optionally, you may provide an $indexKey to index the values in the returned
602 * array by the values from the $indexKey column in the input array.
603 *
604 * @param array $input A multi-dimensional array (record set) from which to pull
605 * a column of values.
606 * @param int|string $columnKey The column of values to return. This value may be the
607 * integer key of the column you wish to retrieve, or it
608 * may be the string key name for an associative array.
609 * @param mixed $indexKey (Optional.) The column to use as the index/keys for
610 * the returned array. This value may be the integer key
611 * of the column, or it may be the string key name.
612 *
613 * @return array|boolean|null
614 */
615 function array_column( $input = null, $columnKey = null, $indexKey = null ) {
616 // Using func_get_args() in order to check for proper number of
617 // parameters and trigger errors exactly as the built-in array_column()
618 // does in PHP 5.5.
619 $argc = func_num_args();
620 $params = func_get_args();
621
622 if ( $argc < 2 ) {
623 trigger_error( sprintf( 'array_column() expects at least 2 parameters, %s given.', $argc ), E_USER_WARNING );
624
625 return null;
626 }
627
628 if ( ! is_array( $params[0] ) ) {
629 trigger_error( sprintf( 'array_column() expects parameter 1 to be array, %s given.', gettype( $params[0] ) ), E_USER_WARNING );
630
631 return null;
632 }
633
634 if ( ! is_int( $params[1] ) && ! is_float( $params[1] ) && ! is_string( $params[1] ) && $params[1] !== null && ! ( is_object( $params[1] ) && method_exists( $params[1], '__toString' ) ) ) {
635 trigger_error( 'array_column(): The column key should be either a string or an integer.', E_USER_WARNING );
636
637 return false;
638 }
639
640 if ( isset( $params[2] ) && ! is_int( $params[2] ) && ! is_float( $params[2] ) && ! is_string( $params[2] ) && ! ( is_object( $params[2] ) && method_exists( $params[2], '__toString' ) ) ) {
641 trigger_error( 'array_column(): The index key should be either a string or an integer.', E_USER_WARNING );
642
643 return false;
644 }
645
646 $paramsInput = $params[0];
647 $paramsColumnKey = ( $params[1] !== null ) ? (string) $params[1] : null;
648
649 $paramsIndexKey = null;
650 if ( isset( $params[2] ) ) {
651 if ( is_float( $params[2] ) || is_int( $params[2] ) ) {
652 $paramsIndexKey = (int) $params[2];
653 } else {
654 $paramsIndexKey = (string) $params[2];
655 }
656 }
657
658 $resultArray = [];
659
660 foreach ( $paramsInput as $row ) {
661 $key = $value = null;
662 $keySet = $valueSet = false;
663
664 if ( $paramsIndexKey !== null && array_key_exists( $paramsIndexKey, $row ) ) {
665 $keySet = true;
666 $key = (string) $row[ $paramsIndexKey ];
667 }
668
669 if ( $paramsColumnKey === null ) {
670 $valueSet = true;
671 $value = $row;
672 } elseif ( is_array( $row ) && array_key_exists( $paramsColumnKey, $row ) ) {
673 $valueSet = true;
674 $value = $row[ $paramsColumnKey ];
675 }
676
677 if ( $valueSet ) {
678 if ( $keySet ) {
679 $resultArray[ $key ] = $value;
680 } else {
681 $resultArray[] = $value;
682 }
683 }
684 }
685
686 return $resultArray;
687 }
688 }// End if().
689
690 /**
691 * Determines the receipt visibility status.
692 *
693 * @param int $donation_id Donation ID.
694 *
695 * @return bool Whether the receipt is visible or not.
696
697 * @since 4.16.6 Require the give_nl cookie to be a scalar string before using it as a donor lookup token.
698 * @since 1.3.2
699 */
700 function give_can_view_receipt( $donation_id ) {
701
702 global $give_receipt_args;
703
704 $donor = false;
705 $can_view_receipt = false;
706
707 // Bail out, if donation id doesn't exist.
708 if ( empty( $donation_id ) ) {
709 return $can_view_receipt;
710 }
711
712 $give_receipt_args['id'] = $donation_id;
713
714 // Add backward compatibility.
715 if ( ! is_numeric( $donation_id ) ) {
716 $give_receipt_args['id'] = give_get_donation_id_by_key( $donation_id );
717 }
718
719 // Return to download receipts from admin panel.
720 if ( current_user_can( 'export_give_reports' ) ) {
721
722 /**
723 * This filter will be used to modify can view receipt response when accessed from admin.
724 *
725 * @since 2.3.1
726 */
727 return apply_filters( 'give_can_admin_view_receipt', true );
728 }
729
730 if ( is_user_logged_in() || current_user_can( 'view_give_sensitive_data' ) ) {
731
732 // Proceed only, if user is logged in or can view sensitive Give data.
733 $donor = Give()->donors->get_donor_by( 'user_id', get_current_user_id() );
734
735 } elseif ( ! is_user_logged_in() ) {
736
737 // Check whether it is purchase session?
738 // This condition is to show receipt to donor after donation.
739 $purchase_session = give_get_purchase_session();
740
741 if (
742 ! empty( $purchase_session )
743 && absint( $purchase_session['donation_id'] ) === absint( $donation_id )
744 ) {
745 $donor = Give()->donors->get_donor_by( 'email', $purchase_session['user_email'] );
746 }
747
748 // Check whether it is receipt access session?
749 $receipt_session = give_get_receipt_session();
750 // The give_nl cookie must be a scalar string token; give_clean() does not coerce arrays
751 // to a string, so require is_string() explicitly before treating it as a token.
752 $email_access_token = ! empty( $_COOKIE['give_nl'] ) && is_string( $_COOKIE['give_nl'] )
753 ? give_clean( $_COOKIE['give_nl'] )
754 : false;
755
756 if (
757 ! empty( $receipt_session ) ||
758 (
759 give_is_setting_enabled( give_get_option( 'email_access' ) ) &&
760 ! empty( $email_access_token )
761 )
762 ) {
763 $donor = ! empty( $email_access_token )
764 ? Give()->donors->get_donor_by_token( $email_access_token )
765 : false;
766 }
767 }
768
769 // If donor object exists, compare the donation ids of donor with the donation receipt donor tries to access.
770 if ( is_object( $donor ) ) {
771 $is_donor_donated = in_array( (int) $donation_id, array_map( 'absint', explode( ',', $donor->payment_ids ) ), true );
772 $can_view_receipt = $is_donor_donated ? true : $can_view_receipt;
773
774 if ( ! $is_donor_donated ) {
775 Give()->session->set( 'donor_donation_mismatch', true );
776 }
777 }
778
779 return (bool) apply_filters( 'give_can_view_receipt', $can_view_receipt, $donation_id );
780
781 }
782
783 /**
784 * Fallback for cal_days_in_month
785 *
786 * Fallback in case the calendar extension is not loaded in PHP; Only supports Gregorian calendar
787 */
788 if ( ! function_exists( 'cal_days_in_month' ) ) {
789 /**
790 * cal_days_in_month
791 *
792 * @param int $calendar
793 * @param int $month
794 * @param int $year
795 *
796 * @return bool|string
797 */
798 function cal_days_in_month( $calendar, $month, $year ) {
799 return date( 't', mktime( 0, 0, 0, $month, 1, $year ) );
800 }
801 }
802
803 /**
804 * Get plugin info including status, type, and license validation.
805 *
806 * @return array Plugin info plus status, type, and license validation if
807 * available.
808 * @since 1.8.0
809 *
810 * @todo update this function to query give addon and additional
811 *
812 * This is an enhanced version of get_plugins() that returns the status
813 * (`active` or `inactive`) of all plugins, type of plugin (`add-on` or `other`
814 * and license validation for Give add-ons (`true` or `false`). Does not include
815 * MU plugins.
816 */
817 function give_get_plugins( $args = [] ) {
818 $plugins = get_plugins();
819 $active_plugin_paths = (array) get_option( 'active_plugins', [] );
820
821 if ( is_multisite() ) {
822 $network_activated_plugin_paths = array_keys( get_site_option( 'active_sitewide_plugins', [] ) );
823 $active_plugin_paths = array_merge( $active_plugin_paths, $network_activated_plugin_paths );
824 }
825
826 foreach ( $plugins as $plugin_path => $plugin_data ) {
827 // Is plugin active?
828 if ( in_array( $plugin_path, $active_plugin_paths ) ) {
829 $plugins[ $plugin_path ]['Status'] = 'active';
830 } else {
831 $plugins[ $plugin_path ]['Status'] = 'inactive';
832 }
833
834 $dirname = strtolower( dirname( $plugin_path ) );
835 $plugins[ $plugin_path ]['Dir'] = $dirname;
836 $plugins[ $plugin_path ]['Path'] = $plugin_path;
837
838 // A third party add-on may contain more then one author like sofort, so it is better to compare array.
839 $author = false !== strpos( $plugin_data['Author'], ',' )
840 ? array_map( 'trim', explode( ',', $plugin_data['Author'] ) )
841 : [ $plugin_data['Author'] ];
842
843 // Is the plugin a Give add-on?
844 if (
845 false !== strpos( $dirname, 'give-' )
846 && (
847 false !== strpos( $plugin_data['PluginURI'], 'givewp.com' )
848 || array_intersect( $author, [ 'WordImpress', 'GiveWP' ] )
849 )
850 ) {
851 // Plugin is a Give-addon.
852 $plugins[ $plugin_path ]['Type'] = 'add-on';
853
854 $license_active = Give_License::get_license_by_plugin_dirname( $dirname );
855
856 // Does a valid license exist?
857 $plugins[ $plugin_path ]['License'] = $license_active && 'valid' === $license_active['license'];
858
859 } else {
860 // Plugin is not a Give add-on.
861 $plugins[ $plugin_path ]['Type'] = 'other';
862 }
863 }
864
865 if ( ! empty( $args['only_add_on'] ) ) {
866 $plugins = array_filter(
867 $plugins,
868 static function( $plugin ) {
869 return 'add-on' === $plugin['Type'];
870 }
871 );
872 }
873
874 if ( ! empty( $args['only_premium_add_ons'] ) ) {
875 $premiumAddonsListManger = give( PremiumAddonsListManager::class );
876
877 foreach ( $plugins as $key => $plugin ) {
878 if ( 'add-on' !== $plugin['Type'] ) {
879 unset( $plugins[ $key ] );
880 }
881
882 if ( ! $premiumAddonsListManger->isPremiumAddons( $plugin['PluginURI'] ) ) {
883 unset( $plugins[ $key ] );
884 }
885 }
886 }
887
888 return $plugins;
889 }
890
891 /**
892 * Check if terms enabled or not for form.
893 *
894 * @param $form_id
895 *
896 * @return bool
897 * @since 1.8
898 */
899 function give_is_terms_enabled( $form_id ) {
900 $form_option = give_get_meta( $form_id, '_give_terms_option', true );
901
902 if ( give_is_setting_enabled( $form_option, 'global' ) && give_is_setting_enabled( give_get_option( 'terms' ) ) ) {
903 return true;
904
905 } elseif ( give_is_setting_enabled( $form_option ) ) {
906 return true;
907
908 } else {
909 return false;
910 }
911 }
912
913 /**
914 * Delete donation stats cache.
915 *
916 * @param string|array $date_range Date for stats.
917 * Date value should be in today, yesterday, this_week, last_week, this_month,
918 * last_month, this_quarter, last_quarter, this_year, last_year. For date value other,
919 * all cache will be removed.
920 *
921 * @param array $args
922 *
923 * @return WP_Error|bool
924 * @since 1.8.7
925 *
926 * @todo Resolve stats cache key naming issue. Currently it is difficult to regenerate cache key.
927 */
928 function give_delete_donation_stats( $date_range = '', $args = [] ) {
929
930 // Delete all cache.
931 $status = Give_Cache::delete( Give_Cache::get_options_like( 'give_stats' ) );
932
933 /**
934 * Fire the action when donation stats delete.
935 *
936 * @param string|array $date_range
937 * @param array $args
938 *
939 * @since 1.8.7
940 */
941 do_action( 'give_delete_donation_stats', $status, $date_range, $args );
942
943 return $status;
944 }
945
946 /**
947 * Check if admin creating new donation form or not.
948 *
949 * @return bool
950 * @since 2.0
951 */
952 function give_is_add_new_form_page() {
953 $status = false;
954
955 if ( false !== strpos( $_SERVER['REQUEST_URI'], '/wp-admin/post-new.php?post_type=give_forms' ) ) {
956 $status = true;
957 }
958
959 return $status;
960 }
961
962 /**
963 * Get Form/Payment meta.
964 *
965 * Note: This function will help you to get meta for payment and form.
966 * If you want to get meta for donors then use get_meta of Give_Donor and
967 * If you want to get meta for logs then use get_meta of Give_Logging->logmeta_db.
968 *
969 * @param int $id
970 * @param string $meta_key
971 * @param bool $single
972 * @param bool $default
973 * @param string $meta_type
974 *
975 * @return mixed
976 * @since 1.8.8
977 */
978 function give_get_meta( $id, $meta_key = '', $single = false, $default = false, $meta_type = '' ) {
979 switch ( $meta_type ) {
980 case 'donation':
981 $meta_value = Give()->payment_meta->get_meta( $id, $meta_key, $single );
982 break;
983
984 case 'form':
985 $meta_value = Give()->form_meta->get_meta( $id, $meta_key, $single );
986 break;
987
988 case 'donor':
989 $meta_value = Give()->donor_meta->get_meta( $id, $meta_key, $single );
990 break;
991
992 default:
993 $meta_value = get_post_meta( $id, $meta_key, $single );
994 }
995
996 /**
997 * Filter the meta value
998 *
999 * @since 1.8.8
1000 */
1001 $meta_value = apply_filters( 'give_get_meta', $meta_value, $id, $meta_key, $default, $meta_type );
1002
1003 if ( ( empty( $meta_key ) || empty( $meta_value ) ) && $default ) {
1004 $meta_value = $default;
1005 }
1006
1007 return $meta_value;
1008 }
1009
1010 /**
1011 * Update Form/Payment meta.
1012 *
1013 * @param int $id
1014 * @param string $meta_key
1015 * @param mixed $meta_value
1016 * @param mixed $prev_value
1017 * @param string $meta_type
1018 *
1019 * @return mixed
1020 * @since 1.8.8
1021 */
1022 function give_update_meta( $id, $meta_key, $meta_value, $prev_value = '', $meta_type = '' ) {
1023 switch ( $meta_type ) {
1024 case 'donation':
1025 $status = Give()->payment_meta->update_meta( $id, $meta_key, $meta_value, $prev_value );
1026 break;
1027
1028 case 'form':
1029 $status = Give()->form_meta->update_meta( $id, $meta_key, $meta_value, $prev_value );
1030 break;
1031
1032 case 'donor':
1033 $status = Give()->donor_meta->update_meta( $id, $meta_key, $meta_value, $prev_value );
1034 break;
1035
1036 default:
1037 $status = update_post_meta( $id, $meta_key, $meta_value, $prev_value );
1038 }
1039
1040 /**
1041 * Filter the meta value update status
1042 *
1043 * @since 1.8.8
1044 */
1045 return apply_filters( 'give_update_meta', $status, $id, $meta_key, $meta_value, $meta_type );
1046 }
1047
1048 /**
1049 * Delete Form/Payment meta.
1050 *
1051 * @param int $id
1052 * @param string $meta_key
1053 * @param string $meta_value
1054 * @param string $meta_type
1055 *
1056 * @return mixed
1057 * @since 1.8.8
1058 */
1059 function give_delete_meta( $id, $meta_key, $meta_value = '', $meta_type = '' ) {
1060 switch ( $meta_type ) {
1061 case 'donation':
1062 $status = Give()->payment_meta->delete_meta( $id, $meta_key, $meta_value );
1063 break;
1064
1065 case 'form':
1066 $status = Give()->form_meta->delete_meta( $id, $meta_key, $meta_value );
1067 break;
1068
1069 case 'donor':
1070 $status = Give()->donor_meta->delete_meta( $id, $meta_key, $meta_value );
1071 break;
1072
1073 default:
1074 $status = delete_post_meta( $id, $meta_key, $meta_value );
1075 }
1076
1077 /**
1078 * Filter the meta value delete status
1079 *
1080 * @since 1.8.8
1081 */
1082 return apply_filters( 'give_delete_meta', $status, $id, $meta_key, $meta_value, $meta_type );
1083 }
1084
1085 /**
1086 * Check if the upgrade routine has been run for a specific action
1087 *
1088 * @param string $upgrade_action The upgrade action to check completion for
1089 *
1090 * @return bool If the action has been added to the completed actions array
1091 * @since 1.0
1092 */
1093 function give_has_upgrade_completed( $upgrade_action = '' ) {
1094 // Bailout.
1095 if ( empty( $upgrade_action ) ) {
1096 return false;
1097 }
1098
1099 // Fresh install?
1100 // If fresh install then all upgrades will be consider as completed.
1101 $is_fresh_install = ! Give_Cache_Setting::get_option( 'give_version' );
1102 if ( $is_fresh_install ) {
1103 return true;
1104 }
1105
1106 $completed_upgrades = give_get_completed_upgrades();
1107
1108 return in_array( $upgrade_action, $completed_upgrades );
1109
1110 }
1111
1112 /**
1113 * For use when doing 'stepped' upgrade routines, to see if we need to start somewhere in the middle
1114 *
1115 * @return mixed When nothing to resume returns false, otherwise starts the upgrade where it left off
1116 * @since 1.8
1117 */
1118 function give_maybe_resume_upgrade() {
1119 $doing_upgrade = get_option( 'give_doing_upgrade', false );
1120 if ( empty( $doing_upgrade ) ) {
1121 return false;
1122 }
1123
1124 return $doing_upgrade;
1125 }
1126
1127 /**
1128 * Adds an upgrade action to the completed upgrades array
1129 *
1130 * @param string $upgrade_action The action to add to the completed upgrades array
1131 *
1132 * @return bool If the function was successfully added
1133 * @since 1.0
1134 */
1135 function give_set_upgrade_complete( $upgrade_action = '' ) {
1136
1137 if ( empty( $upgrade_action ) ) {
1138 return false;
1139 }
1140
1141 $completed_upgrades = give_get_completed_upgrades();
1142 $completed_upgrades[] = $upgrade_action;
1143
1144 // Remove any blanks, and only show uniques.
1145 $completed_upgrades = array_unique( array_values( $completed_upgrades ) );
1146
1147 /**
1148 * Fire the action when any upgrade set to complete.
1149 *
1150 * @since 1.8.12
1151 */
1152 do_action( 'give_set_upgrade_completed', $upgrade_action, $completed_upgrades );
1153
1154 return update_option( 'give_completed_upgrades', $completed_upgrades, false );
1155 }
1156
1157 /**
1158 * Get's the array of completed upgrade actions
1159 *
1160 * @return array The array of completed upgrades
1161 * @since 1.0
1162 */
1163 function give_get_completed_upgrades() {
1164 return (array) Give_Cache_Setting::get_option( 'give_completed_upgrades' );
1165 }
1166
1167 /**
1168 * In 2.0 we updated table for log, payment and form.
1169 *
1170 * Note: internal purpose only.
1171 *
1172 * @param string $type Context for table
1173 *
1174 * @return null|array
1175 *
1176 * @since 4.9.0 rename function - PHP 8 compatibility
1177 * @since 2.0
1178 * @global wpdb $wpdb
1179 */
1180 function give_v20_bc_table_details( $type ) {
1181 global $wpdb;
1182 $table = [];
1183
1184 // Bailout.
1185 if ( empty( $type ) ) {
1186 return null;
1187 }
1188
1189 switch ( $type ) {
1190 case 'form':
1191 $table['name'] = $wpdb->formmeta;
1192 $table['column']['id'] = 'form_id';
1193
1194 break;
1195
1196 case 'payment':
1197 $table['name'] = $wpdb->donationmeta;
1198 $table['column']['id'] = Give()->payment_meta->get_meta_type() . '_id';
1199 }
1200
1201 // Backward compatibility.
1202 if ( ! give_has_upgrade_completed( 'v20_move_metadata_into_new_table' ) ) {
1203 $table['name'] = $wpdb->postmeta;
1204 $table['column']['id'] = 'post_id';
1205 }
1206
1207 return $table;
1208 }
1209
1210 /**
1211 * Remove the Give transaction pages from WP search results.
1212 *
1213 * @param WP_Query $query
1214 *
1215 * @since 1.8.13
1216 */
1217 function give_remove_pages_from_search( $query ) {
1218
1219 if ( ! $query->is_admin && $query->is_search && $query->is_main_query() ) {
1220
1221 $transaction_failed = give_get_option( 'failure_page', 0 );
1222 $success_page = give_get_option( 'success_page', 0 );
1223
1224 $args = apply_filters(
1225 'give_remove_pages_from_search',
1226 [
1227 $transaction_failed,
1228 $success_page,
1229 ],
1230 $query
1231 );
1232 $query->set( 'post__not_in', $args );
1233 }
1234 }
1235
1236 add_action( 'pre_get_posts', 'give_remove_pages_from_search', 10, 1 );
1237
1238 /**
1239 * Inserts a new key/value before a key in the array.
1240 *
1241 * @param string $key The key to insert before.
1242 * @param array $array An array to insert in to.
1243 * @param string $new_key The key to insert.
1244 * @param array|string $new_value An value to insert.
1245 *
1246 * @return array The new array if the key exists, the passed array otherwise.
1247 *
1248 * @since 1.8.13
1249 *
1250 * @see array_insert_before()
1251 */
1252 function give_array_insert_before( $key, array &$array, $new_key, $new_value ) {
1253 if ( array_key_exists( $key, $array ) ) {
1254 $new = [];
1255 foreach ( $array as $k => $value ) {
1256 if ( $k === $key ) {
1257 $new[ $new_key ] = $new_value;
1258 }
1259 $new[ $k ] = $value;
1260 }
1261
1262 return $new;
1263 }
1264
1265 return $array;
1266 }
1267
1268 /**
1269 * Inserts a new key/value after a key in the array.
1270 *
1271 * @param string $key The key to insert after.
1272 * @param array $array An array to insert in to.
1273 * @param string $new_key The key to insert.
1274 * @param array|string $new_value An value to insert.
1275 *
1276 * @return array The new array if the key exists, the passed array otherwise.
1277 *
1278 * @since 1.8.13
1279 *
1280 * @see array_insert_before()
1281 */
1282 function give_array_insert_after( $key, array &$array, $new_key, $new_value ) {
1283 if ( array_key_exists( $key, $array ) ) {
1284 $new = [];
1285 foreach ( $array as $k => $value ) {
1286 $new[ $k ] = $value;
1287 if ( $k === $key ) {
1288 $new[ $new_key ] = $new_value;
1289 }
1290 }
1291
1292 return $new;
1293 }
1294
1295 return $array;
1296 }
1297
1298 /**
1299 * Pluck a certain field out of each object in a list.
1300 *
1301 * This has the same functionality and prototype of
1302 * array_column() (PHP 5.5) but also supports objects.
1303 *
1304 * @param array $list List of objects or arrays
1305 * @param int|string $field Field from the object to place instead of the entire object
1306 * @param int|string $index_key Optional. Field from the object to use as keys for the new array.
1307 * Default null.
1308 *
1309 * @return array Array of found values. If `$index_key` is set, an array of found values with keys
1310 * corresponding to `$index_key`. If `$index_key` is null, array keys from the original
1311 * `$list` will be preserved in the results.
1312 * @since 1.8.13
1313 */
1314 function give_list_pluck( $list, $field, $index_key = null ) {
1315
1316 if ( ! $index_key ) {
1317 /**
1318 * This is simple. Could at some point wrap array_column()
1319 * if we knew we had an array of arrays.
1320 */
1321 foreach ( $list as $key => $value ) {
1322 if ( is_object( $value ) ) {
1323 if ( isset( $value->$field ) ) {
1324 $list[ $key ] = $value->$field;
1325 }
1326 } else {
1327 if ( isset( $value[ $field ] ) ) {
1328 $list[ $key ] = $value[ $field ];
1329 }
1330 }
1331 }
1332
1333 return $list;
1334 }
1335
1336 /*
1337 * When index_key is not set for a particular item, push the value
1338 * to the end of the stack. This is how array_column() behaves.
1339 */
1340 $newlist = [];
1341 foreach ( $list as $value ) {
1342 if ( is_object( $value ) ) {
1343 if ( isset( $value->$index_key ) ) {
1344 $newlist[ $value->$index_key ] = $value->$field;
1345 } else {
1346 $newlist[] = $value->$field;
1347 }
1348 } else {
1349 if ( isset( $value[ $index_key ] ) ) {
1350 $newlist[ $value[ $index_key ] ] = $value[ $field ];
1351 } else {
1352 $newlist[] = $value[ $field ];
1353 }
1354 }
1355 }
1356
1357 $list = $newlist;
1358
1359 return $list;
1360 }
1361
1362 /**
1363 * Add meta data field to a donor.
1364 *
1365 * @param int $donor_id Donor ID.
1366 * @param string $meta_key Metadata name.
1367 * @param mixed $meta_value Metadata value. Must be serializable if non-scalar.
1368 * @param bool $unique Optional. Whether the same key should not be added.
1369 * Default false.
1370 *
1371 * @return int|false Meta ID on success, false on failure.
1372 * @since 1.8.13
1373 */
1374 function add_donor_meta( $donor_id, $meta_key, $meta_value, $unique = false ) {
1375 return add_metadata( 'give_customer', $donor_id, $meta_key, $meta_value, $unique );
1376 }
1377
1378 /**
1379 * Remove metadata matching criteria from a Donor meta.
1380 *
1381 * You can match based on the key, or key and value. Removing based on key and
1382 * value, will keep from removing duplicate metadata with the same key. It also
1383 * allows removing all metadata matching key, if needed.
1384 *
1385 * @param int $donor_id Donor ID
1386 * @param string $meta_key Metadata name.
1387 * @param mixed $meta_value Optional. Metadata value.
1388 *
1389 * @return bool True on success, false on failure.
1390 * @since 1.8.13
1391 */
1392 function delete_donor_meta( $donor_id, $meta_key, $meta_value = '' ) {
1393 return delete_metadata( 'give_customer', $donor_id, $meta_key, $meta_value );
1394 }
1395
1396 /**
1397 * Retrieve donor meta field for a donor meta table.
1398 *
1399 * @param int $donor_id Donor ID.
1400 * @param string $key Optional. The meta key to retrieve. By default, returns data for all keys.
1401 * @param bool $single Whether to return a single value.
1402 *
1403 * @return mixed Will be an array if $single is false. Will be value of meta data field if $single
1404 * is true.
1405 * @since 1.8.13
1406 */
1407 function get_donor_meta( $donor_id, $key = '', $single = false ) {
1408 return get_metadata( 'give_customer', $donor_id, $key, $single );
1409 }
1410
1411 /**
1412 * Update customer meta field based on Donor ID.
1413 *
1414 * If the meta field for the donor does not exist, it will be added.
1415 *
1416 * @param int $donor_id Donor ID.
1417 * @param string $meta_key Metadata key.
1418 * @param mixed $meta_value Metadata value.
1419 * @param mixed $prev_value Optional. Previous value to check before removing.
1420 *
1421 * @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
1422 * @since 1.8.13
1423 */
1424 function update_donor_meta( $donor_id, $meta_key, $meta_value, $prev_value = '' ) {
1425 return update_metadata( 'give_customer', $donor_id, $meta_key, $meta_value, $prev_value );
1426 }
1427
1428
1429 /**
1430 * Give recalculate income and donation of the donation from ID
1431 *
1432 * @param int $form_id Form id of which recalculation needs to be done.
1433 *
1434 * @return void
1435 * @since 1.8.13
1436 */
1437 function give_recount_form_income_donation( $form_id = 0 ) {
1438 // Check if form id is not empty.
1439 if ( ! empty( $form_id ) ) {
1440 /**
1441 * Filter to modify payment status.
1442 *
1443 * @since 1.8.13
1444 */
1445 $accepted_statuses = apply_filters( 'give_recount_accepted_statuses', [ 'publish' ] );
1446
1447 /**
1448 * Filter to modify args of payment query before recalculating the form total
1449 *
1450 * @since 1.8.13
1451 */
1452 $args = apply_filters(
1453 'give_recount_form_stats_args',
1454 [
1455 'give_forms' => $form_id,
1456 'status' => $accepted_statuses,
1457 'number' => - 1,
1458 'fields' => 'ids',
1459 ]
1460 );
1461
1462 $totals = [
1463 'sales' => 0,
1464 'earnings' => 0,
1465 ];
1466
1467 $payments = new Give_Payments_Query( $args );
1468 $payments = $payments->get_payments();
1469
1470 if ( $payments ) {
1471 foreach ( $payments as $payment ) {
1472 // Ensure acceptable status only.
1473 if ( ! in_array( $payment->post_status, $accepted_statuses ) ) {
1474 continue;
1475 }
1476
1477 // Ensure only payments for this form are counted.
1478 if ( $payment->form_id != $form_id ) {
1479 continue;
1480 }
1481
1482 $totals['sales'] ++;
1483 $totals['earnings'] += $payment->total;
1484
1485 }
1486 }
1487 give_update_meta( $form_id, '_give_form_sales', $totals['sales'] );
1488 give_update_meta( $form_id, '_give_form_earnings', give_sanitize_amount_for_db( $totals['earnings'] ) );
1489 }// End if().
1490 }
1491
1492
1493 /**
1494 * Get attribute string
1495 *
1496 * @param array $attributes
1497 * @param array $default_attributes
1498 *
1499 * @return string
1500 * @since 1.8.17
1501 */
1502 function give_get_attribute_str( $attributes, $default_attributes = [] ) {
1503 $attribute_str = '';
1504
1505 if ( isset( $attributes['attributes'] ) ) {
1506 $attributes = $attributes['attributes'];
1507 }
1508
1509 if ( ! empty( $default_attributes ) ) {
1510 $attributes = wp_parse_args( $attributes, $default_attributes );
1511 }
1512
1513 if ( empty( $attributes ) ) {
1514 return $attribute_str;
1515 }
1516
1517 foreach ( $attributes as $tag => $value ) {
1518 if ( 'value' == $tag ) {
1519 $value = esc_attr( $value );
1520 }
1521
1522 $attribute_str .= " {$tag}=\"{$value}\"";
1523 }
1524
1525 return trim( $attribute_str );
1526 }
1527
1528 /**
1529 * Get the upload dir path
1530 *
1531 * @return string $wp_upload_dir;
1532 * @since 1.8.17
1533 */
1534 function give_get_wp_upload_dir() {
1535 $wp_upload_dir = wp_upload_dir();
1536
1537 return ( ! empty( $wp_upload_dir['path'] ) ? $wp_upload_dir['path'] : false );
1538 }
1539
1540 /**
1541 * Get the data from uploaded JSON file
1542 *
1543 * @param string $file_name filename of the json file that is being uploaded
1544 *
1545 * @return string|bool $file_contents File content
1546 * @since 1.8.17
1547 */
1548 function give_get_core_settings_json( $file_name ) {
1549 $upload_dir = give_get_wp_upload_dir();
1550 $file_path = $upload_dir . '/' . $file_name;
1551
1552 if ( is_wp_error( $file_path ) || empty( $file_path ) ) {
1553 Give_Admin_Settings::add_error( 'give-import-csv', __( 'Please upload or provide a valid JSON file.', 'give' ) );
1554 }
1555
1556 $file_contents = file_get_contents( $file_path );
1557
1558 return $file_contents;
1559 }
1560
1561 /**
1562 * Get number of donation to show when user is not login.
1563 *
1564 * @return int $country The two letter country code for the site's base country
1565 * @since 1.8.17
1566 */
1567 function give_get_limit_display_donations() {
1568 return give_get_option( 'limit_display_donations', 1 );
1569 }
1570
1571 /**
1572 * Add footer to the table when donor is view the donation history page with out login
1573 *
1574 * @since 1.8.17
1575 */
1576 function give_donation_history_table_end() {
1577 $email = Give()->session->get( 'give_email' );
1578 ?>
1579 <tfoot>
1580 <tr>
1581 <td colspan="9999">
1582 <div class="give-security-wrap">
1583 <div class="give-security-column give-security-description-wrap">
1584 <?php
1585 echo sprintf( __( 'For security reasons, please confirm your email address (%s) to view your complete donation history.', 'give' ), $email );
1586 ?>
1587 </div>
1588 <div class="give-security-column give-security-button-wrap">
1589 <a href="#" data-email="<?php echo $email; ?>" id="give-confirm-email-btn"
1590 class="give-confirm-email-btn give-btn">
1591 <?php _e( 'Confirm Email', 'give' ); ?>
1592 </a>
1593 <span><?php _e( 'Email Sent!', 'give' ); ?></span>
1594 </div>
1595 </div>
1596 </td>
1597 </tr>
1598 </tfoot>
1599 <?php
1600 }
1601
1602
1603 /**
1604 * Wrapper for _doing_it_wrong.
1605 *
1606 * @param string $function
1607 * @param string $message
1608 * @param string $version deprecated
1609 *
1610 * @return void
1611 * @since 1.8.18
1612 * @since 2.5.13 Refactor function
1613 */
1614 function give_doing_it_wrong( $function, $message, $version = null ) {
1615 /**
1616 * Fires while calling function incorrectly.
1617 *
1618 * Allow you to hook to incorrect function call.
1619 *
1620 * @param string $function The function that was called.
1621 * @param string $replacement Optional. The function that should have been called.
1622 * @param string $version The plugin version that deprecated the function.
1623 *
1624 * @since 2.5.13
1625 */
1626 do_action( 'give_doing_it_wrong', $function, $message, $version );
1627
1628 $show_errors = current_user_can( 'manage_options' );
1629
1630 // Allow plugin to filter the output error trigger.
1631 if ( WP_DEBUG && apply_filters( 'give_doing_it_wrong_trigger_error', $show_errors ) ) {
1632 trigger_error( sprintf( __( '%1$s was called <strong>incorrectly</strong>. %2$s', 'give' ), $function, $message ) );
1633 trigger_error( print_r( wp_debug_backtrace_summary(), 1 ) );// Limited to previous 1028 characters, but since we only need to move back 1 in stack that should be fine.
1634 }
1635 }
1636
1637
1638 /**
1639 * Remove limit from running php script complete.
1640 *
1641 * @since 1.8.18
1642 */
1643 function give_ignore_user_abort() {
1644 ignore_user_abort( true );
1645
1646 if ( ! give_is_func_disabled( 'set_time_limit' )) {
1647 set_time_limit( 0 );
1648 }
1649 }
1650
1651 /**
1652 * Get post type count.
1653 *
1654 * @param string $post_type
1655 * @param array $args
1656 *
1657 * @return int
1658 * @since 2.0.2
1659 */
1660 function give_get_total_post_type_count( $post_type = '', $args = [] ) {
1661 global $wpdb;
1662 $where = '';
1663
1664 if ( ! $post_type ) {
1665 return 0;
1666 }
1667
1668 // Bulit where query
1669 if ( ! empty( $post_type ) ) {
1670 $where .= ' WHERE';
1671
1672 if ( is_array( $post_type ) ) {
1673 $where .= " post_type='" . implode( "' OR post_type='", $post_type ) . "'";
1674 } else {
1675 $where .= " post_type='{$post_type}'";
1676 }
1677 }
1678
1679 $result = $wpdb->get_var( "SELECT count(ID) FROM {$wpdb->posts}{$where}" );
1680
1681 return absint( $result );
1682 }
1683
1684 /**
1685 * Define a constant if it is not already defined.
1686 *
1687 * @param string $name Constant name.
1688 * @param string $value Value.
1689 *
1690 * @credit WooCommerce
1691 * @since 2.0.5
1692 */
1693 function give_maybe_define_constant( $name, $value ) {
1694 if ( ! defined( $name ) ) {
1695 define( $name, $value );
1696 }
1697 }
1698
1699 /**
1700 * Decode time short tag in string
1701 *
1702 * @param string $string
1703 * @param int $timestamp
1704 *
1705 * @return string
1706 * @since 2.1.0
1707 */
1708 function give_time_do_tags( $string, $timestamp = 0 ) {
1709 $current_time = ! empty( $timestamp ) ? $timestamp : current_time( 'timestamp' );
1710
1711 $formatted_string = str_replace(
1712 [
1713 '{D}',
1714 '{DD}',
1715 '{M}',
1716 '{MM}',
1717 '{YY}',
1718 '{YYYY}',
1719 '{H}',
1720 '{HH}',
1721 '{N}',
1722 '{S}',
1723 ],
1724 [
1725 date( 'j', $current_time ),
1726 date( 'd', $current_time ),
1727 date( 'n', $current_time ),
1728 date( 'm', $current_time ),
1729 date( 'Y', $current_time ),
1730 date( 'Y', $current_time ),
1731 date( 'G', $current_time ),
1732 date( 'H', $current_time ),
1733 date( 's', $current_time ),
1734 ],
1735 $string
1736 );
1737
1738 /**
1739 * Filter the parsed string.
1740 *
1741 * @since 2.1.0
1742 */
1743 return apply_filters( 'give_time_do_tags', $formatted_string, $string, $timestamp );
1744 }
1745
1746
1747 /**
1748 * Check if Company field enabled or not for form or globally.
1749 *
1750 * @param $form_id
1751 *
1752 * @return bool
1753 * @since 2.1
1754 */
1755 function give_is_company_field_enabled( $form_id ) {
1756 $form_setting_val = give_get_meta( $form_id, '_give_company_field', true );
1757 $global_setting_val = give_get_option( 'company_field' );
1758
1759 if ( ! empty( $form_setting_val ) ) {
1760 if ( give_is_setting_enabled( $form_setting_val, [ 'required', 'optional' ] ) ) {
1761 return true;
1762 } elseif ( 'global' === $form_setting_val && give_is_setting_enabled(
1763 $global_setting_val,
1764 [
1765 'required',
1766 'optional',
1767 ]
1768 ) ) {
1769 return true;
1770 } else {
1771 return false;
1772 }
1773 } elseif ( give_is_setting_enabled( $global_setting_val, [ 'required', 'optional' ] ) ) {
1774 return true;
1775
1776 } else {
1777 return false;
1778 }
1779 }
1780
1781 /**
1782 * Check if Last Name field is required
1783 *
1784 * @param $form_id
1785 *
1786 * @return bool
1787 * @since 2.15.0
1788 */
1789 function give_is_last_name_required( $form_id ) {
1790 $form_setting_val = give_get_meta( $form_id, '_give_last_name_field_required', true );
1791 $global_setting_val = give_get_option( 'last_name_field_required' );
1792
1793 if ( ! empty( $form_setting_val ) ) {
1794 if ( 'required' === $form_setting_val ) {
1795 return true;
1796 }
1797
1798 return 'global' === $form_setting_val && 'required' === $global_setting_val;
1799 }
1800
1801 return 'required' === $global_setting_val;
1802 }
1803
1804 /**
1805 * Check if anonymous donation field enabled or not for form or globally.
1806 *
1807 * @param $form_id
1808 *
1809 * @return bool
1810 * @since 2.1
1811 */
1812 function give_is_anonymous_donation_field_enabled( $form_id ) {
1813 $form_setting_val = give_get_meta( $form_id, '_give_anonymous_donation', true, 'global' );
1814 $global_setting_val = give_get_option( 'anonymous_donation', 'disabled' );
1815
1816 if ( ! empty( $form_setting_val ) ) {
1817 if ( give_is_setting_enabled( $form_setting_val ) ) {
1818 return true;
1819 } elseif ( 'global' === $form_setting_val && give_is_setting_enabled( $global_setting_val ) ) {
1820 return true;
1821 } else {
1822 return false;
1823 }
1824 } elseif ( give_is_setting_enabled( $global_setting_val ) ) {
1825 return true;
1826 }
1827
1828 return false;
1829 }
1830
1831 /**
1832 * Check if donor comment field enabled or not for form or globally.
1833 *
1834 * @param $form_id
1835 *
1836 * @return bool
1837 * @since 2.1
1838 */
1839 function give_is_donor_comment_field_enabled( $form_id ) {
1840 $form_setting_val = give_get_meta( $form_id, '_give_donor_comment', true, 'global' );
1841 $global_setting_val = give_get_option( 'donor_comment', 'disabled' );
1842
1843 if ( ! empty( $form_setting_val ) ) {
1844 if ( give_is_setting_enabled( $form_setting_val ) ) {
1845 return true;
1846 } elseif ( 'global' === $form_setting_val && give_is_setting_enabled( $global_setting_val ) ) {
1847 return true;
1848 } else {
1849 return false;
1850 }
1851 } elseif ( give_is_setting_enabled( $global_setting_val ) ) {
1852 return true;
1853 }
1854
1855 return false;
1856
1857 }
1858
1859 /**
1860 * Get add-on user meta value information
1861 * Note: only for internal use.
1862 *
1863 * @param string $banner_addon_name Give add-on name.
1864 *
1865 * @return array
1866 *
1867 * @since 4.9.0 rename function - PHP 8 compatibility
1868 * @since 2.1.0
1869 */
1870 function give_get_active_by_user_meta( $banner_addon_name ) {
1871 global $wpdb;
1872
1873 // Get the option key.
1874 $option_name = Give_Addon_Activation_Banner::get_banner_user_meta_key( $banner_addon_name );
1875 $data = [];
1876
1877 if ( empty( $GLOBALS['give_addon_activated_by_user'] ) ) {
1878 $GLOBALS['give_addon_activated_by_user'] = [];
1879
1880 // Get the meta of activation banner by user.
1881 $activation_banners = $wpdb->get_results(
1882 "
1883 SELECT option_name, option_value
1884 FROM {$wpdb->options}
1885 WHERE option_name LIKE '%_active_by_user%'
1886 AND option_name LIKE '%give_addon%'
1887 ",
1888 ARRAY_A
1889 );
1890
1891 if ( ! empty( $activation_banners ) ) {
1892 $GLOBALS['give_addon_activated_by_user'] = array_combine(
1893 wp_list_pluck( $activation_banners, 'option_name' ),
1894 wp_list_pluck( $activation_banners, 'option_value' )
1895 );
1896 }
1897 }
1898
1899 if ( array_key_exists( $option_name, $GLOBALS['give_addon_activated_by_user'] ) ) {
1900 $data = maybe_unserialize( $GLOBALS['give_addon_activated_by_user'][ $option_name ] );
1901 }
1902
1903 return $data;
1904 }
1905
1906 /**
1907 * Get time interval for which nonce is valid
1908 *
1909 * @return int
1910 * @since 2.1.3
1911 */
1912 function give_get_nonce_life() {
1913 /**
1914 * Filters the lifespan of nonces in seconds.
1915 *
1916 * @see wp-inlucdes/pluggable.php:wp_nonce_tick
1917 */
1918 return (int) apply_filters( 'nonce_life', DAY_IN_SECONDS );
1919 }
1920
1921 /**
1922 * Get nonce field without id
1923 *
1924 * @param string $action
1925 * @param string $name
1926 * @param bool $referer
1927 *
1928 * @return string
1929 * @since 2.1.3
1930 */
1931 function give_get_nonce_field( $action, $name, $referer = false ) {
1932 return str_replace(
1933 "id=\"{$name}\"",
1934 '',
1935 wp_nonce_field( $action, $name, $referer, false )
1936 );
1937 }
1938
1939 /**
1940 * Display/Return a formatted goal for a donation form
1941 *
1942 * @since 3.16.0 Add form_id to the array return
1943 * @since 2.1
1944 *
1945 * @param int|Give_Donate_Form $form Form ID or Form Object.
1946 *
1947 * @return array
1948 */
1949 function give_goal_progress_stats( $form ) {
1950
1951 if ( ! $form instanceof Give_Donate_Form ) {
1952 $form = new Give_Donate_Form( $form );
1953 }
1954
1955 $goal_format = give_get_form_goal_format( $form->ID );
1956
1957 /**
1958 * Filter the form.
1959 * @since 1.8.8
1960 */
1961 $total_goal = apply_filters( 'give_goal_amount_target_output', round( give_maybe_sanitize_amount( $form->goal ), 2 ), $form->ID, $form );
1962
1963 switch ( $goal_format ) {
1964 case 'donation':
1965 /**
1966 * Filter the form donations.
1967 *
1968 * @since 2.1
1969 */
1970 $actual = apply_filters( 'give_goal_donations_raised_output', $form->sales, $form->ID, $form );
1971 break;
1972 case 'donors':
1973 /**
1974 * Filter to modify total number if donor for the donation form.
1975 *
1976 * @param int $donors Total number of donors that donated to the form.
1977 * @param int $form_id Donation Form ID.
1978 * @param Give_Donate_Form $form instances of Give_Donate_Form.
1979 *
1980 * @return int $donors Total number of donors that donated to the form.
1981 * @since 2.1.3
1982 */
1983 $actual = apply_filters( 'give_goal_donors_target_output', give_get_form_donor_count( $form->ID ), $form->ID, $form );
1984 break;
1985 default:
1986 /**
1987 * Filter the form income.
1988 *
1989 * @since 3.16.0 Revert changes implemented on the 3.14.0 version
1990 * @since 3.14.0 Replace "$form->earnings" with (new DonationQuery())->form($form->ID)->sumIntendedAmount()
1991 * @since 1.8.8
1992 */
1993 $actual = apply_filters( 'give_goal_amount_raised_output', $form->earnings, $form->ID, $form );
1994 break;
1995 }
1996
1997 $progress = $total_goal ? round( ( $actual / $total_goal ) * 100, 2 ) : 0;
1998
1999 $stats_array = [
2000 'raw_actual' => $actual,
2001 'raw_goal' => $total_goal,
2002 ];
2003
2004 /**
2005 * Filter the goal progress output
2006 *
2007 * @since 1.8.8
2008 */
2009 $progress = apply_filters( 'give_goal_amount_funded_percentage_output', $progress, $form->ID, $form );
2010
2011 // Define Actual Goal based on the goal format.
2012 switch ( $goal_format ) {
2013 case 'percentage':
2014 $actual = "{$progress}%";
2015 $total_goal = '';
2016 break;
2017
2018 case 'amount' === $goal_format:
2019 $actual = give_currency_filter( give_format_amount( $actual ) );
2020 $total_goal = give_currency_filter( give_format_amount( $total_goal ) );
2021 break;
2022
2023 default:
2024 $actual = give_format_amount( $actual, [ 'decimal' => false ] );
2025 $total_goal = give_format_amount( $total_goal, [ 'decimal' => false ] );
2026 break;
2027 }
2028
2029 $stats_array = array_merge(
2030 [
2031 'progress' => $progress,
2032 'actual' => $actual,
2033 'goal' => $total_goal,
2034 'format' => $goal_format,
2035 'form_id' => $form->ID
2036 ],
2037 $stats_array
2038 );
2039
2040 /**
2041 * Filter the goal stats
2042 *
2043 * @since 2.1
2044 */
2045 return apply_filters( 'give_goal_progress_stats', $stats_array );
2046 }
2047
2048 /**
2049 * Get the admin messages key to show the notices.
2050 *
2051 * @return array $message admin message key.
2052 * @since 2.1.4
2053 */
2054 function give_get_admin_messages_key() {
2055 $messages = empty( $_GET['give-messages'] ) ? [] : give_clean( $_GET['give-messages'] );
2056
2057 // backward compatibility.
2058 if ( ! empty( $_GET['give-message'] ) ) {
2059 $messages[] = give_clean( $_GET['give-message'] );
2060 }
2061
2062 /**
2063 * Filter to modify the admin messages key.
2064 *
2065 * @param array $message admin message key.
2066 *
2067 * @return array $message admin message key.
2068 * @since 2.1.4
2069 */
2070 return (array) apply_filters( 'give_get_admin_messages_key', $messages );
2071 }
2072
2073 /**
2074 * Get User Agent String.
2075 *
2076 * @return array|string
2077 * @since 2.1.4
2078 */
2079 function give_get_user_agent() {
2080
2081 // Get User Agent.
2082 $user_agent = ! empty( $_SERVER['HTTP_USER_AGENT'] ) ? give_clean( $_SERVER['HTTP_USER_AGENT'] ) : ''; // WPCS: input var ok.
2083
2084 return $user_agent;
2085 }
2086
2087 /**
2088 * Set a cookie - wrapper for setcookie using WP constants.
2089 *
2090 * @param string $name Name of the cookie being set.
2091 * @param string $value Value of the cookie.
2092 * @param integer $expire Expiry of the cookie.
2093 * @param bool $secure Whether the cookie should be served only over https.
2094 *
2095 * @since 2.2.0
2096 */
2097 function give_setcookie( $name, $value, $expire = 0, $secure = false ) {
2098 if ( ! headers_sent() ) {
2099 setcookie(
2100 $name,
2101 $value,
2102 $expire,
2103 COOKIEPATH ? COOKIEPATH : '/',
2104 COOKIE_DOMAIN,
2105 $secure,
2106 apply_filters( 'give_cookie_httponly', false, $name, $value, $expire, $secure )
2107 );
2108 }
2109 }
2110
2111 /**
2112 * Get formatted billing address.
2113 *
2114 * @param array $address
2115 *
2116 * @return string Formatted address.
2117 * @since 2.2.0
2118 */
2119 function give_get_formatted_address( $address = [] ) {
2120 $formatted_address = '';
2121
2122 /**
2123 * Address format.
2124 *
2125 * @since 2.2.0
2126 */
2127 $address_format = apply_filters( 'give_address_format_template', "{street_address}\n{city}, {state} {postal_code}\n{country}" );
2128 preg_match_all( '/{([A-z0-9\-\_\ ]+)}/s', $address_format, $matches );
2129
2130 if ( ! empty( $matches ) && ! empty( $address ) ) {
2131 $address_values = [];
2132
2133 foreach ( $matches[1] as $address_tag ) {
2134 $address_values[ $address_tag ] = '';
2135
2136 if ( isset( $address[ $address_tag ] ) ) {
2137 $address_values[ $address_tag ] = $address[ $address_tag ];
2138 }
2139 }
2140
2141 $formatted_address = str_ireplace( $matches[0], $address_values, $address_format );
2142 }
2143
2144 /**
2145 * Give get formatted address.
2146 *
2147 * @param string $formatted_address Formatted address.
2148 * @param string $address_format Format of the address.
2149 *
2150 * @since 2.2.0
2151 */
2152 $formatted_address = apply_filters( 'give_get_formatted_address', $formatted_address, $address_format, $address );
2153
2154 return $formatted_address;
2155 }
2156
2157 /**
2158 * Get safe url for assets
2159 * Note: this function will return url without http protocol
2160 *
2161 * @param string $url URL
2162 *
2163 * @return string
2164 * @since 2.2.0
2165 */
2166 function give_get_safe_asset_url( $url ) {
2167
2168 // Bailout, if empty URL passed.
2169 if ( empty( $url ) ) {
2170 return $url;
2171 }
2172
2173 $schema = parse_url( $url, PHP_URL_SCHEME );
2174 $schema_length = strlen( $schema ) + 1;
2175 $url = substr( $url, $schema_length );
2176
2177 /**
2178 * Fire the filter
2179 *
2180 * @since 2.2.0
2181 */
2182 return apply_filters( 'give_get_safe_asset_url', $url );
2183 }
2184
2185 /**
2186 * Give get formatted date.
2187 * Note: This function does not work well with localize translated date strings
2188 *
2189 * @param string $date Date.
2190 * @param string $format Date Format.
2191 * @param string $current_format Current date Format.
2192 * @param bool $localize
2193 *
2194 * @return string
2195 * @since 2.3.0
2196 */
2197 function give_get_formatted_date( $date, $format = 'Y-m-d', $current_format = '', $localize = false ) {
2198 $current_format = empty( $current_format ) ? give_date_format() : $current_format;
2199 $date_obj = DateTime::createFromFormat( $current_format, $date );
2200 $formatted_date = '';
2201
2202 if ( $date_obj instanceof DateTime ) {
2203 $formatted_date = $localize ?
2204 date_i18n( $format, $date_obj->getTimestamp() ) :
2205 $date_obj->format( $format );
2206 }
2207
2208 /**
2209 * Give get formatted date.
2210 *
2211 * @param string $formatted_date Formatted date.
2212 * @param array
2213 *
2214 * @since 2.3.0
2215 */
2216 return apply_filters( 'give_get_formatted_date', $formatted_date, [ $date, $format, $current_format ] );
2217 }
2218
2219 /**
2220 * This function will be used to fetch the donation receipt link.
2221 *
2222 * @param int $donation_id Donation ID.
2223 *
2224 * @return string
2225 * @since 2.3.1
2226 */
2227 function give_get_receipt_link( $donation_id ) {
2228
2229 return sprintf(
2230 '<a href="%1$s">%2$s</a>',
2231 esc_url( give_get_receipt_url( $donation_id ) ),
2232 esc_html__( 'View the receipt in your browser &raquo;', 'give' )
2233 );
2234
2235 }
2236
2237 /**
2238 * Get receipt_url
2239 *
2240 * @param int $donation_id Donation ID.
2241 *
2242 * @return string
2243 * @since 2.0
2244 */
2245 function give_get_receipt_url( $donation_id ) {
2246
2247 $receipt_url = esc_url_raw(
2248 add_query_arg(
2249 [
2250 'donation_id' => $donation_id,
2251 ],
2252 give_get_history_page_uri()
2253 )
2254 );
2255
2256 return $receipt_url;
2257 }
2258
2259 /**
2260 * Get "View in browser" Receipt Link for email.
2261 *
2262 * @param int $donation_id Donation ID.
2263 *
2264 * @return string
2265 * @since 2.4.1
2266 */
2267 function give_get_view_receipt_link( $donation_id ) {
2268
2269 return sprintf(
2270 '<a href="%1$s">%2$s</a>',
2271 give_get_view_receipt_url( $donation_id ),
2272 esc_html__( 'View the receipt in your browser &raquo;', 'give' )
2273 );
2274
2275 }
2276
2277 /**
2278 * Get "View in browser" Receipt URL for email.
2279 *
2280 * @param int $donation_id Donation ID.
2281 *
2282 * @return string
2283 * @since 2.4.1
2284 */
2285 function give_get_view_receipt_url( $donation_id ) {
2286
2287 $receipt_url = esc_url_raw(
2288 add_query_arg(
2289 [
2290 'action' => 'view_in_browser',
2291 '_give_hash' => give_get_payment_key( $donation_id ),
2292 ],
2293 give_get_history_page_uri()
2294 )
2295 );
2296
2297 return $receipt_url;
2298 }
2299
2300 /**
2301 * This function is used to display donation receipt content based on the parameters.
2302 *
2303 * @param $args
2304 *
2305 * @return bool|mixed
2306 * @since 2.4.1
2307 */
2308 function give_display_donation_receipt( $args ) {
2309
2310 global $give_receipt_args;
2311
2312 $give_receipt_args = $args;
2313
2314 ob_start();
2315
2316 $get_data = give_clean( filter_input_array( INPUT_GET ) );
2317 $donation_id = ! empty( $get_data['donation_id'] ) ? $get_data['donation_id'] : false;
2318 $receipt_type = ! empty( $get_data['receipt_type'] ) ? $get_data['receipt_type'] : false;
2319
2320 $give_receipt_args['id'] = $donation_id;
2321
2322 if ( 'view_in_browser' !== $receipt_type ) {
2323
2324 $email_access = give_get_option( 'email_access' );
2325 $is_email_access = give_is_setting_enabled( $email_access ) && ! Give()->email_access->token_exists;
2326
2327 // No donation id found & Email Access is Turned on.
2328 if ( ! $donation_id ) {
2329
2330 if ( $is_email_access ) {
2331 give_get_template_part( 'email-login-form' );
2332 } else {
2333 echo Give_Notices::print_frontend_notice( $args['error'], false, 'error' );
2334 }
2335
2336 return ob_get_clean();
2337 }
2338
2339 // Donation id provided, but user is logged out. Offer them the ability to login and view the receipt.
2340 if ( ! ( $user_can_view = give_can_view_receipt( $donation_id ) ) ) {
2341
2342 if ( true === Give()->session->get( 'donor_donation_mismatch' ) ) {
2343
2344 /**
2345 * This filter will be used to modify the donor mismatch text for front end error notice.
2346 *
2347 * @since 2.3.1
2348 */
2349 $donor_mismatch_text = apply_filters( 'give_receipt_donor_mismatch_notice_text', __( 'You are trying to access invalid donation receipt. Please try again.', 'give' ) );
2350
2351 echo Give_Notices::print_frontend_notice(
2352 $donor_mismatch_text,
2353 false,
2354 'error'
2355 );
2356
2357 } elseif ( $is_email_access ) {
2358
2359 give_get_template_part( 'email-login-form' );
2360
2361 } else {
2362
2363 global $give_login_redirect;
2364
2365 $give_login_redirect = give_get_current_page_url();
2366
2367 Give_Notices::print_frontend_notice(
2368 apply_filters(
2369 'give_must_be_logged_in_error_message',
2370 __( 'You must be logged in to view this donation receipt.', 'give' )
2371 )
2372 );
2373
2374 give_get_template_part( 'shortcode', 'login' );
2375 }
2376
2377 return ob_get_clean();
2378 }
2379
2380 /**
2381 * Check if the user has permission to view the receipt.
2382 *
2383 * If user is logged in, user ID is compared to user ID of ID stored in payment meta
2384 * or if user is logged out and donation was made as a guest, the donation session is checked for
2385 * or if user is logged in and the user can view sensitive shop data.
2386 */
2387 if ( ! apply_filters( 'give_user_can_view_receipt', $user_can_view, $args ) ) {
2388 return Give_Notices::print_frontend_notice( $args['error'], false, 'error' );
2389 }
2390 } else {
2391 $donation_id = give_get_donation_id_by_key( $get_data['donation_id'] );
2392 $give_receipt_args['id'] = $donation_id;
2393 }
2394
2395 give_get_template_part( 'shortcode', 'receipt' );
2396
2397 return ob_get_clean();
2398 }
2399
2400
2401 /**
2402 * Get plugin add-on readme.txt path
2403 * Note: only for internal use
2404 *
2405 * @param $plugin_slug
2406 * @param bool $by_plugin_name
2407 *
2408 * @return mixed|void
2409 * @since 2.5.0
2410 */
2411 function give_get_addon_readme_url( $plugin_slug, $by_plugin_name = false ) {
2412
2413 if ( $by_plugin_name ) {
2414 $plugin_slug = Give_License::get_short_name( $plugin_slug );
2415 }
2416
2417 $website_url = trailingslashit( Give_License::get_website_url() );
2418
2419 /**
2420 * Filter the addon readme.txt url
2421 *
2422 * @since 2.1.4
2423 */
2424 $url = apply_filters(
2425 'give_addon_readme_file_url',
2426 "{$website_url}downloads/plugins/{$plugin_slug}/readme.txt",
2427 $plugin_slug,
2428 $by_plugin_name
2429 );
2430
2431 return $url;
2432 }
2433
2434 /**
2435 * Refresh all givewp license.
2436 *
2437 * @since 4.15.0 add support for Harbor unified licenses
2438 * @since 4.8.0 Update active license date after license refresh when active license is found
2439 * @since 4.3.0 updated to store platform fee percentage
2440 * @since 2.27.0 delete update_plugins transient instead of invalidate it
2441 * @since 2.5.0
2442 *
2443 * @param bool $wp_check_updates
2444 *
2445 * @access public
2446 * @return array|WP_Error
2447 */
2448 function give_refresh_licenses( $wp_check_updates = true ) {
2449 $give_licenses = get_option( 'give_licenses', [] );
2450 $give_addons = give_get_plugins( [ 'only_premium_add_ons' => true ] );
2451
2452 if ( ! $give_licenses && ! $give_addons ) {
2453 return [];
2454 }
2455
2456 $license_keys = $give_licenses ? implode( ',', array_keys( $give_licenses ) ) : '';
2457
2458 // Exclude addons already licensed via Harbor from the unlicensed list sent to the legacy API.
2459 $legacy_unlicensed_addons = array_filter( $give_addons, static function ( $plugin ) {
2460 return ! $plugin['License'];
2461 } );
2462
2463 $unlicensed_give_addon = $legacy_unlicensed_addons
2464 ? array_values(
2465 array_diff(
2466 array_map(
2467 function ( $plugin_name ) {
2468 return trim( str_replace( 'Give - ', '', $plugin_name ) );
2469 },
2470 wp_list_pluck( $legacy_unlicensed_addons, 'Name', true )
2471 ),
2472 wp_list_pluck( $give_licenses, 'item_name', true )
2473 )
2474 )
2475 : [];
2476
2477 // Nothing for the legacy API to check.
2478 if ( empty( $give_licenses ) && empty( $unlicensed_give_addon ) ) {
2479 return [];
2480 }
2481
2482 $tmp = Give_License::request_license_api(
2483 [
2484 'edd_action' => 'check_licenses',
2485 'licenses' => $license_keys,
2486 'unlicensed' => implode( ',', $unlicensed_give_addon ),
2487 ],
2488 true
2489 );
2490
2491 if ( ! $tmp || is_wp_error( $tmp ) ) {
2492 return [];
2493 }
2494
2495 // Prevent fatal error on WP 4.9.10
2496 // Because wp_list_pluck accept only array or array of array in that version.
2497 // @see https://github.com/impress-org/give/issues/4176
2498 $tmp = json_decode( json_encode( $tmp ), true );
2499
2500 // Remove unlicensed add-on from response.
2501 $tmp_unlicensed = [];
2502 foreach ( $tmp as $key => $data ) {
2503 if ( empty( $data ) ) {
2504 unset( $tmp[ "{$key}" ] );
2505 continue;
2506 }
2507
2508 if ( empty( $data['check_license'] ) ) {
2509 $tmp_unlicensed[ $key ] = $data;
2510 unset( $tmp[ "{$key}" ] );
2511 }
2512 }
2513
2514 $check_licenses = wp_list_pluck( $tmp, 'check_license' );
2515
2516 /* @var stdClass $data */
2517 foreach ( $check_licenses as $key => $data ) {
2518 if ( is_wp_error( $data ) ) {
2519 continue;
2520 }
2521
2522 if ( ! $data['success'] ) {
2523 unset( $give_licenses[ $key ] );
2524 continue;
2525 }
2526
2527 $give_licenses[ $key ] = $data;
2528 }
2529
2530 $tmp_update_plugins = array_merge(
2531 array_filter( wp_list_pluck( $tmp, 'get_version' ) ),
2532 array_filter( wp_list_pluck( $tmp, 'get_versions' ) )
2533 );
2534
2535 if ( $tmp_unlicensed ) {
2536 $tmp_update_plugins = array_merge( $tmp_update_plugins, $tmp_unlicensed );
2537 }
2538
2539 update_option( 'give_licenses', $give_licenses, 'no' );
2540 update_option( 'give_get_versions', $tmp_update_plugins, 'no' );
2541
2542 $refresh = Give_License::refresh_license_status();
2543 $refresh['time'] = time();
2544
2545 update_option( 'give_licenses_refreshed_last_checked', $refresh, 'no' );
2546
2547 $platform_fee_percentage = get_platform_fee_from_licenses();
2548
2549 if (!is_null($platform_fee_percentage)) {
2550 update_option( LicenseOptionKeys::PLATFORM_FEE_PERCENTAGE, $platform_fee_percentage, 'no' );
2551 }
2552
2553 // Update active license date after license refresh when active license is found
2554 $active_license_date = get_active_license_date();
2555
2556 if(!is_null($active_license_date)) {
2557 update_option(LicenseOptionKeys::LAST_ACTIVE_LICENSE_DATE, $active_license_date, 'no');
2558 }
2559
2560 // Tell WordPress to look for updates.
2561 if ( $wp_check_updates ) {
2562 delete_site_transient('update_plugins');
2563 }
2564
2565 return [
2566 'give_licenses' => $give_licenses,
2567 'give_get_versions' => $tmp_update_plugins,
2568 ];
2569 }
2570
2571 /**
2572 * Get platform fee from stored licenses
2573 */
2574 function get_platform_fee_from_licenses(): ?float
2575 {
2576 /** @var LicenseRepository $repository */
2577 $repository = give(LicenseRepository::class);
2578
2579 return $repository->findLowestPlatformFeePercentageFromActiveLicenses();
2580 }
2581
2582 /**
2583 * Set Active License Date
2584 *
2585 * @since 4.8.0
2586 */
2587 function get_active_license_date(): ?int
2588 {
2589 /** @var LicenseRepository $repository */
2590 $repository = give(LicenseRepository::class);
2591
2592 return $repository->getCurrentActiveLicenseDate();
2593 }
2594
2595 /**
2596 * Check add-ons updates
2597 * Note: only for internal use
2598 *
2599 * @param stdClass $_transient_data Plugin updates information
2600 *
2601 * @return stdClass
2602 * @since 2.5.0
2603 */
2604 function give_check_addon_updates( $_transient_data ) {
2605 if ( ! is_object( $_transient_data ) ) {
2606 $_transient_data = new stdClass();
2607 }
2608
2609 $update_plugins = get_option( 'give_get_versions', [] );
2610 $check_licenses = get_option( 'give_licenses', [] );
2611
2612 // Skip legacy update checks when Harbor is managing licensing and no legacy licenses exist.
2613 if ( empty( $check_licenses ) && lw_harbor_is_product_license_active( 'give' ) ) {
2614 return $_transient_data;
2615 }
2616
2617 if ( ! $update_plugins ) {
2618 $data = give_refresh_licenses( false );
2619
2620 if (
2621 empty( $data['give_get_versions'] )
2622 || is_wp_error( $data )
2623 ) {
2624 return $_transient_data;
2625 }
2626
2627 $update_plugins = $data['give_get_versions'];
2628 }
2629
2630 foreach ( $update_plugins as $key => $data ) {
2631 $plugins = ! empty( $check_licenses[ $key ] )
2632 ? ( ! empty( $check_licenses[ $key ]['is_all_access_pass'] ) ? $data : [ $data ] )
2633 : [ $data ];
2634
2635 foreach ( $plugins as $plugin ) {
2636 // This value will be empty if any error occurred when verifying version of add-on.
2637 if ( empty( $plugin['new_version'] ) ) {
2638 continue;
2639 }
2640
2641 $plugin = array_map( 'maybe_unserialize', $plugin );
2642 $tmp_plugin = Give_License::get_plugin_by_slug( $plugin['slug'] );
2643
2644 if ( ! $tmp_plugin ) {
2645 continue;
2646 }
2647
2648 $plugin['plugin'] = $tmp_plugin['Path'];
2649
2650 if ( - 1 !== version_compare( $tmp_plugin['Version'], $plugin['new_version'] ) ) {
2651 $_transient_data->no_update[ $tmp_plugin['Path'] ] = (object) $plugin;
2652 } else {
2653 $_transient_data->response[ $tmp_plugin['Path'] ] = (object) $plugin;
2654 }
2655
2656 $_transient_data->checked[ $tmp_plugin['Path'] ] = $tmp_plugin['Version'];
2657 }
2658 }
2659
2660 $_transient_data->last_checked = time();
2661
2662 return $_transient_data;
2663 }
2664
2665 /**
2666 * Get page by title
2667 *
2668 * @since 2.26.0
2669 *
2670 * @param string $page_title
2671 * @param string $output
2672 * @param string $post_type
2673 *
2674 * @return null|WP_Post
2675 */
2676 function give_get_page_by_title(string $page_title, string $output = OBJECT, string $post_type = 'page')
2677 {
2678 $args = [
2679 'title' => $page_title,
2680 'post_type' => $post_type,
2681 'post_status' => get_post_stati(),
2682 'posts_per_page' => 1,
2683 'update_post_term_cache' => false,
2684 'update_post_meta_cache' => false,
2685 'no_found_rows' => true,
2686 'orderby' => 'post_date ID',
2687 'order' => 'ASC',
2688 ];
2689 $query = new WP_Query($args);
2690 $pages = $query->posts;
2691
2692 if (empty($pages)) {
2693 return null;
2694 }
2695
2696 return get_post($pages[0], $output);
2697 }
2698