misc-functions.php ➔ give_refresh_licenses()   F
last analyzed

Complexity

Conditions 15
Paths 261

Size

Total Lines 96

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 15
nc 261
nop 1
dl 0
loc 96
rs 3.5439
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
if ( ! defined( 'ABSPATH' ) ) {
14
	exit;
15
}
16
17
/**
18
 * Is Test Mode Enabled.
19
 *
20
 * @return bool $ret True if return mode is enabled, false otherwise
21
 * @since 1.0
22
 */
23
function give_is_test_mode() {
24
25
	$ret = give_is_setting_enabled( give_get_option( 'test_mode' ) );
26
27
	return (bool) apply_filters( 'give_is_test_mode', $ret );
28
29
}
30
31
/**
32
 * Get the current page URL.
33
 *
34
 * @return string $current_url Current page URL.
35
 * @since 1.0
36
 */
37
function give_get_current_page_url() {
38
39
	global $wp;
40
41
	if ( get_option( 'permalink_structure' ) ) {
42
		$base = trailingslashit( home_url( $wp->request ) );
43
	} else {
44
		$base = add_query_arg( $wp->query_string, '', trailingslashit( home_url( $wp->request ) ) );
45
		$base = remove_query_arg( array( 'post_type', 'name' ), $base );
46
	}
47
48
	$scheme      = is_ssl() ? 'https' : 'http';
49
	$current_uri = set_url_scheme( $base, $scheme );
50
51
	if ( is_front_page() ) {
52
		$current_uri = home_url( '/' );
53
	}
54
55
	/**
56
	 * Filter the current page url
57
	 *
58
	 * @param string $current_uri
59
	 *
60
	 * @since 1.0
61
	 */
62
	return apply_filters( 'give_get_current_page_url', $current_uri );
63
64
}
65
66
67
/**
68
 * Verify credit card numbers live?
69
 *
70
 * @return bool $ret True is verify credit cards is live
71
 * @since 1.0
72
 */
73
function give_is_cc_verify_enabled() {
74
75
	$ret = true;
76
77
	/**
78
	 * Enable if use a single gateway other than PayPal or Manual. We have to assume it accepts credit cards.
79
	 * Enable if using more than one gateway if they are not both PayPal and manual, again assuming credit card usage.
80
	 */
81
	$gateways = give_get_enabled_payment_gateways();
82
83
	if ( count( $gateways ) == 1 && ! isset( $gateways['paypal'] ) && ! isset( $gateways['manual'] ) ) {
84
		$ret = true;
85
	} elseif ( count( $gateways ) == 1 ) {
86
		$ret = false;
87
	} elseif ( count( $gateways ) == 2 && isset( $gateways['paypal'] ) && isset( $gateways['manual'] ) ) {
88
		$ret = false;
89
	}
90
91
	/**
92
	 * Fire the filter
93
	 *
94
	 * @param bool $ret
95
	 *
96
	 * @since 1.0
97
	 */
98
	return (bool) apply_filters( 'give_is_cc_verify_enabled', $ret );
99
}
100
101
/**
102
 * Retrieve timezone.
103
 *
104
 * @return string $timezone The timezone ID.
105
 * @since 1.0
106
 */
107
function give_get_timezone_id() {
108
109
	// if site timezone string exists, return it.
110
	if ( $timezone = get_option( 'timezone_string' ) ) {
111
		return $timezone;
112
	}
113
114
	// get UTC offset, if it isn't set return UTC.
115
	if ( ! ( $utc_offset = 3600 * get_option( 'gmt_offset', 0 ) ) ) {
116
		return 'UTC';
117
	}
118
119
	// attempt to guess the timezone string from the UTC offset.
120
	$timezone = timezone_name_from_abbr( '', $utc_offset );
121
122
	// last try, guess timezone string manually.
123
	if ( $timezone === false ) {
124
125
		$is_dst = date( 'I' );
126
127
		foreach ( timezone_abbreviations_list() as $abbr ) {
128
			foreach ( $abbr as $city ) {
129
				if ( $city['dst'] == $is_dst && $city['offset'] == $utc_offset ) {
130
					return $city['timezone_id'];
131
				}
132
			}
133
		}
134
	}
135
136
	// Fallback.
137
	return 'UTC';
138
}
139
140
141
/**
142
 * Get User IP
143
 *
144
 * Returns the IP address of the current visitor
145
 *
146
 * @return string $ip User's IP address
147
 * @since 1.0
148
 */
149
function give_get_ip() {
150
151
	$ip = '127.0.0.1';
152
153
	if ( ! empty( $_SERVER['HTTP_CLIENT_IP'] ) ) {
154
		// check ip from share internet
155
		$ip = $_SERVER['HTTP_CLIENT_IP'];
156
	} elseif ( ! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
157
		// to check ip is pass from proxy
158
		$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
159
	} elseif ( ! empty( $_SERVER['REMOTE_ADDR'] ) ) {
160
		$ip = $_SERVER['REMOTE_ADDR'];
161
	}
162
163
	/**
164
	 * Filter the IP
165
	 *
166
	 * @since 1.0
167
	 */
168
	$ip = apply_filters( 'give_get_ip', $ip );
169
170
	// Filter empty values.
171
	if ( false !== strpos( $ip, ',' ) ) {
172
		$ip = give_clean( explode( ',', $ip ) );
173
		$ip = array_filter( $ip );
174
		$ip = implode( ',', $ip );
175
	} else {
176
		$ip = give_clean( $ip );
177
	}
178
179
	return $ip;
180
}
181
182
183
/**
184
 * Store Donation Data in Sessions
185
 *
186
 * Used for storing info about donation
187
 *
188
 * @param $purchase_data
189
 *
190
 * @since 1.0
191
 *
192
 * @uses  Give()->session->set()
193
 */
194
function give_set_purchase_session( $purchase_data = array() ) {
195
	Give()->session->set( 'give_purchase', $purchase_data );
196
	Give()->session->set( 'give_email', $purchase_data['user_email'] );
197
}
198
199
/**
200
 * Retrieve Donation Data from Session
201
 *
202
 * Used for retrieving info about donation
203
 * after completing a donation
204
 *
205
 * @return mixed array | false
206
 * @uses  Give()->session->get()
207
 * @since 1.0
208
 */
209
function give_get_purchase_session() {
210
	return Give()->session->get( 'give_purchase' );
211
}
212
213
/**
214
 * Retrieve Payment Key of the Receipt Access Session.
215
 *
216
 * @return array|string
217
 * @since 1.8.17
218
 */
219
function give_get_receipt_session() {
220
	return Give()->session->get( 'receipt_access' );
221
}
222
223
/**
224
 * Retrieve Payment Key of the History Access Session.
225
 *
226
 * @return array|string
227
 * @since 1.8.17
228
 */
229
function give_get_history_session() {
230
	return (bool) Give()->session->get( 'history_access' );
231
}
232
233
/**
234
 * Generate Item Title for Payment Gateway.
235
 *
236
 * @param array $payment_data Payment Data.
237
 *
238
 * @return string By default, the name of the form. Then the price level text if any is found.
239
 * @since 1.8.14
240
 */
241
function give_payment_gateway_item_title( $payment_data ) {
242
243
	$form_id   = intval( $payment_data['post_data']['give-form-id'] );
244
	$item_name = isset( $payment_data['post_data']['give-form-title'] ) ? $payment_data['post_data']['give-form-title'] : '';
245
	$price_id  = isset( $payment_data['post_data']['give-price-id'] ) ? $payment_data['post_data']['give-price-id'] : '';
246
247
	// Verify has variable prices.
248
	if ( give_has_variable_prices( $form_id ) && ! empty( $price_id ) ) {
249
250
		$item_price_level_text = give_get_price_option_name( $form_id, $price_id, 0, false );
251
252
		/**
253
		 * Output donation level text if:
254
		 *
255
		 * 1. It's not a custom amount
256
		 * 2. The level field has actual text and isn't the amount (which is already displayed on the receipt).
257
		 */
258
		if ( 'custom' !== $price_id && ! empty( $item_price_level_text ) ) {
259
			// Matches a donation level - append level text.
260
			$item_name .= ' - ' . $item_price_level_text;
261
		}
262
	}
263
264
	/**
265
	 * Filter the Item Title of Payment Gateway.
266
	 *
267
	 * @param string $item_name    Item Title of Payment Gateway.
268
	 * @param int    $form_id      Donation Form ID.
269
	 * @param array  $payment_data Payment Data.
270
	 *
271
	 * @return string
272
	 * @since 1.8.14
273
	 */
274
	return apply_filters( 'give_payment_gateway_item_title', $item_name, $form_id, $payment_data );
275
}
276
277
/**
278
 * Get Donation Summary
279
 *
280
 * Creates a donation summary for payment gateways from the donation data before the payment is created in the database.
281
 *
282
 * @param array $donation_data
283
 * @param bool  $name_and_email
284
 * @param int   $length
285
 *
286
 * @return string
287
 * @since       1.8.12
288
 */
289
function give_payment_gateway_donation_summary( $donation_data, $name_and_email = true, $length = 255 ) {
290
291
	$form_id  = isset( $donation_data['post_data']['give-form-id'] ) ? $donation_data['post_data']['give-form-id'] : '';
292
	$price_id = isset( $donation_data['post_data']['give-price-id'] ) ? $donation_data['post_data']['give-price-id'] : '';
293
294
	// Form title.
295
	$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' ) ) );
296
297
	// Form multilevel if applicable.
298
	if ( ! empty( $price_id ) && 'custom' !== $price_id ) {
299
		$summary .= ': ' . give_get_price_option_name( $form_id, $donation_data['post_data']['give-price-id'] );
300
	}
301
302
	// Add Donor's name + email if requested.
303
	if ( $name_and_email ) {
304
305
		// First name
306 View Code Duplication
		if ( isset( $donation_data['user_info']['first_name'] ) && ! empty( $donation_data['user_info']['first_name'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
307
			$summary .= ' - ' . $donation_data['user_info']['first_name'];
308
		}
309
310 View Code Duplication
		if ( isset( $donation_data['user_info']['last_name'] ) && ! empty( $donation_data['user_info']['last_name'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
311
			$summary .= ' ' . $donation_data['user_info']['last_name'];
312
		}
313
314
		$summary .= ' (' . $donation_data['user_email'] . ')';
315
	}
316
317
	// Cut the length
318
	$summary = substr( $summary, 0, $length );
319
320
	return apply_filters( 'give_payment_gateway_donation_summary', $summary );
321
}
322
323
324
/**
325
 * Get user host
326
 *
327
 * Returns the webhost this site is using if possible
328
 *
329
 * @return string $host if detected, false otherwise
330
 * @since 1.0
331
 */
332
function give_get_host() {
333
	$find_host = gethostname();
334
335
	if ( strpos( $find_host, 'sgvps.net' ) ) {
336
		$host = 'Siteground';
337
	} elseif ( defined( 'WPE_APIKEY' ) ) {
338
		$host = 'WP Engine';
339
	} elseif ( defined( 'PAGELYBIN' ) || strpos( $find_host, 'pagelyhosting.com' ) ) {
340
		$host = 'Pagely';
341
	} elseif ( strpos( $find_host, 'secureserver.net' ) ) {
342
		$host = 'GoDaddy/Media Temple';
343
	} elseif ( DB_HOST == 'localhost:/tmp/mysql5.sock' ) {
344
		$host = 'ICDSoft';
345
	} elseif ( DB_HOST == 'mysqlv5' ) {
346
		$host = 'NetworkSolutions';
347
	} elseif ( strpos( DB_HOST, 'ipagemysql.com' ) !== false ) {
348
		$host = 'iPage';
349
	} elseif ( strpos( DB_HOST, 'ipowermysql.com' ) !== false ) {
350
		$host = 'IPower';
351
	} elseif ( strpos( DB_HOST, '.gridserver.com' ) !== false ) {
352
		$host = 'MediaTemple Grid';
353
	} elseif ( strpos( DB_HOST, '.pair.com' ) !== false ) {
354
		$host = 'pair Networks';
355
	} elseif ( strpos( DB_HOST, '.stabletransit.com' ) !== false ) {
356
		$host = 'Rackspace Cloud';
357
	} elseif ( strpos( DB_HOST, '.sysfix.eu' ) !== false ) {
358
		$host = 'SysFix.eu Power Hosting';
359
	} elseif ( strpos( $_SERVER['SERVER_NAME'], 'Flywheel' ) !== false || strpos( $find_host, 'fw' ) ) {
360
		$host = 'Flywheel';
361
	} else {
362
		// Adding a general fallback for data gathering
363
		$host = 'DBH: ' . DB_HOST . ', SRV: ' . $_SERVER['SERVER_NAME'];
364
	}
365
366
	return $host;
367
}
368
369
/**
370
 * Marks a function as deprecated and informs when it has been used.
371
 *
372
 * There is a hook give_deprecated_function_run that will be called that can be used
373
 * to get the backtrace up to what file and function called the deprecated
374
 * function.
375
 *
376
 * The current behavior is to trigger a user error if WP_DEBUG is true.
377
 *
378
 * This function is to be used in every function that is deprecated.
379
 *
380
 * @param string $function    The function that was called.
381
 * @param string $version     The plugin version that deprecated the function.
382
 * @param string $replacement Optional. The function that should have been called.
383
 * @param array  $backtrace   Optional. Contains stack backtrace of deprecated function.
384
 *
385
 * @uses do_action() Calls 'give_deprecated_function_run' and passes the function name, what to use instead,
386
 *       and the version the function was deprecated in.
387
 * @uses apply_filters() Calls 'give_deprecated_function_trigger_error' and expects boolean value of true to do
388
 *       trigger or false to not trigger error.
389
 */
390
function _give_deprecated_function( $function, $version, $replacement = null, $backtrace = null ) {
391
392
	/**
393
	 * Fires while give deprecated function call occurs.
394
	 *
395
	 * Allow you to hook to deprecated function call.
396
	 *
397
	 * @param string $function    The function that was called.
398
	 * @param string $replacement Optional. The function that should have been called.
399
	 * @param string $version     The plugin version that deprecated the function.
400
	 *
401
	 * @since 1.0
402
	 */
403
	do_action( 'give_deprecated_function_run', $function, $replacement, $version );
404
405
	$show_errors = current_user_can( 'manage_options' );
406
407
	// Allow plugin to filter the output error trigger.
408
	if ( WP_DEBUG && apply_filters( 'give_deprecated_function_trigger_error', $show_errors ) ) {
409
		if ( ! is_null( $replacement ) ) {
410
			trigger_error( sprintf( __( '%1$s is <strong>deprecated</strong> since Give version %2$s! Use %3$s instead.', 'give' ), $function, $version, $replacement ) );
411
			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.
412
			// Alternatively we could dump this to a file.
413
		} else {
414
			trigger_error( sprintf( __( '%1$s is <strong>deprecated</strong> since Give version %2$s with no alternative available.', 'give' ), $function, $version ) );
415
			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.
416
			// Alternatively we could dump this to a file.
417
		}
418
	}
419
}
420
421
/**
422
 * Give Get Admin ID
423
 *
424
 * Helper function to return the ID of the post for admin usage
425
 *
426
 * @return string $post_id
427
 */
428
function give_get_admin_post_id() {
429
	$post_id = isset( $_REQUEST['post'] ) ? absint( $_REQUEST['post'] ) : null;
430
431
	$post_id = ! empty( $post_id ) ? $post_id : ( isset( $_REQUEST['post_id'] ) ? absint( $_REQUEST['post_id'] ) : null );
432
433
	$post_id = ! empty( $post_id ) ? $post_id : ( isset( $_REQUEST['post_ID'] ) ? absint( $_REQUEST['post_ID'] ) : null );
434
435
	return $post_id;
436
}
437
438
/**
439
 * Get PHP Arg Separator Output
440
 *
441
 * @return string Arg separator output
442
 * @since 1.0
443
 */
444
function give_get_php_arg_separator_output() {
445
	return ini_get( 'arg_separator.output' );
446
}
447
448
449
/**
450
 * Month Num To Name
451
 *
452
 * Takes a month number and returns the name three letter name of it.
453
 *
454
 * @param int $n
455
 *
456
 * @return string Short month name
457
 * @since 1.0
458
 */
459
function give_month_num_to_name( $n ) {
460
	$timestamp = mktime( 0, 0, 0, $n, 1, 2005 );
461
462
	return date_i18n( 'M', $timestamp );
463
}
464
465
/**
466
 * Checks whether function is disabled.
467
 *
468
 * @param string $function Name of the function.
469
 *
470
 * @return bool Whether or not function is disabled.
471
 * @since 1.0
472
 */
473
function give_is_func_disabled( $function ) {
474
	$disabled = explode( ',', ini_get( 'disable_functions' ) );
475
476
	return in_array( $function, $disabled );
477
}
478
479
480
/**
481
 * Create SVG library function
482
 *
483
 * @param string $icon
484
 *
485
 * @return string
486
 */
487
function give_svg_icons( $icon ) {
488
489
	// Store your SVGs in an associative array
490
	$svgs = array(
491
		'microphone'    => 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pg0KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE2LjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPg0KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgd2lkdGg9IjY0cHgiIGhlaWdodD0iMTAwcHgiIHZpZXdCb3g9IjAgLTIwIDY0IDEyMCIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNjQgMTAwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8Zz4NCgk8Zz4NCgkJPHBhdGggZD0iTTYyLDM2LjIxNWgtM2MtMS4xLDAtMiwwLjktMiwyVjUyYzAsNi42ODYtNS4yNjYsMTgtMjUsMThTNyw1OC42ODYsNyw1MlYzOC4yMTVjMC0xLjEtMC45LTItMi0ySDJjLTEuMSwwLTIsMC45LTIsMlY1Mg0KCQkJYzAsMTEuMTg0LDguMjE1LDIzLjE1MiwyNywyNC44MDFWOTBIMTRjLTEuMSwwLTIsMC44OTgtMiwydjZjMCwxLjEsMC45LDIsMiwyaDM2YzEuMSwwLDItMC45LDItMnYtNmMwLTEuMTAyLTAuOS0yLTItMkgzN1Y3Ni44MDENCgkJCUM1NS43ODUsNzUuMTUyLDY0LDYzLjE4NCw2NCw1MlYzOC4yMTVDNjQsMzcuMTE1LDYzLjEsMzYuMjE1LDYyLDM2LjIxNXoiLz4NCgkJPHBhdGggZD0iTTMyLDYwYzExLjczMiwwLDE1LTQuODE4LDE1LThWMzYuMjE1SDE3VjUyQzE3LDU1LjE4MiwyMC4yNjYsNjAsMzIsNjB6Ii8+DQoJCTxwYXRoIGQ9Ik00Nyw4YzAtMy4xODQtMy4yNjgtOC0xNS04QzIwLjI2NiwwLDE3LDQuODE2LDE3LDh2MjEuMjE1aDMwVjh6Ii8+DQoJPC9nPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPC9zdmc+DQo=',
492
		'alert'         => 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pg0KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE2LjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPg0KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgd2lkdGg9IjI4LjkzOHB4IiBoZWlnaHQ9IjI1LjAwNXB4IiB2aWV3Qm94PSIwIDAgMjguOTM4IDI1LjAwNSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMjguOTM4IDI1LjAwNTsiDQoJIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPHBhdGggc3R5bGU9ImZpbGw6IzAwMDAwMDsiIGQ9Ik0yOC44NTksMjQuMTU4TDE0Ljk1NywwLjI3OUMxNC44NTYsMC4xMDYsMTQuNjcsMCwxNC40NjgsMGMtMC4xOTgsMC0wLjM4MywwLjEwNi0wLjQ4MSwwLjI3OQ0KCUwwLjA3OSwyNC4xNThjLTAuMTAyLDAuMTc1LTAuMTA2LDAuMzg5LTAuMDA2LDAuNTY1YzAuMTAzLDAuMTc0LDAuMjg3LDAuMjgyLDAuNDg4LDAuMjgyaDI3LjgxNGMwLjIwMSwwLDAuMzg5LTAuMTA4LDAuNDg4LTAuMjgyDQoJYzAuMDQ3LTAuMDg4LDAuMDc0LTAuMTg2LDAuMDc0LTAuMjgxQzI4LjkzOCwyNC4zNDMsMjguOTExLDI0LjI0NSwyOC44NTksMjQuMTU4eiBNMTYuMzY5LDguNDc1bC0wLjQ2Miw5LjQ5M2gtMi4zODlsLTAuNDYxLTkuNDkzDQoJSDE2LjM2OXogTTE0LjcxMSwyMi44MjhoLTAuMDQyYy0xLjA4OSwwLTEuODQzLTAuODE3LTEuODQzLTEuOTA3YzAtMS4xMzEsMC43NzQtMS45MDcsMS44ODUtMS45MDdzMS44NDYsMC43NzUsMS44NjcsMS45MDcNCglDMTYuNTc5LDIyLjAxMSwxNS44NDQsMjIuODI4LDE0LjcxMSwyMi44Mjh6Ii8+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8L3N2Zz4NCg==',
493
		'placemark'     => 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxNi4wLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB3aWR0aD0iMTAwcHgiIGhlaWdodD0iMTAwcHgiIHZpZXdCb3g9IjAgMCAxMDAgMTAwIiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAxMDAgMTAwIiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxnPg0KCTxwYXRoIGQ9Ik01MC40MzQsMjAuMjcxYy0xMi40OTksMC0yMi42NjgsMTAuMTY5LTIyLjY2OCwyMi42NjhjMCwxMS44MTQsMTguODE1LDMyLjE1NSwyMC45NiwzNC40MzdsMS43MDgsMS44MTZsMS43MDgtMS44MTYNCgkJYzIuMTQ1LTIuMjgxLDIwLjk2LTIyLjYyMywyMC45Ni0zNC40MzdDNzMuMTAzLDMwLjQ0LDYyLjkzNCwyMC4yNzEsNTAuNDM0LDIwLjI3MXogTTUwLjQzNCw1Mi4zMmMtNS4xNzIsMC05LjM4LTQuMjA4LTkuMzgtOS4zOA0KCQlzNC4yMDgtOS4zOCw5LjM4LTkuMzhjNS4xNzMsMCw5LjM4LDQuMjA4LDkuMzgsOS4zOFM1NS42MDcsNTIuMzIsNTAuNDM0LDUyLjMyeiIvPg0KPC9nPg0KPC9zdmc+DQo=',
494
		'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==',
495
		'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',
496
	);
497
498
	// Return the chosen icon's SVG string
499
	return $svgs[ $icon ];
500
}
501
502
/**
503
 * Modify Admin Nav Menu Label
504
 *
505
 * @param object $post_type The current object to add a menu items meta box for.
506
 *
507
 * @return mixed
508
 * @since 1.3
509
 */
510
function modify_nav_menu_meta_box_object( $post_type ) {
511
	if ( isset( $post_type->name ) && $post_type->name == 'give_forms' ) {
512
		$post_type->labels->name = esc_html__( 'Donation Forms', 'give' );
513
	}
514
515
	return $post_type;
516
}
517
518
add_filter( 'nav_menu_meta_box_object', 'modify_nav_menu_meta_box_object' );
519
520
/**
521
 * Show Donation Forms Post Type in Appearance > Menus by default on fresh install.
522
 *
523
 * @return bool
524
 * @todo  Remove this, when WordPress Core ticket is resolved (https://core.trac.wordpress.org/ticket/16828).
525
 *
526
 * @since 1.8.14
527
 */
528
function give_donation_metabox_menu() {
529
530
	// Get Current Screen.
531
	$screen = get_current_screen();
532
533
	// Proceed, if current screen is navigation menus.
534
	if ( 'nav-menus' === $screen->id && give_is_setting_enabled( give_get_option( 'forms_singular' ) ) && ! get_user_option( 'give_is_donation_forms_menu_updated' ) ) {
535
536
		// Return false, if it fails to retrieve hidden meta box list and is not admin.
537
		if ( ! is_admin() || ( ! $hidden_meta_boxes = get_user_option( 'metaboxhidden_nav-menus' ) ) ) {
538
			return false;
539
		}
540
541
		// Return false, In case, we don't find 'Donation Form' in hidden meta box list.
542
		if ( ! in_array( 'add-post-type-give_forms', $hidden_meta_boxes, true ) ) {
543
			return false;
544
		}
545
546
		// Exclude 'Donation Form' value from hidden meta box's list.
547
		$hidden_meta_boxes = array_diff( $hidden_meta_boxes, array( 'add-post-type-give_forms' ) );
548
549
		// Get current user ID.
550
		$user = wp_get_current_user();
551
552
		update_user_option( $user->ID, 'metaboxhidden_nav-menus', $hidden_meta_boxes, true );
553
		update_user_option( $user->ID, 'give_is_donation_forms_menu_updated', true, true );
554
	}
555
}
556
557
add_action( 'current_screen', 'give_donation_metabox_menu' );
558
559
/**
560
 * Array_column backup usage
561
 *
562
 * This file is part of the array_column library.
563
 *
564
 * @since      : 1.3.0.1
565
 *
566
 * @copyright  Copyright (c) Ben Ramsey (http://benramsey.com)
567
 * @license    https://opensource.org/licenses/MIT MIT
568
 */
569
570
if ( ! function_exists( 'array_column' ) ) {
571
	/**
572
	 * Returns the values from a single column of the input array, identified by
573
	 * the $columnKey.
574
	 *
575
	 * Optionally, you may provide an $indexKey to index the values in the returned
576
	 * array by the values from the $indexKey column in the input array.
577
	 *
578
	 * @param array      $input     A multi-dimensional array (record set) from which to pull
579
	 *                              a column of values.
580
	 * @param int|string $columnKey The column of values to return. This value may be the
581
	 *                              integer key of the column you wish to retrieve, or it
582
	 *                              may be the string key name for an associative array.
583
	 * @param mixed      $indexKey  (Optional.) The column to use as the index/keys for
584
	 *                              the returned array. This value may be the integer key
585
	 *                              of the column, or it may be the string key name.
586
	 *
587
	 * @return array
588
	 */
589
	function array_column( $input = null, $columnKey = null, $indexKey = null ) {
0 ignored issues
show
Unused Code introduced by
The parameter $input is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $columnKey is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $indexKey is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
590
		// Using func_get_args() in order to check for proper number of
591
		// parameters and trigger errors exactly as the built-in array_column()
592
		// does in PHP 5.5.
593
		$argc   = func_num_args();
594
		$params = func_get_args();
595
596
		if ( $argc < 2 ) {
597
			trigger_error( sprintf( esc_html__( 'array_column() expects at least 2 parameters, %s given.', 'give' ), $argc ), E_USER_WARNING );
598
599
			return null;
600
		}
601
602
		if ( ! is_array( $params[0] ) ) {
603
			trigger_error( sprintf( esc_html__( 'array_column() expects parameter 1 to be array, %s given.', 'give' ), gettype( $params[0] ) ), E_USER_WARNING );
604
605
			return null;
606
		}
607
608 View Code Duplication
		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' ) ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
609
			trigger_error( esc_html__( 'array_column(): The column key should be either a string or an integer.', 'give' ), E_USER_WARNING );
610
611
			return false;
612
		}
613
614 View Code Duplication
		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' ) ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
615
			trigger_error( esc_html__( 'array_column(): The index key should be either a string or an integer.', 'give' ), E_USER_WARNING );
616
617
			return false;
618
		}
619
620
		$paramsInput     = $params[0];
621
		$paramsColumnKey = ( $params[1] !== null ) ? (string) $params[1] : null;
622
623
		$paramsIndexKey = null;
624
		if ( isset( $params[2] ) ) {
625
			if ( is_float( $params[2] ) || is_int( $params[2] ) ) {
626
				$paramsIndexKey = (int) $params[2];
627
			} else {
628
				$paramsIndexKey = (string) $params[2];
629
			}
630
		}
631
632
		$resultArray = array();
633
634
		foreach ( $paramsInput as $row ) {
635
			$key    = $value = null;
636
			$keySet = $valueSet = false;
637
638
			if ( $paramsIndexKey !== null && array_key_exists( $paramsIndexKey, $row ) ) {
639
				$keySet = true;
640
				$key    = (string) $row[ $paramsIndexKey ];
641
			}
642
643
			if ( $paramsColumnKey === null ) {
644
				$valueSet = true;
645
				$value    = $row;
646
			} elseif ( is_array( $row ) && array_key_exists( $paramsColumnKey, $row ) ) {
647
				$valueSet = true;
648
				$value    = $row[ $paramsColumnKey ];
649
			}
650
651
			if ( $valueSet ) {
652
				if ( $keySet ) {
653
					$resultArray[ $key ] = $value;
654
				} else {
655
					$resultArray[] = $value;
656
				}
657
			}
658
		}
659
660
		return $resultArray;
661
	}
662
}// End if().
663
664
/**
665
 * Determines the receipt visibility status.
666
 *
667
 * @param int $donation_id Donation ID.
668
 *
669
 * @return bool Whether the receipt is visible or not.
670
 * @since 1.3.2
671
 */
672
function give_can_view_receipt( $donation_id ) {
673
674
	global $give_receipt_args;
675
676
	$donor            = false;
677
	$can_view_receipt = false;
678
679
	// Bail out, if donation id doesn't exist.
680
	if ( empty( $donation_id ) ) {
681
		return $can_view_receipt;
682
	}
683
684
	$give_receipt_args['id'] = $donation_id;
685
686
	// Add backward compatibility.
687
	if ( ! is_numeric( $donation_id ) ) {
688
		$give_receipt_args['id'] = give_get_donation_id_by_key( $donation_id );
689
	}
690
691
	// Return to download receipts from admin panel.
692
	if ( current_user_can( 'export_give_reports' ) ) {
693
694
		/**
695
		 * This filter will be used to modify can view receipt response when accessed from admin.
696
		 *
697
		 * @since 2.3.1
698
		 */
699
		return apply_filters( 'give_can_admin_view_receipt', true );
700
	}
701
702
	if ( is_user_logged_in() || current_user_can( 'view_give_sensitive_data' ) ) {
703
704
		// Proceed only, if user is logged in or can view sensitive Give data.
705
		$donor = Give()->donors->get_donor_by( 'user_id', get_current_user_id() );
706
707
	} elseif ( ! is_user_logged_in() ) {
708
709
		// Check whether it is purchase session?
710
		// This condition is to show receipt to donor after donation.
711
		$purchase_session = give_get_purchase_session();
712
713
		if (
714
			! empty( $purchase_session )
715
			&& absint( $purchase_session['donation_id'] ) === absint( $donation_id )
716
		) {
717
			$donor = Give()->donors->get_donor_by( 'email', $purchase_session['user_email'] );
718
		}
719
720
		// Check whether it is receipt access session?
721
		$receipt_session    = give_get_receipt_session();
722
		$email_access_token = ! empty( $_COOKIE['give_nl'] ) ? give_clean( $_COOKIE['give_nl'] ) : false;
723
724
		if (
725
			! empty( $receipt_session ) ||
726
			(
727
				give_is_setting_enabled( give_get_option( 'email_access' ) ) &&
728
				! empty( $email_access_token )
729
			)
730
		) {
731
			$donor = ! empty( $email_access_token )
732
				? Give()->donors->get_donor_by_token( $email_access_token )
0 ignored issues
show
Documentation introduced by
$email_access_token is of type string|array, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
733
				: false;
734
		}
735
	}
736
737
	// If donor object exists, compare the donation ids of donor with the donation receipt donor tries to access.
738
	if ( is_object( $donor ) ) {
739
		$is_donor_donated = in_array( (int) $donation_id, array_map( 'absint', explode( ',', $donor->payment_ids ) ), true );
740
		$can_view_receipt = $is_donor_donated ? true : $can_view_receipt;
741
742
		if ( ! $is_donor_donated ) {
743
			Give()->session->set( 'donor_donation_mismatch', true );
744
		}
745
	}
746
747
	return (bool) apply_filters( 'give_can_view_receipt', $can_view_receipt, $donation_id );
748
749
}
750
751
/**
752
 * Fallback for cal_days_in_month
753
 *
754
 * Fallback in case the calendar extension is not loaded in PHP; Only supports Gregorian calendar
755
 */
756
if ( ! function_exists( 'cal_days_in_month' ) ) {
757
	/**
758
	 * cal_days_in_month
759
	 *
760
	 * @param int $calendar
761
	 * @param int $month
762
	 * @param int $year
763
	 *
764
	 * @return bool|string
765
	 */
766
	function cal_days_in_month( $calendar, $month, $year ) {
0 ignored issues
show
Unused Code introduced by
The parameter $calendar is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
767
		return date( 't', mktime( 0, 0, 0, $month, 1, $year ) );
768
	}
769
}
770
771
/**
772
 * Get plugin info including status, type, and license validation.
773
 *
774
 * @return array Plugin info plus status, type, and license validation if
775
 *               available.
776
 * @since 1.8.0
777
 *
778
 * @todo  update this function to query give addon and additional
779
 *
780
 * This is an enhanced version of get_plugins() that returns the status
781
 * (`active` or `inactive`) of all plugins, type of plugin (`add-on` or `other`
782
 * and license validation for Give add-ons (`true` or `false`). Does not include
783
 * MU plugins.
784
 */
785
function give_get_plugins( $args = array() ) {
786
	$plugins             = get_plugins();
787
	$active_plugin_paths = (array) get_option( 'active_plugins', array() );
788
789
	if ( is_multisite() ) {
790
		$network_activated_plugin_paths = array_keys( get_site_option( 'active_sitewide_plugins', array() ) );
791
		$active_plugin_paths            = array_merge( $active_plugin_paths, $network_activated_plugin_paths );
792
	}
793
794
	foreach ( $plugins as $plugin_path => $plugin_data ) {
795
		// Is plugin active?
796
		if ( in_array( $plugin_path, $active_plugin_paths ) ) {
797
			$plugins[ $plugin_path ]['Status'] = 'active';
798
		} else {
799
			$plugins[ $plugin_path ]['Status'] = 'inactive';
800
		}
801
802
		$dirname                         = strtolower( dirname( $plugin_path ) );
803
		$plugins[ $plugin_path ]['Dir']  = $dirname;
804
		$plugins[ $plugin_path ]['Path'] = $plugin_path;
805
806
		// A third party add-on may contain more then one author like sofort, so it is better to compare array.
807
		$author                          = false !== strpos( $plugin_data['Author'], ',' )
808
			? array_map( 'trim', explode( ',', $plugin_data['Author'] ) )
809
			: array( $plugin_data['Author'] );
810
811
		// Is the plugin a Give add-on?
812
		if (
813
			false !== strpos( $dirname, 'give-' )
814
			&& (
815
				false !== strpos( $plugin_data['PluginURI'], 'givewp.com' )
816
				|| array_intersect( $author, array( 'WordImpress', 'GiveWP' ) )
817
			)
818
		) {
819
			// Plugin is a Give-addon.
820
			$plugins[ $plugin_path ]['Type'] = 'add-on';
821
822
			$license_active = Give_License::get_license_by_plugin_dirname( $dirname );
823
824
			// Does a valid license exist?
825
			$plugins[ $plugin_path ]['License'] = $license_active && 'valid' === $license_active['license'];
0 ignored issues
show
Bug Best Practice introduced by
The expression $license_active of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
826
827
		} else {
828
			// Plugin is not a Give add-on.
829
			$plugins[ $plugin_path ]['Type'] = 'other';
830
		}
831
	}
832
833
	if( ! empty( $args['only_add_on'] ) ) {
834
		$plugins = array_filter( $plugins, function( $plugin ){
835
			return 'add-on' === $plugin['Type'];
836
		});
837
	}
838
839
	if( ! empty( $args['only_premium_add_ons'] ) ) {
840
		$premium_addons_list = give_get_premium_add_ons();
841
842
		foreach ( $plugins as $key => $plugin ){
843
			$addon_shortname = str_replace( 'give-', '', $plugin['Dir'] );
844
			$tmp = $premium_addons_list;
845
			$is_premium = count( array_filter( $tmp, function( $plugin ) use ($addon_shortname){
846
				return false !== strpos( $plugin, $addon_shortname );
847
			}) );
848
849
			if(
850
				'add-on' !== $plugin['Type']
851
				|| ( false === strpos( $plugin['PluginURI'], 'givewp.com' ) && ! $is_premium )
852
			) {
853
				unset( $plugins[$key] );
854
			}
855
		}
856
	}
857
858
	return $plugins;
859
}
860
861
/**
862
 * Check if terms enabled or not for form.
863
 *
864
 * @param $form_id
865
 *
866
 * @return bool
867
 * @since 1.8
868
 */
869
function give_is_terms_enabled( $form_id ) {
870
	$form_option = give_get_meta( $form_id, '_give_terms_option', true );
871
872
	if ( give_is_setting_enabled( $form_option, 'global' ) && give_is_setting_enabled( give_get_option( 'terms' ) ) ) {
873
		return true;
874
875
	} elseif ( give_is_setting_enabled( $form_option ) ) {
876
		return true;
877
878
	} else {
879
		return false;
880
	}
881
}
882
883
/**
884
 * Delete donation stats cache.
885
 *
886
 * @param string|array $date_range Date for stats.
887
 *                                 Date value should be in today, yesterday, this_week, last_week, this_month,
888
 *                                 last_month, this_quarter, last_quarter, this_year, last_year. For date value other,
889
 *                                 all cache will be removed.
890
 *
891
 * @param array        $args
892
 *
893
 * @return WP_Error|bool
894
 * @since 1.8.7
895
 *
896
 * @todo  Resolve stats cache key naming issue. Currently it is difficult to regenerate cache key.
897
 */
898
function give_delete_donation_stats( $date_range = '', $args = array() ) {
899
900
	// Delete all cache.
901
	$status = Give_Cache::delete( Give_Cache::get_options_like( 'give_stats' ) );
902
903
	/**
904
	 * Fire the action when donation stats delete.
905
	 *
906
	 * @param string|array $date_range
907
	 * @param array        $args
908
	 *
909
	 * @since 1.8.7
910
	 */
911
	do_action( 'give_delete_donation_stats', $status, $date_range, $args );
912
913
	return $status;
914
}
915
916
/**
917
 * Check if admin creating new donation form or not.
918
 *
919
 * @return bool
920
 * @since 2.0
921
 */
922
function give_is_add_new_form_page() {
923
	$status = false;
924
925
	if ( false !== strpos( $_SERVER['REQUEST_URI'], '/wp-admin/post-new.php?post_type=give_forms' ) ) {
926
		$status = true;
927
	}
928
929
	return $status;
930
}
931
932
/**
933
 * Get Form/Payment meta.
934
 *
935
 * Note: This function will help you to get meta for payment and form.
936
 *       If you want to get meta for donors then use get_meta of Give_Donor and
937
 *       If you want to get meta for logs then use get_meta of Give_Logging->logmeta_db.
938
 *
939
 * @param int    $id
940
 * @param string $meta_key
941
 * @param bool   $single
942
 * @param bool   $default
943
 * @param string $meta_type
944
 *
945
 * @return mixed
946
 * @since 1.8.8
947
 */
948
function give_get_meta( $id, $meta_key = '', $single = false, $default = false, $meta_type = '' ) {
949 View Code Duplication
	switch ( $meta_type ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
950
		case 'donation':
951
			$meta_value = Give()->payment_meta->get_meta( $id, $meta_key, $single );
952
			break;
953
954
		case 'form':
955
			$meta_value = Give()->form_meta->get_meta( $id, $meta_key, $single );
956
			break;
957
958
		case 'donor':
959
			$meta_value = Give()->donor_meta->get_meta( $id, $meta_key, $single );
960
			break;
961
962
		default:
963
			$meta_value = get_post_meta( $id, $meta_key, $single );
964
	}
965
966
	/**
967
	 * Filter the meta value
968
	 *
969
	 * @since 1.8.8
970
	 */
971
	$meta_value = apply_filters( 'give_get_meta', $meta_value, $id, $meta_key, $default, $meta_value );
972
973
	if ( ( empty( $meta_key ) || empty( $meta_value ) ) && $default ) {
974
		$meta_value = $default;
975
	}
976
977
	return $meta_value;
978
}
979
980
/**
981
 * Update Form/Payment meta.
982
 *
983
 * @param int    $id
984
 * @param string $meta_key
985
 * @param mixed  $meta_value
986
 * @param mixed  $prev_value
987
 * @param string $meta_type
988
 *
989
 * @return mixed
990
 * @since 1.8.8
991
 */
992
function give_update_meta( $id, $meta_key, $meta_value, $prev_value = '', $meta_type = '' ) {
993
	switch ( $meta_type ) {
994
		case 'donation':
995
			$status = Give()->payment_meta->update_meta( $id, $meta_key, $meta_value, $prev_value );
996
			break;
997
998
		case 'form':
999
			$status = Give()->form_meta->update_meta( $id, $meta_key, $meta_value, $prev_value );
1000
			break;
1001
1002
		case 'donor':
1003
			$status = Give()->donor_meta->update_meta( $id, $meta_key, $meta_value, $prev_value );
1004
			break;
1005
1006
		default:
1007
			$status = update_post_meta( $id, $meta_key, $meta_value, $prev_value );
1008
	}
1009
1010
	/**
1011
	 * Filter the meta value update status
1012
	 *
1013
	 * @since 1.8.8
1014
	 */
1015
	return apply_filters( 'give_update_meta', $status, $id, $meta_key, $meta_value, $meta_type );
1016
}
1017
1018
/**
1019
 * Delete Form/Payment meta.
1020
 *
1021
 * @param int    $id
1022
 * @param string $meta_key
1023
 * @param string $meta_value
1024
 * @param string $meta_type
1025
 *
1026
 * @return mixed
1027
 * @since 1.8.8
1028
 */
1029
function give_delete_meta( $id, $meta_key, $meta_value = '', $meta_type = '' ) {
1030 View Code Duplication
	switch ( $meta_type ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1031
		case 'donation':
1032
			$status = Give()->payment_meta->delete_meta( $id, $meta_key, $meta_value );
1033
			break;
1034
1035
		case 'form':
1036
			$status = Give()->form_meta->delete_meta( $id, $meta_key, $meta_value );
1037
			break;
1038
1039
		case 'donor':
1040
			$status = Give()->donor_meta->delete_meta( $id, $meta_key, $meta_value );
1041
			break;
1042
1043
		default:
1044
			$status = delete_post_meta( $id, $meta_key, $meta_value );
1045
	}
1046
1047
	/**
1048
	 * Filter the meta value delete status
1049
	 *
1050
	 * @since 1.8.8
1051
	 */
1052
	return apply_filters( 'give_delete_meta', $status, $id, $meta_key, $meta_value, $meta_type );
1053
}
1054
1055
/**
1056
 * Check if the upgrade routine has been run for a specific action
1057
 *
1058
 * @param string $upgrade_action The upgrade action to check completion for
1059
 *
1060
 * @return bool                   If the action has been added to the completed actions array
1061
 * @since  1.0
1062
 */
1063
function give_has_upgrade_completed( $upgrade_action = '' ) {
1064
	// Bailout.
1065
	if ( empty( $upgrade_action ) ) {
1066
		return false;
1067
	}
1068
1069
	// Fresh install?
1070
	// If fresh install then all upgrades will be consider as completed.
1071
	$is_fresh_install = ! Give_Cache_Setting::get_option( 'give_version' );
1072
	if ( $is_fresh_install ) {
1073
		return true;
1074
	}
1075
1076
	$completed_upgrades = give_get_completed_upgrades();
1077
1078
	return in_array( $upgrade_action, $completed_upgrades );
1079
1080
}
1081
1082
/**
1083
 * For use when doing 'stepped' upgrade routines, to see if we need to start somewhere in the middle
1084
 *
1085
 * @return mixed   When nothing to resume returns false, otherwise starts the upgrade where it left off
1086
 * @since 1.8
1087
 */
1088
function give_maybe_resume_upgrade() {
1089
	$doing_upgrade = get_option( 'give_doing_upgrade', false );
1090
	if ( empty( $doing_upgrade ) ) {
1091
		return false;
1092
	}
1093
1094
	return $doing_upgrade;
1095
}
1096
1097
/**
1098
 * Adds an upgrade action to the completed upgrades array
1099
 *
1100
 * @param string $upgrade_action The action to add to the completed upgrades array
1101
 *
1102
 * @return bool                   If the function was successfully added
1103
 * @since  1.0
1104
 */
1105
function give_set_upgrade_complete( $upgrade_action = '' ) {
1106
1107
	if ( empty( $upgrade_action ) ) {
1108
		return false;
1109
	}
1110
1111
	$completed_upgrades   = give_get_completed_upgrades();
1112
	$completed_upgrades[] = $upgrade_action;
1113
1114
	// Remove any blanks, and only show uniques.
1115
	$completed_upgrades = array_unique( array_values( $completed_upgrades ) );
1116
1117
	/**
1118
	 * Fire the action when any upgrade set to complete.
1119
	 *
1120
	 * @since 1.8.12
1121
	 */
1122
	do_action( 'give_set_upgrade_completed', $upgrade_action, $completed_upgrades );
1123
1124
	return update_option( 'give_completed_upgrades', $completed_upgrades, false );
1125
}
1126
1127
/**
1128
 * Get's the array of completed upgrade actions
1129
 *
1130
 * @return array The array of completed upgrades
1131
 * @since  1.0
1132
 */
1133
function give_get_completed_upgrades() {
1134
	return (array) Give_Cache_Setting::get_option( 'give_completed_upgrades' );
1135
}
1136
1137
/**
1138
 * In 2.0 we updated table for log, payment and form.
1139
 *
1140
 * Note: internal purpose only.
1141
 *
1142
 * @param string $type Context for table
1143
 *
1144
 * @return null|array
1145
 * @since 2.0
1146
 * @global wpdb  $wpdb
1147
 */
1148
function __give_v20_bc_table_details( $type ) {
1149
	global $wpdb;
1150
	$table = array();
1151
1152
	// Bailout.
1153
	if ( empty( $type ) ) {
1154
		return null;
1155
	}
1156
1157
	switch ( $type ) {
1158
		case 'form':
1159
			$table['name']         = $wpdb->formmeta;
1160
			$table['column']['id'] = 'form_id';
1161
1162
			break;
1163
1164
		case 'payment':
1165
			$table['name']         = $wpdb->donationmeta;
1166
			$table['column']['id'] = Give()->payment_meta->get_meta_type() . '_id';
1167
	}
1168
1169
	// Backward compatibility.
1170
	if ( ! give_has_upgrade_completed( 'v20_move_metadata_into_new_table' ) ) {
1171
		$table['name']         = $wpdb->postmeta;
1172
		$table['column']['id'] = 'post_id';
1173
	}
1174
1175
	return $table;
1176
}
1177
1178
/**
1179
 * Remove the Give transaction pages from WP search results.
1180
 *
1181
 * @param WP_Query $query
1182
 *
1183
 * @since 1.8.13
1184
 */
1185
function give_remove_pages_from_search( $query ) {
1186
1187
	if ( ! $query->is_admin && $query->is_search && $query->is_main_query() ) {
1188
1189
		$transaction_failed = give_get_option( 'failure_page', 0 );
1190
		$success_page       = give_get_option( 'success_page', 0 );
1191
1192
		$args = apply_filters(
1193
			'give_remove_pages_from_search',
1194
			array(
1195
				$transaction_failed,
1196
				$success_page,
1197
			),
1198
			$query
1199
		);
1200
		$query->set( 'post__not_in', $args );
1201
	}
1202
}
1203
1204
add_action( 'pre_get_posts', 'give_remove_pages_from_search', 10, 1 );
1205
1206
/**
1207
 * Inserts a new key/value before a key in the array.
1208
 *
1209
 * @param string       $key       The key to insert before.
1210
 * @param array        $array     An array to insert in to.
1211
 * @param string       $new_key   The key to insert.
1212
 * @param array|string $new_value An value to insert.
1213
 *
1214
 * @return array The new array if the key exists, the passed array otherwise.
1215
 *
1216
 * @since 1.8.13
1217
 *
1218
 * @see   array_insert_before()
1219
 */
1220 View Code Duplication
function give_array_insert_before( $key, array &$array, $new_key, $new_value ) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1221
	if ( array_key_exists( $key, $array ) ) {
1222
		$new = array();
1223
		foreach ( $array as $k => $value ) {
1224
			if ( $k === $key ) {
1225
				$new[ $new_key ] = $new_value;
1226
			}
1227
			$new[ $k ] = $value;
1228
		}
1229
1230
		return $new;
1231
	}
1232
1233
	return $array;
1234
}
1235
1236
/**
1237
 * Inserts a new key/value after a key in the array.
1238
 *
1239
 * @param string       $key       The key to insert after.
1240
 * @param array        $array     An array to insert in to.
1241
 * @param string       $new_key   The key to insert.
1242
 * @param array|string $new_value An value to insert.
1243
 *
1244
 * @return array The new array if the key exists, the passed array otherwise.
1245
 *
1246
 * @since 1.8.13
1247
 *
1248
 * @see   array_insert_before()
1249
 */
1250 View Code Duplication
function give_array_insert_after( $key, array &$array, $new_key, $new_value ) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1251
	if ( array_key_exists( $key, $array ) ) {
1252
		$new = array();
1253
		foreach ( $array as $k => $value ) {
1254
			$new[ $k ] = $value;
1255
			if ( $k === $key ) {
1256
				$new[ $new_key ] = $new_value;
1257
			}
1258
		}
1259
1260
		return $new;
1261
	}
1262
1263
	return $array;
1264
}
1265
1266
/**
1267
 * Pluck a certain field out of each object in a list.
1268
 *
1269
 * This has the same functionality and prototype of
1270
 * array_column() (PHP 5.5) but also supports objects.
1271
 *
1272
 * @param array      $list      List of objects or arrays
1273
 * @param int|string $field     Field from the object to place instead of the entire object
1274
 * @param int|string $index_key Optional. Field from the object to use as keys for the new array.
1275
 *                              Default null.
1276
 *
1277
 * @return array Array of found values. If `$index_key` is set, an array of found values with keys
1278
 *               corresponding to `$index_key`. If `$index_key` is null, array keys from the original
1279
 *               `$list` will be preserved in the results.
1280
 * @since 1.8.13
1281
 */
1282
function give_list_pluck( $list, $field, $index_key = null ) {
1283
1284
	if ( ! $index_key ) {
1285
		/**
1286
		 * This is simple. Could at some point wrap array_column()
1287
		 * if we knew we had an array of arrays.
1288
		 */
1289
		foreach ( $list as $key => $value ) {
1290
			if ( is_object( $value ) ) {
1291
				if ( isset( $value->$field ) ) {
1292
					$list[ $key ] = $value->$field;
1293
				}
1294
			} else {
1295
				if ( isset( $value[ $field ] ) ) {
1296
					$list[ $key ] = $value[ $field ];
1297
				}
1298
			}
1299
		}
1300
1301
		return $list;
1302
	}
1303
1304
	/*
1305
	 * When index_key is not set for a particular item, push the value
1306
	 * to the end of the stack. This is how array_column() behaves.
1307
	 */
1308
	$newlist = array();
1309
	foreach ( $list as $value ) {
1310
		if ( is_object( $value ) ) {
1311
			if ( isset( $value->$index_key ) ) {
1312
				$newlist[ $value->$index_key ] = $value->$field;
1313
			} else {
1314
				$newlist[] = $value->$field;
1315
			}
1316
		} else {
1317
			if ( isset( $value[ $index_key ] ) ) {
1318
				$newlist[ $value[ $index_key ] ] = $value[ $field ];
1319
			} else {
1320
				$newlist[] = $value[ $field ];
1321
			}
1322
		}
1323
	}
1324
1325
	$list = $newlist;
1326
1327
	return $list;
1328
}
1329
1330
/**
1331
 * Add meta data field to a donor.
1332
 *
1333
 * @param int    $donor_id   Donor ID.
1334
 * @param string $meta_key   Metadata name.
1335
 * @param mixed  $meta_value Metadata value. Must be serializable if non-scalar.
1336
 * @param bool   $unique     Optional. Whether the same key should not be added.
1337
 *                           Default false.
1338
 *
1339
 * @return int|false Meta ID on success, false on failure.
1340
 * @since 1.8.13
1341
 */
1342
function add_donor_meta( $donor_id, $meta_key, $meta_value, $unique = false ) {
1343
	return add_metadata( 'give_customer', $donor_id, $meta_key, $meta_value, $unique );
1344
}
1345
1346
/**
1347
 * Remove metadata matching criteria from a Donor meta.
1348
 *
1349
 * You can match based on the key, or key and value. Removing based on key and
1350
 * value, will keep from removing duplicate metadata with the same key. It also
1351
 * allows removing all metadata matching key, if needed.
1352
 *
1353
 * @param int    $donor_id   Donor ID
1354
 * @param string $meta_key   Metadata name.
1355
 * @param mixed  $meta_value Optional. Metadata value.
1356
 *
1357
 * @return bool True on success, false on failure.
1358
 * @since 1.8.13
1359
 */
1360
function delete_donor_meta( $donor_id, $meta_key, $meta_value = '' ) {
1361
	return delete_metadata( 'give_customer', $donor_id, $meta_key, $meta_value );
1362
}
1363
1364
/**
1365
 * Retrieve donor meta field for a donor meta table.
1366
 *
1367
 * @param int    $donor_id Donor ID.
1368
 * @param string $key      Optional. The meta key to retrieve. By default, returns data for all keys.
1369
 * @param bool   $single   Whether to return a single value.
1370
 *
1371
 * @return mixed Will be an array if $single is false. Will be value of meta data field if $single
1372
 *  is true.
1373
 * @since 1.8.13
1374
 */
1375
function get_donor_meta( $donor_id, $key = '', $single = false ) {
1376
	return get_metadata( 'give_customer', $donor_id, $key, $single );
1377
}
1378
1379
/**
1380
 * Update customer meta field based on Donor ID.
1381
 *
1382
 * If the meta field for the donor does not exist, it will be added.
1383
 *
1384
 * @param int    $donor_id   Donor ID.
1385
 * @param string $meta_key   Metadata key.
1386
 * @param mixed  $meta_value Metadata value.
1387
 * @param mixed  $prev_value Optional. Previous value to check before removing.
1388
 *
1389
 * @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
1390
 * @since 1.8.13
1391
 */
1392
function update_donor_meta( $donor_id, $meta_key, $meta_value, $prev_value = '' ) {
1393
	return update_metadata( 'give_customer', $donor_id, $meta_key, $meta_value, $prev_value );
1394
}
1395
1396
1397
/**
1398
 * Give recalculate income and donation of the donation from ID
1399
 *
1400
 * @param int $form_id Form id of which recalculation needs to be done.
1401
 *
1402
 * @return void
1403
 * @since 1.8.13
1404
 */
1405
function give_recount_form_income_donation( $form_id = 0 ) {
1406
	// Check if form id is not empty.
1407
	if ( ! empty( $form_id ) ) {
1408
		/**
1409
		 * Filter to modify payment status.
1410
		 *
1411
		 * @since 1.8.13
1412
		 */
1413
		$accepted_statuses = apply_filters( 'give_recount_accepted_statuses', array( 'publish' ) );
1414
1415
		/**
1416
		 * Filter to modify args of payment query before recalculating the form total
1417
		 *
1418
		 * @since 1.8.13
1419
		 */
1420
		$args = apply_filters(
1421
			'give_recount_form_stats_args',
1422
			array(
1423
				'give_forms' => $form_id,
1424
				'status'     => $accepted_statuses,
1425
				'number'     => - 1,
1426
				'fields'     => 'ids',
1427
			)
1428
		);
1429
1430
		$totals = array(
1431
			'sales'    => 0,
1432
			'earnings' => 0,
1433
		);
1434
1435
		$payments = new Give_Payments_Query( $args );
1436
		$payments = $payments->get_payments();
1437
1438
		if ( $payments ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $payments of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1439
			foreach ( $payments as $payment ) {
1440
				// Ensure acceptable status only.
1441
				if ( ! in_array( $payment->post_status, $accepted_statuses ) ) {
1442
					continue;
1443
				}
1444
1445
				// Ensure only payments for this form are counted.
1446
				if ( $payment->form_id != $form_id ) {
1447
					continue;
1448
				}
1449
1450
				$totals['sales'] ++;
1451
				$totals['earnings'] += $payment->total;
1452
1453
			}
1454
		}
1455
		give_update_meta( $form_id, '_give_form_sales', $totals['sales'] );
1456
		give_update_meta( $form_id, '_give_form_earnings', give_sanitize_amount_for_db( $totals['earnings'] ) );
1457
	}// End if().
1458
}
1459
1460
1461
/**
1462
 * Get attribute string
1463
 *
1464
 * @param array $attributes
1465
 * @param array $default_attributes
1466
 *
1467
 * @return string
1468
 * @since 1.8.17
1469
 */
1470
function give_get_attribute_str( $attributes, $default_attributes = array() ) {
1471
	$attribute_str = '';
1472
1473
	if ( isset( $attributes['attributes'] ) ) {
1474
		$attributes = $attributes['attributes'];
1475
	}
1476
1477
	if ( ! empty( $default_attributes ) ) {
1478
		$attributes = wp_parse_args( $attributes, $default_attributes );
1479
	}
1480
1481
	if ( empty( $attributes ) ) {
1482
		return $attribute_str;
1483
	}
1484
1485
	foreach ( $attributes as $tag => $value ) {
1486
		if ( 'value' == $tag ) {
1487
			$value = esc_attr( $value );
1488
		}
1489
1490
		$attribute_str .= " {$tag}=\"{$value}\"";
1491
	}
1492
1493
	return trim( $attribute_str );
1494
}
1495
1496
/**
1497
 * Get the upload dir path
1498
 *
1499
 * @return string $wp_upload_dir;
1500
 * @since 1.8.17
1501
 */
1502
function give_get_wp_upload_dir() {
1503
	$wp_upload_dir = wp_upload_dir();
1504
1505
	return ( ! empty( $wp_upload_dir['path'] ) ? $wp_upload_dir['path'] : false );
1506
}
1507
1508
/**
1509
 * Get the data from uploaded JSON file
1510
 *
1511
 * @param string $file_name filename of the json file that is being uploaded
1512
 *
1513
 * @return string|bool $file_contents File content
1514
 * @since 1.8.17
1515
 */
1516
function give_get_core_settings_json( $file_name ) {
1517
	$upload_dir = give_get_wp_upload_dir();
1518
	$file_path  = $upload_dir . '/' . $file_name;
1519
1520
	if ( is_wp_error( $file_path ) || empty( $file_path ) ) {
1521
		Give_Admin_Settings::add_error( 'give-import-csv', __( 'Please upload or provide a valid JSON file.', 'give' ) );
1522
	}
1523
1524
	$file_contents = file_get_contents( $file_path );
1525
1526
	return $file_contents;
1527
}
1528
1529
/**
1530
 * Get number of donation to show when user is not login.
1531
 *
1532
 * @return int $country The two letter country code for the site's base country
1533
 * @since 1.8.17
1534
 */
1535
function give_get_limit_display_donations() {
1536
	return give_get_option( 'limit_display_donations', 1 );
1537
}
1538
1539
/**
1540
 * Add footer to the table when donor is view the donation history page with out login
1541
 *
1542
 * @since 1.8.17
1543
 */
1544
function give_donation_history_table_end() {
1545
	$email = Give()->session->get( 'give_email' );
1546
	?>
1547
	<tfoot>
1548
		<tr>
1549
			<td colspan="9999">
1550
				<div class="give-security-wrap">
1551
					<div class="give-security-column give-security-description-wrap">
1552
						<?php
1553
						echo sprintf( __( 'For security reasons, please confirm your email address (%s) to view your complete donation history.', 'give' ), $email );
1554
						?>
1555
					</div>
1556
					<div class="give-security-column give-security-button-wrap">
1557
						<a href="#" data-email="<?php echo $email; ?>" id="give-confirm-email-btn"
1558
						   class="give-confirm-email-btn give-btn">
1559
							<?php _e( 'Confirm Email', 'give' ); ?>
1560
						</a>
1561
						<span><?php _e( 'Email Sent!', 'give' ); ?></span>
1562
					</div>
1563
				</div>
1564
			</td>
1565
		</tr>
1566
	</tfoot>
1567
	<?php
1568
}
1569
1570
1571
/**
1572
 * Wrapper for _doing_it_wrong.
1573
 *
1574
 * @param string $function
1575
 * @param string $message
1576
 * @param string $version
1577
 *
1578
 * @return void
1579
 * @since  1.8.18
1580
 */
1581
function give_doing_it_wrong( $function, $message, $version ) {
1582
	$message .= "\nBacktrace:" . wp_debug_backtrace_summary();
1583
1584
	_doing_it_wrong( $function, $message, $version );
1585
}
1586
1587
1588
/**
1589
 * Remove limit from running php script complete.
1590
 *
1591
 * @since 1.8.18
1592
 */
1593
function give_ignore_user_abort() {
1594
	ignore_user_abort( true );
1595
1596
	if ( ! give_is_func_disabled( 'set_time_limit' ) && ! ini_get( 'safe_mode' ) ) {
1597
		set_time_limit( 0 );
1598
	}
1599
}
1600
1601
/**
1602
 * Get post type count.
1603
 *
1604
 * @param string $post_type
1605
 * @param array  $args
1606
 *
1607
 * @return int
1608
 * @since 2.0.2
1609
 */
1610
function give_get_total_post_type_count( $post_type = '', $args = array() ) {
0 ignored issues
show
Unused Code introduced by
The parameter $args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1611
	global $wpdb;
1612
	$where = '';
1613
1614
	if ( ! $post_type ) {
1615
		return 0;
1616
	}
1617
1618
	// Bulit where query
1619
	if ( ! empty( $post_type ) ) {
1620
		$where .= ' WHERE';
1621
1622
		if ( is_array( $post_type ) ) {
1623
			$where .= " post_type='" . implode( "' OR post_type='", $post_type ) . "'";
1624
		} else {
1625
			$where .= " post_type='{$post_type}'";
1626
		}
1627
	}
1628
1629
	$result = $wpdb->get_var( "SELECT count(ID) FROM {$wpdb->posts}{$where}" );
1630
1631
	return absint( $result );
1632
}
1633
1634
/**
1635
 * Define a constant if it is not already defined.
1636
 *
1637
 * @param string $name  Constant name.
1638
 * @param string $value Value.
1639
 *
1640
 * @credit WooCommerce
1641
 * @since  2.0.5
1642
 */
1643
function give_maybe_define_constant( $name, $value ) {
1644
	if ( ! defined( $name ) ) {
1645
		define( $name, $value );
1646
	}
1647
}
1648
1649
/**
1650
 * Decode time short tag in string
1651
 *
1652
 * @param string $string
1653
 * @param int    $timestamp
1654
 *
1655
 * @return string
1656
 * @since 2.1.0
1657
 */
1658
function give_time_do_tags( $string, $timestamp = 0 ) {
1659
	$current_time = ! empty( $timestamp ) ? $timestamp : current_time( 'timestamp' );
1660
1661
	$formatted_string = str_replace(
1662
		array(
1663
			'{D}',
1664
			'{DD}',
1665
			'{M}',
1666
			'{MM}',
1667
			'{YY}',
1668
			'{YYYY}',
1669
			'{H}',
1670
			'{HH}',
1671
			'{N}',
1672
			'{S}',
1673
		),
1674
		array(
1675
			date( 'j', $current_time ),
1676
			date( 'd', $current_time ),
1677
			date( 'n', $current_time ),
1678
			date( 'm', $current_time ),
1679
			date( 'Y', $current_time ),
1680
			date( 'Y', $current_time ),
1681
			date( 'G', $current_time ),
1682
			date( 'H', $current_time ),
1683
			date( 's', $current_time ),
1684
		),
1685
		$string
1686
	);
1687
1688
	/**
1689
	 * Filter the parsed string.
1690
	 *
1691
	 * @since 2.1.0
1692
	 */
1693
	return apply_filters( 'give_time_do_tags', $formatted_string, $string, $timestamp );
1694
}
1695
1696
1697
/**
1698
 * Check if Company field enabled or not for form or globally.
1699
 *
1700
 * @param $form_id
1701
 *
1702
 * @return bool
1703
 * @since 2.1
1704
 */
1705
function give_is_company_field_enabled( $form_id ) {
1706
	$form_setting_val   = give_get_meta( $form_id, '_give_company_field', true );
1707
	$global_setting_val = give_get_option( 'company_field' );
1708
1709
	if ( ! empty( $form_setting_val ) ) {
1710
		if ( give_is_setting_enabled( $form_setting_val, array( 'required', 'optional' ) ) ) {
0 ignored issues
show
Documentation introduced by
array('required', 'optional') is of type array<integer,string,{"0":"string","1":"string"}>, but the function expects a string|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1711
			return true;
1712
		} elseif ( 'global' === $form_setting_val && give_is_setting_enabled(
1713
			$global_setting_val,
1714
			array(
0 ignored issues
show
Documentation introduced by
array('required', 'optional') is of type array<integer,string,{"0":"string","1":"string"}>, but the function expects a string|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1715
				'required',
1716
				'optional',
1717
			)
1718
		) ) {
1719
			return true;
1720
		} else {
1721
			return false;
1722
		}
1723
	} elseif ( give_is_setting_enabled( $global_setting_val, array( 'required', 'optional' ) ) ) {
0 ignored issues
show
Documentation introduced by
array('required', 'optional') is of type array<integer,string,{"0":"string","1":"string"}>, but the function expects a string|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1724
		return true;
1725
1726
	} else {
1727
		return false;
1728
	}
1729
}
1730
1731
/**
1732
 * Check if anonymous donation field enabled or not for form or globally.
1733
 *
1734
 * @param $form_id
1735
 *
1736
 * @return bool
1737
 * @since 2.1
1738
 */
1739 View Code Duplication
function give_is_anonymous_donation_field_enabled( $form_id ) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1740
	$form_setting_val   = give_get_meta( $form_id, '_give_anonymous_donation', true, 'global' );
0 ignored issues
show
Documentation introduced by
'global' is of type string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1741
	$global_setting_val = give_get_option( 'anonymous_donation', 'disabled' );
1742
1743
	if ( ! empty( $form_setting_val ) ) {
1744
		if ( give_is_setting_enabled( $form_setting_val ) ) {
1745
			return true;
1746
		} elseif ( 'global' === $form_setting_val && give_is_setting_enabled( $global_setting_val ) ) {
1747
			return true;
1748
		} else {
1749
			return false;
1750
		}
1751
	} elseif ( give_is_setting_enabled( $global_setting_val ) ) {
1752
		return true;
1753
	}
1754
1755
	return false;
1756
}
1757
1758
/**
1759
 * Check if donor comment field enabled or not for form or globally.
1760
 *
1761
 * @param $form_id
1762
 *
1763
 * @return bool
1764
 * @since 2.1
1765
 */
1766 View Code Duplication
function give_is_donor_comment_field_enabled( $form_id ) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1767
	$form_setting_val   = give_get_meta( $form_id, '_give_donor_comment', true, 'global' );
0 ignored issues
show
Documentation introduced by
'global' is of type string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1768
	$global_setting_val = give_get_option( 'donor_comment', 'disabled' );
1769
1770
	if ( ! empty( $form_setting_val ) ) {
1771
		if ( give_is_setting_enabled( $form_setting_val ) ) {
1772
			return true;
1773
		} elseif ( 'global' === $form_setting_val && give_is_setting_enabled( $global_setting_val ) ) {
1774
			return true;
1775
		} else {
1776
			return false;
1777
		}
1778
	} elseif ( give_is_setting_enabled( $global_setting_val ) ) {
1779
		return true;
1780
	}
1781
1782
	return false;
1783
1784
}
1785
1786
/**
1787
 * Get add-on user meta value information
1788
 * Note: only for internal use.
1789
 *
1790
 * @param string $banner_addon_name Give add-on name.
1791
 *
1792
 * @return array
1793
 * @since 2.1.0
1794
 */
1795
function __give_get_active_by_user_meta( $banner_addon_name ) {
1796
	global $wpdb;
1797
1798
	// Get the option key.
1799
	$option_name = Give_Addon_Activation_Banner::get_banner_user_meta_key( $banner_addon_name );
1800
	$data        = array();
1801
1802
	if ( empty( $GLOBALS['give_addon_activated_by_user'] ) ) {
1803
		$GLOBALS['give_addon_activated_by_user'] = array();
1804
1805
		// Get the meta of activation banner by user.
1806
		$activation_banners = $wpdb->get_results(
1807
			"
1808
					SELECT option_name, option_value
1809
					FROM {$wpdb->options}
1810
					WHERE option_name LIKE '%_active_by_user%'
1811
					AND option_name LIKE '%give_addon%'
1812
					",
1813
			ARRAY_A
1814
		);
1815
1816
		if ( ! empty( $activation_banners ) ) {
1817
			$GLOBALS['give_addon_activated_by_user'] = array_combine(
1818
				wp_list_pluck( $activation_banners, 'option_name' ),
1819
				wp_list_pluck( $activation_banners, 'option_value' )
1820
			);
1821
		}
1822
	}
1823
1824
	if ( array_key_exists( $option_name, $GLOBALS['give_addon_activated_by_user'] ) ) {
1825
		$data = maybe_unserialize( $GLOBALS['give_addon_activated_by_user'][ $option_name ] );
1826
	}
1827
1828
	return $data;
1829
}
1830
1831
/**
1832
 * Get time interval for which nonce is valid
1833
 *
1834
 * @return int
1835
 * @since 2.1.3
1836
 */
1837
function give_get_nonce_life() {
1838
	/**
1839
	 * Filters the lifespan of nonces in seconds.
1840
	 *
1841
	 * @see wp-inlucdes/pluggable.php:wp_nonce_tick
1842
	 */
1843
	return (int) apply_filters( 'nonce_life', DAY_IN_SECONDS );
1844
}
1845
1846
/**
1847
 * Get nonce field without id
1848
 *
1849
 * @param string $action
1850
 * @param string $name
1851
 * @param bool   $referer
1852
 *
1853
 * @return string
1854
 * @since 2.1.3
1855
 */
1856
function give_get_nonce_field( $action, $name, $referer = false ) {
1857
	return str_replace(
1858
		"id=\"{$name}\"",
1859
		'',
1860
		wp_nonce_field( $action, $name, $referer, false )
1861
	);
1862
}
1863
1864
/**
1865
 * Display/Return a formatted goal for a donation form
1866
 *
1867
 * @param int|Give_Donate_Form $form Form ID or Form Object.
1868
 *
1869
 * @return array
1870
 * @since 2.1
1871
 */
1872
function give_goal_progress_stats( $form ) {
1873
1874
	if ( ! $form instanceof Give_Donate_Form ) {
1875
		$form = new Give_Donate_Form( $form );
1876
	}
1877
1878
	$goal_format = give_get_form_goal_format( $form->ID );
1879
1880
	/**
1881
	 * Filter the form.
1882
	 *
1883
	 * @since 1.8.8
1884
	 */
1885
	$total_goal = apply_filters( 'give_goal_amount_target_output', round( give_maybe_sanitize_amount( $form->goal ), 2 ), $form->ID, $form );
1886
1887
	switch ( $goal_format ) {
1888
		case 'donation':
1889
			/**
1890
			 * Filter the form donations.
1891
			 *
1892
			 * @since 2.1
1893
			 */
1894
			$actual = apply_filters( 'give_goal_donations_raised_output', $form->sales, $form->ID, $form );
1895
			break;
1896
		case 'donors':
1897
			/**
1898
			 * Filter to modify total number if donor for the donation form.
1899
			 *
1900
			 * @param int              $donors  Total number of donors that donated to the form.
1901
			 * @param int              $form_id Donation Form ID.
1902
			 * @param Give_Donate_Form $form    instances of Give_Donate_Form.
1903
			 *
1904
			 * @return int $donors Total number of donors that donated to the form.
1905
			 * @since 2.1.3
1906
			 */
1907
			$actual = apply_filters( 'give_goal_donors_target_output', give_get_form_donor_count( $form->ID ), $form->ID, $form );
1908
			break;
1909
		default:
1910
			/**
1911
			 * Filter the form income.
1912
			 *
1913
			 * @since 1.8.8
1914
			 */
1915
			$actual = apply_filters( 'give_goal_amount_raised_output', $form->earnings, $form->ID, $form );
1916
			break;
1917
	}
1918
1919
	$progress = $total_goal ? round( ( $actual / $total_goal ) * 100, 2 ) : 0;
1920
1921
	$stats_array = array(
1922
		'raw_actual' => $actual,
1923
		'raw_goal'   => $total_goal,
1924
	);
1925
1926
	/**
1927
	 * Filter the goal progress output
1928
	 *
1929
	 * @since 1.8.8
1930
	 */
1931
	$progress = apply_filters( 'give_goal_amount_funded_percentage_output', $progress, $form->ID, $form );
1932
1933
	// Define Actual Goal based on the goal format.
1934
	switch ( $goal_format ) {
1935
		case 'percentage':
1936
			$actual     = "{$actual}%";
1937
			$total_goal = '';
1938
			break;
1939
1940
		case 'amount' === $goal_format:
1941
			$actual     = give_currency_filter( give_format_amount( $actual ) );
1942
			$total_goal = give_currency_filter( give_format_amount( $total_goal ) );
1943
			break;
1944
1945
		default:
1946
			$actual     = give_format_amount( $actual, array( 'decimal' => false ) );
1947
			$total_goal = give_format_amount( $total_goal, array( 'decimal' => false ) );
1948
			break;
1949
	}
1950
1951
	$stats_array = array_merge(
1952
		array(
1953
			'progress' => $progress,
1954
			'actual'   => $actual,
1955
			'goal'     => $total_goal,
1956
			'format'   => $goal_format,
1957
		),
1958
		$stats_array
1959
	);
1960
1961
	/**
1962
	 * Filter the goal stats
1963
	 *
1964
	 * @since 2.1
1965
	 */
1966
	return apply_filters( 'give_goal_progress_stats', $stats_array );
1967
}
1968
1969
/**
1970
 * Get the admin messages key to show the notices.
1971
 *
1972
 * @return array $message admin message key.
1973
 * @since 2.1.4
1974
 */
1975
function give_get_admin_messages_key() {
1976
	$messages = empty( $_GET['give-messages'] ) ? array() : give_clean( $_GET['give-messages'] );
1977
1978
	// backward compatibility.
1979
	if ( ! empty( $_GET['give-message'] ) ) {
1980
		$messages[] = give_clean( $_GET['give-message'] );
1981
	}
1982
1983
	/**
1984
	 * Filter to modify the admin messages key.
1985
	 *
1986
	 * @param array $message admin message key.
1987
	 *
1988
	 * @return array $message admin message key.
1989
	 * @since 2.1.4
1990
	 */
1991
	return (array) apply_filters( 'give_get_admin_messages_key', $messages );
1992
}
1993
1994
/**
1995
 * Get User Agent String.
1996
 *
1997
 * @return array|string
1998
 * @since 2.1.4
1999
 */
2000
function give_get_user_agent() {
2001
2002
	// Get User Agent.
2003
	$user_agent = ! empty( $_SERVER['HTTP_USER_AGENT'] ) ? give_clean( $_SERVER['HTTP_USER_AGENT'] ) : ''; // WPCS: input var ok.
2004
2005
	return $user_agent;
2006
}
2007
2008
/**
2009
 * Set a cookie - wrapper for setcookie using WP constants.
2010
 *
2011
 * @param string  $name   Name of the cookie being set.
2012
 * @param string  $value  Value of the cookie.
2013
 * @param integer $expire Expiry of the cookie.
2014
 * @param bool    $secure Whether the cookie should be served only over https.
2015
 *
2016
 * @since 2.2.0
2017
 */
2018
function give_setcookie( $name, $value, $expire = 0, $secure = false ) {
2019
	if ( ! headers_sent() ) {
2020
		setcookie(
2021
			$name,
2022
			$value,
2023
			$expire,
2024
			COOKIEPATH ? COOKIEPATH : '/',
2025
			COOKIE_DOMAIN,
2026
			$secure,
2027
			apply_filters( 'give_cookie_httponly', false, $name, $value, $expire, $secure )
2028
		);
2029
	}
2030
}
2031
2032
/**
2033
 * Get formatted billing address.
2034
 *
2035
 * @param array $address
2036
 *
2037
 * @return string Formatted address.
2038
 * @since 2.2.0
2039
 */
2040
function give_get_formatted_address( $address = array() ) {
2041
	$formatted_address = '';
2042
2043
	/**
2044
	 * Address format.
2045
	 *
2046
	 * @since 2.2.0
2047
	 */
2048
	$address_format = apply_filters( 'give_address_format_template', "{street_address}\n{city}, {state} {postal_code}\n{country}" );
2049
	preg_match_all( '/{([A-z0-9\-\_\ ]+)}/s', $address_format, $matches );
2050
2051
	if ( ! empty( $matches ) && ! empty( $address ) ) {
2052
		$address_values = array();
2053
2054
		foreach ( $matches[1] as $address_tag ) {
2055
			$address_values[ $address_tag ] = '';
2056
2057
			if ( isset( $address[ $address_tag ] ) ) {
2058
				$address_values[ $address_tag ] = $address[ $address_tag ];
2059
			}
2060
		}
2061
2062
		$formatted_address = str_ireplace( $matches[0], $address_values, $address_format );
2063
	}
2064
2065
	/**
2066
	 * Give get formatted address.
2067
	 *
2068
	 * @param string $formatted_address Formatted address.
2069
	 * @param string $address_format    Format of the address.
2070
	 *
2071
	 * @since 2.2.0
2072
	 */
2073
	$formatted_address = apply_filters( 'give_get_formatted_address', $formatted_address, $address_format, $address );
2074
2075
	return $formatted_address;
2076
}
2077
2078
/**
2079
 * Get safe url for assets
2080
 * Note: this function will return url without http protocol
2081
 *
2082
 * @param string $url URL
2083
 *
2084
 * @return string
2085
 * @since 2.2.0
2086
 */
2087
function give_get_safe_asset_url( $url ) {
2088
2089
	// Bailout, if empty URL passed.
2090
	if ( empty( $url ) ) {
2091
		return $url;
2092
	}
2093
2094
	$schema        = parse_url( $url, PHP_URL_SCHEME );
2095
	$schema_length = strlen( $schema ) + 1;
2096
	$url           = substr( $url, $schema_length );
2097
2098
	/**
2099
	 * Fire the filter
2100
	 *
2101
	 * @since 2.2.0
2102
	 */
2103
	return apply_filters( 'give_get_safe_asset_url', $url );
2104
}
2105
2106
/**
2107
 * Give get formatted date.
2108
 * Note: This function does not work well with localize translated  date strings
2109
 *
2110
 * @param string $date           Date.
2111
 * @param string $format         Date Format.
2112
 * @param string $current_format Current date Format.
2113
 *
2114
 * @return string
2115
 * @since 2.3.0
2116
 */
2117
function give_get_formatted_date( $date, $format = 'Y-m-d', $current_format = '' ) {
2118
	$current_format = empty( $current_format ) ? give_date_format() : $current_format;
2119
	$date_obj       = DateTime::createFromFormat( $current_format, $date );
2120
2121
	$formatted_date = $date_obj instanceof DateTime ? $date_obj->format( $format ) : '';
2122
2123
	/**
2124
	 * Give get formatted date.
2125
	 *
2126
	 * @param string $formatted_date Formatted date.
2127
	 * @param array
2128
	 *
2129
	 * @since 2.3.0
2130
	 */
2131
	return apply_filters( 'give_get_formatted_date', $formatted_date, array( $date, $format, $current_format ) );
2132
}
2133
2134
/**
2135
 * This function will be used to fetch the donation receipt link.
2136
 *
2137
 * @param int $donation_id Donation ID.
2138
 *
2139
 * @return string
2140
 * @since 2.3.1
2141
 */
2142
function give_get_receipt_link( $donation_id ) {
2143
2144
	return sprintf(
2145
		'<a href="%1$s">%2$s</a>',
2146
		esc_url( give_get_receipt_url( $donation_id ) ),
2147
		esc_html__( 'View the receipt in your browser &raquo;', 'give' )
2148
	);
2149
2150
}
2151
2152
/**
2153
 * Get receipt_url
2154
 *
2155
 * @param int $donation_id Donation ID.
2156
 *
2157
 * @return string
2158
 * @since 2.0
2159
 */
2160
function give_get_receipt_url( $donation_id ) {
2161
2162
	$receipt_url = esc_url(
2163
		add_query_arg(
2164
			array(
2165
				'donation_id' => $donation_id,
2166
			),
2167
			give_get_history_page_uri()
2168
		)
2169
	);
2170
2171
	return $receipt_url;
2172
}
2173
2174
/**
2175
 * Get "View in browser" Receipt Link for email.
2176
 *
2177
 * @param int $donation_id Donation ID.
2178
 *
2179
 * @return string
2180
 * @since 2.4.1
2181
 */
2182
function give_get_view_receipt_link( $donation_id ) {
2183
2184
	return sprintf(
2185
		'<a href="%1$s">%2$s</a>',
2186
		esc_url( give_get_view_receipt_url( $donation_id ) ),
2187
		esc_html__( 'View the receipt in your browser &raquo;', 'give' )
2188
	);
2189
2190
}
2191
2192
/**
2193
 * Get "View in browser" Receipt URL for email.
2194
 *
2195
 * @param int $donation_id Donation ID.
2196
 *
2197
 * @return string
2198
 * @since 2.4.1
2199
 */
2200
function give_get_view_receipt_url( $donation_id ) {
2201
2202
	$receipt_url = esc_url(
2203
		add_query_arg(
2204
			array(
2205
				'action'     => 'view_in_browser',
2206
				'_give_hash' => give_get_payment_key( $donation_id ),
2207
			),
2208
			give_get_history_page_uri()
2209
		)
2210
	);
2211
2212
	return $receipt_url;
2213
}
2214
2215
/**
2216
 * This function is used to display donation receipt content based on the parameters.
2217
 *
2218
 * @param $args
2219
 *
2220
 * @return bool|mixed
2221
 * @since 2.4.1
2222
 */
2223
function give_display_donation_receipt( $args ) {
2224
2225
	global $give_receipt_args;
2226
2227
	$give_receipt_args = $args;
2228
2229
	ob_start();
2230
2231
	$get_data     = give_clean( filter_input_array( INPUT_GET ) );
2232
	$donation_id  = ! empty( $get_data['donation_id'] ) ? $get_data['donation_id'] : false;
2233
	$receipt_type = ! empty( $get_data['receipt_type'] ) ? $get_data['receipt_type'] : false;
2234
2235
	$give_receipt_args['id'] = $donation_id;
2236
2237
	if ( 'view_in_browser' !== $receipt_type ) {
2238
2239
		$email_access    = give_get_option( 'email_access' );
2240
		$is_email_access = give_is_setting_enabled( $email_access ) && ! Give()->email_access->token_exists;
2241
2242
		// No donation id found & Email Access is Turned on.
2243
		if ( ! $donation_id ) {
2244
2245
			if ( $is_email_access ) {
2246
				give_get_template_part( 'email-login-form' );
2247
			} else {
2248
				echo Give_Notices::print_frontend_notice( $args['error'], false, 'error' );
2249
			}
2250
2251
			return ob_get_clean();
2252
		}
2253
2254
		// Donation id provided, but user is logged out. Offer them the ability to login and view the receipt.
2255
		if ( ! ( $user_can_view = give_can_view_receipt( $donation_id ) ) ) {
2256
2257
			if ( true === Give()->session->get( 'donor_donation_mismatch' ) ) {
2258
2259
				/**
2260
				 * This filter will be used to modify the donor mismatch text for front end error notice.
2261
				 *
2262
				 * @since 2.3.1
2263
				 */
2264
				$donor_mismatch_text = apply_filters( 'give_receipt_donor_mismatch_notice_text', __( 'You are trying to access invalid donation receipt. Please try again.', 'give' ) );
2265
2266
				echo Give_Notices::print_frontend_notice(
2267
					$donor_mismatch_text,
2268
					false,
2269
					'error'
2270
				);
2271
2272
			} elseif ( $is_email_access ) {
2273
2274
				give_get_template_part( 'email-login-form' );
2275
2276
			} else {
2277
2278
				global $give_login_redirect;
2279
2280
				$give_login_redirect = give_get_current_page_url();
2281
2282
				Give_Notices::print_frontend_notice(
2283
					apply_filters(
2284
						'give_must_be_logged_in_error_message',
2285
						__( 'You must be logged in to view this donation receipt.', 'give' )
2286
					)
2287
				);
2288
2289
				give_get_template_part( 'shortcode', 'login' );
2290
			}
2291
2292
			return ob_get_clean();
2293
		}
2294
2295
		/**
2296
		 * Check if the user has permission to view the receipt.
2297
		 *
2298
		 * If user is logged in, user ID is compared to user ID of ID stored in payment meta
2299
		 * or if user is logged out and donation was made as a guest, the donation session is checked for
2300
		 * or if user is logged in and the user can view sensitive shop data.
2301
		 */
2302
		if ( ! apply_filters( 'give_user_can_view_receipt', $user_can_view, $args ) ) {
2303
			return Give_Notices::print_frontend_notice( $args['error'], false, 'error' );
2304
		}
2305
	} else{
2306
		$donation_id =  give_get_donation_id_by_key( $get_data['donation_id'] );
2307
		$give_receipt_args['id'] = $donation_id;
2308
	}
2309
2310
	give_get_template_part( 'shortcode', 'receipt' );
2311
2312
	return ob_get_clean();
2313
}
2314
2315
2316
/**
2317
 * Get plugin add-on readme.txt path
2318
 * Note: only for internal use
2319
 *
2320
 * @param      $plugin_slug
2321
 * @param bool        $by_plugin_name
2322
 *
2323
 * @return mixed|void
2324
 * @since 2.5.0
2325
 */
2326
function give_get_addon_readme_url( $plugin_slug, $by_plugin_name = false ) {
2327
2328
	if ( $by_plugin_name ) {
2329
		$plugin_slug = Give_License::get_short_name( $plugin_slug );
2330
	}
2331
2332
	$website_url = Give_License::get_website_url();
2333
2334
	/**
2335
	 * Filter the addon readme.txt url
2336
	 *
2337
	 * @since 2.1.4
2338
	 */
2339
	$url = apply_filters(
2340
		'give_addon_readme_file_url',
2341
		"{$website_url}/downloads/plugins/{$plugin_slug}/readme.txt",
2342
		$plugin_slug,
2343
		$by_plugin_name
2344
	);
2345
2346
	return $url;
2347
}
2348
2349
/**
2350
 * Refresh all givewp license.
2351
 *
2352
 * @param bool $wp_check_updates
2353
 *
2354
 * @access public
2355
 * @return array|WP_Error
2356
 *
2357
 * @since  2.5.0
2358
 */
2359
function give_refresh_licenses( $wp_check_updates = true ) {
2360
	$give_licenses = get_option( 'give_licenses', array() );
2361
	$give_addons   = give_get_plugins( array( 'only_premium_add_ons' => true ) );
2362
2363
	if ( ! $give_licenses && ! $give_addons ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $give_addons of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
2364
		return array();
2365
	}
2366
2367
	$license_keys = $give_licenses ? implode( ',', array_keys( $give_licenses ) ) : '';
2368
2369
	$unlicensed_give_addon = $give_addons
2370
		? array_values(
2371
			array_diff(
2372
				array_map(
2373
					function ( $plugin_name ) {
2374
						return trim( str_replace( 'Give - ', '', $plugin_name ) );
2375
					},
2376
					wp_list_pluck( $give_addons, 'Name', true )
2377
				),
2378
				wp_list_pluck( $give_licenses, 'item_name', true )
2379
			)
2380
		)
2381
		: array();
2382
2383
	$tmp = Give_License::request_license_api( array(
2384
		'edd_action' => 'check_licenses',
2385
		'licenses'   => $license_keys,
2386
		'unlicensed' => implode( ',', $unlicensed_give_addon ),
2387
	), true );
2388
2389
	if ( ! $tmp || is_wp_error( $tmp ) ) {
2390
		return array();
2391
	}
2392
2393
	// Prevent fatal error on WP 4.9.10
2394
	// Because wp_list_pluck accept only array or array of array in that version.
2395
	// @see https://github.com/impress-org/give/issues/4176
2396
	$tmp = json_decode( json_encode( $tmp ), true );
2397
2398
	// Remove unlicensed add-on from response.
2399
	$tmp_unlicensed = array();
2400
	foreach ( $tmp as $key => $data ) {
2401
		if ( empty( $data ) ) {
2402
			unset( $tmp["{$key}"] );
2403
			continue;
2404
		}
2405
2406
		if ( empty( $data['check_license'] ) ) {
2407
			$tmp_unlicensed[ $key ] = $data;
2408
			unset( $tmp["{$key}"] );
2409
		}
2410
	}
2411
2412
	$check_licenses = wp_list_pluck( $tmp, 'check_license' );
2413
2414
	/* @var stdClass $data */
2415
	foreach ( $check_licenses as $key => $data ) {
2416
		if ( is_wp_error( $data ) ) {
2417
			continue;
2418
		}
2419
2420
		if ( ! $data['success'] ) {
2421
			unset( $give_licenses[ $key ] );
2422
			continue;
2423
		}
2424
2425
		$give_licenses[ $key ] = $data;
2426
	}
2427
2428
	$tmp_update_plugins = array_merge(
2429
		array_filter( wp_list_pluck( $tmp, 'get_version' ) ),
2430
		array_filter( wp_list_pluck( $tmp, 'get_versions' ) )
2431
	);
2432
2433
	if ( $tmp_unlicensed ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $tmp_unlicensed of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
2434
		$tmp_update_plugins = array_merge( $tmp_update_plugins, $tmp_unlicensed );
2435
	}
2436
2437
	update_option( 'give_licenses', $give_licenses, 'no' );
2438
	update_option( 'give_get_versions', $tmp_update_plugins, 'no' );
2439
2440
	$refresh         = Give_License::refresh_license_status();
2441
	$refresh['time'] = current_time( 'timestamp', 1 );
2442
2443
	update_option( 'give_licenses_refreshed_last_checked', $refresh, 'no' );
2444
2445
	// Tell WordPress to look for updates.
2446
	if ( $wp_check_updates ) {
2447
		set_site_transient( 'update_plugins', null );
2448
	}
2449
2450
	return array(
2451
		'give_licenses'     => $give_licenses,
2452
		'give_get_versions' => $tmp_update_plugins,
2453
	);
2454
}
2455
2456
/**
2457
 * Check add-ons updates
2458
 * Note: only for internal use
2459
 *
2460
 * @param stdClass $_transient_data Plugin updates information
2461
 *
2462
 * @return stdClass
2463
 * @since 2.5.0
2464
 */
2465
function give_check_addon_updates( $_transient_data ){
2466
	if ( ! is_object( $_transient_data ) ) {
2467
		$_transient_data = new stdClass;
2468
	}
2469
2470
	$update_plugins = get_option( 'give_get_versions', array() );
2471
	$check_licenses = get_option( 'give_licenses', array() );
2472
2473
	if ( ! $update_plugins ) {
2474
		$data = give_refresh_licenses( false );
2475
2476
		if(
2477
			empty( $data['give_get_versions'] )
2478
			|| is_wp_error( $data )
2479
		) {
2480
			return $_transient_data;
2481
		}
2482
2483
		$update_plugins = $data['give_get_versions'];
2484
	}
2485
2486
	foreach ( $update_plugins as $key => $data ) {
2487
		$plugins = ! empty( $check_licenses[ $key ] )
2488
			?  ( ! empty( $check_licenses[ $key ]['is_all_access_pass'] ) ? $data : array( $data ) )
2489
			: array( $data );
2490
2491
2492
		foreach ( $plugins as $plugin ) {
2493
			// This value will be empty if any error occurred when verifying version of add-on.
2494
			if ( empty( $plugin['new_version'] ) ) {
2495
				continue;
2496
			}
2497
2498
			$plugin     = array_map( 'maybe_unserialize', $plugin );
2499
			$tmp_plugin = Give_License::get_plugin_by_slug( $plugin['slug'] );
2500
2501
			if ( ! $tmp_plugin ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $tmp_plugin of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
2502
				continue;
2503
			}
2504
2505
			$plugin['plugin'] = $tmp_plugin['Path'];
2506
2507
			if ( - 1 !== version_compare( $tmp_plugin['Version'], $plugin['new_version'] ) ) {
2508
				$_transient_data->no_update[ $tmp_plugin['Path'] ] = (object) $plugin;
2509
			} else{
2510
				$_transient_data->response[ $tmp_plugin['Path'] ] = (object) $plugin;
2511
			}
2512
2513
			$_transient_data->checked[ $tmp_plugin['Path'] ]  = $tmp_plugin['Version'];
2514
		}
2515
	}
2516
2517
	$_transient_data->last_checked = time();
2518
2519
	return $_transient_data;
2520
}
2521