Search Unity

【Optimizers】- Easy to use and functional components to optimize any other components!

Discussion in 'Assets and Asset Store' started by FimpossibleCreations, Jan 28, 2020.

  1. FimpossibleCreations

    FimpossibleCreations

    Joined:
    Jun 27, 2018
    Posts:
    540


    Cull, deactivate or activate, adjust quality basing on distance or visibility.
    Do it on anything inside scenes of your project!
    Give your game more FPS and be able to arrange more details!


    Optimizers can optimize almost everything, things like Lights, Particle Systems, Terrains, Renderers, NavMesh Agents, Script Components and more!
    Just add optimizer to your game object, select components of which you want change quality. Define distances and percentage amount of parameters you want to change when reaching certain LOD levels, now your optimizer is ready!

    For more check it on the Asset Store


    MAIN FEATURES:

    • Capability to boost game performance drastically
    • Change quality of any component when it's details are not needed
    • There is no baking or any other complicating operations
    • Various example scenes showcasing different features
    • Clean and responsive editor window with built-in-like gizmos in scene view
    • Optimize Particle Systems, Terrains, Lights, Renderers, NavMeshAgents and more!
    • Progressive adaptation of system to game performance
    • Templates for easy implementation of custom components to be optimized
    • Full source code included

    Demo Builds (Noticable differences and preformance depends on your equipement):
    .Exe(64) WebGL .APK




    V2.0.0


    GUI Update
    Joining obstacle detection and complex shape features just in one component
    Essential Optimizer component which will not support custom components optimization but will work flawlessly with prefabing and without saving additional files in project

    Multi shape component implementation for CullingContainers logics
    Optimizers Manager debug browser

    Auto Max Distance toggle to adjust it automatically for target camera FOV and detection sphere size, so max distance will end where object is so small on screen it's almost not visible on high screen resolutions
    Transitioning possibility for "Hidden" LOD level

    V2.0.5:
    Support for MeshRenderers fade in/out animating shader parameter value

    Limiting first LOD level count to maximum count, for example limiting enabled scripts with foot IK


    Experimental DOTS implementation for Dynamic optimization method and obstacle detection

    V2.1.0
    Tools to set up optimizers on the scene automatically with simple GUI and buttons
    Stop raycasting from LOD (stop from distance)... for Obstacle Detection algorithm


    V2.2.1+...

    Additional option to sync some parameters in presets with project Quality Settings

    Group Culling - Automatically finding groups of objects to optimize inside scene and dividing it to sectors (for giant and dense scenes)

    Performance boost for obstacle raycasting algorithm - Raycast Memory and overlapping


    Full Implementation of DOTS for "Dynamic" optimization method (Burst Compiler and Job System)

    Toggle to hide objects if they're behind other optimizer's detection shape - Similar to Occlusion Culling (DOTS implementation needed)




    Delayed tasks (until someone would need):
    Changes in LOD settings visible in scene view during edit mode when tweaking them (Particle Systems)
    LOD Settings Shader Material DirectX version dependent option

     
    Last edited: Nov 6, 2020
    overthere likes this.
  2. eaque

    eaque

    Joined:
    Aug 20, 2014
    Posts:
    764
    hi,

    Another interesting tool from you!
    can you tell me what it can do with terrain culling?
     
  3. FimpossibleCreations

    FimpossibleCreations

    Joined:
    Jun 27, 2018
    Posts:
    540
    It's useful when you use multiple terrains in your game, if not and whole game is placed on one terrain then you don't need to use it.
     
  4. eaque

    eaque

    Joined:
    Aug 20, 2014
    Posts:
    764
    i mean can you explain me what it will do that unity doesn't do...Sorry i'm kind of noob:p
    i have a big map with 16 terrain and a solution to disable the ones that a re not in sight would be great!

    ill buy it anyway the price is cheap! and im sure it's good stuf like all your assets
     
  5. FimpossibleCreations

    FimpossibleCreations

    Joined:
    Jun 27, 2018
    Posts:
    540
    As I tested in newest version unity is handling terrains a bit better than around 2017 versions, but turning off trees/details and heightmap drawing when you not see terrain can help.
    Also you can adjust pixel error wen you go far from terrain, adjust billboard start distance, you can divide resolution of heightmap if very far or replace it with custom mesh object etc.
     
  6. eaque

    eaque

    Joined:
    Aug 20, 2014
    Posts:
    764

    tons of possibilities, can't wait to test it ! just bought it!
    :)
     
  7. therewillbebrad

    therewillbebrad

    Joined:
    Mar 2, 2018
    Posts:
    151
    Has this been tested in VR?
     
  8. FimpossibleCreations

    FimpossibleCreations

    Joined:
    Jun 27, 2018
    Posts:
    540
    No yet but soon will be, I can send you raport from that when done ;)
     
  9. therewillbebrad

    therewillbebrad

    Joined:
    Mar 2, 2018
    Posts:
    151
    I just went ahead and snagged it because i like your other assets, I keep getting lod lost in prefabs though. Is there a way to prevent that from happening?

    It causes indexoutofrangeexception on my prerfabs.
     
  10. FimpossibleCreations

    FimpossibleCreations

    Joined:
    Jun 27, 2018
    Posts:
    540
    Update 1.0.1 for better support of unity 2018,2019+ is waiting for approval right now.
    Each version of unity needed dedicated work to make it work correctly without using "SharedSettings"
    (which are easier for unity to understand but less confortable in use because you would need to save separate files inside your project)
    Are you using Asset Pipeline Version 2? (added from unity 2019.3 and in 2020 version) I reported some bug reports to unity because there was few incompatibilities, I walked around them, but needs some fixes for full correct workflow.
     
  11. FimpossibleCreations

    FimpossibleCreations

    Joined:
    Jun 27, 2018
    Posts:
    540
    Updated to version 1.0.1:
    IMPORTANT UPDATE

    - Improved compatibility with Unity 2019
    - Added component Optimizer Cleaner to remove unused sub-assets from prefabs generated because of issue with Unity 2019, I recommend to check prefabs with this component (just add to prefab (in project view, no in scene) and use buttons)
    - Many small changes improving integration
    - Some new icons to better understand which file is what
    - Entry integration for Asset Pipeline V2 (Unity 2019.3+)
     
    Last edited: Feb 5, 2020
  12. therewillbebrad

    therewillbebrad

    Joined:
    Mar 2, 2018
    Posts:
    151
    So I'm still getting lod set lost, and the optimize cleaner says No prefab path!
     
  13. therewillbebrad

    therewillbebrad

    Joined:
    Mar 2, 2018
    Posts:
    151
    When I hit retry it appears but it doesn't save that information in to the prefab.
     
  14. therewillbebrad

    therewillbebrad

    Joined:
    Mar 2, 2018
    Posts:
    151
    ullReferenceException: Object reference not set to an instance of an object
    FIMSpace.FOptimizing.FComponentLODsController.SetCurrentLODLevel (System.Int32 currentLODLevel) (at Assets/FImpossible Creations/Optimizers/Scripts/Optimize Base/FComponentLODsController.cs:107)
    FIMSpace.FOptimizing.FOptimizer_Base.ChangeLODLevelTo (System.Int32 lodLevel) (at Assets/FImpossible Creations/Optimizers/Scripts/Optimize Base/FOptimizer_Base.cs:462)
    FIMSpace.FOptimizing.FOptimizer_Base.RefreshVisibilityState (System.Int32 targetLODLevel) (at Assets/FImpossible Creations/Optimizers/Scripts/Optimize Base/FOptimizer_Base.cs:282)
    FIMSpace.FOptimizing.FOptimizer_Base.DynamicLODUpdate (FIMSpace.FOptimizing.FEOptimizingDistance category, System.Single distance) (at Assets/FImpossible Creations/Optimizers/Scripts/Partials/Optimizer Base/FOptimizer_Base.Dynamic.cs:117)
    FIMSpace.FOptimizing.FOptimizers_Manager.AddToDynamic (FIMSpace.FOptimizing.FOptimizer_Base optimizer) (at Assets/FImpossible Creations/Optimizers/Scripts/Partials/Optimizers Manager/FOptimizers_Manager.DynamicOptimization.cs:111)
    FIMSpace.FOptimizing.FOptimizer_Base.InitDynamicOptimizer () (at Assets/FImpossible Creations/Optimizers/Scripts/Partials/Optimizer Base/FOptimizer_Base.Dynamic.cs:47)
    FIMSpace.FOptimizing.FOptimizer_Base.Start () (at Assets/FImpossible Creations/Optimizers/Scripts/Optimize Base/FOptimizer_Base.cs:153)
     
  15. FimpossibleCreations

    FimpossibleCreations

    Joined:
    Jun 27, 2018
    Posts:
    540
    Please write on PM or my email.
    We will investigate what's wrong going on.
    Maybe it's asset pipeline v2, we'll see.

    You probably use it on prefab inside scene, try using it on prefab inside project.
    Also after changes on the scene mode, applying changes is required (Unity 2018.3+ Overrides -> Apply All)


    By the way, I tested it in VR and works as on desktop, as well as rest of my packages ;)

    Please try to not use optimizers with nested prefabs yet.
     
    Last edited: Feb 5, 2020
  16. dsilverthorn

    dsilverthorn

    Joined:
    May 14, 2017
    Posts:
    839
    Just purchased! Looking forward to putting it to use!:)
     
  17. Barritico

    Barritico

    Joined:
    Jun 9, 2017
    Posts:
    374
    Hi.

    My games are based on large terrains. Are about racing cars.

    There are 40km x 40km areas with mountains and things like that.

    I've tried other optimizers (4) and I don't like them. The one that came closest to my goals has a very ugly transition when new areas appear as the vehicle progresses.

    My question is direct.

    Can your product help me in this goal?
    Thank you
     
  18. eaque

    eaque

    Joined:
    Aug 20, 2014
    Posts:
    764

    hi,

    That's a great exemple for all of us! how many tiles have you for the whole map?

    question to the author:
    -terrains appear or disable regarding distance from the camera, can this be regarding altitude of the camera? should it rely on "visibility" in this case?

    didn't try your product yet!! ;)
     
  19. FimpossibleCreations

    FimpossibleCreations

    Joined:
    Jun 27, 2018
    Posts:
    540
    Does your areas include multiple terrains or one big / only few of them?
    Optimizers can do more when there are multiple terrain objects.

    I am not sure if I interpret correctly, but you can try using more LOD levels, adjust LOD settings to smooth out sudden changes or use transitioning to let optimizers change settings inside terrain component smoothly.

    What you mean by that? Different components from my package? There is only one component to use with terrains.

    You can change settings regarding how far camera is from ~nearest point on terrain and deactivate all terrain calculations when camera is not seeing terrain object (conditioned by visibility spheres visible in scene gizmos)
     
    Last edited: Feb 5, 2020
    Barritico likes this.
  20. therewillbebrad

    therewillbebrad

    Joined:
    Mar 2, 2018
    Posts:
    151
    Any update on the prefab error?
     
  21. FimpossibleCreations

    FimpossibleCreations

    Joined:
    Jun 27, 2018
    Posts:
    540
    I updated package lately with small fixes, check new version. If it's still problematic in your case, write to me pm with console log, I will put it on my priority list then.
     
  22. skinwalker

    skinwalker

    Joined:
    Apr 10, 2015
    Posts:
    509
    Does this asset create LOD of meshes from lets say 10k polygons to 5k or its only for disabling components?
     
  23. manurocker95

    manurocker95

    Joined:
    Jun 14, 2016
    Posts:
    210
    Disabling the component in the editor, even without playmode still applies culling. Also, I would like objects to not be completely disabled for having some scripts running. Do I have to make my own LOD system?
     
  24. FimpossibleCreations

    FimpossibleCreations

    Joined:
    Jun 27, 2018
    Posts:
    540

    It's operating on different components, not creating LODs for meshes ;)
    I added note in asset description on the asset store, sorry if you didn't notice that:
    "Don't get it wrong! Package is not generating lower LOD levels for meshes or so, it's changing parameters of components/disabling/enabling to give more optimization"



    I was surprised by this, but I checked it on unity 5.6.0, 2017.4 and 2019.3 and component is disabled properly after entering playmode, but disabling during playmode not stops it indeed, I can send you quick fix for that in pm if you need ;) I wasn't excepting someone will need to stop optimization component, when it's working already.



    I'm not sure if I fully understand, because you can freely define which scripts should be disabled in which LOD level or choose to deactivate or not deactivate whole gameObject in last LOD level.
    If you mean deactivating scripts when target is out of camera view, open "Hidden" LOD, untoggle "Same as culling" then customize LOD settings when camera looking away from target object.
    If you don't want to change anything when camera is looking away and work only on distance ranges, you can untoggle "Cull if not see"
     
    Last edited: Feb 19, 2020
  25. dsilverthorn

    dsilverthorn

    Joined:
    May 14, 2017
    Posts:
    839
    Could you give some more tutorials that are in depth on the different options for each optimizer?
    I am an artist and don't fully understand the manual as to the functions or exactly how to set it all up. I've read the manual several times and watched the videos. Maybe you could do a detailed video? :)
    Right now all I can do is the basic culling setup. Adding components and the different options are a bit confusing to me.
    Sorry I'm not well versed at scripting. But I could understand it better with an in depth tutorial. :)
     
    eaque likes this.
  26. FimpossibleCreations

    FimpossibleCreations

    Joined:
    Jun 27, 2018
    Posts:
    540
    Great you mentioned it, then I will work on that ;) I will try to finish it for next week.
    Quick tip: if you know/was working on parameters of component you want to optimize (light/particle system) then you have it's parameters (ones responsible for performance) inside optimizer window (sometimes names can be different because Unity Editor draw them different inside inspector window, for example in light render mode, "Not Important" = "Force Vertex", "Important" = "Force Pixel")
     
    dsilverthorn and eaque like this.
  27. dsilverthorn

    dsilverthorn

    Joined:
    May 14, 2017
    Posts:
    839
    Thanks
    Looking forward to it!:)
     
  28. Unplug

    Unplug

    Joined:
    Aug 23, 2014
    Posts:
    256
    hello, maybe you can do a video for "advance" feature, because i really don't understand the process of creating custom CS script to manage custom script. The renaming, removing line etc. do a simple exemple

    you should also mention that terrain optimizer is ONLY for multiple terrain setup and that it doesn't give any terrain optimization for single terrain scene (which is probably most popular case)

    And i have to make the optimizers even work. It return LOTS of console error on many type of object without any valuable information. Many of them complain about particlerenderer component is null (even when component to optimized does not contain any particle system script).

    so far, 0 star and 0 gain
     
  29. FimpossibleCreations

    FimpossibleCreations

    Joined:
    Jun 27, 2018
    Posts:
    540
    I could do new example but I would do it in text version.
    Simpliest implementation you can find here:
    https://drive.google.com/open?id=1_x9Lk2AoRAwTdy56RN5EzXJ16EQT7feu

    Sorry for incomprehension, yeah writing "Terrains" not equals "Multiple Terrains" I updated description but waiting for approval.

    What version of Unity you use?
    Are you sure you imported all files from package?
    Maybe you're switched to use shared settings and assigned wrong LOD Set file?
     
    Last edited: Feb 25, 2020
  30. eaque

    eaque

    Joined:
    Aug 20, 2014
    Posts:
    764
    hi,

    Don't know if it's relevant :p, but do you plan to add some "mesh combine" or "material combine" features to your tool?
    A lot exist some are free i know but having everything in one tool would interest me and i trust your products.

    btw : i played few minutes with it and i was amazed to see my terrains culled with the camera!! :p great tool!
    thanks!
    Will definitely rate it when i know it better!!
     
    Lars-Steenhoff likes this.
  31. Unplug

    Unplug

    Joined:
    Aug 23, 2014
    Posts:
    256
    you definitly need to explain how to set everything correctly in the documentation and produce clear tutorial video.

    1- once i have apply the script on the prefab in the folder (and not the one in the scene) it created files and the console error went away
    2- should be clear in product description that "terrain optimizer" doesn't serve any purpose unless you have multiple terrain. I personally thought i would get better performance for my terrain, which it isn't the case
     
  32. Unplug

    Unplug

    Joined:
    Aug 23, 2014
    Posts:
    256
    there are some really robust solution for that already on the store, he should concentrate on doing his own black magic to get the most of out it, but should certainly keep an eye to stay compatible with popular solution
     
  33. FimpossibleCreations

    FimpossibleCreations

    Joined:
    Jun 27, 2018
    Posts:
    540
    Don't worry I will keep updating asset and try to improve it to make it help in as many situations as possible.
    Maybe terrain optimization will be the case but for now there are some things which really needs to be done before working on that.

    As requested, new tutorial videos:


    And also shared settings + obstacle detection explanation:
     
    Unplug, dsilverthorn and AthrunVLokiz like this.
  34. dsilverthorn

    dsilverthorn

    Joined:
    May 14, 2017
    Posts:
    839
    Thanks!
    Looking forward to getting deeper into this! :)
     
  35. Unplug

    Unplug

    Joined:
    Aug 23, 2014
    Posts:
    256
    If i may add a comment, it's annoying that a gameobject is created automaticly because you have to manually delete it if you use a scene structure where you first load your controller and then load the level. It should automaticly delete itself if it detect 2 controller to avoid console error

    so far i havent seen any improvement on my side after "optimizing" lots of prefab and particle. It's in fact even worse since i get cpu peak when moving around the camera as if it took forever to do the culling.

    thanks for the video !!
     
  36. FimpossibleCreations

    FimpossibleCreations

    Joined:
    Jun 27, 2018
    Posts:
    540
    You mean Optimizers Manager?
    I done it already for upcoming update, I had to separate detection of it during edit and playmode.
    (In playmode new detected optimizer will be deleted so one which is working will remain)
    Warning log is just warning, I prefer log it every time in case someone not notice that.

    How many object you have on scene?
    If you use optimizers like on single mehes it can make higher cpu usage because unity is culling them by default so you doing two same things in the same time, meshes should be culled just as addition to culling particles/lights etc. or culling groups of meshes, when doing it like that is more beneficial.
    You can try using "Dynamic" optimization method, it will take much less cpu for sure but it can react slower for objects' visibility in camera (then you can set higher value for "Update Boost" inside optimizers manager), dynamic optimization method will have much more to say when DOTS will be implemented (it may be recommended method then (I'm starting with work on that) )

    Edit: I just found one thing with is making culling tens of thousands of objects not take any load on cpu with effective and static methods by doing this.

    Edit 2: I finished it and effects are great, new version (1.0.2) is waiting to be approved, make sure you update to this version when it's ready on store. (but very wide tests are needed, probably there will not be issues with it but you never know ;) )
     
    Last edited: Mar 2, 2020
    Unplug and eaque like this.
  37. FimpossibleCreations

    FimpossibleCreations

    Joined:
    Jun 27, 2018
    Posts:
    540
    Version 1.0.2 Released!
    Full Changelog since 1.0.1:

    (1.0.2)

    IMPORTANT CHANGE: Implemented CullingContainers logics which are significantly boosting performance for culling detection calculations for tones of objects if they're using same count of LOD levels and same distance values (if you were using more than 1000 optimizers you should notice difference, also now you can freely use like 100 000 optimizers at the same time! ) Feature needs to be tested a bit but seems to be stable.

    ● Now light optimizer "Render Mode" enums will have same names like ones inside Light component's inspector window
    ● Changed drawing for multipliers in light and particle systems LOD settings from 0-1 to 0%-100% ("FPD_Percentage()" instead of "Range()")
    ● Static Game Object automatic detection for "Static" optimization method + dialog to allow for it
    ● Small bug fixes
    ● Disabling optimizer is now fully supported [optimizer.enabled = false] (probably you will not need this but some projects could make use of it)

    (1.0.1.3)
    ● Fixed transform scale detection sphere radius preview in scene view during editor mode
    ● Light transitioning fixes when not using ("change intensity")
    (1.0.1.2)
    ● Added toggle in first LOD level window to unlock disabling and editing parameters (experimental)
    ● Now disabling optimizer component during playmode will prevent changes on optimized objects
    (1.0.1.1)
    ● When using nested prefabs (parent object having optimizer and child objects having optimizers) optimizer will not try adding component onto "To Optimize" list when the same component is in use by other, child optimizer component.
    ● Added LOG warning about creating optimizer inside prefab mode - it's not yet supported

    Roadmap In first post Updated

    Important Tip:

    Some game objects sometimes needs a lot of time for unity to be deactivated, if you experience lags when rotating camera that's probably it, then you can try to just deactivate components instead of whole game object.
    (this info will be displayed in culled LOD settings in next small update)
     
    Last edited: Mar 2, 2020
    Unplug and dsilverthorn like this.
  38. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    Hey @FimpossibleCreations , does your plugin manage enabling and disabling objects inside drawers or closets when they are opened and closed?
    If not, that would be awesome for walking simulators and adventure games.
    In a walking simulator, there can be tons of objects inside closets and drawers that don't need to be enabled until the drawer or closet is opened (not the just the renderer but the whole gameobject).
    Also, the drawers and closets can be opened and closed either by animation or by direct physics (like in VR), so managing this would be awesome :)
     
    dsilverthorn likes this.
  39. eaque

    eaque

    Joined:
    Aug 20, 2014
    Posts:
    764
    hi,

    Of course let's wait for the author answer:)
    but i suppose there is no problem with your "closet" mecanics.
    1-The tool can cull objects by distance so when your character gets close object will appear "maybe even if the locker is closed"...
    2-you can cull it if it is seen by the camera or not...

    So to me (i own it but didn't try this yet) it's a perfect solution that will cover many many "gameplay" mecanics

    Maybe the way you spawn your objects is important??? Just some thoughts...
    The author will tell us;)
     
    atomicjoe likes this.
  40. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    Thanks @eaque but I wonder if checking if the camera can see the objects would be too much overhead, since I suppose it's using ray casting for that.
    I'm targeting the Oculus Quest, so performance is REALLY scarce. (on android, 72fps rock solid is HARD to keep)
     
  41. eaque

    eaque

    Joined:
    Aug 20, 2014
    Posts:
    764
    oops, sorry !!i understand!
    i have 0 knowledge in those fields:p
     
  42. FimpossibleCreations

    FimpossibleCreations

    Joined:
    Jun 27, 2018
    Posts:
    540
    In such situation it's hard to tell how to do it in the most performant way.
    I think nice would be doing something like room zones, raycasting would be computed only for objects in the room when also player camera is inside.
    Closing closet optimization could be solved by detecting how much closet is open and using only that for computing, but when some object leave closet it should be excluded from calculations.
    This mechanics are more project-type-specific.
    It's nice suggestion, I will think about making tools to optimize such things.
     
    atomicjoe likes this.
  43. Unplug

    Unplug

    Joined:
    Aug 23, 2014
    Posts:
    256
    that could be so easily done with a couple of line of code and a trigger collider. it would be much more performant than raycast technique and checking for camera angle or distance all the time for something that really happen when being at a close distance
     
  44. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    Nothing is so easy when you have to make it for thousands of objects.
     
  45. Unplug

    Unplug

    Joined:
    Aug 23, 2014
    Posts:
    256
    just have a gameobject array and turn them off with a "for" loop on a "ontriggerenter" function. cannot be more straight foward than that...
     
  46. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    Of course. And this whole Optimizers asset is as easy to do as enabling and disabling objects by distance or raycast.
    Just do it yourself and spare 30 bucks! It's easy! :)
     
  47. unity0106

    unity0106

    Joined:
    Apr 11, 2019
    Posts:
    4
    hi,
    does it work with Vegetation Studio Pro?
    upload_2020-3-7_19-18-33.png
     
  48. dsilverthorn

    dsilverthorn

    Joined:
    May 14, 2017
    Posts:
    839
    VS Pro has its own culling for trees/plants, but I haven't seen any issues with using them together.
     
  49. FimpossibleCreations

    FimpossibleCreations

    Joined:
    Jun 27, 2018
    Posts:
    540
    Enabling with array and trigger is ok solution if objects are just staying inside closet.
    (but be aware of deactivating whole game objects, disabling components is more often more performant)
    For this you can also use optimizers and with newest version you can put any count of optimizers on level and performance will not be affected (visibility in camera frustum and distance is calculated with culling groups api, it's much much more performant than calculating visibility and distance every frame + with optimizers you have more features)

    but if objects have rigidbodies and can leave closet and move for example to different room you need to apply different logics.

    As I remember vegetation studio is doing culling with customized cells-based mechanics and there is no need to use optimizers with it.
     
  50. unity0106

    unity0106

    Joined:
    Apr 11, 2019
    Posts:
    4
    Thank you