PluginProbe
GiveWP – Donation Plugin and Fundraising Platform / 2.13.1
GiveWP – Donation Plugin and Fundraising Platform v2.13.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 2.31.1 All 253 releases
give / includes / misc-functions.php

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

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