Fermer

avril 2, 2021

Rédaction de code Java dans AEM avec des modèles Sling


J'adore écrire du code. Ce que j'aime le plus, c'est moins d'écrire. Moins de code signifie moins de tests unitaires car vous avez beaucoup moins de couverture à atteindre. Bien organisé, modulaire, court et concis. Comment y parvenez-vous? Bonnes pratiques d'ingénierie logicielle, générateurs de code et exploitation des frameworks et API existants.

Exploitation des frameworks et API

En tant que développeur AEM, vous travaillez au sein d'une plate-forme qui comprend des tonnes de frameworks et d'API OOTB. Consultez la liste des bundles OSGi à l'adresse http: // localhost: 4502 / system / console / bundles . Par exemple, lors d'une récente visite (AEM 6.5.5.0), j'ai remarqué Commons BeanUtils 1.8.2.

Sling Models

L'un des frameworks les plus connus est le Sling Modèles cadre. «Mieux connu» dans la mesure où nous connaissons tous les cas d'utilisation simples. Cependant, peu de gens savent ce qui se passe sous le capot. Assez pour mériter son propre article de blog, c'est certain. Dans le contexte de celui-ci, c’est l’un des cadres qui vous aideront à atteindre notre objectif.

Prenons le cas d’utilisation simple du AEM Granite Multifield . Il semble que tous les projets sur lesquels j'ai travaillé contiennent des tonnes de code pour lire et écrire des données multi-champs. Il y a 3 raisons majeures:

  1. Dans les premières versions, le multifield ne pouvait stocker que des données simples. Les développeurs ont dû l'étendre et des tonnes d'exemples existaient en ligne. Il s'est transformé en ACS Commons Multifield Extension maintenant obsolète. Et donc, une partie du code que je trouve aujourd'hui est héritée.
  2. Les développeurs ne sont pas familiers avec les injecteurs et comment les exploiter.
  3. Parfois, les développeurs copient et collent à partir d'un ancien projet. Horrible, je sais!

Prenons cet exemple de cq: dialog . Il a un texte et plusieurs champs. Le multi-champ est un composite de champs de texte, de chemin et de balise.


    
    
        
            
                
                <page
                    jcr:primaryType="nt:unstructured"
                    sling:resourceType="granite/ui/components/coral/foundation/form/pathfield"
                    fieldLabel="Page"
                    name="./page"/>
                <tags
                    jcr:primaryType="nt:unstructured"
                    sling:resourceType="cq/gui/components/coral/common/form/tagfield"
                    fieldLabel="Tags"
                    multiple="{Boolean}true"
                    name="./tags"/>
            </items>
        </field>
    </multifield>
</items></pre><p> Nous pouvons écrire une interface de modèle Sling simple:</p><pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="dracula"> @Model (adaptables = {Resource.class})
interface publique MyModel {

    @ValueMapValue
    String getText ();

    @ChildResource (injectionStrategy = InjectionStrategy.OPTIONAL)
    List <Item> getItems ();

    @Model (adaptables = Resource.class)
    Élément d'interface {

        @ValueMapValue (nom = "jcr: titre")
        String getTitle ();

        @ResourcePath
        Page getPage ();

        @ValueMapValue
        Liste <String> getTags ();
    }
} </pre><div class="code-block code-block-12" style="margin: 8px 0; clear: both;"></p><div class="sitewide-cta"><div class="sitewide-cta-img-container"><a href="https://www.perficient.com/insights/guides/2019/content-for-everyone-how-to-build-fluid-experiences-for-your-omnichannel-customers"><img decoding="async" src="https://i0.wp.com/blogs.perficient.com/files/Adobe_category_content_everyone.png?resize=300%2C151&ssl=1" alt=" Adobe - Du contenu pour tous " width="300" height="151" class="alignnone size-medium wp-image-273769" data-recalc-dims="1"/></a></div><div class="sitewide-cta-description"><h5 class="heading-five"><a href="https://www.perficient.com/insights/guides/2019/content-for-everyone-how-to-build-fluid-experiences-for-your-omnichannel-customers" style="color: #000; text-decoration: none;"> Du contenu pour tous </a></h5><p> Les entreprises capables de répondre rapidement et systématiquement aux demandes des consommateurs prospèrent à une époque de contenu infini. Découvrez comment créer des expériences fluides pour vos clients omnicanal.</p><p><strong><a href="https://www.perficient.com/insights/guides/2019/content-for-everyone-how-to-build-fluid-experiences-for-your-omnichannel-customers" title="Get the Guide" class="red-link"> Obtenez le guide </a></strong></p></div></div></div><p> Évitez <a href="https://sling.apache.org/documentation/bundles/models.html#basic-usage"> @Inject </a>. L'injection de valeur se produit au moment de l'exécution. Si vous utilisez <em> @Inject </em>vous faites en sorte que le framework fasse des conjectures supplémentaires. Soyez explicite. Voici les <a href="https://sling.apache.org/documentation/bundles/models.html#injector-specific-annotations"> annotations de l'injecteur </a> que j'ai utilisées avec un lien vers le code source. Cela vaut la peine de jeter un œil pour mieux comprendre le fonctionnement de l'injection.</p><ul><li><a href="https://github.com/apache/sling-org-apache-sling-models-impl/blob/master/src/main/java/org/apache/sling/models/impl/injectors/ValueMapInjector.java"> @ValueMapValue </a> – Celui que vous utiliserez le plus, injecter des propriétés de ressources simples.</li><li><a href="https://github.com/apache/sling-org-apache-sling-models-impl/blob/master/src/main/java/org/apache/sling/models/impl/injectors/ChildResourceInjector.java"> @ChildResource </a> – Les données sont enregistrées dans un hiérarchie des ressources que le cadre adaptera davantage au modèle <em> Item </em>.</li><li><a href="https://github.com/apache/sling-org-apache-sling-models-impl/blob/master/src/main/java/org/apache/sling/models/impl/injectors/ResourcePathInjector.java"> @ResourcePath </a> – Cela augmentera la valeur de la propriété, la résoudra en une ressource, puis l'adaptera à un <a href="https://helpx.adobe.com/experience-manager/6-5/sites/developing/using/reference-materials/javadoc/com/day/cq/wcm/api/Page.html"> Page </a>.</li></ul><p> Et voilà! La charpente fournit toute la plomberie. Aucune itération enfant, classes DTO, résolution de ressources ou adaptations d'aucune sorte. Mais attendez… les balises me dérangent vraiment. J'ai pu mapper un chemin de page vers un objet <a href="https://helpx.adobe.com/experience-manager/6-5/sites/developing/using/reference-materials/javadoc/com/day/cq/wcm/api/Page.html"> Page </a> réel. Ne puis-je pas mapper ces identifiants de balise à un objet <a href="https://helpx.adobe.com/experience-manager/6-5/sites/developing/using/reference-materials/javadoc/com/day/cq/tagging/Tag.html"> Tag </a>?</p><p> La réponse courte est non. Les balises sont un concept AEM et c'est Sling Models. Vous ne pouvez même pas résoudre un identifiant de balise via le résolveur de ressources. Vous devez utiliser le <a href="https://helpx.adobe.com/experience-manager/6-5/sites/developing/using/reference-materials/javadoc/com/day/cq/tagging/TagManager.html"> TagManager </a>. Il convient de noter qu’il existe d’autres implémentations d’injecteurs open source. Prenons par exemple ce <a href="https://github.com/icfnext/aem-library/blob/develop/aem-library-models/src/main/groovy/com/icfolson/aem/library/models/impl/TagInjector.groovy"> TagInjector </a> du projet I <a href="http://code.digitalatolson.com/aem-library/injectors.html"> CF Olson AEM Library </a>.</p><h2> My Spidey Sense is Tingling</h2><p> Les implémentations open-source sont très bien et tout; mais il y a même les injecteurs <a href="https://adobe-consulting-services.github.io/acs-aem-commons/features/sling-model-injectors/index.html"> d'ACS Commons </a>. Mais mon sens de l'araignée me dit que je peux toujours utiliser les modèles Sling et obtenir très peu de code. Défi accepté! Je suis allé prendre une tasse de café et j'ai passé un peu de temps avec mes chiens dans la cour. J'ai réfléchi un peu à l'injection, et c'est ce que j'ai proposé.</p><div class="quads-location quads-ad54740 " id="quads-ad54740" style="float:none;margin:0px 3px 3px 3px;padding:0px 0px 0px 0px;" data-lazydelay="0"> <ins class="adsbygoogle"
 style="display:block; text-align:center;"
 data-ad-layout="in-article"
 data-ad-format="fluid"
 data-ad-client="pub-2247171909266990"
 data-ad-slot="3144894705"></ins> <script>(adsbygoogle = window.adsbygoogle || []).push({});</script> </div><p> Les identifiants de balises sont enregistrés dans une propriété <em> String []</em> de la ressource item. Nous savons que dans Sling, même les propriétés sont des ressources qui peuvent être adaptées à leur type de base. Par exemple:</p><pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="dracula"> Resource tags = resource.getChild ("items / item0 / tags");
String [] value = tags.adaptTo (String [] .class); </pre><p> J'ai donc changé le type de retour sur <em> getTags () </em> en mon propre type <em> ItemTags </em> et changé l'annotation d'injecteur à <em> @ChildResource </em>.</p><pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-theme="dracula"> @Model (adaptables = {Resource.class})
interface publique MyModel {

    @ValueMapValue
    String getText ();

    @ChildResource (injectionStrategy = InjectionStrategy.OPTIONAL)
    List <Item> getItems ();

    @Model (adaptables = Resource.class)
    Élément d'interface {

        @ValueMapValue (nom = "jcr: titre")
        String getTitle ();

        @ResourcePath
        Page getPage ();

        @ChildResource
        ItemTags getTags ();
    }

    interface ItemTags étend Iterable <Tag> {

    }

    @Model (adaptables = Resource.class,
           adaptateurs = ItemTags.class)
    la classe finale ItemTagsImpl implémente ItemTags {

        balises de la liste finale privée <Tag>;

        @Injecter
        public ItemTagsImpl (
                @Soi
                @Via ("resourceResolver")
                tagManager final TagManager,
                @Soi
                final String [] ids) {

            this.tags = Arrays.stream (identifiants)
                              .map (tagManager :: résoudre)
                              .filter (Objets :: nonNull)
                              .collect (Collectors.toUnmodifiableList ());
        }

        @Passer outre
        public Iterator <Tag> iterator () {

            return this.tags.iterator ();
        }

        @Passer outre
        public void forEach (action finale du consommateur <? super Tag>) {

            this.tags.forEach (action);
        }

        @Passer outre
        public Spliterator <Tag> spliterator () {

            retourne this.tags.spliterator ();
        }
    }
} </pre><p> Le reste de mes décisions consistait principalement à faciliter les tests unitaires.</p><ul><li> J'ai séparé les <em> ImageTags </em> en interface et implémentation parce que les interfaces facilitent les tests unitaires.</li><li> J'ai choisi l'injection de constructeur parce qu'elle est plus simple de renouveler la classe dans un test unitaire que de configurer des injections simulées.</li><li> La seule couverture de code dont je suis responsable est maintenant de 4 lignes de code (le constructeur et les fonctions getter)</li></ul><p> De plus, l'objet est immuable et itérable pour plus de commodité. Notez l'utilisation de l'annotation <em> @Self </em> et <em> @Via </em> dans l'injection du constructeur. Ils indiquent au framework de prendre la chose à adapter, la propriété tags <em> resource.getChild («items / item0 / tags»), </em> et de l'adapter à un TagManager via le résolveur de ressources. Et aussi l'adapter à un tableau d'identifiants au moyen d'un simple <em> adaptTo (String [] .class) </em>. Bien organisé, modulaire, court et concis.</p><h2> Conclusion: n’oubliez pas de vérifier la plomberie</h2><p> Cela vaut la peine de parcourir la documentation <a href="https://sling.apache.org/documentation/bundles/models.html"> Sling Models </a> et de la connaître. Il fournit beaucoup de plomberie. Même si vous êtes obligé d'implémenter vos propres injecteurs, c'est un excellent moyen de garder votre code modulaire et propre. Dans le prochain article, je traiterai des générateurs de code.</p><p> <span class="TextRun Highlight SCXW10769914 BCX0" lang="EN-US" xml:lang="EN-US" data-contrast="auto"> <span class="NormalTextRun SCXW10769914 BCX0"> J'espère que vous avez trouvé ce billet de blog utile. Pour toute question supplémentaire, veuillez commenter ci-dessous et n'oubliez pas de consulter nos autres </span></span><a class="Hyperlink SCXW10769914 BCX0" href="https://blogs.perficient.com/category/partners/adobe/" target="_blank" rel="noreferrer noopener"><span class="TextRun Highlight Underlined SCXW10769914 BCX0" lang="EN-US" xml:lang="EN-US" data-contrast="none"><span class="NormalTextRun SCXW10769914 BCX0"> blogs Adobe </span></span></a><span class="TextRun Highlight SCXW10769914 BCX0" lang="EN-US" xml:lang="EN-US" data-contrast="auto"><span class="NormalTextRun SCXW10769914 BCX0">. </span></span></p></div><p></p><div class="author-avatar-and-name"><div class="author-avatar-and-name-avatar"> <a href="https://blogs.perficient.com/author/jayala/" style="float: left; margin-right: 1rem;"><img decoding="async" loading="lazy" src="https://i0.wp.com/blogs.perficient.com/wp-content/uploads/avatars/1748/1608219421-bpfull.jpg?w=180" alt="" class=" avatar  avatar-180  photo user-1748-avatar" width="180" height="180"/></a></div><div class="author-avatar-and-name-description"><h5 class="heading-five"> À propos de l'auteur</h5><p> Juan Ayala est un développeur principal dans la pratique Adobe chez Perficient, Inc., axé sur la plate-forme Adobe Experience et les éléments qui l'entourent.</p><p><strong><a href="https://blogs.perficient.com/author/jayala/" title="Juan Ayala" class="red-link"> Plus de cet auteur </a></strong></p></div></p></div></p></div><p><script defer src="data:text/javascript;base64,CiAgICAhIGZ1bmN0aW9uIChmLCBiLCBlLCB2LCBuLCB0LCBzKSB7aWYgKGYuZmJxKSByZXR1cm47IG4gPSBmLmZicSA9IGZ1bmN0aW9uICgpIHtuLmNhbGxNZXRob2Q/CiAgICBuLmNhbGxNZXRob2QuYXBwbHkgKG4sIGFyZ3VtZW50cyk6IG4ucXVldWUucHVzaCAoYXJndW1lbnRzKX07IGlmICghIGYuX2ZicSkgZi5fZmJxID0gbjsKICAgIG4ucHVzaCA9IG47IG4ubG9hZGVkID0hIDA7IG4udmVyc2lvbiA9ICYjMzk7Mi4wJiMzOTs7IG4ucXVldWUgPSBbXTsgdCA9IGIuY3JlYXRlRWxlbWVudCAoZSk7IHQuYXN5bmMgPSEgMDsKICAgIHQuc3JjID0gdjsgcyA9IGIuZ2V0RWxlbWVudHNCeVRhZ05hbWUgKGUpIFswXTsgcy5wYXJlbnROb2RlLmluc2VydEJlZm9yZSAodCwgcyl9IChmZW7DqnRyZSwKICAgIGRvY3VtZW50LCAmIzM5O3NjcmlwdCYjMzk7LCAmIzM5O2h0dHBzOiAvL2Nvbm5lY3QuZmFjZWJvb2submV0L2VuX1VTL2ZiZXZlbnRzLmpzJiMzOTspOwogICAgZmJxICjCq2luaXTCuywgwqs5MTE0MzY2NjU1NzI3MjDCuyk7CiAgICBmYnEgKCYjMzk7dHJhY2smIzM5OywgJnF1b3Q7UGFnZVZpZXcmcXVvdDspOyA="></script><br /> <br /><div class="clearfix button-collection container text-center "></div><div class="clearfix button-collection container text-center "></div><div class="clearfix button-collection container text-center "><a id="layers-widget-layers-pro-call-to-action-3-buttons-554" class="button " href="https://arcoptimizer.com/botinstagram?utm_source=bottom_article_blog&utm_medium=cta&utm_campaign=corporate_estimation"> Le meilleur outil 2023 pour ta croissance Instagram ! </a></div><div class="clearfix text-center "> <button class="circle-action-btn"><div class="circle-action-btn__icon"><i class="ion-speedometer"></i></div> </button></div> <br> <script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <ins class="adsbygoogle"
 style="display:block; text-align:center;"
 data-ad-layout="in-article"
 data-ad-format="fluid"
 data-ad-client="ca-pub-2247171909266990"
 data-ad-slot="5039287111"></ins> <script>(adsbygoogle = window.adsbygoogle || []).push({});</script><br /> <br /><a href="https://blogs.perficient.com/2021/04/02/writing-less-java-code-in-aem-with-sling-models/" target="_blank" rel="follow noopener noreferrer">Source link </a></p><div class="sharedaddy sd-sharing-enabled"><div class="robots-nocontent sd-block sd-social sd-social-icon sd-sharing"><h3 class="sd-title">Partager :</h3><div class="sd-content"><ul><li class="share-twitter"><a rel="nofollow noopener noreferrer" data-shared="sharing-twitter-59885" class="share-twitter sd-button share-icon no-text" href="https://blog.arcoptimizer.com/redaction-de-code-java-dans-aem-avec-des-modeles-sling?share=twitter" target="_blank" title="Cliquez pour partager sur Twitter" ><span></span><span class="sharing-screen-reader-text">Cliquez pour partager sur Twitter(ouvre dans une nouvelle fenêtre)</span></a></li><li class="share-facebook"><a rel="nofollow noopener noreferrer" data-shared="sharing-facebook-59885" class="share-facebook sd-button share-icon no-text" href="https://blog.arcoptimizer.com/redaction-de-code-java-dans-aem-avec-des-modeles-sling?share=facebook" target="_blank" title="Cliquez pour partager sur Facebook" ><span></span><span class="sharing-screen-reader-text">Cliquez pour partager sur Facebook(ouvre dans une nouvelle fenêtre)</span></a></li><li class="share-end"></li></ul></div></div></div></p><div id='jp-relatedposts' class='jp-relatedposts' ><h3 class="jp-relatedposts-headline"><em>Articles similaires</em></h3></div></div><footer class="meta-info"><p><span class="meta-item meta-date"><i class="l-clock-o"></i> avril 2, 2021</span> <span class="meta-item meta-tags"><i class="l-tags"></i> <a href="https://blog.arcoptimizer.com/tag/java" title="View all posts tagged Java">Java</a>, <a href="https://blog.arcoptimizer.com/tag/modeles" title="View all posts tagged modèles">modèles</a>, <a href="https://blog.arcoptimizer.com/tag/redaction" title="View all posts tagged Rédaction">Rédaction</a>, <a href="https://blog.arcoptimizer.com/tag/sling" title="View all posts tagged Sling">Sling</a></span></p></footer></article></div></div><div id="back-to-top"> <a href="#top">Revenir vers le haut</a></div></section><footer id="footer" class="footer-site invert"><div class="container content clearfix"><div class="row copyright"><div class="column span-6"><p class="site-text">Copyright arcoptimizer.com <script>document.write(new Date().getFullYear())</script> article@arcoptimizer.com</p></div><div class="column span-6 clearfix t-right"><nav class="nav nav-horizontal pull-right"><ul id="menu-menu_footer" class="menu"><li id="menu-item-142202" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-142202"><a href="mailto:article@arcoptimizer.com"><i class='fa fa-envelope'></i></a></li><li id="menu-item-142203" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-142203"><a href="http://article@arcoptimizer.com">article@arcoptimizer.com</a></li></ul></nav></div></div></div></footer><div class="search-interface-overlay"><form role="search" method="get" class="search-interface-holder" action="https://blog.arcoptimizer.com/"> <label class="search-text"> Search: </label> <input
 type="text"
 id="layers-modal-search-field"
 class="search-field"
 placeholder="Type Something"
 value=""
 name="s"
 title="Search for:"
 autocomplete="off"
 autocapitalize="off"
 ></form> <a href="#" class="search-close"> <i class="l-close"></i> </a></div></section><style type="text/css">@media (max-width: 480px) {  .ednpro_main_wrapper{display:none; }   }</style><div class="ednpro_main_wrapper ednpro_section"><div class="edn-close-section" id="apex_cookie_0" ><div class="edn-notify-bar edn-position-bottom edn-visibility-show-time edn-custom-template edn_no_close_button" id="edn_custom_template" data-barid="apexbar-0" data-postid="59885"> <input type="hidden" id='effect_type0' value="edn_pro_static"/> <input type="hidden" class='edn_social_optons' value="0"/> <input type="hidden" class='edn_right_optons' value="1"/><div class="edn-container apexnb-bartypeedn_pro_static"><style type="text/css">.edn-notify-bar .edn-custom-design-wrapper .ticker-wrapper .ticker, .edn-notify-bar .ticker-wrapper .ticker{
        font-family: default;
                         font-size: 22px;
                                  background-color: #1e73be;
            }
    /*added custom css*/
    .edn-custom-template[data-barid=apexbar-0] .edn-custom-design-wrapper,
     .edn-custom-template[data-barid=apexbar-0],
    .edn-custom-template[data-barid=apexbar-0] .edn-contact-lightbox .edn-contact-lightbox-inner-wrap,
    .edn-custom-template[data-barid=apexbar-0] .edn-contact-close,
    .edn-custom-template[data-barid=apexbar-0] .edn-contact-lightbox-inner-wrap{
                font-family: default;
                         font-size: 22px;
                                  background-color: #1e73be;
        
    }
    .edn-custom-template[data-barid=apexbar-0] .edn-contact-lightbox-inner-wrap label{
             }
    .edn-custom-template[data-barid=apexbar-0] .edn-mulitple-text-content,
    .edn-custom-template[data-barid=apexbar-0] .edn_static_text, 
    .slider_template_wrapper .edn-tweet-content, .edn-post-title-wrap .edn-post-title li,
    .edn-custom-template[data-barid=apexbar-0] .edn_static_text, 
    .slider_template_wrapper .edn-tweet-content, .edn-post-title-wrap .edn-post-title li,
    .edn-custom-template[data-barid=apexbar-0] .edn-tweet-content,
    .edn-custom-template[data-barid=apexbar-0] .edn-tweet-content a,
    .edn-custom-template[data-barid=apexbar-0] .ticker-content,
    .edn-custom-template[data-barid=apexbar-0] a,
     .edn-custom-template[data-barid=apexbar-0] .ticker-wrapper .ticker-content a, 
    .edn-custom-template[data-barid=apexbar-0] .ticker-wrapper .ticker-content .edn-tweet-content, 
    .edn-custom-template[data-barid=apexbar-0] .ticker-wrapper .edn-mulitple-text-content{
                 font-family: default;
                        font-size: 22px;
                     }
    .edn-custom-template[data-barid=apexbar-0] .edn-contact-form-wrap .edn-contact-close{
                            background-color: #1e73be;
            }
    /*tweets*/

    .edn-custom-template[data-barid=apexbar-0] .ticker-wrapper .edn-post-title-readmore{
                font-family: default;
                          font-size: 22px;
                               }
    /*ticker custom design start*/

    .edn-custom-template[data-barid=apexbar-0] .ticker-wrapper .ticker-content a{
        margin-left: 8px;
    }
    .edn-custom-template[data-barid=apexbar-0] .ticker_pattern .edn-ticker-wrapper  .ticker-wrapper  .ticker-swipe{
                  background-color: #1e73be;
            }

    /*ticker custom design end*/
    .edn-custom-template[data-barid=apexbar-0] .edn-contact-close,input[type="button"].edn-contact-submit{
                   background-color: #1e73be;
            }
    .edn-custom-template[data-barid=apexbar-0] a.edn-controls-close,input[type="button"].edn-contact-submit{
               color: #000000;
             }

    .edn-custom-template[data-barid=apexbar-0] .edn-social-heading-title{
                   font-size: 22px;
            }
    /*Custom Subscribe Form CSS ADDED*/
    .edn-custom-template[data-barid=apexbar-0] h1,
    .edn-custom-template[data-barid=apexbar-0] h2,
    .edn-custom-template[data-barid=apexbar-0] h3,
    .edn-custom-template[data-barid=apexbar-0] h4,
    .edn-custom-template[data-barid=apexbar-0] h5,
    .edn-custom-template[data-barid=apexbar-0] h6,
    .edn-custom-template[data-barid=apexbar-0] .edn-subscribe-form .edn-front-title h3{
                       font-size: 22px;
            }
    .edn-custom-template[data-barid=apexbar-0] .edn-subscribe-form .edn-front-title h3 span{
                }
    .edn-custom-template[data-barid=apexbar-0] .edn-subscribe-form .edn-front-title .show_icon i{
               }
    

    /*Constant Contact Subscribe Form CSS END*/
    /* For all  CUstom buttons start */
    .edn-custom-template[data-barid=apexbar-0] .edn-form-field .constant_subscribe, 
    .edn-custom-template[data-barid=apexbar-0] .edn-subscribe-form .edn-form-field .edn_subs_submit_ajax,   
    .edn-custom-template[data-barid=apexbar-0] .edn-custom-contact-link, 
    .edn-custom-template[data-barid=apexbar-0] .edn-temp1-static-button,
    .edn-custom-template[data-barid=apexbar-0] .apexnb-search-layout1 .apex-search-right-section .btn-search-now,
    .edn-custom-template[data-barid=apexbar-0] .edn_static_text .edn-call-action-button a, 
    .edn-custom-template[data-barid=apexbar-0] .edn-call-action-button a,
    .edn-custom-template[data-barid=apexbar-0] .edn-contact-lightbox .edn-form-field .edn-field input.edn-contact-submit{
               background: #eeee22;
                 color: #000000;
                 font-family: default;
            }
   
         .edn-custom-template[data-barid=apexbar-0] .edn_static_text .edn-call-action-button a:hover,
        .edn-custom-template.edn-notify-bar .edn-custom-contact-link:hover,
        .edn-custom-template[data-barid=apexbar-0] .apexnb-search-layout1 .apex-search-right-section .btn-search-now:hover,
        .edn-custom-template[data-barid=apexbar-0] .edn-subscribe-form .edn-form-field .edn_subs_submit_ajax:hover,
        .edn-custom-template[data-barid=apexbar-0] .edn-form-field .edn_mailchimp_submit_ajax:hover,
        .edn-custom-template[data-barid=apexbar-0] .edn-form-field .constant_subscribe:hover 
        {
            color: #ffffff;
            background: #81d742;
        }

        
        .edn-custom-template[data-barid=apexbar-0] .edn_static_text .edn-text-link a, 
        .edn-custom-template[data-barid=apexbar-0] .edn_multiple_text .edn-mulitple-text-content a,
        edn-custom-template[data-barid=apexbar-0] .edn-multiple-content .edn-mulitple-text-content a,
        .edn-custom-template[data-barid=apexbar-0] .edn-post-title-wrap .edn-post-title li a{
            color: #000000;
            background: ;
        }
        
    /* close button custom css */
       .edn-custom-template[data-barid=apexbar-0]  .edn-top-up-arrow.open,
    .edn-custom-template[data-barid=apexbar-0]  .edn-bottom-down-arrow.open,
    .edn-custom-template[data-barid=apexbar-0]  .edn-bottom-down-arrow.open,
    .edn-custom-template[data-barid=apexbar-0] .edn-left-arrow,
    .edn-custom-template[data-barid=apexbar-0] .edn-right-arrow,
    .edn-custom-template[data-barid=apexbar-0] .edn-cntrol-wrap.ednpro_user-can-close {
               background-image:  url("../../images/showhidetoggledown.png") no-repeat scroll 0 0;

    }
    .edn-custom-template[data-barid=apexbar-0] .edn-cntrol-wrap.ednpro_user-can-close .fa-close{
           }

    .edn-custom-template[data-barid=apexbar-0] .edn-top-up-arrow {
                background-image: url("../../images/showhidetoggletop.png") no-repeat scroll 0 0;
        border-radius: 14px;
    }
    .edn-custom-template[data-barid=apexbar-0] .edn-bottom-down-arrow{
                  border-radius: 14px;
        background-image: url("../../images/showhidetoggledown.png") no-repeat scroll 0 0;
    }
    /* close button custom css */


    .edn-custom-template[data-barid=apexbar-0] .edn_error,.edn-error,
    .edn-constant-error
    .edn-custom-template[data-barid=apexbar-0] .edn-success,
    .edn-constant-success{
               font-family: default;
                   }


    /*social icons custom design start*/
    
        .edn-custom-template[data-barid=apexbar-0] .edn-post-title-wrap .edn-post-title li{
                  }

        
    .edn-custom-template[data-barid=apexbar-0].edn-visibility-show-time{
        display: none;
    }
    .edn-custom-template[data-barid=apexbar-0] .visibility_show-time{
        display: none;
    }
               .edn-notify-bar .edn-custom-design-wrapper .edn-post-title-readmore{
            color: #000000 !important;
            background: #eeee22 !important;
            padding: 2px 8px;
            font-size: 35px !important;             font-weight: bolder !important;         }
            .edn-notify-bar .edn-custom-design-wrapper .edn-post-title-readmore:hover{
            color: #ffffff !important;
            background: #81d742 !important;
        }</style><div class="edn-temp-design-wrapper edn-custom-design-wrapper"><div class="edn_middle_content edn_pro_static_pattern"><div class="edn-text-content-wrap"><div class="edn_static_text"><div class="edn-text-link">L’Outil Surpuissant pour Exploser ton Chiffre d'Affaires en 2024 !</div> <span class="edn-call-action-button"> <span class="edn-ca-custom"> <a class="edn-static-button" href="https://allleads.arcoptimizer.com/fr" target='_blank'> <span class="edn-ca-static-button">Essai Gratuit Aujourd'hui</span> </a> </span> </span></div></div></div></div></div> <input type="hidden" class="edn-ticker-option" id="apexnb-ticker-0"
 data-ticker-speed=""
 data-ticker-direction="vertical"
 data-ticker-title=""
 data-ticker-hover=""
 data-slider-controls=""
 data-slider-animation="horizontal"
 data-slider-duration=""
 data-slider-auto="true"
 data-slider-transition=""
 data-slider-adaptive-height="true"
 data-scroll-controls=""
 data-scroll-direction="ltr"
 data-scroll-animation="reveal"
 data-scroll-speed=""
 data-scroll-title=""
/> <input type="hidden" class="edn-visibility-bar-options edn-visibility-option-0" id="apexnb-0"
 data-show-time-duration="200"
 data-hide-time-duration=""
 data-visibility-type = "show-time"
 data-close-type = "disable"
 data-close-once = ""
 data-duration-close = "" 
 data-show_once_hideshow = ""
 data-notification_bar_id = "0"
/><div class="apexnb-ccform edn-template-3 edn-popup-form" data-formtype="apexnb-static-custom" data-barid="0"><div class="edn-contact-lightbox" id="edn-static-cf-btn-0-lightbox" style="display: none;"><div class="ednpro_overlay"></div><div class="edn-contact-lightbox-inner-wrap " id="edn-contact-lightbox-inner-wrap-0"><div class="edn-contact-lightbox-inner-content edn-contact-lightbox-inner-wrap apexnb-ccustomform-wrapper "></div></div></div></div></div></div></div><script defer src="data:text/javascript;base64,PGFtcC1hdXRvLWFkcyB0eXBlPSJhZHNlbnNlIgogICAgICAgIGRhdGEtYWQtY2xpZW50PSJjYS1wdWItMjI0NzE3MTkwOTI2Njk5MCI+CjwvYW1wLWF1dG8tYWRzPg=="></script> <div id="jp-carousel-loading-overlay"><div id="jp-carousel-loading-wrapper"> <span id="jp-carousel-library-loading"> </span></div></div><div class="jp-carousel-overlay" style="display: none;"><div class="jp-carousel-container"><div
 class="jp-carousel-wrap swiper-container jp-carousel-swiper-container jp-carousel-transitions"
 itemscope
 itemtype="https://schema.org/ImageGallery"><div class="jp-carousel swiper-wrapper"></div><div class="jp-swiper-button-prev swiper-button-prev"> <svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <mask id="maskPrev" mask-type="alpha" maskUnits="userSpaceOnUse" x="8" y="6" width="9" height="12"> <path d="M16.2072 16.59L11.6496 12L16.2072 7.41L14.8041 6L8.8335 12L14.8041 18L16.2072 16.59Z" fill="white"/> </mask> <g mask="url(#maskPrev)"> <rect x="0.579102" width="23.8823" height="24" fill="#FFFFFF"/> </g> </svg></div><div class="jp-swiper-button-next swiper-button-next"> <svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <mask id="maskNext" mask-type="alpha" maskUnits="userSpaceOnUse" x="8" y="6" width="8" height="12"> <path d="M8.59814 16.59L13.1557 12L8.59814 7.41L10.0012 6L15.9718 12L10.0012 18L8.59814 16.59Z" fill="white"/> </mask> <g mask="url(#maskNext)"> <rect x="0.34375" width="23.8822" height="24" fill="#FFFFFF"/> </g> </svg></div></div><div class="jp-carousel-close-hint"> <svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <mask id="maskClose" mask-type="alpha" maskUnits="userSpaceOnUse" x="5" y="5" width="15" height="14"> <path d="M19.3166 6.41L17.9135 5L12.3509 10.59L6.78834 5L5.38525 6.41L10.9478 12L5.38525 17.59L6.78834 19L12.3509 13.41L17.9135 19L19.3166 17.59L13.754 12L19.3166 6.41Z" fill="white"/> </mask> <g mask="url(#maskClose)"> <rect x="0.409668" width="23.8823" height="24" fill="#FFFFFF"/> </g> </svg></div><div class="jp-carousel-info"><div class="jp-carousel-info-footer"><div class="jp-carousel-pagination-container"><div class="jp-swiper-pagination swiper-pagination"></div><div class="jp-carousel-pagination"></div></div><div class="jp-carousel-photo-title-container"><h2 class="jp-carousel-photo-caption"></h2></div><div class="jp-carousel-photo-icons-container"> <a href="#" class="jp-carousel-icon-btn jp-carousel-icon-info" aria-label="Activer la visibilité des métadonnées sur les photos"> <span class="jp-carousel-icon"> <svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <mask id="maskInfo" mask-type="alpha" maskUnits="userSpaceOnUse" x="2" y="2" width="21" height="20"> <path fill-rule="evenodd" clip-rule="evenodd" d="M12.7537 2C7.26076 2 2.80273 6.48 2.80273 12C2.80273 17.52 7.26076 22 12.7537 22C18.2466 22 22.7046 17.52 22.7046 12C22.7046 6.48 18.2466 2 12.7537 2ZM11.7586 7V9H13.7488V7H11.7586ZM11.7586 11V17H13.7488V11H11.7586ZM4.79292 12C4.79292 16.41 8.36531 20 12.7537 20C17.142 20 20.7144 16.41 20.7144 12C20.7144 7.59 17.142 4 12.7537 4C8.36531 4 4.79292 7.59 4.79292 12Z" fill="white"/> </mask> <g mask="url(#maskInfo)"> <rect x="0.8125" width="23.8823" height="24" fill="#FFFFFF"/> </g> </svg> </span> </a> <a href="#" class="jp-carousel-icon-btn jp-carousel-icon-comments" aria-label="Activer la visibilité des commentaires sur les photos"> <span class="jp-carousel-icon"> <svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <mask id="maskComments" mask-type="alpha" maskUnits="userSpaceOnUse" x="2" y="2" width="21" height="20"> <path fill-rule="evenodd" clip-rule="evenodd" d="M4.3271 2H20.2486C21.3432 2 22.2388 2.9 22.2388 4V16C22.2388 17.1 21.3432 18 20.2486 18H6.31729L2.33691 22V4C2.33691 2.9 3.2325 2 4.3271 2ZM6.31729 16H20.2486V4H4.3271V18L6.31729 16Z" fill="white"/> </mask> <g mask="url(#maskComments)"> <rect x="0.34668" width="23.8823" height="24" fill="#FFFFFF"/> </g> </svg> <span class="jp-carousel-has-comments-indicator" aria-label="Cette image comporte des commentaires."></span> </span> </a></div></div><div class="jp-carousel-info-extra"><div class="jp-carousel-info-content-wrapper"><div class="jp-carousel-photo-title-container"><h2 class="jp-carousel-photo-title"></h2></div><div class="jp-carousel-comments-wrapper"><div id="jp-carousel-comments-loading"> <span>Chargement des commentaires…</span></div><div class="jp-carousel-comments"></div><div id="jp-carousel-comment-form-container"> <span id="jp-carousel-comment-form-spinner"> </span><div id="jp-carousel-comment-post-results"></div><form id="jp-carousel-comment-form"> <label for="jp-carousel-comment-form-comment-field" class="screen-reader-text">Écrire un commentaire...</label><textarea
													name="comment"
													class="jp-carousel-comment-form-field jp-carousel-comment-form-textarea"
													id="jp-carousel-comment-form-comment-field"
													placeholder="Écrire un commentaire..."
												></textarea><div id="jp-carousel-comment-form-submit-and-info-wrapper"><div id="jp-carousel-comment-form-commenting-as"><fieldset> <label for="jp-carousel-comment-form-email-field">E-mail (requis)</label> <input type="text" name="email" class="jp-carousel-comment-form-field jp-carousel-comment-form-text-field" id="jp-carousel-comment-form-email-field" /></fieldset><fieldset> <label for="jp-carousel-comment-form-author-field">Nom (requis)</label> <input type="text" name="author" class="jp-carousel-comment-form-field jp-carousel-comment-form-text-field" id="jp-carousel-comment-form-author-field" /></fieldset><fieldset> <label for="jp-carousel-comment-form-url-field">Site web</label> <input type="text" name="url" class="jp-carousel-comment-form-field jp-carousel-comment-form-text-field" id="jp-carousel-comment-form-url-field" /></fieldset></div> <input
 type="submit"
 name="submit"
 class="jp-carousel-comment-form-button"
 id="jp-carousel-comment-form-button-submit"
 value="Laisser un commentaire" /></div></form></div></div><div class="jp-carousel-image-meta"><div class="jp-carousel-title-and-caption"><div class="jp-carousel-photo-info"><h3 class="jp-carousel-caption" itemprop="caption description"></h3></div><div class="jp-carousel-photo-description"></div></div><ul class="jp-carousel-image-exif" style="display: none;"></ul> <a class="jp-carousel-image-download" href="#" target="_blank" style="display: none;"> <svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="3" y="3" width="19" height="18"> <path fill-rule="evenodd" clip-rule="evenodd" d="M5.84615 5V19H19.7775V12H21.7677V19C21.7677 20.1 20.8721 21 19.7775 21H5.84615C4.74159 21 3.85596 20.1 3.85596 19V5C3.85596 3.9 4.74159 3 5.84615 3H12.8118V5H5.84615ZM14.802 5V3H21.7677V10H19.7775V6.41L9.99569 16.24L8.59261 14.83L18.3744 5H14.802Z" fill="white"/> </mask> <g mask="url(#mask0)"> <rect x="0.870605" width="23.8823" height="24" fill="#FFFFFF"/> </g> </svg> <span class="jp-carousel-download-text"></span> </a><div class="jp-carousel-image-map" style="display: none;"></div></div></div></div></div></div></div> <script defer src="data:text/javascript;base64,CgkJd2luZG93LldQQ09NX3NoYXJpbmdfY291bnRzID0geyJodHRwczpcL1wvYmxvZy5hcmNvcHRpbWl6ZXIuY29tXC9yZWRhY3Rpb24tZGUtY29kZS1qYXZhLWRhbnMtYWVtLWF2ZWMtZGVzLW1vZGVsZXMtc2xpbmciOjU5ODg1fTsKCQ=="></script> <link rel='stylesheet' id='aal_style-css' href='https://blog.arcoptimizer.com/wp-content/cache/autoptimize/css/autoptimize_single_4c15efd49114c121de9d8db67a23db93.css' type='text/css' media='all' /> <script defer type='text/javascript' src='https://blog.arcoptimizer.com/wp-content/cache/autoptimize/js/autoptimize_single_328b8123661abdd5f4a0c695e7aa9dcc.js?minify=false&ver=132249e245926ae3e188' id='jetpack-photon-js'></script> <script defer type='text/javascript' src='https://blog.arcoptimizer.com/wp-content/themes/defaut_theme3/assets/js/wow.min.js' id='layers-child-wow-js'></script> <script defer type='text/javascript' src='https://stats.wp.com/e-202416.js' id='jetpack-stats-js'></script> <script type='text/javascript' id='jetpack-stats-js-after'>_stq = window._stq || [];
_stq.push([ "view", {v:'ext',blog:'146388461',post:'59885',tz:'0',srv:'blog.arcoptimizer.com',j:'1:12.8.1'} ]);
_stq.push([ "clickTrackerInit", "146388461", "59885" ]);</script> <script defer type='text/javascript' src='https://blog.arcoptimizer.com/wp-content/cache/autoptimize/js/autoptimize_single_f4c0e5d883b22cceae0e8fbf05d26b3c.js' id='quads-ads-js'></script> <script defer id="jetpack-carousel-js-extra" src="data:text/javascript;base64,Ci8qIDwhW0NEQVRBWyAqLwp2YXIgamV0cGFja1N3aXBlckxpYnJhcnlQYXRoID0geyJ1cmwiOiJodHRwczpcL1wvYmxvZy5hcmNvcHRpbWl6ZXIuY29tXC93cC1jb250ZW50XC9wbHVnaW5zXC9qZXRwYWNrXC9faW5jXC9idWlsZFwvY2Fyb3VzZWxcL3N3aXBlci1idW5kbGUubWluLmpzIn07CnZhciBqZXRwYWNrQ2Fyb3VzZWxTdHJpbmdzID0geyJ3aWR0aHMiOlszNzAsNzAwLDEwMDAsMTIwMCwxNDAwLDIwMDBdLCJpc19sb2dnZWRfaW4iOiIiLCJsYW5nIjoiZnIiLCJhamF4dXJsIjoiaHR0cHM6XC9cL2Jsb2cuYXJjb3B0aW1pemVyLmNvbVwvd3AtYWRtaW5cL2FkbWluLWFqYXgucGhwIiwibm9uY2UiOiJkNGI1NDgzOTE1IiwiZGlzcGxheV9leGlmIjoiMCIsImRpc3BsYXlfY29tbWVudHMiOiIxIiwic2luZ2xlX2ltYWdlX2dhbGxlcnkiOiIxIiwic2luZ2xlX2ltYWdlX2dhbGxlcnlfbWVkaWFfZmlsZSI6IiIsImJhY2tncm91bmRfY29sb3IiOiJibGFjayIsImNvbW1lbnQiOiJDb21tZW50YWlyZSIsInBvc3RfY29tbWVudCI6IkxhaXNzZXIgdW4gY29tbWVudGFpcmUiLCJ3cml0ZV9jb21tZW50IjoiXHUwMGM5Y3JpcmUgdW4gY29tbWVudGFpcmUuLi4iLCJsb2FkaW5nX2NvbW1lbnRzIjoiQ2hhcmdlbWVudCBkZXMgY29tbWVudGFpcmVzXHUyMDI2IiwiZG93bmxvYWRfb3JpZ2luYWwiOiJBZmZpY2hlciBkYW5zIHNhIHRhaWxsZSByXHUwMGU5ZWxsZSA8c3BhbiBjbGFzcz1cInBob3RvLXNpemVcIj57MH08c3BhbiBjbGFzcz1cInBob3RvLXNpemUtdGltZXNcIj5cdTAwZDc8XC9zcGFuPnsxfTxcL3NwYW4+LiIsIm5vX2NvbW1lbnRfdGV4dCI6IlZldWlsbGV6IGFqb3V0ZXIgZHUgY29udGVudSBcdTAwZTAgdm90cmUgY29tbWVudGFpcmUuIiwibm9fY29tbWVudF9lbWFpbCI6Ik1lcmNpIGRlIHJlbnNlaWduZXIgdW5lIGFkcmVzc2UgZS1tYWlsLiIsIm5vX2NvbW1lbnRfYXV0aG9yIjoiTWVyY2kgZGUgcmVuc2VpZ25lciB2b3RyZSBub20uIiwiY29tbWVudF9wb3N0X2Vycm9yIjoiVW5lIGVycmV1ciBzXHUyMDE5ZXN0IHByb2R1aXRlIFx1MDBlMCBsYSBwdWJsaWNhdGlvbiBkZSB2b3RyZSBjb21tZW50YWlyZS4gVmV1aWxsZXogbm91cyBlbiBleGN1c2VyLCBldCByXHUwMGU5ZXNzYXllciBkYW5zIHF1ZWxxdWVzIGluc3RhbnRzLiIsImNvbW1lbnRfYXBwcm92ZWQiOiJWb3RyZSBjb21tZW50YWlyZSBhIFx1MDBlOXRcdTAwZTkgYXBwcm91dlx1MDBlOS4iLCJjb21tZW50X3VuYXBwcm92ZWQiOiJWb3RyZSBjb21tZW50YWlyZSBlc3QgZW4gYXR0ZW50ZSBkZSB2YWxpZGF0aW9uLiIsImNhbWVyYSI6IkFwcGFyZWlsIHBob3RvIiwiYXBlcnR1cmUiOiJPdXZlcnR1cmUiLCJzaHV0dGVyX3NwZWVkIjoiVml0ZXNzZSBkXHUyMDE5b2J0dXJhdGlvbiIsImZvY2FsX2xlbmd0aCI6IkZvY2FsZSIsImNvcHlyaWdodCI6IkNvcHlyaWdodCIsImNvbW1lbnRfcmVnaXN0cmF0aW9uIjoiMCIsInJlcXVpcmVfbmFtZV9lbWFpbCI6IjEiLCJsb2dpbl91cmwiOiJodHRwczpcL1wvYmxvZy5hcmNvcHRpbWl6ZXIuY29tXC93cC1sb2dpbi5waHA/cmVkaXJlY3RfdG89aHR0cHMlM0ElMkYlMkZibG9nLmFyY29wdGltaXplci5jb20lMkZyZWRhY3Rpb24tZGUtY29kZS1qYXZhLWRhbnMtYWVtLWF2ZWMtZGVzLW1vZGVsZXMtc2xpbmciLCJibG9nX2lkIjoiMSIsIm1ldGFfZGF0YSI6WyJjYW1lcmEiLCJhcGVydHVyZSIsInNodXR0ZXJfc3BlZWQiLCJmb2NhbF9sZW5ndGgiLCJjb3B5cmlnaHQiXX07Ci8qIF1dPiAqLwo="></script> <script defer type='text/javascript' src='https://blog.arcoptimizer.com/wp-content/plugins/jetpack/_inc/build/carousel/jetpack-carousel.min.js' id='jetpack-carousel-js'></script> <script defer id="sharing-js-js-extra" src="data:text/javascript;base64,Ci8qIDwhW0NEQVRBWyAqLwp2YXIgc2hhcmluZ19qc19vcHRpb25zID0geyJsYW5nIjoiZW4iLCJjb3VudHMiOiIxIiwiaXNfc3RhdHNfYWN0aXZlIjoiMSJ9OwovKiBdXT4gKi8K"></script> <script defer type='text/javascript' src='https://blog.arcoptimizer.com/wp-content/plugins/jetpack/_inc/build/sharedaddy/sharing.min.js' id='sharing-js-js'></script> <script defer id="sharing-js-js-after" src="data:text/javascript;base64,CnZhciB3aW5kb3dPcGVuOwoJCQkoIGZ1bmN0aW9uICgpIHsKCQkJCWZ1bmN0aW9uIG1hdGNoZXMoIGVsLCBzZWwgKSB7CgkJCQkJcmV0dXJuICEhICgKCQkJCQkJZWwubWF0Y2hlcyAmJiBlbC5tYXRjaGVzKCBzZWwgKSB8fAoJCQkJCQllbC5tc01hdGNoZXNTZWxlY3RvciAmJiBlbC5tc01hdGNoZXNTZWxlY3Rvciggc2VsICkKCQkJCQkpOwoJCQkJfQoKCQkJCWRvY3VtZW50LmJvZHkuYWRkRXZlbnRMaXN0ZW5lciggJ2NsaWNrJywgZnVuY3Rpb24gKCBldmVudCApIHsKCQkJCQlpZiAoICEgZXZlbnQudGFyZ2V0ICkgewoJCQkJCQlyZXR1cm47CgkJCQkJfQoKCQkJCQl2YXIgZWw7CgkJCQkJaWYgKCBtYXRjaGVzKCBldmVudC50YXJnZXQsICdhLnNoYXJlLXR3aXR0ZXInICkgKSB7CgkJCQkJCWVsID0gZXZlbnQudGFyZ2V0OwoJCQkJCX0gZWxzZSBpZiAoIGV2ZW50LnRhcmdldC5wYXJlbnROb2RlICYmIG1hdGNoZXMoIGV2ZW50LnRhcmdldC5wYXJlbnROb2RlLCAnYS5zaGFyZS10d2l0dGVyJyApICkgewoJCQkJCQllbCA9IGV2ZW50LnRhcmdldC5wYXJlbnROb2RlOwoJCQkJCX0KCgkJCQkJaWYgKCBlbCApIHsKCQkJCQkJZXZlbnQucHJldmVudERlZmF1bHQoKTsKCgkJCQkJCS8vIElmIHRoZXJlJ3MgYW5vdGhlciBzaGFyaW5nIHdpbmRvdyBvcGVuLCBjbG9zZSBpdC4KCQkJCQkJaWYgKCB0eXBlb2Ygd2luZG93T3BlbiAhPT0gJ3VuZGVmaW5lZCcgKSB7CgkJCQkJCQl3aW5kb3dPcGVuLmNsb3NlKCk7CgkJCQkJCX0KCQkJCQkJd2luZG93T3BlbiA9IHdpbmRvdy5vcGVuKCBlbC5nZXRBdHRyaWJ1dGUoICdocmVmJyApLCAnd3Bjb210d2l0dGVyJywgJ21lbnViYXI9MSxyZXNpemFibGU9MSx3aWR0aD02MDAsaGVpZ2h0PTM1MCcgKTsKCQkJCQkJcmV0dXJuIGZhbHNlOwoJCQkJCX0KCQkJCX0gKTsKCQkJfSApKCk7CnZhciB3aW5kb3dPcGVuOwoJCQkoIGZ1bmN0aW9uICgpIHsKCQkJCWZ1bmN0aW9uIG1hdGNoZXMoIGVsLCBzZWwgKSB7CgkJCQkJcmV0dXJuICEhICgKCQkJCQkJZWwubWF0Y2hlcyAmJiBlbC5tYXRjaGVzKCBzZWwgKSB8fAoJCQkJCQllbC5tc01hdGNoZXNTZWxlY3RvciAmJiBlbC5tc01hdGNoZXNTZWxlY3Rvciggc2VsICkKCQkJCQkpOwoJCQkJfQoKCQkJCWRvY3VtZW50LmJvZHkuYWRkRXZlbnRMaXN0ZW5lciggJ2NsaWNrJywgZnVuY3Rpb24gKCBldmVudCApIHsKCQkJCQlpZiAoICEgZXZlbnQudGFyZ2V0ICkgewoJCQkJCQlyZXR1cm47CgkJCQkJfQoKCQkJCQl2YXIgZWw7CgkJCQkJaWYgKCBtYXRjaGVzKCBldmVudC50YXJnZXQsICdhLnNoYXJlLWZhY2Vib29rJyApICkgewoJCQkJCQllbCA9IGV2ZW50LnRhcmdldDsKCQkJCQl9IGVsc2UgaWYgKCBldmVudC50YXJnZXQucGFyZW50Tm9kZSAmJiBtYXRjaGVzKCBldmVudC50YXJnZXQucGFyZW50Tm9kZSwgJ2Euc2hhcmUtZmFjZWJvb2snICkgKSB7CgkJCQkJCWVsID0gZXZlbnQudGFyZ2V0LnBhcmVudE5vZGU7CgkJCQkJfQoKCQkJCQlpZiAoIGVsICkgewoJCQkJCQlldmVudC5wcmV2ZW50RGVmYXVsdCgpOwoKCQkJCQkJLy8gSWYgdGhlcmUncyBhbm90aGVyIHNoYXJpbmcgd2luZG93IG9wZW4sIGNsb3NlIGl0LgoJCQkJCQlpZiAoIHR5cGVvZiB3aW5kb3dPcGVuICE9PSAndW5kZWZpbmVkJyApIHsKCQkJCQkJCXdpbmRvd09wZW4uY2xvc2UoKTsKCQkJCQkJfQoJCQkJCQl3aW5kb3dPcGVuID0gd2luZG93Lm9wZW4oIGVsLmdldEF0dHJpYnV0ZSggJ2hyZWYnICksICd3cGNvbWZhY2Vib29rJywgJ21lbnViYXI9MSxyZXNpemFibGU9MSx3aWR0aD02MDAsaGVpZ2h0PTQwMCcgKTsKCQkJCQkJcmV0dXJuIGZhbHNlOwoJCQkJCX0KCQkJCX0gKTsKCQkJfSApKCk7Cg=="></script> <script defer src="data:text/javascript;base64,DQogd293ID0gbmV3IFdPVygNCiB7DQogLy9ib3hDbGFzczogICAgICd3b3cnLCAgICAgIC8vIGRlZmF1bHQNCiAvL2FuaW1hdGVDbGFzczogJ2FuaW1hdGVkJywgLy8gZGVmYXVsdA0KIG9mZnNldDogICAgICAgMTAwLCAgICAgICAgICAvLyBkZWZhdWx0DQogLy9tb2JpbGU6ICAgICAgIHRydWUsICAgICAgIC8vIGRlZmF1bHQNCiAvL2xpdmU6ICAgICAgICAgdHJ1ZSAgICAgICAgLy8gZGVmYXVsdA0KIH0NCiApDQogd293LmluaXQoKTsNCiA="></script> <script defer src="data:text/javascript;base64,DQogICAgICAgIGpRdWVyeShkb2N1bWVudCkucmVhZHkoZnVuY3Rpb24gKCQpIHsNCg0KICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBkb2N1bWVudC5mb3Jtcy5sZW5ndGg7ICsraSkgew0KICAgICAgICAgICAgICAgIGxldCBmb3JtID0gZG9jdW1lbnQuZm9ybXNbaV07DQoJCQkJaWYgKCQoZm9ybSkuYXR0cigibWV0aG9kIikgIT0gImdldCIpIHsgJChmb3JtKS5hcHBlbmQoJzxpbnB1dCB0eXBlPSJoaWRkZW4iIG5hbWU9ImdxZUtwQ04tVHNWUHgiIHZhbHVlPSJWOUBKW1hfOGFxTCIgLz4nKTsgfQppZiAoJChmb3JtKS5hdHRyKCJtZXRob2QiKSAhPSAiZ2V0IikgeyAkKGZvcm0pLmFwcGVuZCgnPGlucHV0IHR5cGU9ImhpZGRlbiIgbmFtZT0id1JrT3VOQS1MZEVybSIgdmFsdWU9Ii5UZkZdYXQiIC8+Jyk7IH0KICAgICAgICAgICAgfQ0KDQogICAgICAgICAgICAkKGRvY3VtZW50KS5vbignc3VibWl0JywgJ2Zvcm0nLCBmdW5jdGlvbiAoKSB7DQoJCQkJaWYgKCQodGhpcykuYXR0cigibWV0aG9kIikgIT0gImdldCIpIHsgJCh0aGlzKS5hcHBlbmQoJzxpbnB1dCB0eXBlPSJoaWRkZW4iIG5hbWU9ImdxZUtwQ04tVHNWUHgiIHZhbHVlPSJWOUBKW1hfOGFxTCIgLz4nKTsgfQppZiAoJCh0aGlzKS5hdHRyKCJtZXRob2QiKSAhPSAiZ2V0IikgeyAkKHRoaXMpLmFwcGVuZCgnPGlucHV0IHR5cGU9ImhpZGRlbiIgbmFtZT0id1JrT3VOQS1MZEVybSIgdmFsdWU9Ii5UZkZdYXQiIC8+Jyk7IH0KICAgICAgICAgICAgICAgIHJldHVybiB0cnVlOw0KICAgICAgICAgICAgfSk7DQoNCiAgICAgICAgICAgIGpRdWVyeS5hamF4U2V0dXAoew0KICAgICAgICAgICAgICAgIGJlZm9yZVNlbmQ6IGZ1bmN0aW9uIChlLCBkYXRhKSB7DQoNCiAgICAgICAgICAgICAgICAgICAgaWYgKGRhdGEudHlwZSAhPT0gJ1BPU1QnKSByZXR1cm47DQoNCiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBkYXRhLmRhdGEgPT09ICdvYmplY3QnICYmIGRhdGEuZGF0YSAhPT0gbnVsbCkgew0KCQkJCQkJZGF0YS5kYXRhLmFwcGVuZCgiZ3FlS3BDTi1Uc1ZQeCIsICJWOUBKW1hfOGFxTCIpOwpkYXRhLmRhdGEuYXBwZW5kKCJ3UmtPdU5BLUxkRXJtIiwgIi5UZkZdYXQiKTsKICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgICAgIGVsc2Ugew0KICAgICAgICAgICAgICAgICAgICAgICAgZGF0YS5kYXRhID0gZGF0YS5kYXRhICsgJyZncWVLcENOLVRzVlB4PVY5QEpbWF84YXFMJndSa091TkEtTGRFcm09LlRmRl1hdCc7DQogICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9KTsNCg0KICAgICAgICB9KTsNCiAgICA="></script> </body></html>