Home › Forums › Calendar Products › Filter Bar › Make filter have no wrapper so that it isn't a dropdown
- This topic has 4 replies, 3 voices, and was last updated 7 years, 11 months ago by Support Droid.
-
AuthorPosts
-
May 11, 2016 at 11:13 am #1113347usminteractiveParticipant
Hello,
I am trying to make it so that the filter doesn’t have a wrapper so that it is not a dropdown by default. Basically this involves removing #tribe_events_filter_item_venues div so that the select is always showing. I attached an image of what I am trying to make it look like.
I have dug through the code and found that this html structure is coming form Filter.php, class Tribe__Events__Filterbar__Filter and method displayFilter
I have tried extending this class in functions.php and changing the method displayFilter but no luck. I have tried removing the action and adding the action back in similar to this thread https://theeventscalendar.com/support/forums/topic/remove-and-add-action-to-override-addqueryargs-for-filterbar/
But I ran into the same issue where the method displayFilter could not reference $this
Anyway you could point me in the right direction of how to do this?
May 11, 2016 at 9:49 pm #1113595BrookParticipantHowdy USM,
I would love to point you in the right direction here. I suspect this has to do with class inheritance. Would you mind sharing your code? I can review it and see if something stands out.
Cheers!
– Brook
May 12, 2016 at 5:06 am #1113695usminteractiveParticipantThanks! Here is what I have tried…I have tried extending the class so in functions.php it looks like this…
class customFilterBar extends Tribe__Events__Filterbar__Filter { public function addCustomHooks() { if ( $this->is_filtering() ) { add_action( 'tribe_events_custom_filter_view_do_display_filters', array( $this, 'displayCustomFilter' ), $this->priority ); add_action( 'tribe_events_pre_get_posts', array( $this, 'addQueryArgs' ), 10 ); } add_filter( 'tribe_events_all_filters_array', array( $this, 'allFiltersArray' ), 10, 1 ); } public function displayCustomFilter() { $values = apply_filters( 'tribe_events_filter_values', $this->get_values(), $this->slug ); if ( ! empty( $values ) ) { ?> <div class="tribe_events_filter_item" id="tribe_events_filter_item_<?php echo esc_attr( $this->slug ); ?>"> <?php switch ( $this->type ) { case 'select': // It's possible for multiple values to be specified in array form, but we can // only use one of those for the select filter $current_value = is_array( $this->currentValue ) ? current( $this->currentValue ) : $this->currentValue; ?> <h3 class="tribe-events-filters-group-heading"><span></span><?php echo stripslashes( $this->title ); ?></h3> <div class="tribe-events-filter-group tribe-events-filter-select"> <select name="<?php echo esc_attr( 'tribe_' . $this->slug ); ?>"> <option value="" <?php selected( trim( $current_value ), '' ) ?>><?php esc_html_e( 'Select', 'tribe-events-filter-view' ); ?></option> <?php foreach ( $values as $option ): $data = array(); if ( isset( $option['data'] ) && is_array( $option['data'] ) ) { foreach ( $option['data'] as $attr => $value ) { $data[] = 'data-' . esc_attr( $attr ) . '="' . trim( $value ) . '"'; } } $data = join( ' ', $data ); // output option to screen printf( '<option value="%s" %s %s >%s</option>', esc_attr( $option['value'] ), selected( trim( $current_value ), trim( $option['value'] ), false ), $data, esc_html( stripslashes( $option['name'] ) ) ); ?> <?php endforeach ?> </select> </div> <?php break; //Option for Chosen Dropdown case 'autocomplete': if ( ! isset( $this->currentValue ) ) $this->currentValue = array(); ?> <h3 class="tribe-events-filters-group-heading"><span></span><?php echo stripslashes( $this->title ); ?></h3> <div class="tribe-events-filter-group tribe-events-filter-autocomplete"> <select data-no-results-text="<?php esc_attr_e( 'No items match', 'tribe-events-filter-view' ); ?>" data-placeholder="<?php esc_attr_e( 'Select an Item', 'tribe-events-filter-view' ); ?>" multiple class="chosen-dropdown" name="<?php echo esc_attr( 'tribe_' . $this->slug . '[]' ); ?>"> <?php foreach ( $values as $option ): $data = array(); if ( isset( $option['data'] ) ) { foreach ( $option['data'] as $attr => $value ) { $data[] = 'data-' . esc_attr( $attr ) . '="' . trim( $value ) . '"'; } } $data = join( ' ', $data ); // output option to screen printf( '<option value="%s" %s %s >%s</option>', esc_attr( $option['value'] ), selected( $this->is_selected( trim( $option['value'] ) ) ), $data, esc_html( stripslashes( $option['name'] ) ) ); ?> <?php endforeach ?> </select> </div> <?php break; case 'checkbox': if ( ! isset( $this->currentValue ) ) { $this->currentValue = array(); } ?> <h3 class="tribe-events-filters-group-heading"><span></span><?php echo stripslashes( $this->title ); ?></h3> <div class="tribe-events-filter-group tribe-events-filter-checkboxes"> <ul> <?php foreach ( $values as $option ): $data = array(); if ( isset( $option['data'] ) && is_array( $option['data'] ) ) { foreach ( $option['data'] as $attr => $value ) { $data[] = 'data-' . esc_attr( $attr ) . '="' . trim( $value ) . '"'; } } $data = join( ' ', $data ); // Support CSS classes per list item $class = ''; if ( isset( $option['class'] ) && ! empty( $option['class'] ) ) { $class = ' class="' . esc_attr( $option['class'] ) . '"'; } // output option to screen printf( '<li%s><label><input type="checkbox" value="%s" %s name="%s" %s /><span title="%s">%s</span></label></li>', $class, esc_attr( $option['value'] ), checked( $this->is_selected( trim( $option['value'] ) ), true, false ), esc_attr( 'tribe_' . $this->slug . '[]' ), $data, esc_html( stripslashes( $option['name'] ) ), esc_html( stripslashes( $option['name'] ) ) ); ?> <?php endforeach; ?> </ul> </div> <?php break; case 'radio': if ( ! isset( $this->currentValue ) ) { $current_value = ''; } else { $current_value = is_array( $this->currentValue ) ? current( $this->currentValue ) : $this->currentValue; } ?> <h3 class="tribe-events-filters-group-heading"><span></span><?php echo stripslashes( $this->title ); ?></h3> <div class="tribe-events-filter-group tribe-events-filter-radio"> <ul> <?php foreach ( $values as $option ): $data = array(); if ( isset( $option['data'] ) && is_array( $option['data'] ) ) { foreach ( $option['data'] as $attr => $value ) { $data[] = 'data-' . esc_attr( $attr ) . '="' . trim( $value ) . '"'; } } $data = join( ' ', $data ); // Support CSS classes per list item $class = ''; if ( isset( $option['class'] ) && ! empty( $option['class'] ) ) { $class = ' class="' . esc_attr( $option['class'] ) . '"'; } // output option to screen printf( '<li%s><label><input type="radio" value="%s" %s name="%s" %s /><span title="%s">%s</span></label></li>', $class, esc_attr( $option['value'] ), checked( trim( $option['value'] ), $current_value, false ), esc_attr( 'tribe_' . $this->slug ), $data, esc_html( stripslashes( $option['name'] ) ), esc_html( stripslashes( $option['name'] ) ) ); ?> <?php endforeach; ?> </ul> </div> <?php break; case 'range': if ( ! empty( $this->currentValue ) && is_array( $this->currentValue ) ) { $current = reset( $this->currentValue ); } else { $current = $values; } $min_value = preg_replace( '/[^.0-9]/', '', floor( $values['min'] ) ); $max_value = preg_replace( '/[^.0-9]/', '', floor( $values['max'] ) ); if ( $current['min'] != $min_value || $current['max'] != $max_value ) { $set_value = $current['min'] . '-' . $current['max']; } else { $set_value = ''; } // Get our currency symbol $currency_symbol = tribe_get_option( 'defaultCurrencySymbol' ); ?> <h3 class="tribe-events-filters-group-heading"><span></span><?php echo stripslashes( $this->title ); ?></h3> <div class="tribe-events-filter-group tribe-events-filter-range"> <span id="<?php echo esc_attr( 'tribe_events_filter_' . $this->slug ); ?>_display" class="tribe_events_slider_val"></span> <input type="hidden" id="<?php echo esc_attr( 'tribe_events_filter_' . $this->slug ); ?>" name="<?php echo esc_attr( 'tribe_' . $this->slug ); ?>" value="<?php echo esc_attr( $set_value ); ?>" /> <div id="<?php echo esc_attr( 'tribe_events_filter_' . $this->slug . '_slider' ); ?>"></div> </div> <script> <?php //Check to see if currency position setting is in front of or behind the value $reverse_position = tribe_get_option( 'reverseCurrencyPosition', false ); ?> jQuery(document).ready(function($) { $( "#<?php echo 'tribe_events_filter_' . $this->slug . '_slider'; ?>" ).slider({ range: true, min: <?php echo $min_value; ?>, max: <?php echo $max_value; ?>, values: [ <?php echo preg_replace( '/[^.0-9]/', '', $current['min'] ); ?>, <?php echo preg_replace( '/[^.0-9]/', '', $current['max'] ); ?> ], slide: function( event, ui ) { <?php if ( $reverse_position ) { ?> $( "#<?php echo 'tribe_events_filter_' . $this->slug; ?>_display" ).text( ui.values[ 0 ] + "<?php echo $currency_symbol; ?>" + "-" + ui.values[ 1 ] + "<?php echo $currency_symbol; ?>" ); <?php } else { ?> $( "#<?php echo 'tribe_events_filter_' . $this->slug; ?>_display" ).text( "<?php echo $currency_symbol; ?>" + ui.values[ 0 ] + "-<?php echo $currency_symbol; ?>" + ui.values[ 1 ] ); <?php } ?> if( ui.values[ 0 ] === <?php echo $min_value; ?> && <?php echo $max_value; ?> === ui.values[ 1 ] ) { $( "#<?php echo 'tribe_events_filter_' . $this->slug; ?>" ).val(''); } else { $( "#<?php echo 'tribe_events_filter_' . $this->slug; ?>" ).val( ui.values[ 0 ] + "-" + ui.values[ 1 ] ); } } }); <?php if ( $reverse_position ) { ?> $( "#<?php echo 'tribe_events_filter_' . $this->slug; ?>_display" ).text( $( "#<?php echo 'tribe_events_filter_' . $this->slug . '_slider'; ?>" ).slider( "values", 0 ) + "<?php echo $currency_symbol; ?>" + "-" + $( "#<?php echo 'tribe_events_filter_' . $this->slug . '_slider'; ?>" ).slider( "values", 1 ) + "<?php echo $currency_symbol; ?>" ); <?php } else { ?> $( "#<?php echo 'tribe_events_filter_' . $this->slug; ?>_display" ).text( "<?php echo $currency_symbol; ?>" + $( "#<?php echo 'tribe_events_filter_' . $this->slug . '_slider'; ?>" ).slider( "values", 0 ) + "-<?php echo $currency_symbol; ?>" + $( "#<?php echo 'tribe_events_filter_' . $this->slug . '_slider'; ?>" ).slider( "values", 1 ) ); <?php } ?> }); </script> <?php break; case 'multi-select': if ( ! isset( $this->currentValue ) ) { $this->currentValue = array(); } ?> <h3 class="tribe-events-filters-group-heading"><span></span><?php echo stripslashes( $this->title ); ?></h3> <div class="tribe-events-filter-group tribe-events-filter-multi-select"> <select multiple="true" id="<?php echo esc_attr( 'tribe_events_filter_' . $this->slug ); ?>" name="<?php echo esc_attr( 'tribe_' . $this->slug ); ?>[]"> <?php foreach ( $values as $option ): $data = array(); if ( isset( $option['data'] ) ) { foreach ( $option['data'] as $attr => $value ) { $data[] = 'data-' . esc_attr( $attr ) . '="' . trim( $value ) . '"'; } } $data = join( ' ', $data ); // output option to screen printf( '<option value="%s" %s %s >%s</option>', esc_attr( $option['value'] ), selected( $this->currentValue, trim( $option['value'] ) ), $data, esc_html( stripslashes( $option['name'] ) ) ); ?> <?php endforeach ?> </select> </div> <?php break; } ?> </div> <?php } } }
In this I extended the main class and then changed the name of the action that is called in filter-view-horizontal.php so the section of this file that spits out the filter looks like this….
<form id="tribe_events_filters_form" method="post" action=""> <?php do_action( 'tribe_events_custom_filter_view_do_display_filters' ); ?> <input type="submit" value="<?php esc_attr_e( 'Submit', 'tribe-events-filter-view' ) ?>" /> </form>
The issue with this is it is not overriding the class in Filter.php
I have also tried removing the action in addHooks() and adding it back in like this in functions.php
class customTribeFilter extends Tribe__Events__Filterbar__Filter { public function customActions() { remove_action( 'tribe_events_filter_view_do_display_filters', array( 'Tribe__Events__Filterbar__Filter', 'displayFilter' ), 10 ); add_action( 'tribe_events_filter_view_do_display_filters', 'customDisplayFilter', 10 ); } public function customDisplayFilter() { $values = apply_filters( 'tribe_events_filter_values', $this->get_values(), $this->slug ); if ( ! empty( $values ) ) { ?> <div class="tribe_events_filter_item" id="tribe_events_filter_item_<?php echo esc_attr( $this->slug ); ?>"> <?php switch ( $this->type ) { case 'select': // It's possible for multiple values to be specified in array form, but we can // only use one of those for the select filter $current_value = is_array( $this->currentValue ) ? current( $this->currentValue ) : $this->currentValue; ?> <h3 class="tribe-events-filters-group-heading"><span></span><?php echo stripslashes( $this->title ); ?></h3> <div class="tribe-events-filter-group tribe-events-filter-select"> <select name="<?php echo esc_attr( 'tribe_' . $this->slug ); ?>"> <option value="" <?php selected( trim( $current_value ), '' ) ?>><?php esc_html_e( 'Select', 'tribe-events-filter-view' ); ?></option> <?php foreach ( $values as $option ): $data = array(); if ( isset( $option['data'] ) && is_array( $option['data'] ) ) { foreach ( $option['data'] as $attr => $value ) { $data[] = 'data-' . esc_attr( $attr ) . '="' . trim( $value ) . '"'; } } $data = join( ' ', $data ); // output option to screen printf( '<option value="%s" %s %s >%s</option>', esc_attr( $option['value'] ), selected( trim( $current_value ), trim( $option['value'] ), false ), $data, esc_html( stripslashes( $option['name'] ) ) ); ?> <?php endforeach ?> </select> </div> <?php break; //Option for Chosen Dropdown case 'autocomplete': if ( ! isset( $this->currentValue ) ) $this->currentValue = array(); ?> <h3 class="tribe-events-filters-group-heading"><span></span><?php echo stripslashes( $this->title ); ?></h3> <div class="tribe-events-filter-group tribe-events-filter-autocomplete"> <select data-no-results-text="<?php esc_attr_e( 'No items match', 'tribe-events-filter-view' ); ?>" data-placeholder="<?php esc_attr_e( 'Select an Item', 'tribe-events-filter-view' ); ?>" multiple class="chosen-dropdown" name="<?php echo esc_attr( 'tribe_' . $this->slug . '[]' ); ?>"> <?php foreach ( $values as $option ): $data = array(); if ( isset( $option['data'] ) ) { foreach ( $option['data'] as $attr => $value ) { $data[] = 'data-' . esc_attr( $attr ) . '="' . trim( $value ) . '"'; } } $data = join( ' ', $data ); // output option to screen printf( '<option value="%s" %s %s >%s</option>', esc_attr( $option['value'] ), selected( $this->is_selected( trim( $option['value'] ) ) ), $data, esc_html( stripslashes( $option['name'] ) ) ); ?> <?php endforeach ?> </select> </div> <?php break; case 'checkbox': if ( ! isset( $this->currentValue ) ) { $this->currentValue = array(); } ?> <h3 class="tribe-events-filters-group-heading"><span></span><?php echo stripslashes( $this->title ); ?></h3> <div class="tribe-events-filter-group tribe-events-filter-checkboxes"> <ul> <?php foreach ( $values as $option ): $data = array(); if ( isset( $option['data'] ) && is_array( $option['data'] ) ) { foreach ( $option['data'] as $attr => $value ) { $data[] = 'data-' . esc_attr( $attr ) . '="' . trim( $value ) . '"'; } } $data = join( ' ', $data ); // Support CSS classes per list item $class = ''; if ( isset( $option['class'] ) && ! empty( $option['class'] ) ) { $class = ' class="' . esc_attr( $option['class'] ) . '"'; } // output option to screen printf( '<li%s><label><input type="checkbox" value="%s" %s name="%s" %s /><span title="%s">%s</span></label></li>', $class, esc_attr( $option['value'] ), checked( $this->is_selected( trim( $option['value'] ) ), true, false ), esc_attr( 'tribe_' . $this->slug . '[]' ), $data, esc_html( stripslashes( $option['name'] ) ), esc_html( stripslashes( $option['name'] ) ) ); ?> <?php endforeach; ?> </ul> </div> <?php break; case 'radio': if ( ! isset( $this->currentValue ) ) { $current_value = ''; } else { $current_value = is_array( $this->currentValue ) ? current( $this->currentValue ) : $this->currentValue; } ?> <h3 class="tribe-events-filters-group-heading"><span></span><?php echo stripslashes( $this->title ); ?></h3> <div class="tribe-events-filter-group tribe-events-filter-radio"> <ul> <?php foreach ( $values as $option ): $data = array(); if ( isset( $option['data'] ) && is_array( $option['data'] ) ) { foreach ( $option['data'] as $attr => $value ) { $data[] = 'data-' . esc_attr( $attr ) . '="' . trim( $value ) . '"'; } } $data = join( ' ', $data ); // Support CSS classes per list item $class = ''; if ( isset( $option['class'] ) && ! empty( $option['class'] ) ) { $class = ' class="' . esc_attr( $option['class'] ) . '"'; } // output option to screen printf( '<li%s><label><input type="radio" value="%s" %s name="%s" %s /><span title="%s">%s</span></label></li>', $class, esc_attr( $option['value'] ), checked( trim( $option['value'] ), $current_value, false ), esc_attr( 'tribe_' . $this->slug ), $data, esc_html( stripslashes( $option['name'] ) ), esc_html( stripslashes( $option['name'] ) ) ); ?> <?php endforeach; ?> </ul> </div> <?php break; case 'range': if ( ! empty( $this->currentValue ) && is_array( $this->currentValue ) ) { $current = reset( $this->currentValue ); } else { $current = $values; } $min_value = preg_replace( '/[^.0-9]/', '', floor( $values['min'] ) ); $max_value = preg_replace( '/[^.0-9]/', '', floor( $values['max'] ) ); if ( $current['min'] != $min_value || $current['max'] != $max_value ) { $set_value = $current['min'] . '-' . $current['max']; } else { $set_value = ''; } // Get our currency symbol $currency_symbol = tribe_get_option( 'defaultCurrencySymbol' ); ?> <h3 class="tribe-events-filters-group-heading"><span></span><?php echo stripslashes( $this->title ); ?></h3> <div class="tribe-events-filter-group tribe-events-filter-range"> <span id="<?php echo esc_attr( 'tribe_events_filter_' . $this->slug ); ?>_display" class="tribe_events_slider_val"></span> <input type="hidden" id="<?php echo esc_attr( 'tribe_events_filter_' . $this->slug ); ?>" name="<?php echo esc_attr( 'tribe_' . $this->slug ); ?>" value="<?php echo esc_attr( $set_value ); ?>" /> <div id="<?php echo esc_attr( 'tribe_events_filter_' . $this->slug . '_slider' ); ?>"></div> </div> <script> <?php //Check to see if currency position setting is in front of or behind the value $reverse_position = tribe_get_option( 'reverseCurrencyPosition', false ); ?> jQuery(document).ready(function($) { $( "#<?php echo 'tribe_events_filter_' . $this->slug . '_slider'; ?>" ).slider({ range: true, min: <?php echo $min_value; ?>, max: <?php echo $max_value; ?>, values: [ <?php echo preg_replace( '/[^.0-9]/', '', $current['min'] ); ?>, <?php echo preg_replace( '/[^.0-9]/', '', $current['max'] ); ?> ], slide: function( event, ui ) { <?php if ( $reverse_position ) { ?> $( "#<?php echo 'tribe_events_filter_' . $this->slug; ?>_display" ).text( ui.values[ 0 ] + "<?php echo $currency_symbol; ?>" + "-" + ui.values[ 1 ] + "<?php echo $currency_symbol; ?>" ); <?php } else { ?> $( "#<?php echo 'tribe_events_filter_' . $this->slug; ?>_display" ).text( "<?php echo $currency_symbol; ?>" + ui.values[ 0 ] + "-<?php echo $currency_symbol; ?>" + ui.values[ 1 ] ); <?php } ?> if( ui.values[ 0 ] === <?php echo $min_value; ?> && <?php echo $max_value; ?> === ui.values[ 1 ] ) { $( "#<?php echo 'tribe_events_filter_' . $this->slug; ?>" ).val(''); } else { $( "#<?php echo 'tribe_events_filter_' . $this->slug; ?>" ).val( ui.values[ 0 ] + "-" + ui.values[ 1 ] ); } } }); <?php if ( $reverse_position ) { ?> $( "#<?php echo 'tribe_events_filter_' . $this->slug; ?>_display" ).text( $( "#<?php echo 'tribe_events_filter_' . $this->slug . '_slider'; ?>" ).slider( "values", 0 ) + "<?php echo $currency_symbol; ?>" + "-" + $( "#<?php echo 'tribe_events_filter_' . $this->slug . '_slider'; ?>" ).slider( "values", 1 ) + "<?php echo $currency_symbol; ?>" ); <?php } else { ?> $( "#<?php echo 'tribe_events_filter_' . $this->slug; ?>_display" ).text( "<?php echo $currency_symbol; ?>" + $( "#<?php echo 'tribe_events_filter_' . $this->slug . '_slider'; ?>" ).slider( "values", 0 ) + "-<?php echo $currency_symbol; ?>" + $( "#<?php echo 'tribe_events_filter_' . $this->slug . '_slider'; ?>" ).slider( "values", 1 ) ); <?php } ?> }); </script> <?php break; case 'multi-select': if ( ! isset( $this->currentValue ) ) { $this->currentValue = array(); } ?> <h3 class="tribe-events-filters-group-heading"><span></span><?php echo stripslashes( $this->title ); ?></h3> <div class="tribe-events-filter-group tribe-events-filter-multi-select"> <select multiple="true" id="<?php echo esc_attr( 'tribe_events_filter_' . $this->slug ); ?>" name="<?php echo esc_attr( 'tribe_' . $this->slug ); ?>[]"> <?php foreach ( $values as $option ): $data = array(); if ( isset( $option['data'] ) ) { foreach ( $option['data'] as $attr => $value ) { $data[] = 'data-' . esc_attr( $attr ) . '="' . trim( $value ) . '"'; } } $data = join( ' ', $data ); // output option to screen printf( '<option value="%s" %s %s >%s</option>', esc_attr( $option['value'] ), selected( $this->currentValue, trim( $option['value'] ) ), $data, esc_html( stripslashes( $option['name'] ) ) ); ?> <?php endforeach ?> </select> </div> <?php break; } ?> </div> <?php } } }
Hope that is helpful! Any guidance would be much appreciated.
Thanks,
PeteMay 16, 2016 at 10:16 pm #1115227BrookParticipantHowdy Pete,
Please pardon the delay. I was not able to fully review this Friday like I had hoped.
There is only one thing that stood out to me in your code:
remove_action( 'tribe_events_filter_view_do_display_filters', array( 'Tribe__Events__Filterbar__Filter', 'displayFilter' ), 10 );
In order to remove a method you will need to reference the class itself, not its name. So you will need to do Tribe__Events__Filterbar__Filter::instance() not the string ‘Tribe__Events__Filterbar__Filter’ .
Other than that nothing really stood out. Part of your code must be missing. I am not sure how you are actually instantiating this since the method addCustomHooks() will need to be manually called somewhere. That could have an impact on things.
I hope that helps get you pointed in the right direction. I am definitely here for specific questions. If this continues to give you trouble I would try to simplify it as much as possible. Strip out everything from your new class that you do not need to test if it is overriding. Often times while stripping things down to their simplest form it will just start working, then you can start adding things back until it becomes apparent what’s broken. If it’s still giving you trouble at its simplest state perhaps you could reshare the code and tell me specifically what you’re expecting to happen that’s not.
Cheers!
– Brook
May 31, 2016 at 9:35 am #1120721Support DroidKeymasterThis topic has not been active for quite some time and will now be closed.
If you still need assistance please simply open a new topic (linking to this one if necessary)
and one of the team will be only too happy to help. -
AuthorPosts
- The topic ‘Make filter have no wrapper so that it isn't a dropdown’ is closed to new replies.