Please, a script for unifying FPS events

pierre-k wrote on 5/14/2024, 2:34 AM

Hello.
Can you help me, please?
I always get material that has different fps - 25, 29, 30, 50, 60.
The resulting render is always 25fps.

For now, I'm changing the events separately -
from 60fps to 50fps and from 29 and 30fps to 25fps.

Can any of you please create a script that will automatically change the fps for marked events?

I need the script to automatically change all events from 60fps to 50fps and all events from 23, 29, 30fps to 25fps.

The script itself must know what fps each event has and change them as I wrote.
Thanks for your tips.

Comments

zzzzzz9125 wrote on 5/14/2024, 4:12 AM

Regardless of scripting, there is a convenient way in Vegas to unify FPS. Set the project framerate to 25fps in advance, then right-click the files in Project Media and select "Add at Project Framerate", which will make the files match the project framerate. However, for 60fps files, it will also be stretched to 25fps instead of 50fps.

Last changed by zzzzzz9125 on 5/14/2024, 4:25 AM, changed a total of 4 times.

Using VEGAS Pro 22 build 248 & VEGAS Pro 21 build 208.

Information about my PC:
Brand Name: HP VICTUS Laptop
System: Windows 11.0 (64-bit) 10.00.22631
CPU: 12th Gen Intel(R) Core(TM) i7-12700H
GPU: NVIDIA GeForce RTX 3050 Laptop GPU
GPU Driver: NVIDIA Studio Driver 560.70

pierre-k wrote on 5/14/2024, 4:36 AM

Regardless of scripting, there is a convenient way in Vegas to unify FPS. Set the project framerate to 25fps in advance, then right-click the files in Project Media and select "Add at Project Framerate", which will make the files match the project framerate. However, for 60fps files, it will also be stretched to 25fps instead of 50fps.

And this is exactly what I don't want. If the video is 60fps, then I need 50fps. Not 25fps. That's why I need that script.

zzzzzz9125 wrote on 5/14/2024, 5:19 AM

And this is exactly what I don't want. If the video is 60fps, then I need 50fps. Not 25fps. That's why I need that script.

I just wrote one. You can test if it works.

using ScriptPortal.Vegas;  // "ScriptPortal.Vegas" for Magix Vegas Pro 14 or above, "Sony.Vegas" for Sony Vegas Pro 13 or below

namespace Test_Script
{
    public class Class
    {
        public Vegas myVegas;
        public void Main(Vegas vegas)
        {
            myVegas = vegas;

            foreach (Track myTrack in myVegas.Project.Tracks)
            {
                if (myTrack.IsVideo())
                {
                    foreach (TrackEvent evnt in myTrack.Events)
                    {
                        if (evnt.Selected)
                        {
                            VideoEvent vEvent = (VideoEvent) evnt;

                            double rateSave = vEvent.PlaybackRate;
                            vEvent.PlaybackRate = myVegas.Project.Video.FrameRate / ((VideoStream)vEvent.ActiveTake.MediaStream).FrameRate;
                            if (vEvent.PlaybackRate < 0.6) {
                                vEvent.PlaybackRate *= 2;
                            }
                            vEvent.Length = Timecode.FromNanos((long)(vEvent.Length.Nanos * rateSave / vEvent.PlaybackRate));
                            if (vEvent.IsGrouped)
                            {
                                foreach (TrackEvent groupEvent in vEvent.Group)
                                {
                                    if (groupEvent == vEvent)
                                    {
                                        continue;
                                    }
                                    rateSave = groupEvent.PlaybackRate;
                                    groupEvent.PlaybackRate = vEvent.PlaybackRate;
                                    groupEvent.Length = Timecode.FromNanos((long)(groupEvent.Length.Nanos * rateSave / groupEvent.PlaybackRate));
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

public class EntryPoint
{
    public void FromVegas(Vegas vegas)
    //public void FromVegas(Vegas vegas, String scriptFile, XmlDocument scriptSettings, ScriptArgs args)
    {
        Test_Script.Class test = new Test_Script.Class();
        test.Main(vegas);
    }
}

It converts the framerate of the selected video events (and other events in their own groups) into the result you want.

0.6 is the threshold to determine whether to *2, you can change to another suitable value.

Last changed by zzzzzz9125 on 5/14/2024, 5:42 AM, changed a total of 2 times.

Using VEGAS Pro 22 build 248 & VEGAS Pro 21 build 208.

Information about my PC:
Brand Name: HP VICTUS Laptop
System: Windows 11.0 (64-bit) 10.00.22631
CPU: 12th Gen Intel(R) Core(TM) i7-12700H
GPU: NVIDIA GeForce RTX 3050 Laptop GPU
GPU Driver: NVIDIA Studio Driver 560.70

pierre-k wrote on 5/14/2024, 5:41 AM

And this is exactly what I don't want. If the video is 60fps, then I need 50fps. Not 25fps. That's why I need that script.

I just wrote one. You can test if it works.

 

It converts the framerate of the selected video events (and other events in their own groups) into the result you want.

I tried it now.
It's great that the script will automatically extend the events.

Is it possible for a script to sequence events without Transitions?

Please make one change.
Your script changes even an event that has 50fps to half the speed.


Please ignore 50fps as well as 25fps.

Thank you very much.
Good job!!!!

zzzzzz9125 wrote on 5/14/2024, 5:47 AM

Please make one change.
Your script changes even an event that has 50fps to half the speed.

Yeah I just found I made a mistake, please change the threshold to 0.6 (it was 0.47 before), it should be greater than 0.5.

Using VEGAS Pro 22 build 248 & VEGAS Pro 21 build 208.

Information about my PC:
Brand Name: HP VICTUS Laptop
System: Windows 11.0 (64-bit) 10.00.22631
CPU: 12th Gen Intel(R) Core(TM) i7-12700H
GPU: NVIDIA GeForce RTX 3050 Laptop GPU
GPU Driver: NVIDIA Studio Driver 560.70

pierre-k wrote on 5/14/2024, 5:51 AM

Please make one change.
Your script changes even an event that has 50fps to half the speed.

Yeah I just found I made a mistake, please change the threshold to 0.6 (it was 0.47 before), it should be greater than 0.5.

Amazing. It works perfectly!

pierre-k wrote on 5/14/2024, 6:06 AM

Please make one change.
Your script changes even an event that has 50fps to half the speed.

Yeah I just found I made a mistake, please change the threshold to 0.6 (it was 0.47 before), it should be greater than 0.5.

Can you please get rid of transitions and automatically advance all changed events?

zzzzzz9125 wrote on 5/14/2024, 6:15 AM

Can you please get rid of transitions and automatically advance all changed events?

Try this:

using ScriptPortal.Vegas;  // "ScriptPortal.Vegas" for Magix Vegas Pro 14 or above, "Sony.Vegas" for Sony Vegas Pro 13 or below

namespace Test_Script
{
    public class Class
    {
        public Vegas myVegas;
        public void Main(Vegas vegas)
        {
            myVegas = vegas;

            foreach (Track myTrack in myVegas.Project.Tracks)
            {
                if (myTrack.IsVideo())
                {
                    Timecode offset = Timecode.FromNanos(0);
                    foreach (TrackEvent evnt in myTrack.Events)
                    {
                        if (evnt.Selected)
                        {
                            VideoEvent vEvent = (VideoEvent) evnt;
                            double rateSave = vEvent.PlaybackRate;
                            vEvent.PlaybackRate = myVegas.Project.Video.FrameRate / ((VideoStream)vEvent.ActiveTake.MediaStream).FrameRate;
                            if (vEvent.PlaybackRate < 0.6) {
                                vEvent.PlaybackRate *= 2;
                            }
                            Timecode lengthSave = vEvent.Length;
                            vEvent.Length = Timecode.FromNanos((long)(vEvent.Length.Nanos * rateSave / vEvent.PlaybackRate));
                            vEvent.Start += offset;

                            if (vEvent.IsGrouped)
                            {
                                foreach (TrackEvent groupEvent in vEvent.Group)
                                {
                                    if (groupEvent == vEvent)
                                    {
                                        continue;
                                    }
                                    groupEvent.Start += offset;
                                    rateSave = groupEvent.PlaybackRate;
                                    groupEvent.PlaybackRate = vEvent.PlaybackRate;
                                    groupEvent.Length = Timecode.FromNanos((long)(groupEvent.Length.Nanos * rateSave / groupEvent.PlaybackRate));
                                }
                            }
                            offset += vEvent.Length - lengthSave;
                        }
                    }
                }
            }
        }
    }
}

public class EntryPoint
{
    public void FromVegas(Vegas vegas)
    //public void FromVegas(Vegas vegas, String scriptFile, XmlDocument scriptSettings, ScriptArgs args)
    {
        Test_Script.Class test = new Test_Script.Class();
        test.Main(vegas);
    }
}

Now it calculates the offset for events later in the same track.

Last changed by zzzzzz9125 on 5/14/2024, 6:22 AM, changed a total of 1 times.

Using VEGAS Pro 22 build 248 & VEGAS Pro 21 build 208.

Information about my PC:
Brand Name: HP VICTUS Laptop
System: Windows 11.0 (64-bit) 10.00.22631
CPU: 12th Gen Intel(R) Core(TM) i7-12700H
GPU: NVIDIA GeForce RTX 3050 Laptop GPU
GPU Driver: NVIDIA Studio Driver 560.70

pierre-k wrote on 5/14/2024, 6:38 AM

@zzzzzz9125

Tried.

If I only have 30fps events, then the transition is always done.

If I only have 60fps, this is what happens:

zzzzzz9125 wrote on 5/14/2024, 6:44 AM

If I only have 60fps, this is what happens:

Please use the latest version, I just made a mistake and have corrected it 20 minutes ago.

Using VEGAS Pro 22 build 248 & VEGAS Pro 21 build 208.

Information about my PC:
Brand Name: HP VICTUS Laptop
System: Windows 11.0 (64-bit) 10.00.22631
CPU: 12th Gen Intel(R) Core(TM) i7-12700H
GPU: NVIDIA GeForce RTX 3050 Laptop GPU
GPU Driver: NVIDIA Studio Driver 560.70

pierre-k wrote on 5/14/2024, 6:47 AM

@zzzzzz9125

update: If you mark multiple 60fps events, some will not convert to 50fps.

pierre-k wrote on 5/14/2024, 6:54 AM

I have updated your script now.

Now the same thing happens for both 60fps and 30fps - some events don't convert and both look like this:

pierre-k wrote on 5/14/2024, 6:58 AM

I'm trying on the VP21 b108 version

zzzzzz9125 wrote on 5/14/2024, 7:19 AM

I have updated your script now.

Now the same thing happens for both 60fps and 30fps - some events don't convert and both look like this:

Final version:

using System.Collections.Generic;

using ScriptPortal.Vegas;  // "ScriptPortal.Vegas" for Magix Vegas Pro 14 or above, "Sony.Vegas" for Sony Vegas Pro 13 or below

namespace Test_Script
{
    public class Class
    {
        public Vegas myVegas;
        public void Main(Vegas vegas)
        {
            myVegas = vegas;

            foreach (Track myTrack in myVegas.Project.Tracks)
            {
                if (myTrack.IsVideo())
                {
                    List<VideoEvent> eventList = new List<VideoEvent>();
                    foreach (TrackEvent evnt in myTrack.Events)
                    {
                        if (evnt.Selected)
                        {
                            eventList.Add((VideoEvent)evnt);
                        }
                    }

                    if (eventList.Count == 0)
                    {
                        continue;
                    }
                    //eventList.Sort(delegate(VideoEvent x, VideoEvent y) { return x.Start.CompareTo(y.Start); });
                    Timecode offset = Timecode.FromNanos(0);

                    foreach (VideoEvent vEvent in eventList)
                    {
                        double rateSave = vEvent.PlaybackRate;
                        vEvent.PlaybackRate = myVegas.Project.Video.FrameRate / ((VideoStream)vEvent.ActiveTake.MediaStream).FrameRate;
                        if (vEvent.PlaybackRate < 0.6) {
                            vEvent.PlaybackRate *= 2;
                        }
                        Timecode lengthSave = vEvent.Length;
                        vEvent.Length = Timecode.FromNanos((long)(vEvent.Length.Nanos * rateSave / vEvent.PlaybackRate));
                        vEvent.Start += offset;

                        if (vEvent.IsGrouped)
                        {
                            foreach (TrackEvent groupEvent in vEvent.Group)
                            {
                                if (groupEvent == vEvent)
                                {
                                    continue;
                                }
                                groupEvent.Start += offset;
                                rateSave = groupEvent.PlaybackRate;
                                groupEvent.PlaybackRate = vEvent.PlaybackRate;
                                groupEvent.Length = Timecode.FromNanos((long)(groupEvent.Length.Nanos * rateSave / groupEvent.PlaybackRate));
                            }
                        }
                        offset += vEvent.Length - lengthSave;
                    }
                }
            }
        }
    }
}

public class EntryPoint
{
    public void FromVegas(Vegas vegas)
    //public void FromVegas(Vegas vegas, String scriptFile, XmlDocument scriptSettings, ScriptArgs args)
    {
        Test_Script.Class test = new Test_Script.Class();
        test.Main(vegas);
    }
}

I realized that I should sort the list. Now it should no longer have order problems.

 

Update: In fact, should I say, it probably doesn't need sorting? Delete the sorting line does NOT affect the actual result. Actually, it should be the foreach loop. I changed the vEvent.Start while looping, which caused the loop itself to mess up. Just separate the two steps of "foreach (TrackEvent evnt in myTrack.Events)" and "vEvent.Start += offset" and it'll be fine. I've now commented out the sorting code.

Last changed by zzzzzz9125 on 5/14/2024, 7:41 AM, changed a total of 2 times.

Using VEGAS Pro 22 build 248 & VEGAS Pro 21 build 208.

Information about my PC:
Brand Name: HP VICTUS Laptop
System: Windows 11.0 (64-bit) 10.00.22631
CPU: 12th Gen Intel(R) Core(TM) i7-12700H
GPU: NVIDIA GeForce RTX 3050 Laptop GPU
GPU Driver: NVIDIA Studio Driver 560.70

zzzzzz9125 wrote on 5/14/2024, 7:45 AM

@zzzzzz9125

Cool. Now that's perfect!!!! You saved me several hours of time!!! Thank you very much!

The goal of this script is to unify the speeds at the beginning before editing, so that some events are not jerky in the rendering. In addition, with synchronized audio!

If you find my answer helpful, you can set it as a "Solution". 👏

Using VEGAS Pro 22 build 248 & VEGAS Pro 21 build 208.

Information about my PC:
Brand Name: HP VICTUS Laptop
System: Windows 11.0 (64-bit) 10.00.22631
CPU: 12th Gen Intel(R) Core(TM) i7-12700H
GPU: NVIDIA GeForce RTX 3050 Laptop GPU
GPU Driver: NVIDIA Studio Driver 560.70

jetdv wrote on 5/14/2024, 7:54 AM

pierre-k wrote on 5/14/2024, 8:18 AM

Thank you so much zzzzzz9125 for a great job!!!! You are a god!

Use:
- Before the cut itself
- only on marked events in the Timeline
- synchronization with sound
- automatically extends events
- if you mark multiple events, they will be arranged automatically one after the other without transitions and spaces
- 23,29,30fps will change to 25fps
- 59 and 60fps will change to 50fps
- if you have the project set to a different fps, the script should adapt.

The goal of the script is that the resulting video is not choppy at times.

C:\Program Files\VEGAS\VEGAS Pro 21.0\Script Menu

pierre-k wrote on 9/4/2024, 7:36 AM

@zzzzzz9125

Hi.
I ask you for one more correction.

The script works great, I just need to trim the last frame of the events according to the project.

Let me explain:
The project is 25 frames per second.
Events that are 60fps will change the script to 50fps and extend. That's great. This is how it's supposed to work.
But the events are not aligned in the timeline to the 25fps project, but always extend a bit more. Which is strange, but it's true.
When events shorten with Auto Ripple on, I get a gap between events.

I am asking for a modification so that when changing the events to 50fps or 25fps (depending on whether the video is 60 or 29fps), they are shortened at the end to match the project settings.

Do you understand my request please?

https://drive.google.com/file/d/1cz7PkHLNIwsXEtNQCXO0WmQpfkirsFjW/view?usp=drive_link

pierre-k wrote on 9/4/2024, 7:48 AM

0.833 is not enough and 0.834 is too much.
0.8335 would be ideal, but Vegas can't do that.

zzzzzz9125 wrote on 9/4/2024, 9:34 AM

@pierre-k It's due to the fact that you have "Quantize to Frames" enabled and editing will round to the exact frame position in the project, while my script doesn't.

Here's a corrected version:

using System;
using System.Collections.Generic;

using ScriptPortal.Vegas;  // "ScriptPortal.Vegas" for Magix Vegas Pro 14 or above, "Sony.Vegas" for Sony Vegas Pro 13 or below

namespace Test_Script
{
    public class Class
    {
        public Vegas myVegas;
        public void Main(Vegas vegas)
        {
            myVegas = vegas;

            foreach (Track myTrack in myVegas.Project.Tracks)
            {
                if (myTrack.IsVideo())
                {
                    List<VideoEvent> eventList = new List<VideoEvent>();
                    foreach (TrackEvent evnt in myTrack.Events)
                    {
                        if (evnt.Selected)
                        {
                            eventList.Add((VideoEvent)evnt);
                        }
                    }

                    if (eventList.Count == 0)
                    {
                        continue;
                    }

                    Timecode offset = Timecode.FromNanos(0);

                    foreach (VideoEvent vEvent in eventList)
                    {
                        double rateSave = vEvent.PlaybackRate;
                        double rate = myVegas.Project.Video.FrameRate / ((VideoStream)vEvent.ActiveTake.MediaStream).FrameRate;
                        if (rate < 0.6) {
                            rate *= 2;
                        }
                        Timecode lengthSave = vEvent.Length;
                        vEvent.Length = Timecode.FromFrames((long)(Math.Round(lengthSave.Nanos * myVegas.Project.Video.FrameRate * rateSave / rate / 10000000)));
                        vEvent.PlaybackRate = lengthSave.Nanos * rateSave / vEvent.Length.Nanos;

                        vEvent.Start += offset;

                        if (vEvent.IsGrouped)
                        {
                            foreach (TrackEvent groupEvent in vEvent.Group)
                            {
                                if (groupEvent == vEvent)
                                {
                                    continue;
                                }
                                groupEvent.Start += offset;
                                rateSave = groupEvent.PlaybackRate;
                                groupEvent.PlaybackRate = vEvent.PlaybackRate;
                                groupEvent.Length = Timecode.FromNanos((long)(groupEvent.Length.Nanos * rateSave / groupEvent.PlaybackRate));
                            }
                        }
                        offset += vEvent.Length - lengthSave;
                    }
                }
            }
        }
    }
}

public class EntryPoint
{
    public void FromVegas(Vegas vegas)
    //public void FromVegas(Vegas vegas, String scriptFile, XmlDocument scriptSettings, ScriptArgs args)
    {
        Test_Script.Class test = new Test_Script.Class();
        test.Main(vegas);
    }
}

The script now rounds off the end of the event to the project frame position. You can also change Math.Round() to Math.Floor() or Math.Ceiling(), depending on the rounding method you want to use.

Last changed by zzzzzz9125 on 9/4/2024, 9:40 AM, changed a total of 2 times.

Using VEGAS Pro 22 build 248 & VEGAS Pro 21 build 208.

Information about my PC:
Brand Name: HP VICTUS Laptop
System: Windows 11.0 (64-bit) 10.00.22631
CPU: 12th Gen Intel(R) Core(TM) i7-12700H
GPU: NVIDIA GeForce RTX 3050 Laptop GPU
GPU Driver: NVIDIA Studio Driver 560.70

pierre-k wrote on 9/4/2024, 10:30 AM

@zzzzzz9125

Thank you.
Now it does this for me:

I probably need to change the sequence of actions in the script. That?
1. fps change
2. shortening of events according to project settings
3. and finally - remove spaces.

I tried to create a script with AI but it still shows me an error table. I'm not familiar with scripts at all. I'm glad you're helping me.

pierre-k wrote on 9/4/2024, 10:58 AM

now almost every event has a different speed.
0.834
0.826
0.840
0.836

I need:
1. so that the speed is the same 0.833.
2. to cut the event at the end. She didn't speed up or slow down.

zzzzzz9125 wrote on 9/5/2024, 5:45 AM

3. and finally - remove spaces.

@pierre-k Are you sure these events are tightly coupled before you run the script? Are these gaps really not created due to "Quantize to Frames"? I mention it because when it's enabled and you add footage that does not match the project framerate, it quantizes your edit frame to the project frame position, which may create gaps. The previous script does not change the relative positions between events. They should be as wide as they were before the script was run.

Of course, we can also close the gaps between all events in advance, using the following code:

for (int i = 0; i < eventList.Count - 1; i++)
{
    if (eventList[i+1].IsGrouped)
    {
        Timecode tc = eventList[i+1].Start - eventList[i].End;
        foreach (TrackEvent ev in eventList[i+1].Group)
        {
            ev.Start -= tc;
        }
    }
    else
    {
        eventList[i+1].Start = eventList[i].End;
    }
}

 

now almost every event has a different speed.
0.834
0.826
0.840
0.836

I need:
1. so that the speed is the same 0.833.
2. to cut the event at the end. She didn't speed up or slow down.

Based on all of your above requirements:

using System;
using System.Collections.Generic;

using ScriptPortal.Vegas;  // "ScriptPortal.Vegas" for Magix Vegas Pro 14 or above, "Sony.Vegas" for Sony Vegas Pro 13 or below

namespace Test_Script
{
    public class Class
    {
        public Vegas myVegas;
        public void Main(Vegas vegas)
        {
            myVegas = vegas;

            foreach (Track myTrack in myVegas.Project.Tracks)
            {
                if (myTrack.IsVideo())
                {
                    List<VideoEvent> eventList = new List<VideoEvent>();
                    foreach (TrackEvent evnt in myTrack.Events)
                    {
                        if (evnt.Selected)
                        {
                            eventList.Add((VideoEvent)evnt);
                        }
                    }

                    if (eventList.Count == 0)
                    {
                        continue;
                    }

                    Timecode offset = Timecode.FromNanos(0);

                    for (int i = 0; i < eventList.Count - 1; i++)
                    {
                        if (eventList[i+1].IsGrouped)
                        {
                            Timecode tc = eventList[i+1].Start - eventList[i].End;
                            foreach (TrackEvent ev in eventList[i+1].Group)
                            {
                                ev.Start -= tc;
                            }
                        }
                        else
                        {
                            eventList[i+1].Start = eventList[i].End;
                        }
                    }

                    foreach (VideoEvent vEvent in eventList)
                    {
                        double rateSave = vEvent.PlaybackRate;
                        double rate = myVegas.Project.Video.FrameRate / ((VideoStream)vEvent.ActiveTake.MediaStream).FrameRate;
                        if (rate < 0.6) {
                            rate *= 2;
                        }
                        Timecode lengthSave = vEvent.Length;
                        vEvent.Length = Timecode.FromFrames((long)(Math.Floor(lengthSave.Nanos * myVegas.Project.Video.FrameRate * rateSave / rate / 10000000)));
                        vEvent.PlaybackRate = rate;

                        vEvent.Start += offset;

                        if (vEvent.IsGrouped)
                        {
                            foreach (TrackEvent groupEvent in vEvent.Group)
                            {
                                if (groupEvent == vEvent)
                                {
                                    continue;
                                }
                                groupEvent.Start += offset;
                                rateSave = groupEvent.PlaybackRate;
                                groupEvent.PlaybackRate = vEvent.PlaybackRate;
                                groupEvent.Length = Timecode.FromNanos((long)(groupEvent.Length.Nanos * rateSave / groupEvent.PlaybackRate));
                            }
                        }
                        offset += vEvent.Length - lengthSave;
                    }
                }
            }
        }
    }
}

public class EntryPoint
{
    public void FromVegas(Vegas vegas)
    //public void FromVegas(Vegas vegas, String scriptFile, XmlDocument scriptSettings, ScriptArgs args)
    {
        Test_Script.Class test = new Test_Script.Class();
        test.Main(vegas);
    }
}

 

Using VEGAS Pro 22 build 248 & VEGAS Pro 21 build 208.

Information about my PC:
Brand Name: HP VICTUS Laptop
System: Windows 11.0 (64-bit) 10.00.22631
CPU: 12th Gen Intel(R) Core(TM) i7-12700H
GPU: NVIDIA GeForce RTX 3050 Laptop GPU
GPU Driver: NVIDIA Studio Driver 560.70

pierre-k wrote on 9/5/2024, 11:31 AM

@zzzzzz9125

Now the script is perfect.
It nicely cuts off the end of each changed event and aligns it to a frame in the Timeline. During subsequent cutting, there are no gaps and everything fits perfectly without gaps.

Ingenious!
Thank you very much!