PluginProbe
GiveWP – Donation Plugin and Fundraising Platform / 4.16.8.1
GiveWP – Donation Plugin and Fundraising Platform v4.16.8.1
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 2.3.1 2.3.2 2.30.0 2.31.0 All 254 releases
give / includes / misc-functions.php

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

2,768 lines 116.9 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 * Store recently activated Give's addons to wp options.
1908 *
1909 * @since 4.16.7.1 Moved from includes/admin/plugins.php so the listener is registered on every
1910 * request, and fall back to the plugin file passed by the `activated_plugin`
1911 * action so add-ons activated outside of plugins.php (REST, WP-CLI,
1912 * programmatic `activate_plugin()`, etc.) are recorded too.
1913 * @since 2.1.0
1914 *
1915 * @param string $activated_plugin Plugin file passed by the `activated_plugin` action.
1916 */
1917 function give_recently_activated_addons( $activated_plugin = '' ) {
1918 $plugins = [];
1919
1920 // Check if action is set.
1921 if ( isset( $_REQUEST['action'] ) ) {
1922 $plugin_action = ( '-1' !== $_REQUEST['action'] ) ? $_REQUEST['action'] : ( isset( $_REQUEST['action2'] ) ? $_REQUEST['action2'] : '' );
1923
1924 switch ( $plugin_action ) {
1925 case 'activate': // Single add-on activation.
1926 $plugins[] = $_REQUEST['plugin'];
1927 break;
1928 case 'activate-selected': // If multiple add-ons activated.
1929 $plugins = $_REQUEST['checked'];
1930 break;
1931 }
1932 }
1933
1934 /**
1935 * Activations that do not come from the plugins.php form (Harbor's feature manager,
1936 * WP-CLI, plugin dependencies, any direct `activate_plugin()` call) have no matching
1937 * request parameters, so use the plugin file the action itself provides.
1938 */
1939 if ( empty( $plugins ) && ! empty( $activated_plugin ) ) {
1940 $plugins[] = $activated_plugin;
1941 }
1942
1943 if ( ! empty( $plugins ) ) {
1944
1945 $give_addons = give_get_recently_activated_addons();
1946
1947 foreach ( $plugins as $plugin ) {
1948 // Get plugins which has 'Give-' as prefix.
1949 if ( stripos( $plugin, 'Give-' ) !== false ) {
1950 $give_addons[] = $plugin;
1951 }
1952 }
1953
1954 if ( ! empty( $give_addons ) ) {
1955 // Update the Give's activated add-ons.
1956 update_option( 'give_recently_activated_addons', $give_addons, false );
1957 }
1958 }
1959 }
1960
1961 // Add add-on plugins to wp option table.
1962 add_action( 'activated_plugin', 'give_recently_activated_addons', 10 );
1963
1964 /**
1965 * Get list of add-on last activated.
1966 *
1967 * @since 4.16.7.1 Moved from includes/admin/plugins.php.
1968 * @since 2.1.3
1969 *
1970 * @return mixed|array list of recently activated add-on
1971 */
1972 function give_get_recently_activated_addons() {
1973 return get_option( 'give_recently_activated_addons', [] );
1974 }
1975
1976 /**
1977 * Get time interval for which nonce is valid
1978 *
1979 * @return int
1980 * @since 2.1.3
1981 */
1982 function give_get_nonce_life() {
1983 /**
1984 * Filters the lifespan of nonces in seconds.
1985 *
1986 * @see wp-inlucdes/pluggable.php:wp_nonce_tick
1987 */
1988 return (int) apply_filters( 'nonce_life', DAY_IN_SECONDS );
1989 }
1990
1991 /**
1992 * Get nonce field without id
1993 *
1994 * @param string $action
1995 * @param string $name
1996 * @param bool $referer
1997 *
1998 * @return string
1999 * @since 2.1.3
2000 */
2001 function give_get_nonce_field( $action, $name, $referer = false ) {
2002 return str_replace(
2003 "id=\"{$name}\"",
2004 '',
2005 wp_nonce_field( $action, $name, $referer, false )
2006 );
2007 }
2008
2009 /**
2010 * Display/Return a formatted goal for a donation form
2011 *
2012 * @since 3.16.0 Add form_id to the array return
2013 * @since 2.1
2014 *
2015 * @param int|Give_Donate_Form $form Form ID or Form Object.
2016 *
2017 * @return array
2018 */
2019 function give_goal_progress_stats( $form ) {
2020
2021 if ( ! $form instanceof Give_Donate_Form ) {
2022 $form = new Give_Donate_Form( $form );
2023 }
2024
2025 $goal_format = give_get_form_goal_format( $form->ID );
2026
2027 /**
2028 * Filter the form.
2029 * @since 1.8.8
2030 */
2031 $total_goal = apply_filters( 'give_goal_amount_target_output', round( give_maybe_sanitize_amount( $form->goal ), 2 ), $form->ID, $form );
2032
2033 switch ( $goal_format ) {
2034 case 'donation':
2035 /**
2036 * Filter the form donations.
2037 *
2038 * @since 2.1
2039 */
2040 $actual = apply_filters( 'give_goal_donations_raised_output', $form->sales, $form->ID, $form );
2041 break;
2042 case 'donors':
2043 /**
2044 * Filter to modify total number if donor for the donation form.
2045 *
2046 * @param int $donors Total number of donors that donated to the form.
2047 * @param int $form_id Donation Form ID.
2048 * @param Give_Donate_Form $form instances of Give_Donate_Form.
2049 *
2050 * @return int $donors Total number of donors that donated to the form.
2051 * @since 2.1.3
2052 */
2053 $actual = apply_filters( 'give_goal_donors_target_output', give_get_form_donor_count( $form->ID ), $form->ID, $form );
2054 break;
2055 default:
2056 /**
2057 * Filter the form income.
2058 *
2059 * @since 3.16.0 Revert changes implemented on the 3.14.0 version
2060 * @since 3.14.0 Replace "$form->earnings" with (new DonationQuery())->form($form->ID)->sumIntendedAmount()
2061 * @since 1.8.8
2062 */
2063 $actual = apply_filters( 'give_goal_amount_raised_output', $form->earnings, $form->ID, $form );
2064 break;
2065 }
2066
2067 $progress = $total_goal ? round( ( $actual / $total_goal ) * 100, 2 ) : 0;
2068
2069 $stats_array = [
2070 'raw_actual' => $actual,
2071 'raw_goal' => $total_goal,
2072 ];
2073
2074 /**
2075 * Filter the goal progress output
2076 *
2077 * @since 1.8.8
2078 */
2079 $progress = apply_filters( 'give_goal_amount_funded_percentage_output', $progress, $form->ID, $form );
2080
2081 // Define Actual Goal based on the goal format.
2082 switch ( $goal_format ) {
2083 case 'percentage':
2084 $actual = "{$progress}%";
2085 $total_goal = '';
2086 break;
2087
2088 case 'amount' === $goal_format:
2089 $actual = give_currency_filter( give_format_amount( $actual ) );
2090 $total_goal = give_currency_filter( give_format_amount( $total_goal ) );
2091 break;
2092
2093 default:
2094 $actual = give_format_amount( $actual, [ 'decimal' => false ] );
2095 $total_goal = give_format_amount( $total_goal, [ 'decimal' => false ] );
2096 break;
2097 }
2098
2099 $stats_array = array_merge(
2100 [
2101 'progress' => $progress,
2102 'actual' => $actual,
2103 'goal' => $total_goal,
2104 'format' => $goal_format,
2105 'form_id' => $form->ID
2106 ],
2107 $stats_array
2108 );
2109
2110 /**
2111 * Filter the goal stats
2112 *
2113 * @since 2.1
2114 */
2115 return apply_filters( 'give_goal_progress_stats', $stats_array );
2116 }
2117
2118 /**
2119 * Get the admin messages key to show the notices.
2120 *
2121 * @return array $message admin message key.
2122 * @since 2.1.4
2123 */
2124 function give_get_admin_messages_key() {
2125 $messages = empty( $_GET['give-messages'] ) ? [] : give_clean( $_GET['give-messages'] );
2126
2127 // backward compatibility.
2128 if ( ! empty( $_GET['give-message'] ) ) {
2129 $messages[] = give_clean( $_GET['give-message'] );
2130 }
2131
2132 /**
2133 * Filter to modify the admin messages key.
2134 *
2135 * @param array $message admin message key.
2136 *
2137 * @return array $message admin message key.
2138 * @since 2.1.4
2139 */
2140 return (array) apply_filters( 'give_get_admin_messages_key', $messages );
2141 }
2142
2143 /**
2144 * Get User Agent String.
2145 *
2146 * @return array|string
2147 * @since 2.1.4
2148 */
2149 function give_get_user_agent() {
2150
2151 // Get User Agent.
2152 $user_agent = ! empty( $_SERVER['HTTP_USER_AGENT'] ) ? give_clean( $_SERVER['HTTP_USER_AGENT'] ) : ''; // WPCS: input var ok.
2153
2154 return $user_agent;
2155 }
2156
2157 /**
2158 * Set a cookie - wrapper for setcookie using WP constants.
2159 *
2160 * @param string $name Name of the cookie being set.
2161 * @param string $value Value of the cookie.
2162 * @param integer $expire Expiry of the cookie.
2163 * @param bool $secure Whether the cookie should be served only over https.
2164 *
2165 * @since 2.2.0
2166 */
2167 function give_setcookie( $name, $value, $expire = 0, $secure = false ) {
2168 if ( ! headers_sent() ) {
2169 setcookie(
2170 $name,
2171 $value,
2172 $expire,
2173 COOKIEPATH ? COOKIEPATH : '/',
2174 COOKIE_DOMAIN,
2175 $secure,
2176 apply_filters( 'give_cookie_httponly', false, $name, $value, $expire, $secure )
2177 );
2178 }
2179 }
2180
2181 /**
2182 * Get formatted billing address.
2183 *
2184 * @param array $address
2185 *
2186 * @return string Formatted address.
2187 * @since 2.2.0
2188 */
2189 function give_get_formatted_address( $address = [] ) {
2190 $formatted_address = '';
2191
2192 /**
2193 * Address format.
2194 *
2195 * @since 2.2.0
2196 */
2197 $address_format = apply_filters( 'give_address_format_template', "{street_address}\n{city}, {state} {postal_code}\n{country}" );
2198 preg_match_all( '/{([A-z0-9\-\_\ ]+)}/s', $address_format, $matches );
2199
2200 if ( ! empty( $matches ) && ! empty( $address ) ) {
2201 $address_values = [];
2202
2203 foreach ( $matches[1] as $address_tag ) {
2204 $address_values[ $address_tag ] = '';
2205
2206 if ( isset( $address[ $address_tag ] ) ) {
2207 $address_values[ $address_tag ] = $address[ $address_tag ];
2208 }
2209 }
2210
2211 $formatted_address = str_ireplace( $matches[0], $address_values, $address_format );
2212 }
2213
2214 /**
2215 * Give get formatted address.
2216 *
2217 * @param string $formatted_address Formatted address.
2218 * @param string $address_format Format of the address.
2219 *
2220 * @since 2.2.0
2221 */
2222 $formatted_address = apply_filters( 'give_get_formatted_address', $formatted_address, $address_format, $address );
2223
2224 return $formatted_address;
2225 }
2226
2227 /**
2228 * Get safe url for assets
2229 * Note: this function will return url without http protocol
2230 *
2231 * @param string $url URL
2232 *
2233 * @return string
2234 * @since 2.2.0
2235 */
2236 function give_get_safe_asset_url( $url ) {
2237
2238 // Bailout, if empty URL passed.
2239 if ( empty( $url ) ) {
2240 return $url;
2241 }
2242
2243 $schema = parse_url( $url, PHP_URL_SCHEME );
2244 $schema_length = strlen( $schema ) + 1;
2245 $url = substr( $url, $schema_length );
2246
2247 /**
2248 * Fire the filter
2249 *
2250 * @since 2.2.0
2251 */
2252 return apply_filters( 'give_get_safe_asset_url', $url );
2253 }
2254
2255 /**
2256 * Give get formatted date.
2257 * Note: This function does not work well with localize translated date strings
2258 *
2259 * @param string $date Date.
2260 * @param string $format Date Format.
2261 * @param string $current_format Current date Format.
2262 * @param bool $localize
2263 *
2264 * @return string
2265 * @since 2.3.0
2266 */
2267 function give_get_formatted_date( $date, $format = 'Y-m-d', $current_format = '', $localize = false ) {
2268 $current_format = empty( $current_format ) ? give_date_format() : $current_format;
2269 $date_obj = DateTime::createFromFormat( $current_format, $date );
2270 $formatted_date = '';
2271
2272 if ( $date_obj instanceof DateTime ) {
2273 $formatted_date = $localize ?
2274 date_i18n( $format, $date_obj->getTimestamp() ) :
2275 $date_obj->format( $format );
2276 }
2277
2278 /**
2279 * Give get formatted date.
2280 *
2281 * @param string $formatted_date Formatted date.
2282 * @param array
2283 *
2284 * @since 2.3.0
2285 */
2286 return apply_filters( 'give_get_formatted_date', $formatted_date, [ $date, $format, $current_format ] );
2287 }
2288
2289 /**
2290 * This function will be used to fetch the donation receipt link.
2291 *
2292 * @param int $donation_id Donation ID.
2293 *
2294 * @return string
2295 * @since 2.3.1
2296 */
2297 function give_get_receipt_link( $donation_id ) {
2298
2299 return sprintf(
2300 '<a href="%1$s">%2$s</a>',
2301 esc_url( give_get_receipt_url( $donation_id ) ),
2302 esc_html__( 'View the receipt in your browser &raquo;', 'give' )
2303 );
2304
2305 }
2306
2307 /**
2308 * Get receipt_url
2309 *
2310 * @param int $donation_id Donation ID.
2311 *
2312 * @return string
2313 * @since 2.0
2314 */
2315 function give_get_receipt_url( $donation_id ) {
2316
2317 $receipt_url = esc_url_raw(
2318 add_query_arg(
2319 [
2320 'donation_id' => $donation_id,
2321 ],
2322 give_get_history_page_uri()
2323 )
2324 );
2325
2326 return $receipt_url;
2327 }
2328
2329 /**
2330 * Get "View in browser" Receipt Link for email.
2331 *
2332 * @param int $donation_id Donation ID.
2333 *
2334 * @return string
2335 * @since 2.4.1
2336 */
2337 function give_get_view_receipt_link( $donation_id ) {
2338
2339 return sprintf(
2340 '<a href="%1$s">%2$s</a>',
2341 give_get_view_receipt_url( $donation_id ),
2342 esc_html__( 'View the receipt in your browser &raquo;', 'give' )
2343 );
2344
2345 }
2346
2347 /**
2348 * Get "View in browser" Receipt URL for email.
2349 *
2350 * @param int $donation_id Donation ID.
2351 *
2352 * @return string
2353 * @since 2.4.1
2354 */
2355 function give_get_view_receipt_url( $donation_id ) {
2356
2357 $receipt_url = esc_url_raw(
2358 add_query_arg(
2359 [
2360 'action' => 'view_in_browser',
2361 '_give_hash' => give_get_payment_key( $donation_id ),
2362 ],
2363 give_get_history_page_uri()
2364 )
2365 );
2366
2367 return $receipt_url;
2368 }
2369
2370 /**
2371 * This function is used to display donation receipt content based on the parameters.
2372 *
2373 * @param $args
2374 *
2375 * @return bool|mixed
2376 * @since 2.4.1
2377 */
2378 function give_display_donation_receipt( $args ) {
2379
2380 global $give_receipt_args;
2381
2382 $give_receipt_args = $args;
2383
2384 ob_start();
2385
2386 $get_data = give_clean( filter_input_array( INPUT_GET ) );
2387 $donation_id = ! empty( $get_data['donation_id'] ) ? $get_data['donation_id'] : false;
2388 $receipt_type = ! empty( $get_data['receipt_type'] ) ? $get_data['receipt_type'] : false;
2389
2390 $give_receipt_args['id'] = $donation_id;
2391
2392 if ( 'view_in_browser' !== $receipt_type ) {
2393
2394 $email_access = give_get_option( 'email_access' );
2395 $is_email_access = give_is_setting_enabled( $email_access ) && ! Give()->email_access->token_exists;
2396
2397 // No donation id found & Email Access is Turned on.
2398 if ( ! $donation_id ) {
2399
2400 if ( $is_email_access ) {
2401 give_get_template_part( 'email-login-form' );
2402 } else {
2403 echo Give_Notices::print_frontend_notice( $args['error'], false, 'error' );
2404 }
2405
2406 return ob_get_clean();
2407 }
2408
2409 // Donation id provided, but user is logged out. Offer them the ability to login and view the receipt.
2410 if ( ! ( $user_can_view = give_can_view_receipt( $donation_id ) ) ) {
2411
2412 if ( true === Give()->session->get( 'donor_donation_mismatch' ) ) {
2413
2414 /**
2415 * This filter will be used to modify the donor mismatch text for front end error notice.
2416 *
2417 * @since 2.3.1
2418 */
2419 $donor_mismatch_text = apply_filters( 'give_receipt_donor_mismatch_notice_text', __( 'You are trying to access invalid donation receipt. Please try again.', 'give' ) );
2420
2421 echo Give_Notices::print_frontend_notice(
2422 $donor_mismatch_text,
2423 false,
2424 'error'
2425 );
2426
2427 } elseif ( $is_email_access ) {
2428
2429 give_get_template_part( 'email-login-form' );
2430
2431 } else {
2432
2433 global $give_login_redirect;
2434
2435 $give_login_redirect = give_get_current_page_url();
2436
2437 Give_Notices::print_frontend_notice(
2438 apply_filters(
2439 'give_must_be_logged_in_error_message',
2440 __( 'You must be logged in to view this donation receipt.', 'give' )
2441 )
2442 );
2443
2444 give_get_template_part( 'shortcode', 'login' );
2445 }
2446
2447 return ob_get_clean();
2448 }
2449
2450 /**
2451 * Check if the user has permission to view the receipt.
2452 *
2453 * If user is logged in, user ID is compared to user ID of ID stored in payment meta
2454 * or if user is logged out and donation was made as a guest, the donation session is checked for
2455 * or if user is logged in and the user can view sensitive shop data.
2456 */
2457 if ( ! apply_filters( 'give_user_can_view_receipt', $user_can_view, $args ) ) {
2458 return Give_Notices::print_frontend_notice( $args['error'], false, 'error' );
2459 }
2460 } else {
2461 $donation_id = give_get_donation_id_by_key( $get_data['donation_id'] );
2462 $give_receipt_args['id'] = $donation_id;
2463 }
2464
2465 give_get_template_part( 'shortcode', 'receipt' );
2466
2467 return ob_get_clean();
2468 }
2469
2470
2471 /**
2472 * Get plugin add-on readme.txt path
2473 * Note: only for internal use
2474 *
2475 * @param $plugin_slug
2476 * @param bool $by_plugin_name
2477 *
2478 * @return mixed|void
2479 * @since 2.5.0
2480 */
2481 function give_get_addon_readme_url( $plugin_slug, $by_plugin_name = false ) {
2482
2483 if ( $by_plugin_name ) {
2484 $plugin_slug = Give_License::get_short_name( $plugin_slug );
2485 }
2486
2487 $website_url = trailingslashit( Give_License::get_website_url() );
2488
2489 /**
2490 * Filter the addon readme.txt url
2491 *
2492 * @since 2.1.4
2493 */
2494 $url = apply_filters(
2495 'give_addon_readme_file_url',
2496 "{$website_url}downloads/plugins/{$plugin_slug}/readme.txt",
2497 $plugin_slug,
2498 $by_plugin_name
2499 );
2500
2501 return $url;
2502 }
2503
2504 /**
2505 * Refresh all givewp license.
2506 *
2507 * @since 4.15.0 add support for Harbor unified licenses
2508 * @since 4.8.0 Update active license date after license refresh when active license is found
2509 * @since 4.3.0 updated to store platform fee percentage
2510 * @since 2.27.0 delete update_plugins transient instead of invalidate it
2511 * @since 2.5.0
2512 *
2513 * @param bool $wp_check_updates
2514 *
2515 * @access public
2516 * @return array|WP_Error
2517 */
2518 function give_refresh_licenses( $wp_check_updates = true ) {
2519 $give_licenses = get_option( 'give_licenses', [] );
2520 $give_addons = give_get_plugins( [ 'only_premium_add_ons' => true ] );
2521
2522 if ( ! $give_licenses && ! $give_addons ) {
2523 return [];
2524 }
2525
2526 $license_keys = $give_licenses ? implode( ',', array_keys( $give_licenses ) ) : '';
2527
2528 // Exclude addons already licensed via Harbor from the unlicensed list sent to the legacy API.
2529 $legacy_unlicensed_addons = array_filter( $give_addons, static function ( $plugin ) {
2530 return ! $plugin['License'];
2531 } );
2532
2533 $unlicensed_give_addon = $legacy_unlicensed_addons
2534 ? array_values(
2535 array_diff(
2536 array_map(
2537 function ( $plugin_name ) {
2538 return trim( str_replace( 'Give - ', '', $plugin_name ) );
2539 },
2540 wp_list_pluck( $legacy_unlicensed_addons, 'Name', true )
2541 ),
2542 wp_list_pluck( $give_licenses, 'item_name', true )
2543 )
2544 )
2545 : [];
2546
2547 // Nothing for the legacy API to check.
2548 if ( empty( $give_licenses ) && empty( $unlicensed_give_addon ) ) {
2549 return [];
2550 }
2551
2552 $tmp = Give_License::request_license_api(
2553 [
2554 'edd_action' => 'check_licenses',
2555 'licenses' => $license_keys,
2556 'unlicensed' => implode( ',', $unlicensed_give_addon ),
2557 ],
2558 true
2559 );
2560
2561 if ( ! $tmp || is_wp_error( $tmp ) ) {
2562 return [];
2563 }
2564
2565 // Prevent fatal error on WP 4.9.10
2566 // Because wp_list_pluck accept only array or array of array in that version.
2567 // @see https://github.com/impress-org/give/issues/4176
2568 $tmp = json_decode( json_encode( $tmp ), true );
2569
2570 // Remove unlicensed add-on from response.
2571 $tmp_unlicensed = [];
2572 foreach ( $tmp as $key => $data ) {
2573 if ( empty( $data ) ) {
2574 unset( $tmp[ "{$key}" ] );
2575 continue;
2576 }
2577
2578 if ( empty( $data['check_license'] ) ) {
2579 $tmp_unlicensed[ $key ] = $data;
2580 unset( $tmp[ "{$key}" ] );
2581 }
2582 }
2583
2584 $check_licenses = wp_list_pluck( $tmp, 'check_license' );
2585
2586 /* @var stdClass $data */
2587 foreach ( $check_licenses as $key => $data ) {
2588 if ( is_wp_error( $data ) ) {
2589 continue;
2590 }
2591
2592 if ( ! $data['success'] ) {
2593 unset( $give_licenses[ $key ] );
2594 continue;
2595 }
2596
2597 $give_licenses[ $key ] = $data;
2598 }
2599
2600 $tmp_update_plugins = array_merge(
2601 array_filter( wp_list_pluck( $tmp, 'get_version' ) ),
2602 array_filter( wp_list_pluck( $tmp, 'get_versions' ) )
2603 );
2604
2605 if ( $tmp_unlicensed ) {
2606 $tmp_update_plugins = array_merge( $tmp_update_plugins, $tmp_unlicensed );
2607 }
2608
2609 update_option( 'give_licenses', $give_licenses, 'no' );
2610 update_option( 'give_get_versions', $tmp_update_plugins, 'no' );
2611
2612 $refresh = Give_License::refresh_license_status();
2613 $refresh['time'] = time();
2614
2615 update_option( 'give_licenses_refreshed_last_checked', $refresh, 'no' );
2616
2617 $platform_fee_percentage = get_platform_fee_from_licenses();
2618
2619 if (!is_null($platform_fee_percentage)) {
2620 update_option( LicenseOptionKeys::PLATFORM_FEE_PERCENTAGE, $platform_fee_percentage, 'no' );
2621 }
2622
2623 // Update active license date after license refresh when active license is found
2624 $active_license_date = get_active_license_date();
2625
2626 if(!is_null($active_license_date)) {
2627 update_option(LicenseOptionKeys::LAST_ACTIVE_LICENSE_DATE, $active_license_date, 'no');
2628 }
2629
2630 // Tell WordPress to look for updates.
2631 if ( $wp_check_updates ) {
2632 delete_site_transient('update_plugins');
2633 }
2634
2635 return [
2636 'give_licenses' => $give_licenses,
2637 'give_get_versions' => $tmp_update_plugins,
2638 ];
2639 }
2640
2641 /**
2642 * Get platform fee from stored licenses
2643 */
2644 function get_platform_fee_from_licenses(): ?float
2645 {
2646 /** @var LicenseRepository $repository */
2647 $repository = give(LicenseRepository::class);
2648
2649 return $repository->findLowestPlatformFeePercentageFromActiveLicenses();
2650 }
2651
2652 /**
2653 * Set Active License Date
2654 *
2655 * @since 4.8.0
2656 */
2657 function get_active_license_date(): ?int
2658 {
2659 /** @var LicenseRepository $repository */
2660 $repository = give(LicenseRepository::class);
2661
2662 return $repository->getCurrentActiveLicenseDate();
2663 }
2664
2665 /**
2666 * Check add-ons updates
2667 * Note: only for internal use
2668 *
2669 * @param stdClass $_transient_data Plugin updates information
2670 *
2671 * @return stdClass
2672 * @since 2.5.0
2673 */
2674 function give_check_addon_updates( $_transient_data ) {
2675 if ( ! is_object( $_transient_data ) ) {
2676 $_transient_data = new stdClass();
2677 }
2678
2679 $update_plugins = get_option( 'give_get_versions', [] );
2680 $check_licenses = get_option( 'give_licenses', [] );
2681
2682 // Skip legacy update checks when Harbor is managing licensing and no legacy licenses exist.
2683 if ( empty( $check_licenses ) && lw_harbor_is_product_license_active( 'give' ) ) {
2684 return $_transient_data;
2685 }
2686
2687 if ( ! $update_plugins ) {
2688 $data = give_refresh_licenses( false );
2689
2690 if (
2691 empty( $data['give_get_versions'] )
2692 || is_wp_error( $data )
2693 ) {
2694 return $_transient_data;
2695 }
2696
2697 $update_plugins = $data['give_get_versions'];
2698 }
2699
2700 foreach ( $update_plugins as $key => $data ) {
2701 $plugins = ! empty( $check_licenses[ $key ] )
2702 ? ( ! empty( $check_licenses[ $key ]['is_all_access_pass'] ) ? $data : [ $data ] )
2703 : [ $data ];
2704
2705 foreach ( $plugins as $plugin ) {
2706 // This value will be empty if any error occurred when verifying version of add-on.
2707 if ( empty( $plugin['new_version'] ) ) {
2708 continue;
2709 }
2710
2711 $plugin = array_map( 'maybe_unserialize', $plugin );
2712 $tmp_plugin = Give_License::get_plugin_by_slug( $plugin['slug'] );
2713
2714 if ( ! $tmp_plugin ) {
2715 continue;
2716 }
2717
2718 $plugin['plugin'] = $tmp_plugin['Path'];
2719
2720 if ( - 1 !== version_compare( $tmp_plugin['Version'], $plugin['new_version'] ) ) {
2721 $_transient_data->no_update[ $tmp_plugin['Path'] ] = (object) $plugin;
2722 } else {
2723 $_transient_data->response[ $tmp_plugin['Path'] ] = (object) $plugin;
2724 }
2725
2726 $_transient_data->checked[ $tmp_plugin['Path'] ] = $tmp_plugin['Version'];
2727 }
2728 }
2729
2730 $_transient_data->last_checked = time();
2731
2732 return $_transient_data;
2733 }
2734
2735 /**
2736 * Get page by title
2737 *
2738 * @since 2.26.0
2739 *
2740 * @param string $page_title
2741 * @param string $output
2742 * @param string $post_type
2743 *
2744 * @return null|WP_Post
2745 */
2746 function give_get_page_by_title(string $page_title, string $output = OBJECT, string $post_type = 'page')
2747 {
2748 $args = [
2749 'title' => $page_title,
2750 'post_type' => $post_type,
2751 'post_status' => get_post_stati(),
2752 'posts_per_page' => 1,
2753 'update_post_term_cache' => false,
2754 'update_post_meta_cache' => false,
2755 'no_found_rows' => true,
2756 'orderby' => 'post_date ID',
2757 'order' => 'ASC',
2758 ];
2759 $query = new WP_Query($args);
2760 $pages = $query->posts;
2761
2762 if (empty($pages)) {
2763 return null;
2764 }
2765
2766 return get_post($pages[0], $output);
2767 }
2768