15
     ˆ0À¿Å  /   ˆl–Ðz¾”Jn-jq@5p ¸ËªbÑ¿Ãƒs_‹uÐb&=LV[(ÁÇ 4    package SelectSaver;

our $VERSION = '1.02';

=head1 NAME

SelectSaver - save and restore selected file handle

=head1 SYNOPSIS

    use SelectSaver;

    {
       my $saver = SelectSaver->new(FILEHANDLE);
       # FILEHANDLE is selected
    }
    # previous handle is selected

    {
       my $saver = SelectSaver->new;
       # new handle may be selected, or not
    }
    # previous handle is selected

=head1 DESCRIPTION

A C<SelectSaver> object contains a reference to the file handle that
was selected when it was created.  If its C<new> method gets an extra
parameter, then that parameter is selected; otherwise, the selected
file handle remains unchanged.

When a C<SelectSaver> is destroyed, it re-selects the file handle
that was selected when it was created.

=cut

require 5.000;
use Carp;
use Symbol;

sub new {
    @_ >= 1 && @_ <= 2 or croak 'usage: SelectSaver->new( [FILEHANDLE] )';
    my $fh = select;
    my $self = bless \$fh, $_[0];
    select qualify($_[1], caller) if @_ > 1;
    $self;
}

sub DESTROY {
    my $self = $_[0];
    select $$self;
}

1;
  F   ˆl–ß=¿Jµ5*q@½p@¸ÓJbÑ¿Åƒe—E_‹I|¥Žƒî4ÃVŸa–Ðz¾”Šj"Tâ€ÆÜ¸©‹FÿÊ ,    import { register } from '@elementor/frontend-handlers';

const getYoutubeVideoIdFromUrl = ( url ) => {
	const regex = /^(?:https?:\/\/)?(?:www\.)?(?:m\.)?(?:youtu\.be\/|youtube\.com\/(?:(?:watch)?\?(?:.*&)?vi?=|(?:embed|v|vi|user|shorts)\/))([^?&"'>]+)/;
	const match = url.match( regex );
	return match ? match[ 1 ] : null;
};

const loadYouTubeAPI = () => {
	return new Promise( ( resolve ) => {
		if ( window.YT && window.YT.loaded ) {
			resolve( window.YT );
			return;
		}

		const YOUTUBE_IFRAME_API_URL = 'https://www.youtube.com/iframe_api';
		if ( ! document.querySelector( `script[src="${ YOUTUBE_IFRAME_API_URL }"]` ) ) {
			const tag = document.createElement( 'script' );
			tag.src = YOUTUBE_IFRAME_API_URL;
			const firstScriptTag = document.getElementsByTagName( 'script' )[ 0 ];
			firstScriptTag.parentNode.insertBefore( tag, firstScriptTag );
		}

		const checkYT = () => {
			if ( window.YT && window.YT.loaded ) {
				resolve( window.YT );
			} else {
				setTimeout( checkYT, 350 );
			}
		};
		checkYT();
	} );
};

register( {
	elementType: 'e-youtube',
	id: 'e-youtube-handler',
	callback: ( { element } ) => {
		const youtubeElement = document.createElement( 'div' );
		youtubeElement.style.height = '100%';
		element.appendChild( youtubeElement );

		const settingsAttr = element.getAttribute( 'data-settings' );
		const parsedSettings = settingsAttr ? JSON.parse( settingsAttr ) : {};

		const videoId = getYoutubeVideoIdFromUrl( parsedSettings.source );

		if ( ! videoId ) {
			return;
		}

		let player;
		let observer;

		const prepareYTVideo = ( YT ) => {
			const playerOptions = {
				videoId,
				events: {
					onReady: () => {
						if ( parsedSettings.mute ) {
							player.mute();
						}

						if ( parsedSettings.autoplay ) {
							player.playVideo();
						}
					},
					onStateChange: ( event ) => {
						if ( event.data === YT.PlayerState.ENDED && parsedSettings.loop ) {
							player.seekTo( parsedSettings.start || 0 );
						}
					},
				},
				playerVars: {
					controls: parsedSettings.controls ? 1 : 0,
					rel: parsedSettings.rel ? 0 : 1,
					cc_load_policy: parsedSettings.cc_load_policy ? 1 : 0,
					autoplay: parsedSettings.autoplay ? 1 : 0,
					start: parsedSettings.start,
					end: parsedSettings.end,
				},
			};

			// To handle CORS issues, when the default host is changed, the origin parameter has to be set.
			if ( parsedSettings.privacy ) {
				playerOptions.host = 'https://www.youtube-nocookie.com';
				playerOptions.origin = window.location.hostname;
			}

			player = new YT.Player( youtubeElement, playerOptions );

			return player;
		};

		if ( parsedSettings.lazyload ) {
			observer = new IntersectionObserver(
				( entries ) => {
					if ( entries[ 0 ].isIntersecting ) {
						loadYouTubeAPI().then( ( apiObject ) => prepareYTVideo( apiObject ) );
						o