ldapsaisie/doc/dist/4.2.0-1-56-g22a5be4d/LdapSaisie.html

8920 lines
No EOL
1,012 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html class="no-js" lang="fr"><head>
<meta charset="utf-8"/>
<meta content="width=device-width,initial-scale=1" name="viewport"/>
<meta content="Documentation" name="description"/>
<meta content="Benjamin Renard &lt;brenard@easter-eggs.com / brenard@zionetrix.net&gt;" name="author"/>
<link href="https://ldapsaisie.org/doc/print_page/" rel="canonical"/>
<link href="../assets/images/favicon.png" rel="icon"/>
<meta content="mkdocs-1.6.1, mkdocs-material-9.5.48" name="generator"/>
<title>Documentation - LdapSaisie</title>
<link href="data:text/css,%40charset%20%22UTF-8%22%3Bhtml%7B-webkit-text-size-adjust%3Anone%3B-moz-text-size-adjust%3Anone%3Btext-size-adjust%3Anone%3Bbox-sizing%3Aborder-box%7D%2A%2C%3Aafter%2C%3Abefore%7Bbox-sizing%3Ainherit%7D%40media%20%28prefers-reduced-motion%29%7B%2A%2C%3Aafter%2C%3Abefore%7Btransition%3Anone%21important%7D%7Dbody%7Bmargin%3A0%7Da%2Cbutton%2Cinput%2Clabel%7B-webkit-tap-highlight-color%3Atransparent%7Da%7Bcolor%3Ainherit%3Btext-decoration%3Anone%7Dhr%7Bborder%3A0%3Bbox-sizing%3Ainitial%3Bdisplay%3Ablock%3Bheight%3A.05rem%3Boverflow%3Avisible%3Bpadding%3A0%7Dsmall%7Bfont-size%3A80%25%7Dsub%2Csup%7Bline-height%3A1em%7Dimg%7Bborder-style%3Anone%7Dtable%7Bborder-collapse%3Ainitial%3Bborder-spacing%3A0%7Dtd%2Cth%7Bfont-weight%3A400%3Bvertical-align%3Atop%7Dbutton%7Bbackground%3A%230000%3Bborder%3A0%3Bfont-family%3Ainherit%3Bfont-size%3Ainherit%3Bmargin%3A0%3Bpadding%3A0%7Dinput%7Bborder%3A0%3Boutline%3Anone%7D%3Aroot%7B--md-primary-fg-color%3A%234051b5%3B--md-primary-fg-color--light%3A%235d6cc0%3B--md-primary-fg-color--dark%3A%23303fa1%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%3B--md-accent-fg-color%3A%23526cfe%3B--md-accent-fg-color--transparent%3A%23526cfe1a%3B--md-accent-bg-color%3A%23fff%3B--md-accent-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-scheme%3Ddefault%5D%7Bcolor-scheme%3Alight%7D%5Bdata-md-color-scheme%3Ddefault%5D%20img%5Bsrc%24%3D%22%23gh-dark-mode-only%22%5D%2C%5Bdata-md-color-scheme%3Ddefault%5D%20img%5Bsrc%24%3D%22%23only-dark%22%5D%7Bdisplay%3Anone%7D%3Aroot%2C%5Bdata-md-color-scheme%3Ddefault%5D%7B--md-hue%3A225deg%3B--md-default-fg-color%3A%23000000de%3B--md-default-fg-color--light%3A%230000008a%3B--md-default-fg-color--lighter%3A%2300000052%3B--md-default-fg-color--lightest%3A%2300000012%3B--md-default-bg-color%3A%23fff%3B--md-default-bg-color--light%3A%23ffffffb3%3B--md-default-bg-color--lighter%3A%23ffffff4d%3B--md-default-bg-color--lightest%3A%23ffffff1f%3B--md-code-fg-color%3A%2336464e%3B--md-code-bg-color%3A%23f5f5f5%3B--md-code-hl-color%3A%234287ff%3B--md-code-hl-color--light%3A%234287ff1a%3B--md-code-hl-number-color%3A%23d52a2a%3B--md-code-hl-special-color%3A%23db1457%3B--md-code-hl-function-color%3A%23a846b9%3B--md-code-hl-constant-color%3A%236e59d9%3B--md-code-hl-keyword-color%3A%233f6ec6%3B--md-code-hl-string-color%3A%231c7d4d%3B--md-code-hl-name-color%3Avar%28--md-code-fg-color%29%3B--md-code-hl-operator-color%3Avar%28--md-default-fg-color--light%29%3B--md-code-hl-punctuation-color%3Avar%28--md-default-fg-color--light%29%3B--md-code-hl-comment-color%3Avar%28--md-default-fg-color--light%29%3B--md-code-hl-generic-color%3Avar%28--md-default-fg-color--light%29%3B--md-code-hl-variable-color%3Avar%28--md-default-fg-color--light%29%3B--md-typeset-color%3Avar%28--md-default-fg-color%29%3B--md-typeset-a-color%3Avar%28--md-primary-fg-color%29%3B--md-typeset-del-color%3A%23f5503d26%3B--md-typeset-ins-color%3A%230bd57026%3B--md-typeset-kbd-color%3A%23fafafa%3B--md-typeset-kbd-accent-color%3A%23fff%3B--md-typeset-kbd-border-color%3A%23b8b8b8%3B--md-typeset-mark-color%3A%23ffff0080%3B--md-typeset-table-color%3A%230000001f%3B--md-typeset-table-color--light%3Argba%280%2C0%2C0%2C.035%29%3B--md-admonition-fg-color%3Avar%28--md-default-fg-color%29%3B--md-admonition-bg-color%3Avar%28--md-default-bg-color%29%3B--md-warning-fg-color%3A%23000000de%3B--md-warning-bg-color%3A%23ff9%3B--md-footer-fg-color%3A%23fff%3B--md-footer-fg-color--light%3A%23ffffffb3%3B--md-footer-fg-color--lighter%3A%23ffffff73%3B--md-footer-bg-color%3A%23000000de%3B--md-footer-bg-color--dark%3A%2300000052%3B--md-shadow-z1%3A0%200.2rem%200.5rem%20%230000000d%2C0%200%200.05rem%20%230000001a%3B--md-shadow-z2%3A0%200.2rem%200.5rem%20%230000001a%2C0%200%200.05rem%20%2300000040%3B--md-shadow-z3%3A0%200.2rem%200.5rem%20%230003%2C0%200%200.05rem%20%2300000059%7D.md-icon%20svg%7Bfill%3Acurrentcolor%3Bdisplay%3Ablock%3Bheight%3A1.2rem%3Bwidth%3A1.2rem%7Dbody%7B-webkit-font-smoothing%3Aantialiased%3B-moz-osx-font-smoothing%3Agrayscale%3B--md-text-font-family%3Avar%28--md-text-font%2C_%29%2C-apple-system%2CBlinkMacSystemFont%2CHelvetica%2CArial%2Csans-serif%3B--md-code-font-family%3Avar%28--md-code-font%2C_%29%2CSFMono-Regular%2CConsolas%2CMenlo%2Cmonospace%7Daside%2Cbody%2Cinput%7Bfont-feature-settings%3A%22kern%22%2C%22liga%22%3Bcolor%3Avar%28--md-typeset-color%29%3Bfont-family%3Avar%28--md-text-font-family%29%7Dcode%2Ckbd%2Cpre%7Bfont-feature-settings%3A%22kern%22%3Bfont-family%3Avar%28--md-code-font-family%29%7D%3Aroot%7B--md-typeset-table-sort-icon%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22m18%2021-4-4h3V7h-3l4-4%204%204h-3v10h3M2%2019v-2h10v2M2%2013v-2h7v2M2%207V5h4v2z%22/%3E%3C/svg%3E%27%29%3B--md-typeset-table-sort-icon--asc%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M19%2017h3l-4%204-4-4h3V3h2M2%2017h10v2H2M6%205v2H2V5m0%206h7v2H2z%22/%3E%3C/svg%3E%27%29%3B--md-typeset-table-sort-icon--desc%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M19%207h3l-4-4-4%204h3v14h2M2%2017h10v2H2M6%205v2H2V5m0%206h7v2H2z%22/%3E%3C/svg%3E%27%29%7D.md-typeset%7B-webkit-print-color-adjust%3Aexact%3Bcolor-adjust%3Aexact%3Bfont-size%3A.8rem%3Bline-height%3A1.6%7D%40media%20print%7B.md-typeset%7Bfont-size%3A.68rem%7D%7D.md-typeset%20blockquote%2C.md-typeset%20dl%2C.md-typeset%20figure%2C.md-typeset%20ol%2C.md-typeset%20pre%2C.md-typeset%20ul%7Bmargin-bottom%3A1em%3Bmargin-top%3A1em%7D.md-typeset%20h1%7Bcolor%3Avar%28--md-default-fg-color--light%29%3Bfont-size%3A2em%3Bline-height%3A1.3%3Bmargin%3A0%200%201.25em%7D.md-typeset%20h1%2C.md-typeset%20h2%7Bfont-weight%3A300%3Bletter-spacing%3A-.01em%7D.md-typeset%20h2%7Bfont-size%3A1.5625em%3Bline-height%3A1.4%3Bmargin%3A1.6em%200%20.64em%7D.md-typeset%20h3%7Bfont-size%3A1.25em%3Bfont-weight%3A400%3Bletter-spacing%3A-.01em%3Bline-height%3A1.5%3Bmargin%3A1.6em%200%20.8em%7D.md-typeset%20h2%2Bh3%7Bmargin-top%3A.8em%7D.md-typeset%20h4%7Bfont-weight%3A700%3Bletter-spacing%3A-.01em%3Bmargin%3A1em%200%7D.md-typeset%20h5%2C.md-typeset%20h6%7Bcolor%3Avar%28--md-default-fg-color--light%29%3Bfont-size%3A.8em%3Bfont-weight%3A700%3Bletter-spacing%3A-.01em%3Bmargin%3A1.25em%200%7D.md-typeset%20h5%7Btext-transform%3Auppercase%7D.md-typeset%20h5%20code%7Btext-transform%3Anone%7D.md-typeset%20hr%7Bborder-bottom%3A.05rem%20solid%20var%28--md-default-fg-color--lightest%29%3Bdisplay%3Aflow-root%3Bmargin%3A1.5em%200%7D.md-typeset%20a%7Bcolor%3Avar%28--md-typeset-a-color%29%3Bword-break%3Abreak-word%7D.md-typeset%20a%2C.md-typeset%20a%3Abefore%7Btransition%3Acolor%20125ms%7D.md-typeset%20a%3Afocus%2C.md-typeset%20a%3Ahover%7Bcolor%3Avar%28--md-accent-fg-color%29%7D.md-typeset%20a%3Afocus%20code%2C.md-typeset%20a%3Ahover%20code%7Bbackground-color%3Avar%28--md-accent-fg-color--transparent%29%7D.md-typeset%20a%20code%7Bcolor%3Acurrentcolor%3Btransition%3Abackground-color%20125ms%7D.md-typeset%20a.focus-visible%7Boutline-color%3Avar%28--md-accent-fg-color%29%3Boutline-offset%3A.2rem%7D.md-typeset%20code%2C.md-typeset%20kbd%2C.md-typeset%20pre%7Bcolor%3Avar%28--md-code-fg-color%29%3Bdirection%3Altr%3Bfont-variant-ligatures%3Anone%7D%40media%20print%7B.md-typeset%20code%2C.md-typeset%20kbd%2C.md-typeset%20pre%7Bwhite-space%3Apre-wrap%7D%7D.md-typeset%20code%7Bbackground-color%3Avar%28--md-code-bg-color%29%3Bborder-radius%3A.1rem%3B-webkit-box-decoration-break%3Aclone%3Bbox-decoration-break%3Aclone%3Bfont-size%3A.85em%3Bpadding%3A0%20.2941176471em%3Bword-break%3Abreak-word%7D.md-typeset%20code%3Anot%28.focus-visible%29%7B-webkit-tap-highlight-color%3Atransparent%3Boutline%3Anone%7D.md-typeset%20pre%7Bdisplay%3Aflow-root%3Bline-height%3A1.4%3Bposition%3Arelative%7D.md-typeset%20pre%3Ecode%7B-webkit-box-decoration-break%3Aslice%3Bbox-decoration-break%3Aslice%3Bbox-shadow%3Anone%3Bdisplay%3Ablock%3Bmargin%3A0%3Boutline-color%3Avar%28--md-accent-fg-color%29%3Boverflow%3Aauto%3Bpadding%3A.7720588235em%201.1764705882em%3Bscrollbar-color%3Avar%28--md-default-fg-color--lighter%29%20%230000%3Bscrollbar-width%3Athin%3Btouch-action%3Aauto%3Bword-break%3Anormal%7D.md-typeset%20pre%3Ecode%3Ahover%7Bscrollbar-color%3Avar%28--md-accent-fg-color%29%20%230000%7D.md-typeset%20pre%3Ecode%3A%3A-webkit-scrollbar%7Bheight%3A.2rem%3Bwidth%3A.2rem%7D.md-typeset%20pre%3Ecode%3A%3A-webkit-scrollbar-thumb%7Bbackground-color%3Avar%28--md-default-fg-color--lighter%29%7D.md-typeset%20pre%3Ecode%3A%3A-webkit-scrollbar-thumb%3Ahover%7Bbackground-color%3Avar%28--md-accent-fg-color%29%7D.md-typeset%20kbd%7Bbackground-color%3Avar%28--md-typeset-kbd-color%29%3Bborder-radius%3A.1rem%3Bbox-shadow%3A0%20.1rem%200%20.05rem%20var%28--md-typeset-kbd-border-color%29%2C0%20.1rem%200%20var%28--md-typeset-kbd-border-color%29%2C0%20-.1rem%20.2rem%20var%28--md-typeset-kbd-accent-color%29%20inset%3Bcolor%3Avar%28--md-default-fg-color%29%3Bdisplay%3Ainline-block%3Bfont-size%3A.75em%3Bpadding%3A0%20.6666666667em%3Bvertical-align%3Atext-top%3Bword-break%3Abreak-word%7D.md-typeset%20mark%7Bbackground-color%3Avar%28--md-typeset-mark-color%29%3B-webkit-box-decoration-break%3Aclone%3Bbox-decoration-break%3Aclone%3Bcolor%3Ainherit%3Bword-break%3Abreak-word%7D.md-typeset%20abbr%7Bborder-bottom%3A.05rem%20dotted%20var%28--md-default-fg-color--light%29%3Bcursor%3Ahelp%3Btext-decoration%3Anone%7D.md-typeset%20small%7Bopacity%3A.75%7D%5Bdir%3Dltr%5D%20.md-typeset%20sub%2C%5Bdir%3Dltr%5D%20.md-typeset%20sup%7Bmargin-left%3A.078125em%7D%5Bdir%3Drtl%5D%20.md-typeset%20sub%2C%5Bdir%3Drtl%5D%20.md-typeset%20sup%7Bmargin-right%3A.078125em%7D%5Bdir%3Dltr%5D%20.md-typeset%20blockquote%7Bpadding-left%3A.6rem%7D%5Bdir%3Drtl%5D%20.md-typeset%20blockquote%7Bpadding-right%3A.6rem%7D%5Bdir%3Dltr%5D%20.md-typeset%20blockquote%7Bborder-left%3A.2rem%20solid%20var%28--md-default-fg-color--lighter%29%7D%5Bdir%3Drtl%5D%20.md-typeset%20blockquote%7Bborder-right%3A.2rem%20solid%20var%28--md-default-fg-color--lighter%29%7D.md-typeset%20blockquote%7Bcolor%3Avar%28--md-default-fg-color--light%29%3Bmargin-left%3A0%3Bmargin-right%3A0%7D.md-typeset%20ul%7Blist-style-type%3Adisc%7D.md-typeset%20ul%5Btype%5D%7Blist-style-type%3Arevert-layer%7D%5Bdir%3Dltr%5D%20.md-typeset%20ol%2C%5Bdir%3Dltr%5D%20.md-typeset%20ul%7Bmargin-left%3A.625em%7D%5Bdir%3Drtl%5D%20.md-typeset%20ol%2C%5Bdir%3Drtl%5D%20.md-typeset%20ul%7Bmargin-right%3A.625em%7D.md-typeset%20ol%2C.md-typeset%20ul%7Bpadding%3A0%7D.md-typeset%20ol%3Anot%28%5Bhidden%5D%29%2C.md-typeset%20ul%3Anot%28%5Bhidden%5D%29%7Bdisplay%3Aflow-root%7D.md-typeset%20ol%20ol%2C.md-typeset%20ul%20ol%7Blist-style-type%3Alower-alpha%7D.md-typeset%20ol%20ol%20ol%2C.md-typeset%20ul%20ol%20ol%7Blist-style-type%3Alower-roman%7D.md-typeset%20ol%20ol%20ol%20ol%2C.md-typeset%20ul%20ol%20ol%20ol%7Blist-style-type%3Aupper-alpha%7D.md-typeset%20ol%20ol%20ol%20ol%20ol%2C.md-typeset%20ul%20ol%20ol%20ol%20ol%7Blist-style-type%3Aupper-roman%7D.md-typeset%20ol%5Btype%5D%2C.md-typeset%20ul%5Btype%5D%7Blist-style-type%3Arevert-layer%7D%5Bdir%3Dltr%5D%20.md-typeset%20ol%20li%2C%5Bdir%3Dltr%5D%20.md-typeset%20ul%20li%7Bmargin-left%3A1.25em%7D%5Bdir%3Drtl%5D%20.md-typeset%20ol%20li%2C%5Bdir%3Drtl%5D%20.md-typeset%20ul%20li%7Bmargin-right%3A1.25em%7D.md-typeset%20ol%20li%2C.md-typeset%20ul%20li%7Bmargin-bottom%3A.5em%7D.md-typeset%20ol%20li%20blockquote%2C.md-typeset%20ol%20li%20p%2C.md-typeset%20ul%20li%20blockquote%2C.md-typeset%20ul%20li%20p%7Bmargin%3A.5em%200%7D.md-typeset%20ol%20li%3Alast-child%2C.md-typeset%20ul%20li%3Alast-child%7Bmargin-bottom%3A0%7D%5Bdir%3Dltr%5D%20.md-typeset%20ol%20li%20ol%2C%5Bdir%3Dltr%5D%20.md-typeset%20ol%20li%20ul%2C%5Bdir%3Dltr%5D%20.md-typeset%20ul%20li%20ol%2C%5Bdir%3Dltr%5D%20.md-typeset%20ul%20li%20ul%7Bmargin-left%3A.625em%7D%5Bdir%3Drtl%5D%20.md-typeset%20ol%20li%20ol%2C%5Bdir%3Drtl%5D%20.md-typeset%20ol%20li%20ul%2C%5Bdir%3Drtl%5D%20.md-typeset%20ul%20li%20ol%2C%5Bdir%3Drtl%5D%20.md-typeset%20ul%20li%20ul%7Bmargin-right%3A.625em%7D.md-typeset%20ol%20li%20ol%2C.md-typeset%20ol%20li%20ul%2C.md-typeset%20ul%20li%20ol%2C.md-typeset%20ul%20li%20ul%7Bmargin-bottom%3A.5em%3Bmargin-top%3A.5em%7D%5Bdir%3Dltr%5D%20.md-typeset%20dd%7Bmargin-left%3A1.875em%7D%5Bdir%3Drtl%5D%20.md-typeset%20dd%7Bmargin-right%3A1.875em%7D.md-typeset%20dd%7Bmargin-bottom%3A1.5em%3Bmargin-top%3A1em%7D.md-typeset%20img%2C.md-typeset%20svg%2C.md-typeset%20video%7Bheight%3Aauto%3Bmax-width%3A100%25%7D.md-typeset%20img%5Balign%3Dleft%5D%7Bmargin%3A1em%201em%201em%200%7D.md-typeset%20img%5Balign%3Dright%5D%7Bmargin%3A1em%200%201em%201em%7D.md-typeset%20img%5Balign%5D%3Aonly-child%7Bmargin-top%3A0%7D.md-typeset%20figure%7Bdisplay%3Aflow-root%3Bmargin%3A1em%20auto%3Bmax-width%3A100%25%3Btext-align%3Acenter%3Bwidth%3A-moz-fit-content%3Bwidth%3Afit-content%7D.md-typeset%20figure%20img%7Bdisplay%3Ablock%3Bmargin%3A0%20auto%7D.md-typeset%20figcaption%7Bfont-style%3Aitalic%3Bmargin%3A1em%20auto%3Bmax-width%3A24rem%7D.md-typeset%20iframe%7Bmax-width%3A100%25%7D.md-typeset%20table%3Anot%28%5Bclass%5D%29%7Bbackground-color%3Avar%28--md-default-bg-color%29%3Bborder%3A.05rem%20solid%20var%28--md-typeset-table-color%29%3Bborder-radius%3A.1rem%3Bdisplay%3Ainline-block%3Bfont-size%3A.64rem%3Bmax-width%3A100%25%3Boverflow%3Aauto%3Btouch-action%3Aauto%7D%40media%20print%7B.md-typeset%20table%3Anot%28%5Bclass%5D%29%7Bdisplay%3Atable%7D%7D.md-typeset%20table%3Anot%28%5Bclass%5D%29%2B%2A%7Bmargin-top%3A1.5em%7D.md-typeset%20table%3Anot%28%5Bclass%5D%29%20td%3E%3Afirst-child%2C.md-typeset%20table%3Anot%28%5Bclass%5D%29%20th%3E%3Afirst-child%7Bmargin-top%3A0%7D.md-typeset%20table%3Anot%28%5Bclass%5D%29%20td%3E%3Alast-child%2C.md-typeset%20table%3Anot%28%5Bclass%5D%29%20th%3E%3Alast-child%7Bmargin-bottom%3A0%7D.md-typeset%20table%3Anot%28%5Bclass%5D%29%20td%3Anot%28%5Balign%5D%29%2C.md-typeset%20table%3Anot%28%5Bclass%5D%29%20th%3Anot%28%5Balign%5D%29%7Btext-align%3Aleft%7D%5Bdir%3Drtl%5D%20.md-typeset%20table%3Anot%28%5Bclass%5D%29%20td%3Anot%28%5Balign%5D%29%2C%5Bdir%3Drtl%5D%20.md-typeset%20table%3Anot%28%5Bclass%5D%29%20th%3Anot%28%5Balign%5D%29%7Btext-align%3Aright%7D.md-typeset%20table%3Anot%28%5Bclass%5D%29%20th%7Bfont-weight%3A700%3Bmin-width%3A5rem%3Bpadding%3A.9375em%201.25em%3Bvertical-align%3Atop%7D.md-typeset%20table%3Anot%28%5Bclass%5D%29%20td%7Bborder-top%3A.05rem%20solid%20var%28--md-typeset-table-color%29%3Bpadding%3A.9375em%201.25em%3Bvertical-align%3Atop%7D.md-typeset%20table%3Anot%28%5Bclass%5D%29%20tbody%20tr%7Btransition%3Abackground-color%20125ms%7D.md-typeset%20table%3Anot%28%5Bclass%5D%29%20tbody%20tr%3Ahover%7Bbackground-color%3Avar%28--md-typeset-table-color--light%29%3Bbox-shadow%3A0%20.05rem%200%20var%28--md-default-bg-color%29%20inset%7D.md-typeset%20table%3Anot%28%5Bclass%5D%29%20a%7Bword-break%3Anormal%7D.md-typeset%20table%20th%5Brole%3Dcolumnheader%5D%7Bcursor%3Apointer%7D%5Bdir%3Dltr%5D%20.md-typeset%20table%20th%5Brole%3Dcolumnheader%5D%3Aafter%7Bmargin-left%3A.5em%7D%5Bdir%3Drtl%5D%20.md-typeset%20table%20th%5Brole%3Dcolumnheader%5D%3Aafter%7Bmargin-right%3A.5em%7D.md-typeset%20table%20th%5Brole%3Dcolumnheader%5D%3Aafter%7Bcontent%3A%22%22%3Bdisplay%3Ainline-block%3Bheight%3A1.2em%3B-webkit-mask-image%3Avar%28--md-typeset-table-sort-icon%29%3Bmask-image%3Avar%28--md-typeset-table-sort-icon%29%3B-webkit-mask-repeat%3Ano-repeat%3Bmask-repeat%3Ano-repeat%3B-webkit-mask-size%3Acontain%3Bmask-size%3Acontain%3Btransition%3Abackground-color%20125ms%3Bvertical-align%3Atext-bottom%3Bwidth%3A1.2em%7D.md-typeset%20table%20th%5Brole%3Dcolumnheader%5D%3Ahover%3Aafter%7Bbackground-color%3Avar%28--md-default-fg-color--lighter%29%7D.md-typeset%20table%20th%5Brole%3Dcolumnheader%5D%5Baria-sort%3Dascending%5D%3Aafter%7Bbackground-color%3Avar%28--md-default-fg-color--light%29%3B-webkit-mask-image%3Avar%28--md-typeset-table-sort-icon--asc%29%3Bmask-image%3Avar%28--md-typeset-table-sort-icon--asc%29%7D.md-typeset%20table%20th%5Brole%3Dcolumnheader%5D%5Baria-sort%3Ddescending%5D%3Aafter%7Bbackground-color%3Avar%28--md-default-fg-color--light%29%3B-webkit-mask-image%3Avar%28--md-typeset-table-sort-icon--desc%29%3Bmask-image%3Avar%28--md-typeset-table-sort-icon--desc%29%7D.md-typeset__scrollwrap%7Bmargin%3A1em%20-.8rem%3Boverflow-x%3Aauto%3Btouch-action%3Aauto%7D.md-typeset__table%7Bdisplay%3Ainline-block%3Bmargin-bottom%3A.5em%3Bpadding%3A0%20.8rem%7D%40media%20print%7B.md-typeset__table%7Bdisplay%3Ablock%7D%7Dhtml%20.md-typeset__table%20table%7Bdisplay%3Atable%3Bmargin%3A0%3Boverflow%3Ahidden%3Bwidth%3A100%25%7D%40media%20screen%20and%20%28max-width%3A44.984375em%29%7B.md-content__inner%3Epre%7Bmargin%3A1em%20-.8rem%7D.md-content__inner%3Epre%20code%7Bborder-radius%3A0%7D%7D.md-typeset%20.md-author%7Bborder-radius%3A100%25%3Bdisplay%3Ablock%3Bflex-shrink%3A0%3Bheight%3A1.6rem%3Boverflow%3Ahidden%3Bposition%3Arelative%3Btransition%3Acolor%20125ms%2Ctransform%20125ms%3Bwidth%3A1.6rem%7D.md-typeset%20.md-author%20img%7Bdisplay%3Ablock%7D.md-typeset%20.md-author--more%7Bbackground%3Avar%28--md-default-fg-color--lightest%29%3Bcolor%3Avar%28--md-default-fg-color--lighter%29%3Bfont-size%3A.6rem%3Bfont-weight%3A700%3Bline-height%3A1.6rem%3Btext-align%3Acenter%7D.md-typeset%20.md-author--long%7Bheight%3A2.4rem%3Bwidth%3A2.4rem%7D.md-typeset%20a.md-author%7Btransform%3Ascale%281%29%7D.md-typeset%20a.md-author%20img%7Bborder-radius%3A100%25%3Bfilter%3Agrayscale%28100%25%29%20opacity%2875%25%29%3Btransition%3Afilter%20125ms%7D.md-typeset%20a.md-author%3Afocus%2C.md-typeset%20a.md-author%3Ahover%7Btransform%3Ascale%281.1%29%3Bz-index%3A1%7D.md-typeset%20a.md-author%3Afocus%20img%2C.md-typeset%20a.md-author%3Ahover%20img%7Bfilter%3Agrayscale%280%29%7D.md-banner%7Bbackground-color%3Avar%28--md-footer-bg-color%29%3Bcolor%3Avar%28--md-footer-fg-color%29%3Boverflow%3Aauto%7D%40media%20print%7B.md-banner%7Bdisplay%3Anone%7D%7D.md-banner--warning%7Bbackground-color%3Avar%28--md-warning-bg-color%29%3Bcolor%3Avar%28--md-warning-fg-color%29%7D.md-banner__inner%7Bfont-size%3A.7rem%3Bmargin%3A.6rem%20auto%3Bpadding%3A0%20.8rem%7D%5Bdir%3Dltr%5D%20.md-banner__button%7Bfloat%3Aright%7D%5Bdir%3Drtl%5D%20.md-banner__button%7Bfloat%3Aleft%7D.md-banner__button%7Bcolor%3Ainherit%3Bcursor%3Apointer%3Btransition%3Aopacity%20.25s%7D.no-js%20.md-banner__button%7Bdisplay%3Anone%7D.md-banner__button%3Ahover%7Bopacity%3A.7%7Dhtml%7Bfont-size%3A125%25%3Bheight%3A100%25%3Boverflow-x%3Ahidden%7D%40media%20screen%20and%20%28min-width%3A100em%29%7Bhtml%7Bfont-size%3A137.5%25%7D%7D%40media%20screen%20and%20%28min-width%3A125em%29%7Bhtml%7Bfont-size%3A150%25%7D%7Dbody%7Bbackground-color%3Avar%28--md-default-bg-color%29%3Bdisplay%3Aflex%3Bflex-direction%3Acolumn%3Bfont-size%3A.5rem%3Bmin-height%3A100%25%3Bposition%3Arelative%3Bwidth%3A100%25%7D%40media%20print%7Bbody%7Bdisplay%3Ablock%7D%7D%40media%20screen%20and%20%28max-width%3A59.984375em%29%7Bbody%5Bdata-md-scrolllock%5D%7Bposition%3Afixed%7D%7D.md-grid%7Bmargin-left%3Aauto%3Bmargin-right%3Aauto%3Bmax-width%3A61rem%7D.md-container%7Bdisplay%3Aflex%3Bflex-direction%3Acolumn%3Bflex-grow%3A1%7D%40media%20print%7B.md-container%7Bdisplay%3Ablock%7D%7D.md-main%7Bflex-grow%3A1%7D.md-main__inner%7Bdisplay%3Aflex%3Bheight%3A100%25%3Bmargin-top%3A1.5rem%7D.md-ellipsis%7Boverflow%3Ahidden%3Btext-overflow%3Aellipsis%7D.md-toggle%7Bdisplay%3Anone%7D.md-option%7Bheight%3A0%3Bopacity%3A0%3Bposition%3Aabsolute%3Bwidth%3A0%7D.md-option%3Achecked%2Blabel%3Anot%28%5Bhidden%5D%29%7Bdisplay%3Ablock%7D.md-option.focus-visible%2Blabel%7Boutline-color%3Avar%28--md-accent-fg-color%29%3Boutline-style%3Aauto%7D.md-skip%7Bbackground-color%3Avar%28--md-default-fg-color%29%3Bborder-radius%3A.1rem%3Bcolor%3Avar%28--md-default-bg-color%29%3Bfont-size%3A.64rem%3Bmargin%3A.5rem%3Bopacity%3A0%3Boutline-color%3Avar%28--md-accent-fg-color%29%3Bpadding%3A.3rem%20.5rem%3Bposition%3Afixed%3Btransform%3AtranslateY%28.4rem%29%3Bz-index%3A-1%7D.md-skip%3Afocus%7Bopacity%3A1%3Btransform%3AtranslateY%280%29%3Btransition%3Atransform%20.25s%20cubic-bezier%28.4%2C0%2C.2%2C1%29%2Copacity%20175ms%2075ms%3Bz-index%3A10%7D%40page%7Bmargin%3A25mm%7D%3Aroot%7B--md-clipboard-icon%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M19%2021H8V7h11m0-2H8a2%202%200%200%200-2%202v14a2%202%200%200%200%202%202h11a2%202%200%200%200%202-2V7a2%202%200%200%200-2-2m-3-4H4a2%202%200%200%200-2%202v14h2V3h12z%22/%3E%3C/svg%3E%27%29%7D.md-clipboard%7Bborder-radius%3A.1rem%3Bcolor%3Avar%28--md-default-fg-color--lightest%29%3Bcursor%3Apointer%3Bheight%3A1.5em%3Boutline-color%3Avar%28--md-accent-fg-color%29%3Boutline-offset%3A.1rem%3Bposition%3Aabsolute%3Bright%3A.5em%3Btop%3A.5em%3Btransition%3Acolor%20.25s%3Bwidth%3A1.5em%3Bz-index%3A1%7D%40media%20print%7B.md-clipboard%7Bdisplay%3Anone%7D%7D.md-clipboard%3Anot%28.focus-visible%29%7B-webkit-tap-highlight-color%3Atransparent%3Boutline%3Anone%7D%3Ahover%3E.md-clipboard%7Bcolor%3Avar%28--md-default-fg-color--light%29%7D.md-clipboard%3Afocus%2C.md-clipboard%3Ahover%7Bcolor%3Avar%28--md-accent-fg-color%29%7D.md-clipboard%3Aafter%7Bbackground-color%3Acurrentcolor%3Bcontent%3A%22%22%3Bdisplay%3Ablock%3Bheight%3A1.125em%3Bmargin%3A0%20auto%3B-webkit-mask-image%3Avar%28--md-clipboard-icon%29%3Bmask-image%3Avar%28--md-clipboard-icon%29%3B-webkit-mask-position%3Acenter%3Bmask-position%3Acenter%3B-webkit-mask-repeat%3Ano-repeat%3Bmask-repeat%3Ano-repeat%3B-webkit-mask-size%3Acontain%3Bmask-size%3Acontain%3Bwidth%3A1.125em%7D.md-clipboard--inline%7Bcursor%3Apointer%7D.md-clipboard--inline%20code%7Btransition%3Acolor%20.25s%2Cbackground-color%20.25s%7D.md-clipboard--inline%3Afocus%20code%2C.md-clipboard--inline%3Ahover%20code%7Bbackground-color%3Avar%28--md-accent-fg-color--transparent%29%3Bcolor%3Avar%28--md-accent-fg-color%29%7D.md-typeset%20.md-code__content%7Bdisplay%3Agrid%7D%40keyframes%20consent%7B0%25%7Bopacity%3A0%3Btransform%3AtranslateY%28100%25%29%7Dto%7Bopacity%3A1%3Btransform%3AtranslateY%280%29%7D%7D%40keyframes%20overlay%7B0%25%7Bopacity%3A0%7Dto%7Bopacity%3A1%7D%7D.md-consent__overlay%7Banimation%3Aoverlay%20.25s%20both%3B-webkit-backdrop-filter%3Ablur%28.1rem%29%3Bbackdrop-filter%3Ablur%28.1rem%29%3Bbackground-color%3A%230000008a%3Bheight%3A100%25%3Bopacity%3A1%3Bposition%3Afixed%3Btop%3A0%3Bwidth%3A100%25%3Bz-index%3A5%7D.md-consent__inner%7Banimation%3Aconsent%20.5s%20cubic-bezier%28.1%2C.7%2C.1%2C1%29%20both%3Bbackground-color%3Avar%28--md-default-bg-color%29%3Bborder%3A0%3Bborder-radius%3A.1rem%3Bbottom%3A0%3Bbox-shadow%3A0%200%20.2rem%20%230000001a%2C0%20.2rem%20.4rem%20%230003%3Bmax-height%3A100%25%3Boverflow%3Aauto%3Bpadding%3A0%3Bposition%3Afixed%3Bwidth%3A100%25%3Bz-index%3A5%7D.md-consent__form%7Bpadding%3A.8rem%7D.md-consent__settings%7Bdisplay%3Anone%3Bmargin%3A1em%200%7Dinput%3Achecked%2B.md-consent__settings%7Bdisplay%3Ablock%7D.md-consent__controls%7Bmargin-bottom%3A.8rem%7D.md-typeset%20.md-consent__controls%20.md-button%7Bdisplay%3Ainline%7D%40media%20screen%20and%20%28max-width%3A44.984375em%29%7B.md-typeset%20.md-consent__controls%20.md-button%7Bdisplay%3Ablock%3Bmargin-top%3A.4rem%3Btext-align%3Acenter%3Bwidth%3A100%25%7D%7D.md-consent%20label%7Bcursor%3Apointer%7D.md-content%7Bflex-grow%3A1%3Bmin-width%3A0%7D.md-content__inner%7Bmargin%3A0%20.8rem%201.2rem%3Bpadding-top%3A.6rem%7D%40media%20screen%20and%20%28min-width%3A76.25em%29%7B%5Bdir%3Dltr%5D%20.md-sidebar--primary%3Anot%28%5Bhidden%5D%29~.md-content%3E.md-content__inner%7Bmargin-left%3A1.2rem%7D%5Bdir%3Dltr%5D%20.md-sidebar--secondary%3Anot%28%5Bhidden%5D%29~.md-content%3E.md-content__inner%2C%5Bdir%3Drtl%5D%20.md-sidebar--primary%3Anot%28%5Bhidden%5D%29~.md-content%3E.md-content__inner%7Bmargin-right%3A1.2rem%7D%5Bdir%3Drtl%5D%20.md-sidebar--secondary%3Anot%28%5Bhidden%5D%29~.md-content%3E.md-content__inner%7Bmargin-left%3A1.2rem%7D%7D.md-content__inner%3Abefore%7Bcontent%3A%22%22%3Bdisplay%3Ablock%3Bheight%3A.4rem%7D.md-content__inner%3E%3Alast-child%7Bmargin-bottom%3A0%7D%5Bdir%3Dltr%5D%20.md-content__button%7Bfloat%3Aright%7D%5Bdir%3Drtl%5D%20.md-content__button%7Bfloat%3Aleft%7D%5Bdir%3Dltr%5D%20.md-content__button%7Bmargin-left%3A.4rem%7D%5Bdir%3Drtl%5D%20.md-content__button%7Bmargin-right%3A.4rem%7D.md-content__button%7Bmargin%3A.4rem%200%3Bpadding%3A0%7D%40media%20print%7B.md-content__button%7Bdisplay%3Anone%7D%7D.md-typeset%20.md-content__button%7Bcolor%3Avar%28--md-default-fg-color--lighter%29%7D.md-content__button%20svg%7Bdisplay%3Ainline%3Bvertical-align%3Atop%7D%5Bdir%3Drtl%5D%20.md-content__button%20svg%7Btransform%3AscaleX%28-1%29%7D%5Bdir%3Dltr%5D%20.md-dialog%7Bright%3A.8rem%7D%5Bdir%3Drtl%5D%20.md-dialog%7Bleft%3A.8rem%7D.md-dialog%7Bbackground-color%3Avar%28--md-default-fg-color%29%3Bborder-radius%3A.1rem%3Bbottom%3A.8rem%3Bbox-shadow%3Avar%28--md-shadow-z3%29%3Bmin-width%3A11.1rem%3Bopacity%3A0%3Bpadding%3A.4rem%20.6rem%3Bpointer-events%3Anone%3Bposition%3Afixed%3Btransform%3AtranslateY%28100%25%29%3Btransition%3Atransform%200ms%20.4s%2Copacity%20.4s%3Bz-index%3A4%7D%40media%20print%7B.md-dialog%7Bdisplay%3Anone%7D%7D.md-dialog--active%7Bopacity%3A1%3Bpointer-events%3Aauto%3Btransform%3AtranslateY%280%29%3Btransition%3Atransform%20.4s%20cubic-bezier%28.075%2C.85%2C.175%2C1%29%2Copacity%20.4s%7D.md-dialog__inner%7Bcolor%3Avar%28--md-default-bg-color%29%3Bfont-size%3A.7rem%7D.md-feedback%7Bmargin%3A2em%200%201em%3Btext-align%3Acenter%7D.md-feedback%20fieldset%7Bborder%3Anone%3Bmargin%3A0%3Bpadding%3A0%7D.md-feedback__title%7Bfont-weight%3A700%3Bmargin%3A1em%20auto%7D.md-feedback__inner%7Bposition%3Arelative%7D.md-feedback__list%7Bdisplay%3Aflex%3Bflex-wrap%3Awrap%3Bplace-content%3Abaseline%20center%3Bposition%3Arelative%7D.md-feedback__list%3Ahover%20.md-icon%3Anot%28%3Adisabled%29%7Bcolor%3Avar%28--md-default-fg-color--lighter%29%7D%3Adisabled%20.md-feedback__list%7Bmin-height%3A1.8rem%7D.md-feedback__icon%7Bcolor%3Avar%28--md-default-fg-color--light%29%3Bcursor%3Apointer%3Bflex-shrink%3A0%3Bmargin%3A0%20.1rem%3Btransition%3Acolor%20125ms%7D.md-feedback__icon%3Anot%28%3Adisabled%29.md-icon%3Ahover%7Bcolor%3Avar%28--md-accent-fg-color%29%7D.md-feedback__icon%3Adisabled%7Bcolor%3Avar%28--md-default-fg-color--lightest%29%3Bpointer-events%3Anone%7D.md-feedback__note%7Bopacity%3A0%3Bposition%3Arelative%3Btransform%3AtranslateY%28.4rem%29%3Btransition%3Atransform%20.4s%20cubic-bezier%28.1%2C.7%2C.1%2C1%29%2Copacity%20.15s%7D.md-feedback__note%3E%2A%7Bmargin%3A0%20auto%3Bmax-width%3A16rem%7D%3Adisabled%20.md-feedback__note%7Bopacity%3A1%3Btransform%3AtranslateY%280%29%7D%40media%20print%7B.md-feedback%7Bdisplay%3Anone%7D%7D.md-footer%7Bbackground-color%3Avar%28--md-footer-bg-color%29%3Bcolor%3Avar%28--md-footer-fg-color%29%7D%40media%20print%7B.md-footer%7Bdisplay%3Anone%7D%7D.md-footer__inner%7Bjustify-content%3Aspace-between%3Boverflow%3Aauto%3Bpadding%3A.2rem%7D.md-footer__inner%3Anot%28%5Bhidden%5D%29%7Bdisplay%3Aflex%7D.md-footer__link%7Balign-items%3Aend%3Bdisplay%3Aflex%3Bflex-grow%3A0.01%3Bmargin-bottom%3A.4rem%3Bmargin-top%3A1rem%3Bmax-width%3A100%25%3Boutline-color%3Avar%28--md-accent-fg-color%29%3Boverflow%3Ahidden%3Btransition%3Aopacity%20.25s%7D.md-footer__link%3Afocus%2C.md-footer__link%3Ahover%7Bopacity%3A.7%7D%5Bdir%3Drtl%5D%20.md-footer__link%20svg%7Btransform%3AscaleX%28-1%29%7D%40media%20screen%20and%20%28max-width%3A44.984375em%29%7B.md-footer__link--prev%7Bflex-shrink%3A0%7D.md-footer__link--prev%20.md-footer__title%7Bdisplay%3Anone%7D%7D%5Bdir%3Dltr%5D%20.md-footer__link--next%7Bmargin-left%3Aauto%7D%5Bdir%3Drtl%5D%20.md-footer__link--next%7Bmargin-right%3Aauto%7D.md-footer__link--next%7Btext-align%3Aright%7D%5Bdir%3Drtl%5D%20.md-footer__link--next%7Btext-align%3Aleft%7D.md-footer__title%7Bflex-grow%3A1%3Bfont-size%3A.9rem%3Bmargin-bottom%3A.7rem%3Bmax-width%3Acalc%28100%25%20-%202.4rem%29%3Bpadding%3A0%201rem%3Bwhite-space%3Anowrap%7D.md-footer__button%7Bmargin%3A.2rem%3Bpadding%3A.4rem%7D.md-footer__direction%7Bfont-size%3A.64rem%3Bopacity%3A.7%7D.md-footer-meta%7Bbackground-color%3Avar%28--md-footer-bg-color--dark%29%7D.md-footer-meta__inner%7Bdisplay%3Aflex%3Bflex-wrap%3Awrap%3Bjustify-content%3Aspace-between%3Bpadding%3A.2rem%7Dhtml%20.md-footer-meta.md-typeset%20a%7Bcolor%3Avar%28--md-footer-fg-color--light%29%7Dhtml%20.md-footer-meta.md-typeset%20a%3Afocus%2Chtml%20.md-footer-meta.md-typeset%20a%3Ahover%7Bcolor%3Avar%28--md-footer-fg-color%29%7D.md-copyright%7Bcolor%3Avar%28--md-footer-fg-color--lighter%29%3Bfont-size%3A.64rem%3Bmargin%3Aauto%20.6rem%3Bpadding%3A.4rem%200%3Bwidth%3A100%25%7D%40media%20screen%20and%20%28min-width%3A45em%29%7B.md-copyright%7Bwidth%3Aauto%7D%7D.md-copyright__highlight%7Bcolor%3Avar%28--md-footer-fg-color--light%29%7D.md-social%7Bdisplay%3Ainline-flex%3Bgap%3A.2rem%3Bmargin%3A0%20.4rem%3Bpadding%3A.2rem%200%20.6rem%7D%40media%20screen%20and%20%28min-width%3A45em%29%7B.md-social%7Bpadding%3A.6rem%200%7D%7D.md-social__link%7Bdisplay%3Ainline-block%3Bheight%3A1.6rem%3Btext-align%3Acenter%3Bwidth%3A1.6rem%7D.md-social__link%3Abefore%7Bline-height%3A1.9%7D.md-social__link%20svg%7Bfill%3Acurrentcolor%3Bmax-height%3A.8rem%3Bvertical-align%3A-25%25%7D.md-typeset%20.md-button%7Bborder%3A.1rem%20solid%3Bborder-radius%3A.1rem%3Bcolor%3Avar%28--md-primary-fg-color%29%3Bcursor%3Apointer%3Bdisplay%3Ainline-block%3Bfont-weight%3A700%3Bpadding%3A.625em%202em%3Btransition%3Acolor%20125ms%2Cbackground-color%20125ms%2Cborder-color%20125ms%7D.md-typeset%20.md-button--primary%7Bbackground-color%3Avar%28--md-primary-fg-color%29%3Bborder-color%3Avar%28--md-primary-fg-color%29%3Bcolor%3Avar%28--md-primary-bg-color%29%7D.md-typeset%20.md-button%3Afocus%2C.md-typeset%20.md-button%3Ahover%7Bbackground-color%3Avar%28--md-accent-fg-color%29%3Bborder-color%3Avar%28--md-accent-fg-color%29%3Bcolor%3Avar%28--md-accent-bg-color%29%7D%5Bdir%3Dltr%5D%20.md-typeset%20.md-input%7Bborder-top-left-radius%3A.1rem%7D%5Bdir%3Dltr%5D%20.md-typeset%20.md-input%2C%5Bdir%3Drtl%5D%20.md-typeset%20.md-input%7Bborder-top-right-radius%3A.1rem%7D%5Bdir%3Drtl%5D%20.md-typeset%20.md-input%7Bborder-top-left-radius%3A.1rem%7D.md-typeset%20.md-input%7Bborder-bottom%3A.1rem%20solid%20var%28--md-default-fg-color--lighter%29%3Bbox-shadow%3Avar%28--md-shadow-z1%29%3Bfont-size%3A.8rem%3Bheight%3A1.8rem%3Bpadding%3A0%20.6rem%3Btransition%3Aborder%20.25s%2Cbox-shadow%20.25s%7D.md-typeset%20.md-input%3Afocus%2C.md-typeset%20.md-input%3Ahover%7Bborder-bottom-color%3Avar%28--md-accent-fg-color%29%3Bbox-shadow%3Avar%28--md-shadow-z2%29%7D.md-typeset%20.md-input--stretch%7Bwidth%3A100%25%7D.md-header%7Bbackground-color%3Avar%28--md-primary-fg-color%29%3Bbox-shadow%3A0%200%20.2rem%20%230000%2C0%20.2rem%20.4rem%20%230000%3Bcolor%3Avar%28--md-primary-bg-color%29%3Bdisplay%3Ablock%3Bleft%3A0%3Bposition%3Asticky%3Bright%3A0%3Btop%3A0%3Bz-index%3A4%7D%40media%20print%7B.md-header%7Bdisplay%3Anone%7D%7D.md-header%5Bhidden%5D%7Btransform%3AtranslateY%28-100%25%29%3Btransition%3Atransform%20.25s%20cubic-bezier%28.8%2C0%2C.6%2C1%29%2Cbox-shadow%20.25s%7D.md-header--shadow%7Bbox-shadow%3A0%200%20.2rem%20%230000001a%2C0%20.2rem%20.4rem%20%230003%3Btransition%3Atransform%20.25s%20cubic-bezier%28.1%2C.7%2C.1%2C1%29%2Cbox-shadow%20.25s%7D.md-header__inner%7Balign-items%3Acenter%3Bdisplay%3Aflex%3Bpadding%3A0%20.2rem%7D.md-header__button%7Bcolor%3Acurrentcolor%3Bcursor%3Apointer%3Bmargin%3A.2rem%3Boutline-color%3Avar%28--md-accent-fg-color%29%3Bpadding%3A.4rem%3Bposition%3Arelative%3Btransition%3Aopacity%20.25s%3Bvertical-align%3Amiddle%3Bz-index%3A1%7D.md-header__button%3Ahover%7Bopacity%3A.7%7D.md-header__button%3Anot%28%5Bhidden%5D%29%7Bdisplay%3Ainline-block%7D.md-header__button%3Anot%28.focus-visible%29%7B-webkit-tap-highlight-color%3Atransparent%3Boutline%3Anone%7D.md-header__button.md-logo%7Bmargin%3A.2rem%3Bpadding%3A.4rem%7D%40media%20screen%20and%20%28max-width%3A76.234375em%29%7B.md-header__button.md-logo%7Bdisplay%3Anone%7D%7D.md-header__button.md-logo%20img%2C.md-header__button.md-logo%20svg%7Bfill%3Acurrentcolor%3Bdisplay%3Ablock%3Bheight%3A1.2rem%3Bwidth%3Aauto%7D%40media%20screen%20and%20%28min-width%3A60em%29%7B.md-header__button%5Bfor%3D__search%5D%7Bdisplay%3Anone%7D%7D.no-js%20.md-header__button%5Bfor%3D__search%5D%7Bdisplay%3Anone%7D%5Bdir%3Drtl%5D%20.md-header__button%5Bfor%3D__search%5D%20svg%7Btransform%3AscaleX%28-1%29%7D%40media%20screen%20and%20%28min-width%3A76.25em%29%7B.md-header__button%5Bfor%3D__drawer%5D%7Bdisplay%3Anone%7D%7D.md-header__topic%7Bdisplay%3Aflex%3Bmax-width%3A100%25%3Bposition%3Aabsolute%3Btransition%3Atransform%20.4s%20cubic-bezier%28.1%2C.7%2C.1%2C1%29%2Copacity%20.15s%3Bwhite-space%3Anowrap%7D.md-header__topic%2B.md-header__topic%7Bopacity%3A0%3Bpointer-events%3Anone%3Btransform%3AtranslateX%281.25rem%29%3Btransition%3Atransform%20.4s%20cubic-bezier%281%2C.7%2C.1%2C.1%29%2Copacity%20.15s%3Bz-index%3A-1%7D%5Bdir%3Drtl%5D%20.md-header__topic%2B.md-header__topic%7Btransform%3AtranslateX%28-1.25rem%29%7D.md-header__topic%3Afirst-child%7Bfont-weight%3A700%7D%5Bdir%3Dltr%5D%20.md-header__title%7Bmargin-left%3A1rem%3Bmargin-right%3A.4rem%7D%5Bdir%3Drtl%5D%20.md-header__title%7Bmargin-left%3A.4rem%3Bmargin-right%3A1rem%7D.md-header__title%7Bflex-grow%3A1%3Bfont-size%3A.9rem%3Bheight%3A2.4rem%3Bline-height%3A2.4rem%7D.md-header__title--active%20.md-header__topic%7Bopacity%3A0%3Bpointer-events%3Anone%3Btransform%3AtranslateX%28-1.25rem%29%3Btransition%3Atransform%20.4s%20cubic-bezier%281%2C.7%2C.1%2C.1%29%2Copacity%20.15s%3Bz-index%3A-1%7D%5Bdir%3Drtl%5D%20.md-header__title--active%20.md-header__topic%7Btransform%3AtranslateX%281.25rem%29%7D.md-header__title--active%20.md-header__topic%2B.md-header__topic%7Bopacity%3A1%3Bpointer-events%3Aauto%3Btransform%3AtranslateX%280%29%3Btransition%3Atransform%20.4s%20cubic-bezier%28.1%2C.7%2C.1%2C1%29%2Copacity%20.15s%3Bz-index%3A0%7D.md-header__title%3E.md-header__ellipsis%7Bheight%3A100%25%3Bposition%3Arelative%3Bwidth%3A100%25%7D.md-header__option%7Bdisplay%3Aflex%3Bflex-shrink%3A0%3Bmax-width%3A100%25%3Btransition%3Amax-width%200ms%20.25s%2Copacity%20.25s%20.25s%3Bwhite-space%3Anowrap%7D%5Bdata-md-toggle%3Dsearch%5D%3Achecked~.md-header%20.md-header__option%7Bmax-width%3A0%3Bopacity%3A0%3Btransition%3Amax-width%200ms%2Copacity%200ms%7D.md-header__option%3Einput%7Bbottom%3A0%7D.md-header__source%7Bdisplay%3Anone%7D%40media%20screen%20and%20%28min-width%3A60em%29%7B%5Bdir%3Dltr%5D%20.md-header__source%7Bmargin-left%3A1rem%7D%5Bdir%3Drtl%5D%20.md-header__source%7Bmargin-right%3A1rem%7D.md-header__source%7Bdisplay%3Ablock%3Bmax-width%3A11.7rem%3Bwidth%3A11.7rem%7D%7D%40media%20screen%20and%20%28min-width%3A76.25em%29%7B%5Bdir%3Dltr%5D%20.md-header__source%7Bmargin-left%3A1.4rem%7D%5Bdir%3Drtl%5D%20.md-header__source%7Bmargin-right%3A1.4rem%7D%7D.md-meta%7Bcolor%3Avar%28--md-default-fg-color--light%29%3Bfont-size%3A.7rem%3Bline-height%3A1.3%7D.md-meta__list%7Bdisplay%3Ainline-flex%3Bflex-wrap%3Awrap%3Blist-style%3Anone%3Bmargin%3A0%3Bpadding%3A0%7D.md-meta__item%3Anot%28%3Alast-child%29%3Aafter%7Bcontent%3A%22%C2%B7%22%3Bmargin-left%3A.2rem%3Bmargin-right%3A.2rem%7D.md-meta__link%7Bcolor%3Avar%28--md-typeset-a-color%29%7D.md-meta__link%3Afocus%2C.md-meta__link%3Ahover%7Bcolor%3Avar%28--md-accent-fg-color%29%7D.md-draft%7Bbackground-color%3A%23ff1744%3Bborder-radius%3A.125em%3Bcolor%3A%23fff%3Bdisplay%3Ainline-block%3Bfont-weight%3A700%3Bpadding-left%3A.5714285714em%3Bpadding-right%3A.5714285714em%7D%3Aroot%7B--md-nav-icon--prev%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M20%2011v2H8l5.5%205.5-1.42%201.42L4.16%2012l7.92-7.92L13.5%205.5%208%2011z%22/%3E%3C/svg%3E%27%29%3B--md-nav-icon--next%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M8.59%2016.58%2013.17%2012%208.59%207.41%2010%206l6%206-6%206z%22/%3E%3C/svg%3E%27%29%3B--md-toc-icon%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M3%209h14V7H3zm0%204h14v-2H3zm0%204h14v-2H3zm16%200h2v-2h-2zm0-10v2h2V7zm0%206h2v-2h-2z%22/%3E%3C/svg%3E%27%29%7D.md-nav%7Bfont-size%3A.7rem%3Bline-height%3A1.3%7D.md-nav__title%7Bcolor%3Avar%28--md-default-fg-color--light%29%3Bdisplay%3Ablock%3Bfont-weight%3A700%3Boverflow%3Ahidden%3Bpadding%3A0%20.6rem%3Btext-overflow%3Aellipsis%7D.md-nav__title%20.md-nav__button%7Bdisplay%3Anone%7D.md-nav__title%20.md-nav__button%20img%7Bheight%3A100%25%3Bwidth%3Aauto%7D.md-nav__title%20.md-nav__button.md-logo%20img%2C.md-nav__title%20.md-nav__button.md-logo%20svg%7Bfill%3Acurrentcolor%3Bdisplay%3Ablock%3Bheight%3A2.4rem%3Bmax-width%3A100%25%3Bobject-fit%3Acontain%3Bwidth%3Aauto%7D.md-nav__list%7Blist-style%3Anone%3Bmargin%3A0%3Bpadding%3A0%7D.md-nav__link%7Balign-items%3Aflex-start%3Bdisplay%3Aflex%3Bgap%3A.4rem%3Bmargin-top%3A.625em%3Bscroll-snap-align%3Astart%3Btransition%3Acolor%20125ms%7D.md-nav__link--passed%7Bcolor%3Avar%28--md-default-fg-color--light%29%7D.md-nav__item%20.md-nav__link--active%2C.md-nav__item%20.md-nav__link--active%20code%7Bcolor%3Avar%28--md-typeset-a-color%29%7D.md-nav__link%20.md-ellipsis%7Bposition%3Arelative%7D%5Bdir%3Dltr%5D%20.md-nav__link%20.md-icon%3Alast-child%7Bmargin-left%3Aauto%7D%5Bdir%3Drtl%5D%20.md-nav__link%20.md-icon%3Alast-child%7Bmargin-right%3Aauto%7D.md-nav__link%20svg%7Bfill%3Acurrentcolor%3Bflex-shrink%3A0%3Bheight%3A1.3em%3Bposition%3Arelative%7D.md-nav__link%5Bfor%5D%3Afocus%2C.md-nav__link%5Bfor%5D%3Ahover%2C.md-nav__link%5Bhref%5D%3Afocus%2C.md-nav__link%5Bhref%5D%3Ahover%7Bcolor%3Avar%28--md-accent-fg-color%29%3Bcursor%3Apointer%7D.md-nav__link.focus-visible%7Boutline-color%3Avar%28--md-accent-fg-color%29%3Boutline-offset%3A.2rem%7D.md-nav--primary%20.md-nav__link%5Bfor%3D__toc%5D%7Bdisplay%3Anone%7D.md-nav--primary%20.md-nav__link%5Bfor%3D__toc%5D%20.md-icon%3Aafter%7Bbackground-color%3Acurrentcolor%3Bdisplay%3Ablock%3Bheight%3A100%25%3B-webkit-mask-image%3Avar%28--md-toc-icon%29%3Bmask-image%3Avar%28--md-toc-icon%29%3Bwidth%3A100%25%7D.md-nav--primary%20.md-nav__link%5Bfor%3D__toc%5D~.md-nav%7Bdisplay%3Anone%7D.md-nav__container%3E.md-nav__link%7Bmargin-top%3A0%7D.md-nav__container%3E.md-nav__link%3Afirst-child%7Bflex-grow%3A1%3Bmin-width%3A0%7D.md-nav__icon%7Bflex-shrink%3A0%7D.md-nav__source%7Bdisplay%3Anone%7D%40media%20screen%20and%20%28max-width%3A76.234375em%29%7B.md-nav--primary%2C.md-nav--primary%20.md-nav%7Bbackground-color%3Avar%28--md-default-bg-color%29%3Bdisplay%3Aflex%3Bflex-direction%3Acolumn%3Bheight%3A100%25%3Bleft%3A0%3Bposition%3Aabsolute%3Bright%3A0%3Btop%3A0%3Bz-index%3A1%7D.md-nav--primary%20.md-nav__item%2C.md-nav--primary%20.md-nav__title%7Bfont-size%3A.8rem%3Bline-height%3A1.5%7D.md-nav--primary%20.md-nav__title%7Bbackground-color%3Avar%28--md-default-fg-color--lightest%29%3Bcolor%3Avar%28--md-default-fg-color--light%29%3Bcursor%3Apointer%3Bheight%3A5.6rem%3Bline-height%3A2.4rem%3Bpadding%3A3rem%20.8rem%20.2rem%3Bposition%3Arelative%3Bwhite-space%3Anowrap%7D%5Bdir%3Dltr%5D%20.md-nav--primary%20.md-nav__title%20.md-nav__icon%7Bleft%3A.4rem%7D%5Bdir%3Drtl%5D%20.md-nav--primary%20.md-nav__title%20.md-nav__icon%7Bright%3A.4rem%7D.md-nav--primary%20.md-nav__title%20.md-nav__icon%7Bdisplay%3Ablock%3Bheight%3A1.2rem%3Bmargin%3A.2rem%3Bposition%3Aabsolute%3Btop%3A.4rem%3Bwidth%3A1.2rem%7D.md-nav--primary%20.md-nav__title%20.md-nav__icon%3Aafter%7Bbackground-color%3Acurrentcolor%3Bcontent%3A%22%22%3Bdisplay%3Ablock%3Bheight%3A100%25%3B-webkit-mask-image%3Avar%28--md-nav-icon--prev%29%3Bmask-image%3Avar%28--md-nav-icon--prev%29%3B-webkit-mask-position%3Acenter%3Bmask-position%3Acenter%3B-webkit-mask-repeat%3Ano-repeat%3Bmask-repeat%3Ano-repeat%3B-webkit-mask-size%3Acontain%3Bmask-size%3Acontain%3Bwidth%3A100%25%7D.md-nav--primary%20.md-nav__title~.md-nav__list%7Bbackground-color%3Avar%28--md-default-bg-color%29%3Bbox-shadow%3A0%20.05rem%200%20var%28--md-default-fg-color--lightest%29%20inset%3Boverflow-y%3Aauto%3Bscroll-snap-type%3Ay%20mandatory%3Btouch-action%3Apan-y%7D.md-nav--primary%20.md-nav__title~.md-nav__list%3E%3Afirst-child%7Bborder-top%3A0%7D.md-nav--primary%20.md-nav__title%5Bfor%3D__drawer%5D%7Bbackground-color%3Avar%28--md-primary-fg-color%29%3Bcolor%3Avar%28--md-primary-bg-color%29%3Bfont-weight%3A700%7D.md-nav--primary%20.md-nav__title%20.md-logo%7Bdisplay%3Ablock%3Bleft%3A.2rem%3Bmargin%3A.2rem%3Bpadding%3A.4rem%3Bposition%3Aabsolute%3Bright%3A.2rem%3Btop%3A.2rem%7D.md-nav--primary%20.md-nav__list%7Bflex%3A1%7D.md-nav--primary%20.md-nav__item%7Bborder-top%3A.05rem%20solid%20var%28--md-default-fg-color--lightest%29%7D.md-nav--primary%20.md-nav__item--active%3E.md-nav__link%7Bcolor%3Avar%28--md-typeset-a-color%29%7D.md-nav--primary%20.md-nav__item--active%3E.md-nav__link%3Afocus%2C.md-nav--primary%20.md-nav__item--active%3E.md-nav__link%3Ahover%7Bcolor%3Avar%28--md-accent-fg-color%29%7D.md-nav--primary%20.md-nav__link%7Bmargin-top%3A0%3Bpadding%3A.6rem%20.8rem%7D.md-nav--primary%20.md-nav__link%20svg%7Bmargin-top%3A.1em%7D.md-nav--primary%20.md-nav__link%3E.md-nav__link%7Bpadding%3A0%7D%5Bdir%3Dltr%5D%20.md-nav--primary%20.md-nav__link%20.md-nav__icon%7Bmargin-right%3A-.2rem%7D%5Bdir%3Drtl%5D%20.md-nav--primary%20.md-nav__link%20.md-nav__icon%7Bmargin-left%3A-.2rem%7D.md-nav--primary%20.md-nav__link%20.md-nav__icon%7Bfont-size%3A1.2rem%3Bheight%3A1.2rem%3Bwidth%3A1.2rem%7D.md-nav--primary%20.md-nav__link%20.md-nav__icon%3Aafter%7Bbackground-color%3Acurrentcolor%3Bcontent%3A%22%22%3Bdisplay%3Ablock%3Bheight%3A100%25%3B-webkit-mask-image%3Avar%28--md-nav-icon--next%29%3Bmask-image%3Avar%28--md-nav-icon--next%29%3B-webkit-mask-position%3Acenter%3Bmask-position%3Acenter%3B-webkit-mask-repeat%3Ano-repeat%3Bmask-repeat%3Ano-repeat%3B-webkit-mask-size%3Acontain%3Bmask-size%3Acontain%3Bwidth%3A100%25%7D%5Bdir%3Drtl%5D%20.md-nav--primary%20.md-nav__icon%3Aafter%7Btransform%3Ascale%28-1%29%7D.md-nav--primary%20.md-nav--secondary%20.md-nav%7Bbackground-color%3Ainitial%3Bposition%3Astatic%7D%5Bdir%3Dltr%5D%20.md-nav--primary%20.md-nav--secondary%20.md-nav%20.md-nav__link%7Bpadding-left%3A1.4rem%7D%5Bdir%3Drtl%5D%20.md-nav--primary%20.md-nav--secondary%20.md-nav%20.md-nav__link%7Bpadding-right%3A1.4rem%7D%5Bdir%3Dltr%5D%20.md-nav--primary%20.md-nav--secondary%20.md-nav%20.md-nav%20.md-nav__link%7Bpadding-left%3A2rem%7D%5Bdir%3Drtl%5D%20.md-nav--primary%20.md-nav--secondary%20.md-nav%20.md-nav%20.md-nav__link%7Bpadding-right%3A2rem%7D%5Bdir%3Dltr%5D%20.md-nav--primary%20.md-nav--secondary%20.md-nav%20.md-nav%20.md-nav%20.md-nav__link%7Bpadding-left%3A2.6rem%7D%5Bdir%3Drtl%5D%20.md-nav--primary%20.md-nav--secondary%20.md-nav%20.md-nav%20.md-nav%20.md-nav__link%7Bpadding-right%3A2.6rem%7D%5Bdir%3Dltr%5D%20.md-nav--primary%20.md-nav--secondary%20.md-nav%20.md-nav%20.md-nav%20.md-nav%20.md-nav__link%7Bpadding-left%3A3.2rem%7D%5Bdir%3Drtl%5D%20.md-nav--primary%20.md-nav--secondary%20.md-nav%20.md-nav%20.md-nav%20.md-nav%20.md-nav__link%7Bpadding-right%3A3.2rem%7D.md-nav--secondary%7Bbackground-color%3Ainitial%7D.md-nav__toggle~.md-nav%7Bdisplay%3Aflex%3Bopacity%3A0%3Btransform%3AtranslateX%28100%25%29%3Btransition%3Atransform%20.25s%20cubic-bezier%28.8%2C0%2C.6%2C1%29%2Copacity%20125ms%2050ms%7D%5Bdir%3Drtl%5D%20.md-nav__toggle~.md-nav%7Btransform%3AtranslateX%28-100%25%29%7D.md-nav__toggle%3Achecked~.md-nav%7Bopacity%3A1%3Btransform%3AtranslateX%280%29%3Btransition%3Atransform%20.25s%20cubic-bezier%28.4%2C0%2C.2%2C1%29%2Copacity%20125ms%20125ms%7D.md-nav__toggle%3Achecked~.md-nav%3E.md-nav__list%7B-webkit-backface-visibility%3Ahidden%3Bbackface-visibility%3Ahidden%7D%7D%40media%20screen%20and%20%28max-width%3A59.984375em%29%7B.md-nav--primary%20.md-nav__link%5Bfor%3D__toc%5D%7Bdisplay%3Aflex%7D.md-nav--primary%20.md-nav__link%5Bfor%3D__toc%5D%20.md-icon%3Aafter%7Bcontent%3A%22%22%7D.md-nav--primary%20.md-nav__link%5Bfor%3D__toc%5D%2B.md-nav__link%7Bdisplay%3Anone%7D.md-nav--primary%20.md-nav__link%5Bfor%3D__toc%5D~.md-nav%7Bdisplay%3Aflex%7D.md-nav__source%7Bbackground-color%3Avar%28--md-primary-fg-color--dark%29%3Bcolor%3Avar%28--md-primary-bg-color%29%3Bdisplay%3Ablock%3Bpadding%3A0%20.2rem%7D%7D%40media%20screen%20and%20%28min-width%3A60em%29%20and%20%28max-width%3A76.234375em%29%7B.md-nav--integrated%20.md-nav__link%5Bfor%3D__toc%5D%7Bdisplay%3Aflex%7D.md-nav--integrated%20.md-nav__link%5Bfor%3D__toc%5D%20.md-icon%3Aafter%7Bcontent%3A%22%22%7D.md-nav--integrated%20.md-nav__link%5Bfor%3D__toc%5D%2B.md-nav__link%7Bdisplay%3Anone%7D.md-nav--integrated%20.md-nav__link%5Bfor%3D__toc%5D~.md-nav%7Bdisplay%3Aflex%7D%7D%40media%20screen%20and%20%28min-width%3A60em%29%7B.md-nav%7Bmargin-bottom%3A-.4rem%7D.md-nav--secondary%20.md-nav__title%7Bbackground%3Avar%28--md-default-bg-color%29%3Bbox-shadow%3A0%200%20.4rem%20.4rem%20var%28--md-default-bg-color%29%3Bposition%3Asticky%3Btop%3A0%3Bz-index%3A1%7D.md-nav--secondary%20.md-nav__title%5Bfor%3D__toc%5D%7Bscroll-snap-align%3Astart%7D.md-nav--secondary%20.md-nav__title%20.md-nav__icon%7Bdisplay%3Anone%7D%5Bdir%3Dltr%5D%20.md-nav--secondary%20.md-nav__list%7Bpadding-left%3A.6rem%7D%5Bdir%3Drtl%5D%20.md-nav--secondary%20.md-nav__list%7Bpadding-right%3A.6rem%7D.md-nav--secondary%20.md-nav__list%7Bpadding-bottom%3A.4rem%7D%5Bdir%3Dltr%5D%20.md-nav--secondary%20.md-nav__item%3E.md-nav__link%7Bmargin-right%3A.4rem%7D%5Bdir%3Drtl%5D%20.md-nav--secondary%20.md-nav__item%3E.md-nav__link%7Bmargin-left%3A.4rem%7D%7D%40media%20screen%20and%20%28min-width%3A76.25em%29%7B.md-nav%7Bmargin-bottom%3A-.4rem%3Btransition%3Amax-height%20.25s%20cubic-bezier%28.86%2C0%2C.07%2C1%29%7D.md-nav--primary%20.md-nav__title%7Bbackground%3Avar%28--md-default-bg-color%29%3Bbox-shadow%3A0%200%20.4rem%20.4rem%20var%28--md-default-bg-color%29%3Bposition%3Asticky%3Btop%3A0%3Bz-index%3A1%7D.md-nav--primary%20.md-nav__title%5Bfor%3D__drawer%5D%7Bscroll-snap-align%3Astart%7D.md-nav--primary%20.md-nav__title%20.md-nav__icon%7Bdisplay%3Anone%7D%5Bdir%3Dltr%5D%20.md-nav--primary%20.md-nav__list%7Bpadding-left%3A.6rem%7D%5Bdir%3Drtl%5D%20.md-nav--primary%20.md-nav__list%7Bpadding-right%3A.6rem%7D.md-nav--primary%20.md-nav__list%7Bpadding-bottom%3A.4rem%7D%5Bdir%3Dltr%5D%20.md-nav--primary%20.md-nav__item%3E.md-nav__link%7Bmargin-right%3A.4rem%7D%5Bdir%3Drtl%5D%20.md-nav--primary%20.md-nav__item%3E.md-nav__link%7Bmargin-left%3A.4rem%7D.md-nav__toggle~.md-nav%7Bdisplay%3Agrid%3Bgrid-template-rows%3A0fr%3Bopacity%3A0%3Btransition%3Agrid-template-rows%20.25s%20cubic-bezier%28.86%2C0%2C.07%2C1%29%2Copacity%20.25s%2Cvisibility%200ms%20.25s%3Bvisibility%3Acollapse%7D.md-nav__toggle~.md-nav%3E.md-nav__list%7Boverflow%3Ahidden%7D.md-nav__toggle.md-toggle--indeterminate~.md-nav%2C.md-nav__toggle%3Achecked~.md-nav%7Bgrid-template-rows%3A1fr%3Bopacity%3A1%3Btransition%3Agrid-template-rows%20.25s%20cubic-bezier%28.86%2C0%2C.07%2C1%29%2Copacity%20.15s%20.1s%2Cvisibility%200ms%3Bvisibility%3Avisible%7D.md-nav__toggle.md-toggle--indeterminate~.md-nav%7Btransition%3Anone%7D.md-nav__item--nested%3E.md-nav%3E.md-nav__title%7Bdisplay%3Anone%7D.md-nav__item--section%7Bdisplay%3Ablock%3Bmargin%3A1.25em%200%7D.md-nav__item--section%3Alast-child%7Bmargin-bottom%3A0%7D.md-nav__item--section%3E.md-nav__link%7Bfont-weight%3A700%7D.md-nav__item--section%3E.md-nav__link%5Bfor%5D%7Bcolor%3Avar%28--md-default-fg-color--light%29%7D.md-nav__item--section%3E.md-nav__link%3Anot%28.md-nav__container%29%7Bpointer-events%3Anone%7D.md-nav__item--section%3E.md-nav__link%20.md-icon%2C.md-nav__item--section%3E.md-nav__link%3E%5Bfor%5D%7Bdisplay%3Anone%7D%5Bdir%3Dltr%5D%20.md-nav__item--section%3E.md-nav%7Bmargin-left%3A-.6rem%7D%5Bdir%3Drtl%5D%20.md-nav__item--section%3E.md-nav%7Bmargin-right%3A-.6rem%7D.md-nav__item--section%3E.md-nav%7Bdisplay%3Ablock%3Bopacity%3A1%3Bvisibility%3Avisible%7D.md-nav__item--section%3E.md-nav%3E.md-nav__list%3E.md-nav__item%7Bpadding%3A0%7D.md-nav__icon%7Bborder-radius%3A100%25%3Bheight%3A.9rem%3Btransition%3Abackground-color%20.25s%3Bwidth%3A.9rem%7D.md-nav__icon%3Ahover%7Bbackground-color%3Avar%28--md-accent-fg-color--transparent%29%7D.md-nav__icon%3Aafter%7Bbackground-color%3Acurrentcolor%3Bborder-radius%3A100%25%3Bcontent%3A%22%22%3Bdisplay%3Ainline-block%3Bheight%3A100%25%3B-webkit-mask-image%3Avar%28--md-nav-icon--next%29%3Bmask-image%3Avar%28--md-nav-icon--next%29%3B-webkit-mask-position%3Acenter%3Bmask-position%3Acenter%3B-webkit-mask-repeat%3Ano-repeat%3Bmask-repeat%3Ano-repeat%3B-webkit-mask-size%3Acontain%3Bmask-size%3Acontain%3Btransition%3Atransform%20.25s%3Bvertical-align%3A-.1rem%3Bwidth%3A100%25%7D%5Bdir%3Drtl%5D%20.md-nav__icon%3Aafter%7Btransform%3Arotate%28180deg%29%7D.md-nav__item--nested%20.md-nav__toggle%3Achecked~.md-nav__link%20.md-nav__icon%3Aafter%2C.md-nav__item--nested%20.md-toggle--indeterminate~.md-nav__link%20.md-nav__icon%3Aafter%7Btransform%3Arotate%2890deg%29%7D.md-nav--lifted%3E.md-nav__list%3E.md-nav__item%2C.md-nav--lifted%3E.md-nav__title%7Bdisplay%3Anone%7D.md-nav--lifted%3E.md-nav__list%3E.md-nav__item--active%7Bdisplay%3Ablock%7D.md-nav--lifted%3E.md-nav__list%3E.md-nav__item--active%3E.md-nav__link%7Bbackground%3Avar%28--md-default-bg-color%29%3Bbox-shadow%3A0%200%20.4rem%20.4rem%20var%28--md-default-bg-color%29%3Bmargin-top%3A0%3Bposition%3Asticky%3Btop%3A0%3Bz-index%3A1%7D.md-nav--lifted%3E.md-nav__list%3E.md-nav__item--active%3E.md-nav__link%3Anot%28.md-nav__container%29%7Bpointer-events%3Anone%7D.md-nav--lifted%3E.md-nav__list%3E.md-nav__item--active.md-nav__item--section%7Bmargin%3A0%7D%5Bdir%3Dltr%5D%20.md-nav--lifted%3E.md-nav__list%3E.md-nav__item%3E.md-nav%3Anot%28.md-nav--secondary%29%7Bmargin-left%3A-.6rem%7D%5Bdir%3Drtl%5D%20.md-nav--lifted%3E.md-nav__list%3E.md-nav__item%3E.md-nav%3Anot%28.md-nav--secondary%29%7Bmargin-right%3A-.6rem%7D.md-nav--lifted%3E.md-nav__list%3E.md-nav__item%3E%5Bfor%5D%7Bcolor%3Avar%28--md-default-fg-color--light%29%7D.md-nav--lifted%20.md-nav%5Bdata-md-level%3D%221%22%5D%7Bgrid-template-rows%3A1fr%3Bopacity%3A1%3Bvisibility%3Avisible%7D%5Bdir%3Dltr%5D%20.md-nav--integrated%3E.md-nav__list%3E.md-nav__item--active%20.md-nav--secondary%7Bborder-left%3A.05rem%20solid%20var%28--md-primary-fg-color%29%7D%5Bdir%3Drtl%5D%20.md-nav--integrated%3E.md-nav__list%3E.md-nav__item--active%20.md-nav--secondary%7Bborder-right%3A.05rem%20solid%20var%28--md-primary-fg-color%29%7D.md-nav--integrated%3E.md-nav__list%3E.md-nav__item--active%20.md-nav--secondary%7Bdisplay%3Ablock%3Bmargin-bottom%3A1.25em%3Bopacity%3A1%3Bvisibility%3Avisible%7D.md-nav--integrated%3E.md-nav__list%3E.md-nav__item--active%20.md-nav--secondary%3E.md-nav__list%7Boverflow%3Avisible%3Bpadding-bottom%3A0%7D.md-nav--integrated%3E.md-nav__list%3E.md-nav__item--active%20.md-nav--secondary%3E.md-nav__title%7Bdisplay%3Anone%7D%7D.md-pagination%7Bfont-size%3A.8rem%3Bfont-weight%3A700%3Bgap%3A.4rem%7D.md-pagination%2C.md-pagination%3E%2A%7Balign-items%3Acenter%3Bdisplay%3Aflex%3Bjustify-content%3Acenter%7D.md-pagination%3E%2A%7Bborder-radius%3A.2rem%3Bheight%3A1.8rem%3Bmin-width%3A1.8rem%3Btext-align%3Acenter%7D.md-pagination__current%7Bbackground-color%3Avar%28--md-default-fg-color--lightest%29%3Bcolor%3Avar%28--md-default-fg-color--light%29%7D.md-pagination__link%7Btransition%3Acolor%20125ms%2Cbackground-color%20125ms%7D.md-pagination__link%3Afocus%2C.md-pagination__link%3Ahover%7Bbackground-color%3Avar%28--md-accent-fg-color--transparent%29%3Bcolor%3Avar%28--md-accent-fg-color%29%7D.md-pagination__link%3Afocus%20svg%2C.md-pagination__link%3Ahover%20svg%7Bcolor%3Avar%28--md-accent-fg-color%29%7D.md-pagination__link.focus-visible%7Boutline-color%3Avar%28--md-accent-fg-color%29%3Boutline-offset%3A.2rem%7D.md-pagination__link%20svg%7Bfill%3Acurrentcolor%3Bcolor%3Avar%28--md-default-fg-color--lighter%29%3Bdisplay%3Ablock%3Bmax-height%3A100%25%3Bwidth%3A1.2rem%7D.md-post__back%7Bborder-bottom%3A.05rem%20solid%20var%28--md-default-fg-color--lightest%29%3Bmargin-bottom%3A1.2rem%3Bpadding-bottom%3A1.2rem%7D%40media%20screen%20and%20%28max-width%3A76.234375em%29%7B.md-post__back%7Bdisplay%3Anone%7D%7D%5Bdir%3Drtl%5D%20.md-post__back%20svg%7Btransform%3AscaleX%28-1%29%7D.md-post__authors%7Bdisplay%3Aflex%3Bflex-direction%3Acolumn%3Bgap%3A.6rem%3Bmargin%3A0%20.6rem%201.2rem%7D.md-post%20.md-post__meta%20a%7Btransition%3Acolor%20125ms%7D.md-post%20.md-post__meta%20a%3Afocus%2C.md-post%20.md-post__meta%20a%3Ahover%7Bcolor%3Avar%28--md-accent-fg-color%29%7D.md-post__title%7Bcolor%3Avar%28--md-default-fg-color--light%29%3Bfont-weight%3A700%7D.md-post--excerpt%7Bmargin-bottom%3A3.2rem%7D.md-post--excerpt%20.md-post__header%7Balign-items%3Acenter%3Bdisplay%3Aflex%3Bgap%3A.6rem%3Bmin-height%3A1.6rem%7D.md-post--excerpt%20.md-post__authors%7Balign-items%3Acenter%3Bdisplay%3Ainline-flex%3Bflex-direction%3Arow%3Bgap%3A.2rem%3Bmargin%3A0%3Bmin-height%3A2.4rem%7D%5Bdir%3Dltr%5D%20.md-post--excerpt%20.md-post__meta%20.md-meta__list%7Bmargin-right%3A.4rem%7D%5Bdir%3Drtl%5D%20.md-post--excerpt%20.md-post__meta%20.md-meta__list%7Bmargin-left%3A.4rem%7D.md-post--excerpt%20.md-post__content%3E%3Afirst-child%7B--md-scroll-margin%3A6rem%3Bmargin-top%3A0%7D.md-post%3E.md-nav--secondary%7Bmargin%3A1em%200%7D.md-profile%7Balign-items%3Acenter%3Bdisplay%3Aflex%3Bfont-size%3A.7rem%3Bgap%3A.6rem%3Bline-height%3A1.4%3Bwidth%3A100%25%7D.md-profile__description%7Bflex-grow%3A1%7D.md-content--post%7Bdisplay%3Aflex%7D%40media%20screen%20and%20%28max-width%3A76.234375em%29%7B.md-content--post%7Bflex-flow%3Acolumn-reverse%7D%7D.md-content--post%3E.md-content__inner%7Bmin-width%3A0%7D%40media%20screen%20and%20%28min-width%3A76.25em%29%7B%5Bdir%3Dltr%5D%20.md-content--post%3E.md-content__inner%7Bmargin-left%3A1.2rem%7D%5Bdir%3Drtl%5D%20.md-content--post%3E.md-content__inner%7Bmargin-right%3A1.2rem%7D%7D%40media%20screen%20and%20%28max-width%3A76.234375em%29%7B.md-sidebar.md-sidebar--post%7Bpadding%3A0%3Bposition%3Astatic%3Bwidth%3A100%25%7D.md-sidebar.md-sidebar--post%20.md-sidebar__scrollwrap%7Boverflow%3Avisible%7D.md-sidebar.md-sidebar--post%20.md-sidebar__inner%7Bpadding%3A0%7D.md-sidebar.md-sidebar--post%20.md-post__meta%7Bmargin-left%3A.6rem%3Bmargin-right%3A.6rem%7D.md-sidebar.md-sidebar--post%20.md-nav__item%7Bborder%3Anone%3Bdisplay%3Ainline%7D.md-sidebar.md-sidebar--post%20.md-nav__list%7Bdisplay%3Ainline-flex%3Bflex-wrap%3Awrap%3Bgap%3A.6rem%3Bpadding-bottom%3A.6rem%3Bpadding-top%3A.6rem%7D.md-sidebar.md-sidebar--post%20.md-nav__link%7Bpadding%3A0%7D.md-sidebar.md-sidebar--post%20.md-nav%7Bheight%3Aauto%3Bmargin-bottom%3A0%3Bposition%3Astatic%7D%7D%3Aroot%7B--md-progress-value%3A0%3B--md-progress-delay%3A400ms%7D.md-progress%7Bbackground%3Avar%28--md-primary-bg-color%29%3Bheight%3A.075rem%3Bopacity%3Amin%28clamp%280%2Cvar%28--md-progress-value%29%2C1%29%2Cclamp%280%2C100%20-%20var%28--md-progress-value%29%2C1%29%29%3Bposition%3Afixed%3Btop%3A0%3Btransform%3AscaleX%28calc%28var%28--md-progress-value%29%2A1%25%29%29%3Btransform-origin%3Aleft%3Btransition%3Atransform%20.5s%20cubic-bezier%28.19%2C1%2C.22%2C1%29%2Copacity%20.25s%20var%28--md-progress-delay%29%3Bwidth%3A100%25%3Bz-index%3A4%7D%3Aroot%7B--md-search-result-icon%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M14%202H6a2%202%200%200%200-2%202v16a2%202%200%200%200%202%202h7c-.41-.25-.8-.56-1.14-.9-.33-.33-.61-.7-.86-1.1H6V4h7v5h5v1.18c.71.16%201.39.43%202%20.82V8zm6.31%2016.9c1.33-2.11.69-4.9-1.4-6.22-2.11-1.33-4.91-.68-6.22%201.4-1.34%202.11-.69%204.89%201.4%206.22%201.46.93%203.32.93%204.79.02L22%2023.39%2023.39%2022zm-3.81.1a2.5%202.5%200%200%201-2.5-2.5%202.5%202.5%200%200%201%202.5-2.5%202.5%202.5%200%200%201%202.5%202.5%202.5%202.5%200%200%201-2.5%202.5%22/%3E%3C/svg%3E%27%29%7D.md-search%7Bposition%3Arelative%7D%40media%20screen%20and%20%28min-width%3A60em%29%7B.md-search%7Bpadding%3A.2rem%200%7D%7D.no-js%20.md-search%7Bdisplay%3Anone%7D.md-search__overlay%7Bopacity%3A0%3Bz-index%3A1%7D%40media%20screen%20and%20%28max-width%3A59.984375em%29%7B%5Bdir%3Dltr%5D%20.md-search__overlay%7Bleft%3A-2.2rem%7D%5Bdir%3Drtl%5D%20.md-search__overlay%7Bright%3A-2.2rem%7D.md-search__overlay%7Bbackground-color%3Avar%28--md-default-bg-color%29%3Bborder-radius%3A1rem%3Bheight%3A2rem%3Boverflow%3Ahidden%3Bpointer-events%3Anone%3Bposition%3Aabsolute%3Btop%3A-1rem%3Btransform-origin%3Acenter%3Btransition%3Atransform%20.3s%20.1s%2Copacity%20.2s%20.2s%3Bwidth%3A2rem%7D%5Bdata-md-toggle%3Dsearch%5D%3Achecked~.md-header%20.md-search__overlay%7Bopacity%3A1%3Btransition%3Atransform%20.4s%2Copacity%20.1s%7D%7D%40media%20screen%20and%20%28min-width%3A60em%29%7B%5Bdir%3Dltr%5D%20.md-search__overlay%7Bleft%3A0%7D%5Bdir%3Drtl%5D%20.md-search__overlay%7Bright%3A0%7D.md-search__overlay%7Bbackground-color%3A%230000008a%3Bcursor%3Apointer%3Bheight%3A0%3Bposition%3Afixed%3Btop%3A0%3Btransition%3Awidth%200ms%20.25s%2Cheight%200ms%20.25s%2Copacity%20.25s%3Bwidth%3A0%7D%5Bdata-md-toggle%3Dsearch%5D%3Achecked~.md-header%20.md-search__overlay%7Bheight%3A200vh%3Bopacity%3A1%3Btransition%3Awidth%200ms%2Cheight%200ms%2Copacity%20.25s%3Bwidth%3A100%25%7D%7D%40media%20screen%20and%20%28max-width%3A29.984375em%29%7B%5Bdata-md-toggle%3Dsearch%5D%3Achecked~.md-header%20.md-search__overlay%7Btransform%3Ascale%2845%29%7D%7D%40media%20screen%20and%20%28min-width%3A30em%29%20and%20%28max-width%3A44.984375em%29%7B%5Bdata-md-toggle%3Dsearch%5D%3Achecked~.md-header%20.md-search__overlay%7Btransform%3Ascale%2860%29%7D%7D%40media%20screen%20and%20%28min-width%3A45em%29%20and%20%28max-width%3A59.984375em%29%7B%5Bdata-md-toggle%3Dsearch%5D%3Achecked~.md-header%20.md-search__overlay%7Btransform%3Ascale%2875%29%7D%7D.md-search__inner%7B-webkit-backface-visibility%3Ahidden%3Bbackface-visibility%3Ahidden%7D%40media%20screen%20and%20%28max-width%3A59.984375em%29%7B%5Bdir%3Dltr%5D%20.md-search__inner%7Bleft%3A0%7D%5Bdir%3Drtl%5D%20.md-search__inner%7Bright%3A0%7D.md-search__inner%7Bheight%3A0%3Bopacity%3A0%3Boverflow%3Ahidden%3Bposition%3Afixed%3Btop%3A0%3Btransform%3AtranslateX%285%25%29%3Btransition%3Awidth%200ms%20.3s%2Cheight%200ms%20.3s%2Ctransform%20.15s%20cubic-bezier%28.4%2C0%2C.2%2C1%29%20.15s%2Copacity%20.15s%20.15s%3Bwidth%3A0%3Bz-index%3A2%7D%5Bdir%3Drtl%5D%20.md-search__inner%7Btransform%3AtranslateX%28-5%25%29%7D%5Bdata-md-toggle%3Dsearch%5D%3Achecked~.md-header%20.md-search__inner%7Bheight%3A100%25%3Bopacity%3A1%3Btransform%3AtranslateX%280%29%3Btransition%3Awidth%200ms%200ms%2Cheight%200ms%200ms%2Ctransform%20.15s%20cubic-bezier%28.1%2C.7%2C.1%2C1%29%20.15s%2Copacity%20.15s%20.15s%3Bwidth%3A100%25%7D%7D%40media%20screen%20and%20%28min-width%3A60em%29%7B%5Bdir%3Dltr%5D%20.md-search__inner%7Bfloat%3Aright%7D%5Bdir%3Drtl%5D%20.md-search__inner%7Bfloat%3Aleft%7D.md-search__inner%7Bpadding%3A.1rem%200%3Bposition%3Arelative%3Btransition%3Awidth%20.25s%20cubic-bezier%28.1%2C.7%2C.1%2C1%29%3Bwidth%3A11.7rem%7D%7D%40media%20screen%20and%20%28min-width%3A60em%29%20and%20%28max-width%3A76.234375em%29%7B%5Bdata-md-toggle%3Dsearch%5D%3Achecked~.md-header%20.md-search__inner%7Bwidth%3A23.4rem%7D%7D%40media%20screen%20and%20%28min-width%3A76.25em%29%7B%5Bdata-md-toggle%3Dsearch%5D%3Achecked~.md-header%20.md-search__inner%7Bwidth%3A34.4rem%7D%7D.md-search__form%7Bbackground-color%3Avar%28--md-default-bg-color%29%3Bbox-shadow%3A0%200%20.6rem%20%230000%3Bheight%3A2.4rem%3Bposition%3Arelative%3Btransition%3Acolor%20.25s%2Cbackground-color%20.25s%3Bz-index%3A2%7D%40media%20screen%20and%20%28min-width%3A60em%29%7B.md-search__form%7Bbackground-color%3A%2300000042%3Bborder-radius%3A.1rem%3Bheight%3A1.8rem%7D.md-search__form%3Ahover%7Bbackground-color%3A%23ffffff1f%7D%7D%5Bdata-md-toggle%3Dsearch%5D%3Achecked~.md-header%20.md-search__form%7Bbackground-color%3Avar%28--md-default-bg-color%29%3Bborder-radius%3A.1rem%20.1rem%200%200%3Bbox-shadow%3A0%200%20.6rem%20%2300000012%3Bcolor%3Avar%28--md-default-fg-color%29%7D%5Bdir%3Dltr%5D%20.md-search__input%7Bpadding-left%3A3.6rem%3Bpadding-right%3A2.2rem%7D%5Bdir%3Drtl%5D%20.md-search__input%7Bpadding-left%3A2.2rem%3Bpadding-right%3A3.6rem%7D.md-search__input%7Bbackground%3A%230000%3Bfont-size%3A.9rem%3Bheight%3A100%25%3Bposition%3Arelative%3Btext-overflow%3Aellipsis%3Bwidth%3A100%25%3Bz-index%3A2%7D.md-search__input%3A%3Aplaceholder%7Btransition%3Acolor%20.25s%7D.md-search__input%3A%3Aplaceholder%2C.md-search__input~.md-search__icon%7Bcolor%3Avar%28--md-default-fg-color--light%29%7D.md-search__input%3A%3A-ms-clear%7Bdisplay%3Anone%7D%40media%20screen%20and%20%28max-width%3A59.984375em%29%7B.md-search__input%7Bfont-size%3A.9rem%3Bheight%3A2.4rem%3Bwidth%3A100%25%7D%7D%40media%20screen%20and%20%28min-width%3A60em%29%7B%5Bdir%3Dltr%5D%20.md-search__input%7Bpadding-left%3A2.2rem%7D%5Bdir%3Drtl%5D%20.md-search__input%7Bpadding-right%3A2.2rem%7D.md-search__input%7Bcolor%3Ainherit%3Bfont-size%3A.8rem%7D.md-search__input%3A%3Aplaceholder%7Bcolor%3Avar%28--md-primary-bg-color--light%29%7D.md-search__input%2B.md-search__icon%7Bcolor%3Avar%28--md-primary-bg-color%29%7D%5Bdata-md-toggle%3Dsearch%5D%3Achecked~.md-header%20.md-search__input%7Btext-overflow%3Aclip%7D%5Bdata-md-toggle%3Dsearch%5D%3Achecked~.md-header%20.md-search__input%2B.md-search__icon%7Bcolor%3Avar%28--md-default-fg-color--light%29%7D%5Bdata-md-toggle%3Dsearch%5D%3Achecked~.md-header%20.md-search__input%3A%3Aplaceholder%7Bcolor%3A%230000%7D%7D.md-search__icon%7Bcursor%3Apointer%3Bdisplay%3Ainline-block%3Bheight%3A1.2rem%3Btransition%3Acolor%20.25s%2Copacity%20.25s%3Bwidth%3A1.2rem%7D.md-search__icon%3Ahover%7Bopacity%3A.7%7D%5Bdir%3Dltr%5D%20.md-search__icon%5Bfor%3D__search%5D%7Bleft%3A.5rem%7D%5Bdir%3Drtl%5D%20.md-search__icon%5Bfor%3D__search%5D%7Bright%3A.5rem%7D.md-search__icon%5Bfor%3D__search%5D%7Bposition%3Aabsolute%3Btop%3A.3rem%3Bz-index%3A2%7D%5Bdir%3Drtl%5D%20.md-search__icon%5Bfor%3D__search%5D%20svg%7Btransform%3AscaleX%28-1%29%7D%40media%20screen%20and%20%28max-width%3A59.984375em%29%7B%5Bdir%3Dltr%5D%20.md-search__icon%5Bfor%3D__search%5D%7Bleft%3A.8rem%7D%5Bdir%3Drtl%5D%20.md-search__icon%5Bfor%3D__search%5D%7Bright%3A.8rem%7D.md-search__icon%5Bfor%3D__search%5D%7Btop%3A.6rem%7D.md-search__icon%5Bfor%3D__search%5D%20svg%3Afirst-child%7Bdisplay%3Anone%7D%7D%40media%20screen%20and%20%28min-width%3A60em%29%7B.md-search__icon%5Bfor%3D__search%5D%7Bpointer-events%3Anone%7D.md-search__icon%5Bfor%3D__search%5D%20svg%3Alast-child%7Bdisplay%3Anone%7D%7D%5Bdir%3Dltr%5D%20.md-search__options%7Bright%3A.5rem%7D%5Bdir%3Drtl%5D%20.md-search__options%7Bleft%3A.5rem%7D.md-search__options%7Bpointer-events%3Anone%3Bposition%3Aabsolute%3Btop%3A.3rem%3Bz-index%3A2%7D%40media%20screen%20and%20%28max-width%3A59.984375em%29%7B%5Bdir%3Dltr%5D%20.md-search__options%7Bright%3A.8rem%7D%5Bdir%3Drtl%5D%20.md-search__options%7Bleft%3A.8rem%7D.md-search__options%7Btop%3A.6rem%7D%7D%5Bdir%3Dltr%5D%20.md-search__options%3E.md-icon%7Bmargin-left%3A.2rem%7D%5Bdir%3Drtl%5D%20.md-search__options%3E.md-icon%7Bmargin-right%3A.2rem%7D.md-search__options%3E.md-icon%7Bcolor%3Avar%28--md-default-fg-color--light%29%3Bopacity%3A0%3Btransform%3Ascale%28.75%29%3Btransition%3Atransform%20.15s%20cubic-bezier%28.1%2C.7%2C.1%2C1%29%2Copacity%20.15s%7D.md-search__options%3E.md-icon%3Anot%28.focus-visible%29%7B-webkit-tap-highlight-color%3Atransparent%3Boutline%3Anone%7D%5Bdata-md-toggle%3Dsearch%5D%3Achecked~.md-header%20.md-search__input%3Avalid~.md-search__options%3E.md-icon%7Bopacity%3A1%3Bpointer-events%3Aauto%3Btransform%3Ascale%281%29%7D%5Bdata-md-toggle%3Dsearch%5D%3Achecked~.md-header%20.md-search__input%3Avalid~.md-search__options%3E.md-icon%3Ahover%7Bopacity%3A.7%7D%5Bdir%3Dltr%5D%20.md-search__suggest%7Bpadding-left%3A3.6rem%3Bpadding-right%3A2.2rem%7D%5Bdir%3Drtl%5D%20.md-search__suggest%7Bpadding-left%3A2.2rem%3Bpadding-right%3A3.6rem%7D.md-search__suggest%7Balign-items%3Acenter%3Bcolor%3Avar%28--md-default-fg-color--lighter%29%3Bdisplay%3Aflex%3Bfont-size%3A.9rem%3Bheight%3A100%25%3Bopacity%3A0%3Bposition%3Aabsolute%3Btop%3A0%3Btransition%3Aopacity%2050ms%3Bwhite-space%3Anowrap%3Bwidth%3A100%25%7D%40media%20screen%20and%20%28min-width%3A60em%29%7B%5Bdir%3Dltr%5D%20.md-search__suggest%7Bpadding-left%3A2.2rem%7D%5Bdir%3Drtl%5D%20.md-search__suggest%7Bpadding-right%3A2.2rem%7D.md-search__suggest%7Bfont-size%3A.8rem%7D%7D%5Bdata-md-toggle%3Dsearch%5D%3Achecked~.md-header%20.md-search__suggest%7Bopacity%3A1%3Btransition%3Aopacity%20.3s%20.1s%7D%5Bdir%3Dltr%5D%20.md-search__output%7Bborder-bottom-left-radius%3A.1rem%7D%5Bdir%3Dltr%5D%20.md-search__output%2C%5Bdir%3Drtl%5D%20.md-search__output%7Bborder-bottom-right-radius%3A.1rem%7D%5Bdir%3Drtl%5D%20.md-search__output%7Bborder-bottom-left-radius%3A.1rem%7D.md-search__output%7Boverflow%3Ahidden%3Bposition%3Aabsolute%3Bwidth%3A100%25%3Bz-index%3A1%7D%40media%20screen%20and%20%28max-width%3A59.984375em%29%7B.md-search__output%7Bbottom%3A0%3Btop%3A2.4rem%7D%7D%40media%20screen%20and%20%28min-width%3A60em%29%7B.md-search__output%7Bopacity%3A0%3Btop%3A1.9rem%3Btransition%3Aopacity%20.4s%7D%5Bdata-md-toggle%3Dsearch%5D%3Achecked~.md-header%20.md-search__output%7Bbox-shadow%3Avar%28--md-shadow-z3%29%3Bopacity%3A1%7D%7D.md-search__scrollwrap%7B-webkit-backface-visibility%3Ahidden%3Bbackface-visibility%3Ahidden%3Bbackground-color%3Avar%28--md-default-bg-color%29%3Bheight%3A100%25%3Boverflow-y%3Aauto%3Btouch-action%3Apan-y%7D%40media%20%28-webkit-max-device-pixel-ratio%3A1%29%2C%28max-resolution%3A1dppx%29%7B.md-search__scrollwrap%7Btransform%3AtranslateZ%280%29%7D%7D%40media%20screen%20and%20%28min-width%3A60em%29%20and%20%28max-width%3A76.234375em%29%7B.md-search__scrollwrap%7Bwidth%3A23.4rem%7D%7D%40media%20screen%20and%20%28min-width%3A76.25em%29%7B.md-search__scrollwrap%7Bwidth%3A34.4rem%7D%7D%40media%20screen%20and%20%28min-width%3A60em%29%7B.md-search__scrollwrap%7Bmax-height%3A0%3Bscrollbar-color%3Avar%28--md-default-fg-color--lighter%29%20%230000%3Bscrollbar-width%3Athin%7D%5Bdata-md-toggle%3Dsearch%5D%3Achecked~.md-header%20.md-search__scrollwrap%7Bmax-height%3A75vh%7D.md-search__scrollwrap%3Ahover%7Bscrollbar-color%3Avar%28--md-accent-fg-color%29%20%230000%7D.md-search__scrollwrap%3A%3A-webkit-scrollbar%7Bheight%3A.2rem%3Bwidth%3A.2rem%7D.md-search__scrollwrap%3A%3A-webkit-scrollbar-thumb%7Bbackground-color%3Avar%28--md-default-fg-color--lighter%29%7D.md-search__scrollwrap%3A%3A-webkit-scrollbar-thumb%3Ahover%7Bbackground-color%3Avar%28--md-accent-fg-color%29%7D%7D.md-search-result%7Bcolor%3Avar%28--md-default-fg-color%29%3Bword-break%3Abreak-word%7D.md-search-result__meta%7Bbackground-color%3Avar%28--md-default-fg-color--lightest%29%3Bcolor%3Avar%28--md-default-fg-color--light%29%3Bfont-size%3A.64rem%3Bline-height%3A1.8rem%3Bpadding%3A0%20.8rem%3Bscroll-snap-align%3Astart%7D%40media%20screen%20and%20%28min-width%3A60em%29%7B%5Bdir%3Dltr%5D%20.md-search-result__meta%7Bpadding-left%3A2.2rem%7D%5Bdir%3Drtl%5D%20.md-search-result__meta%7Bpadding-right%3A2.2rem%7D%7D.md-search-result__list%7Blist-style%3Anone%3Bmargin%3A0%3Bpadding%3A0%3B-webkit-user-select%3Anone%3Buser-select%3Anone%7D.md-search-result__item%7Bbox-shadow%3A0%20-.05rem%20var%28--md-default-fg-color--lightest%29%7D.md-search-result__item%3Afirst-child%7Bbox-shadow%3Anone%7D.md-search-result__link%7Bdisplay%3Ablock%3Boutline%3Anone%3Bscroll-snap-align%3Astart%3Btransition%3Abackground-color%20.25s%7D.md-search-result__link%3Afocus%2C.md-search-result__link%3Ahover%7Bbackground-color%3Avar%28--md-accent-fg-color--transparent%29%7D.md-search-result__link%3Alast-child%20p%3Alast-child%7Bmargin-bottom%3A.6rem%7D.md-search-result__more%3Esummary%7Bcursor%3Apointer%3Bdisplay%3Ablock%3Boutline%3Anone%3Bposition%3Asticky%3Bscroll-snap-align%3Astart%3Btop%3A0%3Bz-index%3A1%7D.md-search-result__more%3Esummary%3A%3Amarker%7Bdisplay%3Anone%7D.md-search-result__more%3Esummary%3A%3A-webkit-details-marker%7Bdisplay%3Anone%7D.md-search-result__more%3Esummary%3Ediv%7Bcolor%3Avar%28--md-typeset-a-color%29%3Bfont-size%3A.64rem%3Bpadding%3A.75em%20.8rem%3Btransition%3Acolor%20.25s%2Cbackground-color%20.25s%7D%40media%20screen%20and%20%28min-width%3A60em%29%7B%5Bdir%3Dltr%5D%20.md-search-result__more%3Esummary%3Ediv%7Bpadding-left%3A2.2rem%7D%5Bdir%3Drtl%5D%20.md-search-result__more%3Esummary%3Ediv%7Bpadding-right%3A2.2rem%7D%7D.md-search-result__more%3Esummary%3Afocus%3Ediv%2C.md-search-result__more%3Esummary%3Ahover%3Ediv%7Bbackground-color%3Avar%28--md-accent-fg-color--transparent%29%3Bcolor%3Avar%28--md-accent-fg-color%29%7D.md-search-result__more%5Bopen%5D%3Esummary%7Bbackground-color%3Avar%28--md-default-bg-color%29%7D.md-search-result__article%7Boverflow%3Ahidden%3Bpadding%3A0%20.8rem%3Bposition%3Arelative%7D%40media%20screen%20and%20%28min-width%3A60em%29%7B%5Bdir%3Dltr%5D%20.md-search-result__article%7Bpadding-left%3A2.2rem%7D%5Bdir%3Drtl%5D%20.md-search-result__article%7Bpadding-right%3A2.2rem%7D%7D%5Bdir%3Dltr%5D%20.md-search-result__icon%7Bleft%3A0%7D%5Bdir%3Drtl%5D%20.md-search-result__icon%7Bright%3A0%7D.md-search-result__icon%7Bcolor%3Avar%28--md-default-fg-color--light%29%3Bheight%3A1.2rem%3Bmargin%3A.5rem%3Bposition%3Aabsolute%3Bwidth%3A1.2rem%7D%40media%20screen%20and%20%28max-width%3A59.984375em%29%7B.md-search-result__icon%7Bdisplay%3Anone%7D%7D.md-search-result__icon%3Aafter%7Bbackground-color%3Acurrentcolor%3Bcontent%3A%22%22%3Bdisplay%3Ainline-block%3Bheight%3A100%25%3B-webkit-mask-image%3Avar%28--md-search-result-icon%29%3Bmask-image%3Avar%28--md-search-result-icon%29%3B-webkit-mask-position%3Acenter%3Bmask-position%3Acenter%3B-webkit-mask-repeat%3Ano-repeat%3Bmask-repeat%3Ano-repeat%3B-webkit-mask-size%3Acontain%3Bmask-size%3Acontain%3Bwidth%3A100%25%7D%5Bdir%3Drtl%5D%20.md-search-result__icon%3Aafter%7Btransform%3AscaleX%28-1%29%7D.md-search-result%20.md-typeset%7Bcolor%3Avar%28--md-default-fg-color--light%29%3Bfont-size%3A.64rem%3Bline-height%3A1.6%7D.md-search-result%20.md-typeset%20h1%7Bcolor%3Avar%28--md-default-fg-color%29%3Bfont-size%3A.8rem%3Bfont-weight%3A400%3Bline-height%3A1.4%3Bmargin%3A.55rem%200%7D.md-search-result%20.md-typeset%20h1%20mark%7Btext-decoration%3Anone%7D.md-search-result%20.md-typeset%20h2%7Bcolor%3Avar%28--md-default-fg-color%29%3Bfont-size%3A.64rem%3Bfont-weight%3A700%3Bline-height%3A1.6%3Bmargin%3A.5em%200%7D.md-search-result%20.md-typeset%20h2%20mark%7Btext-decoration%3Anone%7D.md-search-result__terms%7Bcolor%3Avar%28--md-default-fg-color%29%3Bdisplay%3Ablock%3Bfont-size%3A.64rem%3Bfont-style%3Aitalic%3Bmargin%3A.5em%200%7D.md-search-result%20mark%7Bbackground-color%3Ainitial%3Bcolor%3Avar%28--md-accent-fg-color%29%3Btext-decoration%3Aunderline%7D.md-select%7Bposition%3Arelative%3Bz-index%3A1%7D.md-select__inner%7Bbackground-color%3Avar%28--md-default-bg-color%29%3Bborder-radius%3A.1rem%3Bbox-shadow%3Avar%28--md-shadow-z2%29%3Bcolor%3Avar%28--md-default-fg-color%29%3Bleft%3A50%25%3Bmargin-top%3A.2rem%3Bmax-height%3A0%3Bopacity%3A0%3Bposition%3Aabsolute%3Btop%3Acalc%28100%25%20-%20.2rem%29%3Btransform%3Atranslate3d%28-50%25%2C.3rem%2C0%29%3Btransition%3Atransform%20.25s%20375ms%2Copacity%20.25s%20.25s%2Cmax-height%200ms%20.5s%7D.md-select%3Afocus-within%20.md-select__inner%2C.md-select%3Ahover%20.md-select__inner%7Bmax-height%3A10rem%3Bopacity%3A1%3Btransform%3Atranslate3d%28-50%25%2C0%2C0%29%3Btransition%3Atransform%20.25s%20cubic-bezier%28.1%2C.7%2C.1%2C1%29%2Copacity%20.25s%2Cmax-height%200ms%7D.md-select__inner%3Aafter%7Bborder-bottom%3A.2rem%20solid%20%230000%3Bborder-bottom-color%3Avar%28--md-default-bg-color%29%3Bborder-left%3A.2rem%20solid%20%230000%3Bborder-right%3A.2rem%20solid%20%230000%3Bborder-top%3A0%3Bcontent%3A%22%22%3Bheight%3A0%3Bleft%3A50%25%3Bmargin-left%3A-.2rem%3Bmargin-top%3A-.2rem%3Bposition%3Aabsolute%3Btop%3A0%3Bwidth%3A0%7D.md-select__list%7Bborder-radius%3A.1rem%3Bfont-size%3A.8rem%3Blist-style-type%3Anone%3Bmargin%3A0%3Bmax-height%3Ainherit%3Boverflow%3Aauto%3Bpadding%3A0%7D.md-select__item%7Bline-height%3A1.8rem%7D%5Bdir%3Dltr%5D%20.md-select__link%7Bpadding-left%3A.6rem%3Bpadding-right%3A1.2rem%7D%5Bdir%3Drtl%5D%20.md-select__link%7Bpadding-left%3A1.2rem%3Bpadding-right%3A.6rem%7D.md-select__link%7Bcursor%3Apointer%3Bdisplay%3Ablock%3Boutline%3Anone%3Bscroll-snap-align%3Astart%3Btransition%3Abackground-color%20.25s%2Ccolor%20.25s%3Bwidth%3A100%25%7D.md-select__link%3Afocus%2C.md-select__link%3Ahover%7Bcolor%3Avar%28--md-accent-fg-color%29%7D.md-select__link%3Afocus%7Bbackground-color%3Avar%28--md-default-fg-color--lightest%29%7D.md-sidebar%7Balign-self%3Aflex-start%3Bflex-shrink%3A0%3Bpadding%3A1.2rem%200%3Bposition%3Asticky%3Btop%3A2.4rem%3Bwidth%3A12.1rem%7D%40media%20print%7B.md-sidebar%7Bdisplay%3Anone%7D%7D%40media%20screen%20and%20%28max-width%3A76.234375em%29%7B%5Bdir%3Dltr%5D%20.md-sidebar--primary%7Bleft%3A-12.1rem%7D%5Bdir%3Drtl%5D%20.md-sidebar--primary%7Bright%3A-12.1rem%7D.md-sidebar--primary%7Bbackground-color%3Avar%28--md-default-bg-color%29%3Bdisplay%3Ablock%3Bheight%3A100%25%3Bposition%3Afixed%3Btop%3A0%3Btransform%3AtranslateX%280%29%3Btransition%3Atransform%20.25s%20cubic-bezier%28.4%2C0%2C.2%2C1%29%2Cbox-shadow%20.25s%3Bwidth%3A12.1rem%3Bz-index%3A5%7D%5Bdata-md-toggle%3Ddrawer%5D%3Achecked~.md-container%20.md-sidebar--primary%7Bbox-shadow%3Avar%28--md-shadow-z3%29%3Btransform%3AtranslateX%2812.1rem%29%7D%5Bdir%3Drtl%5D%20%5Bdata-md-toggle%3Ddrawer%5D%3Achecked~.md-container%20.md-sidebar--primary%7Btransform%3AtranslateX%28-12.1rem%29%7D.md-sidebar--primary%20.md-sidebar__scrollwrap%7Bbottom%3A0%3Bleft%3A0%3Bmargin%3A0%3Boverflow%3Ahidden%3Bposition%3Aabsolute%3Bright%3A0%3Bscroll-snap-type%3Anone%3Btop%3A0%7D%7D%40media%20screen%20and%20%28min-width%3A76.25em%29%7B.md-sidebar%7Bheight%3A0%7D.no-js%20.md-sidebar%7Bheight%3Aauto%7D.md-header--lifted~.md-container%20.md-sidebar%7Btop%3A4.8rem%7D%7D.md-sidebar--secondary%7Bdisplay%3Anone%3Border%3A2%7D%40media%20screen%20and%20%28min-width%3A60em%29%7B.md-sidebar--secondary%7Bheight%3A0%7D.no-js%20.md-sidebar--secondary%7Bheight%3Aauto%7D.md-sidebar--secondary%3Anot%28%5Bhidden%5D%29%7Bdisplay%3Ablock%7D.md-sidebar--secondary%20.md-sidebar__scrollwrap%7Btouch-action%3Apan-y%7D%7D.md-sidebar__scrollwrap%7Bscrollbar-gutter%3Astable%3B-webkit-backface-visibility%3Ahidden%3Bbackface-visibility%3Ahidden%3Bmargin%3A0%20.2rem%3Boverflow-y%3Aauto%3Bscrollbar-color%3Avar%28--md-default-fg-color--lighter%29%20%230000%3Bscrollbar-width%3Athin%7D.md-sidebar__scrollwrap%3A%3A-webkit-scrollbar%7Bheight%3A.2rem%3Bwidth%3A.2rem%7D.md-sidebar__scrollwrap%3Afocus-within%2C.md-sidebar__scrollwrap%3Ahover%7Bscrollbar-color%3Avar%28--md-accent-fg-color%29%20%230000%7D.md-sidebar__scrollwrap%3Afocus-within%3A%3A-webkit-scrollbar-thumb%2C.md-sidebar__scrollwrap%3Ahover%3A%3A-webkit-scrollbar-thumb%7Bbackground-color%3Avar%28--md-default-fg-color--lighter%29%7D.md-sidebar__scrollwrap%3Afocus-within%3A%3A-webkit-scrollbar-thumb%3Ahover%2C.md-sidebar__scrollwrap%3Ahover%3A%3A-webkit-scrollbar-thumb%3Ahover%7Bbackground-color%3Avar%28--md-accent-fg-color%29%7D%40supports%20selector%28%3A%3A-webkit-scrollbar%29%7B.md-sidebar__scrollwrap%7Bscrollbar-gutter%3Aauto%7D%5Bdir%3Dltr%5D%20.md-sidebar__inner%7Bpadding-right%3Acalc%28100%25%20-%2011.5rem%29%7D%5Bdir%3Drtl%5D%20.md-sidebar__inner%7Bpadding-left%3Acalc%28100%25%20-%2011.5rem%29%7D%7D%40media%20screen%20and%20%28max-width%3A76.234375em%29%7B.md-overlay%7Bbackground-color%3A%230000008a%3Bheight%3A0%3Bopacity%3A0%3Bposition%3Afixed%3Btop%3A0%3Btransition%3Awidth%200ms%20.25s%2Cheight%200ms%20.25s%2Copacity%20.25s%3Bwidth%3A0%3Bz-index%3A5%7D%5Bdata-md-toggle%3Ddrawer%5D%3Achecked~.md-overlay%7Bheight%3A100%25%3Bopacity%3A1%3Btransition%3Awidth%200ms%2Cheight%200ms%2Copacity%20.25s%3Bwidth%3A100%25%7D%7D%40keyframes%20facts%7B0%25%7Bheight%3A0%7Dto%7Bheight%3A.65rem%7D%7D%40keyframes%20fact%7B0%25%7Bopacity%3A0%3Btransform%3AtranslateY%28100%25%29%7D50%25%7Bopacity%3A0%7Dto%7Bopacity%3A1%3Btransform%3AtranslateY%280%29%7D%7D%3Aroot%7B--md-source-forks-icon%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M5%205.372v.878c0%20.414.336.75.75.75h4.5a.75.75%200%200%200%20.75-.75v-.878a2.25%202.25%200%201%201%201.5%200v.878a2.25%202.25%200%200%201-2.25%202.25h-1.5v2.128a2.251%202.251%200%201%201-1.5%200V8.5h-1.5A2.25%202.25%200%200%201%203.5%206.25v-.878a2.25%202.25%200%201%201%201.5%200M5%203.25a.75.75%200%201%200-1.5%200%20.75.75%200%200%200%201.5%200m6.75.75a.75.75%200%201%200%200-1.5.75.75%200%200%200%200%201.5m-3%208.75a.75.75%200%201%200-1.5%200%20.75.75%200%200%200%201.5%200%22/%3E%3C/svg%3E%27%29%3B--md-source-repositories-icon%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M2%202.5A2.5%202.5%200%200%201%204.5%200h8.75a.75.75%200%200%201%20.75.75v12.5a.75.75%200%200%201-.75.75h-2.5a.75.75%200%200%201%200-1.5h1.75v-2h-8a1%201%200%200%200-.714%201.7.75.75%200%201%201-1.072%201.05A2.5%202.5%200%200%201%202%2011.5Zm10.5-1h-8a1%201%200%200%200-1%201v6.708A2.5%202.5%200%200%201%204.5%209h8ZM5%2012.25a.25.25%200%200%201%20.25-.25h3.5a.25.25%200%200%201%20.25.25v3.25a.25.25%200%200%201-.4.2l-1.45-1.087a.25.25%200%200%200-.3%200L5.4%2015.7a.25.25%200%200%201-.4-.2Z%22/%3E%3C/svg%3E%27%29%3B--md-source-stars-icon%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M8%20.25a.75.75%200%200%201%20.673.418l1.882%203.815%204.21.612a.75.75%200%200%201%20.416%201.279l-3.046%202.97.719%204.192a.751.751%200%200%201-1.088.791L8%2012.347l-3.766%201.98a.75.75%200%200%201-1.088-.79l.72-4.194L.818%206.374a.75.75%200%200%201%20.416-1.28l4.21-.611L7.327.668A.75.75%200%200%201%208%20.25m0%202.445L6.615%205.5a.75.75%200%200%201-.564.41l-3.097.45%202.24%202.184a.75.75%200%200%201%20.216.664l-.528%203.084%202.769-1.456a.75.75%200%200%201%20.698%200l2.77%201.456-.53-3.084a.75.75%200%200%201%20.216-.664l2.24-2.183-3.096-.45a.75.75%200%200%201-.564-.41z%22/%3E%3C/svg%3E%27%29%3B--md-source-version-icon%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cpath%20d%3D%22M1%207.775V2.75C1%201.784%201.784%201%202.75%201h5.025c.464%200%20.91.184%201.238.513l6.25%206.25a1.75%201.75%200%200%201%200%202.474l-5.026%205.026a1.75%201.75%200%200%201-2.474%200l-6.25-6.25A1.75%201.75%200%200%201%201%207.775m1.5%200c0%20.066.026.13.073.177l6.25%206.25a.25.25%200%200%200%20.354%200l5.025-5.025a.25.25%200%200%200%200-.354l-6.25-6.25a.25.25%200%200%200-.177-.073H2.75a.25.25%200%200%200-.25.25ZM6%205a1%201%200%201%201%200%202%201%201%200%200%201%200-2%22/%3E%3C/svg%3E%27%29%7D.md-source%7B-webkit-backface-visibility%3Ahidden%3Bbackface-visibility%3Ahidden%3Bdisplay%3Ablock%3Bfont-size%3A.65rem%3Bline-height%3A1.2%3Boutline-color%3Avar%28--md-accent-fg-color%29%3Btransition%3Aopacity%20.25s%3Bwhite-space%3Anowrap%7D.md-source%3Ahover%7Bopacity%3A.7%7D.md-source__icon%7Bdisplay%3Ainline-block%3Bheight%3A2.4rem%3Bvertical-align%3Amiddle%3Bwidth%3A2rem%7D%5Bdir%3Dltr%5D%20.md-source__icon%20svg%7Bmargin-left%3A.6rem%7D%5Bdir%3Drtl%5D%20.md-source__icon%20svg%7Bmargin-right%3A.6rem%7D.md-source__icon%20svg%7Bmargin-top%3A.6rem%7D%5Bdir%3Dltr%5D%20.md-source__icon%2B.md-source__repository%7Bpadding-left%3A2rem%7D%5Bdir%3Drtl%5D%20.md-source__icon%2B.md-source__repository%7Bpadding-right%3A2rem%7D%5Bdir%3Dltr%5D%20.md-source__icon%2B.md-source__repository%7Bmargin-left%3A-2rem%7D%5Bdir%3Drtl%5D%20.md-source__icon%2B.md-source__repository%7Bmargin-right%3A-2rem%7D%5Bdir%3Dltr%5D%20.md-source__repository%7Bmargin-left%3A.6rem%7D%5Bdir%3Drtl%5D%20.md-source__repository%7Bmargin-right%3A.6rem%7D.md-source__repository%7Bdisplay%3Ainline-block%3Bmax-width%3Acalc%28100%25%20-%201.2rem%29%3Boverflow%3Ahidden%3Btext-overflow%3Aellipsis%3Bvertical-align%3Amiddle%7D.md-source__facts%7Bdisplay%3Aflex%3Bfont-size%3A.55rem%3Bgap%3A.4rem%3Blist-style-type%3Anone%3Bmargin%3A.1rem%200%200%3Bopacity%3A.75%3Boverflow%3Ahidden%3Bpadding%3A0%3Bwidth%3A100%25%7D.md-source__repository--active%20.md-source__facts%7Banimation%3Afacts%20.25s%20ease-in%7D.md-source__fact%7Boverflow%3Ahidden%3Btext-overflow%3Aellipsis%7D.md-source__repository--active%20.md-source__fact%7Banimation%3Afact%20.4s%20ease-out%7D%5Bdir%3Dltr%5D%20.md-source__fact%3Abefore%7Bmargin-right%3A.1rem%7D%5Bdir%3Drtl%5D%20.md-source__fact%3Abefore%7Bmargin-left%3A.1rem%7D.md-source__fact%3Abefore%7Bbackground-color%3Acurrentcolor%3Bcontent%3A%22%22%3Bdisplay%3Ainline-block%3Bheight%3A.6rem%3B-webkit-mask-position%3Acenter%3Bmask-position%3Acenter%3B-webkit-mask-repeat%3Ano-repeat%3Bmask-repeat%3Ano-repeat%3B-webkit-mask-size%3Acontain%3Bmask-size%3Acontain%3Bvertical-align%3Atext-top%3Bwidth%3A.6rem%7D.md-source__fact%3Anth-child%281n%2B2%29%7Bflex-shrink%3A0%7D.md-source__fact--version%3Abefore%7B-webkit-mask-image%3Avar%28--md-source-version-icon%29%3Bmask-image%3Avar%28--md-source-version-icon%29%7D.md-source__fact--stars%3Abefore%7B-webkit-mask-image%3Avar%28--md-source-stars-icon%29%3Bmask-image%3Avar%28--md-source-stars-icon%29%7D.md-source__fact--forks%3Abefore%7B-webkit-mask-image%3Avar%28--md-source-forks-icon%29%3Bmask-image%3Avar%28--md-source-forks-icon%29%7D.md-source__fact--repositories%3Abefore%7B-webkit-mask-image%3Avar%28--md-source-repositories-icon%29%3Bmask-image%3Avar%28--md-source-repositories-icon%29%7D.md-source-file%7Bmargin%3A1em%200%7D%5Bdir%3Dltr%5D%20.md-source-file__fact%7Bmargin-right%3A.6rem%7D%5Bdir%3Drtl%5D%20.md-source-file__fact%7Bmargin-left%3A.6rem%7D.md-source-file__fact%7Balign-items%3Acenter%3Bcolor%3Avar%28--md-default-fg-color--light%29%3Bdisplay%3Ainline-flex%3Bfont-size%3A.68rem%3Bgap%3A.3rem%7D.md-source-file__fact%20.md-icon%7Bflex-shrink%3A0%3Bmargin-bottom%3A.05rem%7D%5Bdir%3Dltr%5D%20.md-source-file__fact%20.md-author%7Bfloat%3Aleft%7D%5Bdir%3Drtl%5D%20.md-source-file__fact%20.md-author%7Bfloat%3Aright%7D.md-source-file__fact%20.md-author%7Bmargin-right%3A.2rem%7D.md-source-file__fact%20svg%7Bwidth%3A.9rem%7D%3Aroot%7B--md-status%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M11%209h2V7h-2m1%2013c-4.41%200-8-3.59-8-8s3.59-8%208-8%208%203.59%208%208-3.59%208-8%208m0-18A10%2010%200%200%200%202%2012a10%2010%200%200%200%2010%2010%2010%2010%200%200%200%2010-10A10%2010%200%200%200%2012%202m-1%2015h2v-6h-2z%22/%3E%3C/svg%3E%27%29%3B--md-status--new%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22m23%2012-2.44-2.78.34-3.68-3.61-.82-1.89-3.18L12%203%208.6%201.54%206.71%204.72l-3.61.81.34%203.68L1%2012l2.44%202.78-.34%203.69%203.61.82%201.89%203.18L12%2021l3.4%201.46%201.89-3.18%203.61-.82-.34-3.68zm-10%205h-2v-2h2zm0-4h-2V7h2z%22/%3E%3C/svg%3E%27%29%3B--md-status--deprecated%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M9%203v1H4v2h1v13a2%202%200%200%200%202%202h10a2%202%200%200%200%202-2V6h1V4h-5V3zm0%205h2v9H9zm4%200h2v9h-2z%22/%3E%3C/svg%3E%27%29%3B--md-status--encrypted%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M12%201%203%205v6c0%205.55%203.84%2010.74%209%2012%205.16-1.26%209-6.45%209-12V5zm0%206c1.4%200%202.8%201.1%202.8%202.5V11c.6%200%201.2.6%201.2%201.3v3.5c0%20.6-.6%201.2-1.3%201.2H9.2c-.6%200-1.2-.6-1.2-1.3v-3.5c0-.6.6-1.2%201.2-1.2V9.5C9.2%208.1%2010.6%207%2012%207m0%201.2c-.8%200-1.5.5-1.5%201.3V11h3V9.5c0-.8-.7-1.3-1.5-1.3%22/%3E%3C/svg%3E%27%29%7D.md-status%3Aafter%7Bbackground-color%3Avar%28--md-default-fg-color--light%29%3Bcontent%3A%22%22%3Bdisplay%3Ainline-block%3Bheight%3A1.125em%3B-webkit-mask-image%3Avar%28--md-status%29%3Bmask-image%3Avar%28--md-status%29%3B-webkit-mask-position%3Acenter%3Bmask-position%3Acenter%3B-webkit-mask-repeat%3Ano-repeat%3Bmask-repeat%3Ano-repeat%3B-webkit-mask-size%3Acontain%3Bmask-size%3Acontain%3Bvertical-align%3Atext-bottom%3Bwidth%3A1.125em%7D.md-status%3Ahover%3Aafter%7Bbackground-color%3Acurrentcolor%7D.md-status--new%3Aafter%7B-webkit-mask-image%3Avar%28--md-status--new%29%3Bmask-image%3Avar%28--md-status--new%29%7D.md-status--deprecated%3Aafter%7B-webkit-mask-image%3Avar%28--md-status--deprecated%29%3Bmask-image%3Avar%28--md-status--deprecated%29%7D.md-status--encrypted%3Aafter%7B-webkit-mask-image%3Avar%28--md-status--encrypted%29%3Bmask-image%3Avar%28--md-status--encrypted%29%7D.md-tabs%7Bbackground-color%3Avar%28--md-primary-fg-color%29%3Bcolor%3Avar%28--md-primary-bg-color%29%3Bdisplay%3Ablock%3Bline-height%3A1.3%3Boverflow%3Aauto%3Bwidth%3A100%25%3Bz-index%3A3%7D%40media%20print%7B.md-tabs%7Bdisplay%3Anone%7D%7D%40media%20screen%20and%20%28max-width%3A76.234375em%29%7B.md-tabs%7Bdisplay%3Anone%7D%7D.md-tabs%5Bhidden%5D%7Bpointer-events%3Anone%7D%5Bdir%3Dltr%5D%20.md-tabs__list%7Bmargin-left%3A.2rem%7D%5Bdir%3Drtl%5D%20.md-tabs__list%7Bmargin-right%3A.2rem%7D.md-tabs__list%7Bcontain%3Acontent%3Bdisplay%3Aflex%3Blist-style%3Anone%3Bmargin%3A0%3Boverflow%3Aauto%3Bpadding%3A0%3Bscrollbar-width%3Anone%3Bwhite-space%3Anowrap%7D.md-tabs__list%3A%3A-webkit-scrollbar%7Bdisplay%3Anone%7D.md-tabs__item%7Bheight%3A2.4rem%3Bpadding-left%3A.6rem%3Bpadding-right%3A.6rem%7D.md-tabs__item--active%20.md-tabs__link%7Bcolor%3Ainherit%3Bopacity%3A1%7D.md-tabs__link%7B-webkit-backface-visibility%3Ahidden%3Bbackface-visibility%3Ahidden%3Bdisplay%3Aflex%3Bfont-size%3A.7rem%3Bmargin-top%3A.8rem%3Bopacity%3A.7%3Boutline-color%3Avar%28--md-accent-fg-color%29%3Boutline-offset%3A.2rem%3Btransition%3Atransform%20.4s%20cubic-bezier%28.1%2C.7%2C.1%2C1%29%2Copacity%20.25s%7D.md-tabs__link%3Afocus%2C.md-tabs__link%3Ahover%7Bcolor%3Ainherit%3Bopacity%3A1%7D%5Bdir%3Dltr%5D%20.md-tabs__link%20svg%7Bmargin-right%3A.4rem%7D%5Bdir%3Drtl%5D%20.md-tabs__link%20svg%7Bmargin-left%3A.4rem%7D.md-tabs__link%20svg%7Bfill%3Acurrentcolor%3Bheight%3A1.3em%7D.md-tabs__item%3Anth-child%282%29%20.md-tabs__link%7Btransition-delay%3A20ms%7D.md-tabs__item%3Anth-child%283%29%20.md-tabs__link%7Btransition-delay%3A40ms%7D.md-tabs__item%3Anth-child%284%29%20.md-tabs__link%7Btransition-delay%3A60ms%7D.md-tabs__item%3Anth-child%285%29%20.md-tabs__link%7Btransition-delay%3A80ms%7D.md-tabs__item%3Anth-child%286%29%20.md-tabs__link%7Btransition-delay%3A.1s%7D.md-tabs__item%3Anth-child%287%29%20.md-tabs__link%7Btransition-delay%3A.12s%7D.md-tabs__item%3Anth-child%288%29%20.md-tabs__link%7Btransition-delay%3A.14s%7D.md-tabs__item%3Anth-child%289%29%20.md-tabs__link%7Btransition-delay%3A.16s%7D.md-tabs__item%3Anth-child%2810%29%20.md-tabs__link%7Btransition-delay%3A.18s%7D.md-tabs__item%3Anth-child%2811%29%20.md-tabs__link%7Btransition-delay%3A.2s%7D.md-tabs__item%3Anth-child%2812%29%20.md-tabs__link%7Btransition-delay%3A.22s%7D.md-tabs__item%3Anth-child%2813%29%20.md-tabs__link%7Btransition-delay%3A.24s%7D.md-tabs__item%3Anth-child%2814%29%20.md-tabs__link%7Btransition-delay%3A.26s%7D.md-tabs__item%3Anth-child%2815%29%20.md-tabs__link%7Btransition-delay%3A.28s%7D.md-tabs__item%3Anth-child%2816%29%20.md-tabs__link%7Btransition-delay%3A.3s%7D.md-tabs%5Bhidden%5D%20.md-tabs__link%7Bopacity%3A0%3Btransform%3AtranslateY%2850%25%29%3Btransition%3Atransform%200ms%20.1s%2Copacity%20.1s%7D%3Aroot%7B--md-tag-icon%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22m5.41%2021%20.71-4h-4l.35-2h4l1.06-6h-4l.35-2h4l.71-4h2l-.71%204h6l.71-4h2l-.71%204h4l-.35%202h-4l-1.06%206h4l-.35%202h-4l-.71%204h-2l.71-4h-6l-.71%204zM9.53%209l-1.06%206h6l1.06-6z%22/%3E%3C/svg%3E%27%29%7D.md-typeset%20.md-tags%3Anot%28%5Bhidden%5D%29%7Bdisplay%3Ainline-flex%3Bflex-wrap%3Awrap%3Bgap%3A.5em%3Bmargin-bottom%3A.75em%3Bmargin-top%3A-.125em%7D.md-typeset%20.md-tag%7Balign-items%3Acenter%3Bbackground%3Avar%28--md-default-fg-color--lightest%29%3Bborder-radius%3A2.4rem%3Bdisplay%3Ainline-flex%3Bfont-size%3A.64rem%3Bfont-size%3Amin%28.8em%2C.64rem%29%3Bfont-weight%3A700%3Bgap%3A.5em%3Bletter-spacing%3Anormal%3Bline-height%3A1.6%3Bpadding%3A.3125em%20.78125em%7D.md-typeset%20.md-tag%5Bhref%5D%7B-webkit-tap-highlight-color%3Atransparent%3Bcolor%3Ainherit%3Boutline%3Anone%3Btransition%3Acolor%20125ms%2Cbackground-color%20125ms%7D.md-typeset%20.md-tag%5Bhref%5D%3Afocus%2C.md-typeset%20.md-tag%5Bhref%5D%3Ahover%7Bbackground-color%3Avar%28--md-accent-fg-color%29%3Bcolor%3Avar%28--md-accent-bg-color%29%7D%5Bid%5D%3E.md-typeset%20.md-tag%7Bvertical-align%3Atext-top%7D.md-typeset%20.md-tag-icon%3Abefore%7Bbackground-color%3Avar%28--md-default-fg-color--lighter%29%3Bcontent%3A%22%22%3Bdisplay%3Ainline-block%3Bheight%3A1.2em%3B-webkit-mask-image%3Avar%28--md-tag-icon%29%3Bmask-image%3Avar%28--md-tag-icon%29%3B-webkit-mask-position%3Acenter%3Bmask-position%3Acenter%3B-webkit-mask-repeat%3Ano-repeat%3Bmask-repeat%3Ano-repeat%3B-webkit-mask-size%3Acontain%3Bmask-size%3Acontain%3Btransition%3Abackground-color%20125ms%3Bvertical-align%3Atext-bottom%3Bwidth%3A1.2em%7D.md-typeset%20.md-tag-icon%5Bhref%5D%3Afocus%3Abefore%2C.md-typeset%20.md-tag-icon%5Bhref%5D%3Ahover%3Abefore%7Bbackground-color%3Avar%28--md-accent-bg-color%29%7D%40keyframes%20pulse%7B0%25%7Btransform%3Ascale%28.95%29%7D75%25%7Btransform%3Ascale%281%29%7Dto%7Btransform%3Ascale%28.95%29%7D%7D%3Aroot%7B--md-annotation-bg-icon%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M12%202A10%2010%200%200%200%202%2012a10%2010%200%200%200%2010%2010%2010%2010%200%200%200%2010-10A10%2010%200%200%200%2012%202%22/%3E%3C/svg%3E%27%29%3B--md-annotation-icon%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M17%2013h-4v4h-2v-4H7v-2h4V7h2v4h4m-5-9A10%2010%200%200%200%202%2012a10%2010%200%200%200%2010%2010%2010%2010%200%200%200%2010-10A10%2010%200%200%200%2012%202%22/%3E%3C/svg%3E%27%29%7D.md-tooltip%7B-webkit-backface-visibility%3Ahidden%3Bbackface-visibility%3Ahidden%3Bbackground-color%3Avar%28--md-default-bg-color%29%3Bborder-radius%3A.1rem%3Bbox-shadow%3Avar%28--md-shadow-z2%29%3Bcolor%3Avar%28--md-default-fg-color%29%3Bfont-family%3Avar%28--md-text-font-family%29%3Bleft%3Aclamp%28var%28--md-tooltip-0%2C0rem%29%20%2B%20.8rem%2Cvar%28--md-tooltip-x%29%2C100vw%20%2B%20var%28--md-tooltip-0%2C0rem%29%20%2B%20.8rem%20-%20var%28--md-tooltip-width%29%20-%202%20%2A%20.8rem%29%3Bmax-width%3Acalc%28100vw%20-%201.6rem%29%3Bopacity%3A0%3Bposition%3Aabsolute%3Btop%3Avar%28--md-tooltip-y%29%3Btransform%3AtranslateY%28-.4rem%29%3Btransition%3Atransform%200ms%20.25s%2Copacity%20.25s%2Cz-index%20.25s%3Bwidth%3Avar%28--md-tooltip-width%29%3Bz-index%3A0%7D.md-tooltip--active%7Bopacity%3A1%3Btransform%3AtranslateY%280%29%3Btransition%3Atransform%20.25s%20cubic-bezier%28.1%2C.7%2C.1%2C1%29%2Copacity%20.25s%2Cz-index%200ms%3Bz-index%3A2%7D.md-tooltip--inline%7Bfont-weight%3A700%3B-webkit-user-select%3Anone%3Buser-select%3Anone%3Bwidth%3Aauto%7D.md-tooltip--inline%3Anot%28.md-tooltip--active%29%7Btransform%3AtranslateY%28.2rem%29%20scale%28.9%29%7D.md-tooltip--inline%20.md-tooltip__inner%7Bfont-size%3A.5rem%3Bpadding%3A.2rem%20.4rem%7D%5Bhidden%5D%2B.md-tooltip--inline%7Bdisplay%3Anone%7D.focus-visible%3E.md-tooltip%2C.md-tooltip%3Atarget%7Boutline%3Avar%28--md-accent-fg-color%29%20auto%7D.md-tooltip__inner%7Bfont-size%3A.64rem%3Bpadding%3A.8rem%7D.md-tooltip__inner.md-typeset%3E%3Afirst-child%7Bmargin-top%3A0%7D.md-tooltip__inner.md-typeset%3E%3Alast-child%7Bmargin-bottom%3A0%7D.md-annotation%7Bfont-style%3Anormal%3Bfont-weight%3A400%3Boutline%3Anone%3Btext-align%3Ainitial%3Bvertical-align%3Atext-bottom%3Bwhite-space%3Anormal%7D%5Bdir%3Drtl%5D%20.md-annotation%7Bdirection%3Artl%7Dcode%20.md-annotation%7Bfont-family%3Avar%28--md-code-font-family%29%3Bfont-size%3Ainherit%7D.md-annotation%3Anot%28%5Bhidden%5D%29%7Bdisplay%3Ainline-block%3Bline-height%3A1.25%7D.md-annotation__index%7Bborder-radius%3A.01px%3Bcursor%3Apointer%3Bdisplay%3Ainline-block%3Bmargin-left%3A.4ch%3Bmargin-right%3A.4ch%3Boutline%3Anone%3Boverflow%3Ahidden%3Bposition%3Arelative%3B-webkit-user-select%3Anone%3Buser-select%3Anone%3Bvertical-align%3Atext-top%3Bz-index%3A0%7D.md-annotation%20.md-annotation__index%7Btransition%3Az-index%20.25s%7D%40media%20screen%7B.md-annotation__index%7Bwidth%3A2.2ch%7D%5Bdata-md-visible%5D%3E.md-annotation__index%7Banimation%3Apulse%202s%20infinite%7D.md-annotation__index%3Abefore%7Bbackground%3Avar%28--md-default-bg-color%29%3B-webkit-mask-image%3Avar%28--md-annotation-bg-icon%29%3Bmask-image%3Avar%28--md-annotation-bg-icon%29%7D.md-annotation__index%3Aafter%2C.md-annotation__index%3Abefore%7Bcontent%3A%22%22%3Bheight%3A2.2ch%3B-webkit-mask-position%3Acenter%3Bmask-position%3Acenter%3B-webkit-mask-repeat%3Ano-repeat%3Bmask-repeat%3Ano-repeat%3B-webkit-mask-size%3Acontain%3Bmask-size%3Acontain%3Bposition%3Aabsolute%3Btop%3A-.1ch%3Bwidth%3A2.2ch%3Bz-index%3A-1%7D.md-annotation__index%3Aafter%7Bbackground-color%3Avar%28--md-default-fg-color--lighter%29%3B-webkit-mask-image%3Avar%28--md-annotation-icon%29%3Bmask-image%3Avar%28--md-annotation-icon%29%3Btransform%3Ascale%281.0001%29%3Btransition%3Abackground-color%20.25s%2Ctransform%20.25s%7D.md-tooltip--active%2B.md-annotation__index%3Aafter%7Btransform%3Arotate%2845deg%29%7D.md-tooltip--active%2B.md-annotation__index%3Aafter%2C%3Ahover%3E.md-annotation__index%3Aafter%7Bbackground-color%3Avar%28--md-accent-fg-color%29%7D%7D.md-tooltip--active%2B.md-annotation__index%7Banimation-play-state%3Apaused%3Btransition-duration%3A0ms%3Bz-index%3A2%7D.md-annotation__index%20%5Bdata-md-annotation-id%5D%7Bdisplay%3Ainline-block%7D%40media%20print%7B.md-annotation__index%20%5Bdata-md-annotation-id%5D%7Bbackground%3Avar%28--md-default-fg-color--lighter%29%3Bborder-radius%3A2ch%3Bcolor%3Avar%28--md-default-bg-color%29%3Bfont-weight%3A700%3Bpadding%3A0%20.6ch%3Bwhite-space%3Anowrap%7D.md-annotation__index%20%5Bdata-md-annotation-id%5D%3Aafter%7Bcontent%3Aattr%28data-md-annotation-id%29%7D%7D.md-typeset%20.md-annotation-list%7Bcounter-reset%3Axxx%3Blist-style%3Anone%7D.md-typeset%20.md-annotation-list%20li%7Bposition%3Arelative%7D%5Bdir%3Dltr%5D%20.md-typeset%20.md-annotation-list%20li%3Abefore%7Bleft%3A-2.125em%7D%5Bdir%3Drtl%5D%20.md-typeset%20.md-annotation-list%20li%3Abefore%7Bright%3A-2.125em%7D.md-typeset%20.md-annotation-list%20li%3Abefore%7Bbackground%3Avar%28--md-default-fg-color--lighter%29%3Bborder-radius%3A2ch%3Bcolor%3Avar%28--md-default-bg-color%29%3Bcontent%3Acounter%28xxx%29%3Bcounter-increment%3Axxx%3Bfont-size%3A.8875em%3Bfont-weight%3A700%3Bheight%3A2ch%3Bline-height%3A1.25%3Bmin-width%3A2ch%3Bpadding%3A0%20.6ch%3Bposition%3Aabsolute%3Btext-align%3Acenter%3Btop%3A.25em%7D%3Aroot%7B--md-tooltip-width%3A20rem%3B--md-tooltip-tail%3A0.3rem%7D.md-tooltip2%7B-webkit-backface-visibility%3Ahidden%3Bbackface-visibility%3Ahidden%3Bcolor%3Avar%28--md-default-fg-color%29%3Bfont-family%3Avar%28--md-text-font-family%29%3Bopacity%3A0%3Bpointer-events%3Anone%3Bposition%3Aabsolute%3Btop%3Acalc%28var%28--md-tooltip-host-y%29%20%2B%20var%28--md-tooltip-y%29%29%3Btransform%3AtranslateY%28-.4rem%29%3Btransform-origin%3Acalc%28var%28--md-tooltip-host-x%29%20%2B%20var%28--md-tooltip-x%29%29%200%3Btransition%3Atransform%200ms%20.25s%2Copacity%20.25s%2Cz-index%20.25s%3Bwidth%3A100%25%3Bz-index%3A0%7D.md-tooltip2%3Abefore%7Bborder-left%3Avar%28--md-tooltip-tail%29%20solid%20%230000%3Bborder-right%3Avar%28--md-tooltip-tail%29%20solid%20%230000%3Bcontent%3A%22%22%3Bdisplay%3Ablock%3Bleft%3Aclamp%281.5%20%2A%20.8rem%2Cvar%28--md-tooltip-host-x%29%20%2B%20var%28--md-tooltip-x%29%20-%20var%28--md-tooltip-tail%29%2C100vw%20-%202%20%2A%20var%28--md-tooltip-tail%29%20-%201.5%20%2A%20.8rem%29%3Bposition%3Aabsolute%3Bz-index%3A1%7D.md-tooltip2--top%3Abefore%7Bborder-top%3Avar%28--md-tooltip-tail%29%20solid%20var%28--md-default-bg-color%29%3Bbottom%3Acalc%28var%28--md-tooltip-tail%29%2A-1%20%2B%20.025rem%29%3Bfilter%3Adrop-shadow%280%201px%200%20hsla%280%2C0%25%2C0%25%2C.05%29%29%7D.md-tooltip2--bottom%3Abefore%7Bborder-bottom%3Avar%28--md-tooltip-tail%29%20solid%20var%28--md-default-bg-color%29%3Bfilter%3Adrop-shadow%280%20-1px%200%20hsla%280%2C0%25%2C0%25%2C.05%29%29%3Btop%3Acalc%28var%28--md-tooltip-tail%29%2A-1%20%2B%20.025rem%29%7D.md-tooltip2--active%7Bopacity%3A1%3Btransform%3AtranslateY%280%29%3Btransition%3Atransform%20.4s%20cubic-bezier%280%2C1%2C.5%2C1%29%2Copacity%20.25s%2Cz-index%200ms%3Bz-index%3A2%7D.md-tooltip2__inner%7Bscrollbar-gutter%3Astable%3Bbackground-color%3Avar%28--md-default-bg-color%29%3Bborder-radius%3A.1rem%3Bbox-shadow%3Avar%28--md-shadow-z2%29%3Bleft%3Aclamp%28.8rem%2Cvar%28--md-tooltip-host-x%29%20-%20.8rem%2C100vw%20-%20var%28--md-tooltip-width%29%20-%20.8rem%29%3Bmax-height%3A40vh%3Bmax-width%3Acalc%28100vw%20-%201.6rem%29%3Bposition%3Arelative%3Bscrollbar-width%3Athin%7D.md-tooltip2__inner%3A%3A-webkit-scrollbar%7Bheight%3A.2rem%3Bwidth%3A.2rem%7D.md-tooltip2__inner%3A%3A-webkit-scrollbar-thumb%7Bbackground-color%3Avar%28--md-default-fg-color--lighter%29%7D.md-tooltip2__inner%3A%3A-webkit-scrollbar-thumb%3Ahover%7Bbackground-color%3Avar%28--md-accent-fg-color%29%7D%5Brole%3Dtooltip%5D%3E.md-tooltip2__inner%7Bfont-size%3A.5rem%3Bfont-weight%3A700%3Bleft%3Aclamp%28.8rem%2Cvar%28--md-tooltip-host-x%29%20%2B%20var%28--md-tooltip-x%29%20-%20var%28--md-tooltip-width%29/2%2C100vw%20-%20var%28--md-tooltip-width%29%20-%20.8rem%29%3Bmax-width%3Amin%28100vw%20-%202%20%2A%20.8rem%2C400px%29%3Bpadding%3A.2rem%20.4rem%3B-webkit-user-select%3Anone%3Buser-select%3Anone%3Bwidth%3A-moz-fit-content%3Bwidth%3Afit-content%7D.md-tooltip2__inner.md-typeset%3E%3Afirst-child%7Bmargin-top%3A0%7D.md-tooltip2__inner.md-typeset%3E%3Alast-child%7Bmargin-bottom%3A0%7D%5Bdir%3Dltr%5D%20.md-top%7Bmargin-left%3A50%25%7D%5Bdir%3Drtl%5D%20.md-top%7Bmargin-right%3A50%25%7D.md-top%7Bbackground-color%3Avar%28--md-default-bg-color%29%3Bborder-radius%3A1.6rem%3Bbox-shadow%3Avar%28--md-shadow-z2%29%3Bcolor%3Avar%28--md-default-fg-color--light%29%3Bcursor%3Apointer%3Bdisplay%3Ablock%3Bfont-size%3A.7rem%3Boutline%3Anone%3Bpadding%3A.4rem%20.8rem%3Bposition%3Afixed%3Btop%3A3.2rem%3Btransform%3Atranslate%28-50%25%29%3Btransition%3Acolor%20125ms%2Cbackground-color%20125ms%2Ctransform%20125ms%20cubic-bezier%28.4%2C0%2C.2%2C1%29%2Copacity%20125ms%3Bz-index%3A2%7D%40media%20print%7B.md-top%7Bdisplay%3Anone%7D%7D%5Bdir%3Drtl%5D%20.md-top%7Btransform%3Atranslate%2850%25%29%7D.md-top%5Bhidden%5D%7Bopacity%3A0%3Bpointer-events%3Anone%3Btransform%3Atranslate%28-50%25%2C.2rem%29%3Btransition-duration%3A0ms%7D%5Bdir%3Drtl%5D%20.md-top%5Bhidden%5D%7Btransform%3Atranslate%2850%25%2C.2rem%29%7D.md-top%3Afocus%2C.md-top%3Ahover%7Bbackground-color%3Avar%28--md-accent-fg-color%29%3Bcolor%3Avar%28--md-accent-bg-color%29%7D.md-top%20svg%7Bdisplay%3Ainline-block%3Bvertical-align%3A-.5em%7D%40keyframes%20hoverfix%7B0%25%7Bpointer-events%3Anone%7D%7D%3Aroot%7B--md-version-icon%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%20320%20512%22%3E%3C%21--%21%20Font%20Awesome%20Free%206.7.1%20by%20%40fontawesome%20-%20https%3A//fontawesome.com%20License%20-%20https%3A//fontawesome.com/license/free%20%28Icons%3A%20CC%20BY%204.0%2C%20Fonts%3A%20SIL%20OFL%201.1%2C%20Code%3A%20MIT%20License%29%20Copyright%202024%20Fonticons%2C%20Inc.--%3E%3Cpath%20d%3D%22M137.4%20374.6c12.5%2012.5%2032.8%2012.5%2045.3%200l128-128c9.2-9.2%2011.9-22.9%206.9-34.9S301%20191.9%20288%20191.9L32%20192c-12.9%200-24.6%207.8-29.6%2019.8s-2.2%2025.7%206.9%2034.9l128%20128z%22/%3E%3C/svg%3E%27%29%7D.md-version%7Bflex-shrink%3A0%3Bfont-size%3A.8rem%3Bheight%3A2.4rem%7D%5Bdir%3Dltr%5D%20.md-version__current%7Bmargin-left%3A1.4rem%3Bmargin-right%3A.4rem%7D%5Bdir%3Drtl%5D%20.md-version__current%7Bmargin-left%3A.4rem%3Bmargin-right%3A1.4rem%7D.md-version__current%7Bcolor%3Ainherit%3Bcursor%3Apointer%3Boutline%3Anone%3Bposition%3Arelative%3Btop%3A.05rem%7D%5Bdir%3Dltr%5D%20.md-version__current%3Aafter%7Bmargin-left%3A.4rem%7D%5Bdir%3Drtl%5D%20.md-version__current%3Aafter%7Bmargin-right%3A.4rem%7D.md-version__current%3Aafter%7Bbackground-color%3Acurrentcolor%3Bcontent%3A%22%22%3Bdisplay%3Ainline-block%3Bheight%3A.6rem%3B-webkit-mask-image%3Avar%28--md-version-icon%29%3Bmask-image%3Avar%28--md-version-icon%29%3B-webkit-mask-position%3Acenter%3Bmask-position%3Acenter%3B-webkit-mask-repeat%3Ano-repeat%3Bmask-repeat%3Ano-repeat%3B-webkit-mask-size%3Acontain%3Bmask-size%3Acontain%3Bwidth%3A.4rem%7D.md-version__alias%7Bmargin-left%3A.3rem%3Bopacity%3A.7%7D.md-version__list%7Bbackground-color%3Avar%28--md-default-bg-color%29%3Bborder-radius%3A.1rem%3Bbox-shadow%3Avar%28--md-shadow-z2%29%3Bcolor%3Avar%28--md-default-fg-color%29%3Blist-style-type%3Anone%3Bmargin%3A.2rem%20.8rem%3Bmax-height%3A0%3Bopacity%3A0%3Boverflow%3Aauto%3Bpadding%3A0%3Bposition%3Aabsolute%3Bscroll-snap-type%3Ay%20mandatory%3Btop%3A.15rem%3Btransition%3Amax-height%200ms%20.5s%2Copacity%20.25s%20.25s%3Bz-index%3A3%7D.md-version%3Afocus-within%20.md-version__list%2C.md-version%3Ahover%20.md-version__list%7Bmax-height%3A10rem%3Bopacity%3A1%3Btransition%3Amax-height%200ms%2Copacity%20.25s%7D%40media%20%28hover%3Anone%29%2C%28pointer%3Acoarse%29%7B.md-version%3Ahover%20.md-version__list%7Banimation%3Ahoverfix%20.25s%20forwards%7D.md-version%3Afocus-within%20.md-version__list%7Banimation%3Anone%7D%7D.md-version__item%7Bline-height%3A1.8rem%7D%5Bdir%3Dltr%5D%20.md-version__link%7Bpadding-left%3A.6rem%3Bpadding-right%3A1.2rem%7D%5Bdir%3Drtl%5D%20.md-version__link%7Bpadding-left%3A1.2rem%3Bpadding-right%3A.6rem%7D.md-version__link%7Bcursor%3Apointer%3Bdisplay%3Ablock%3Boutline%3Anone%3Bscroll-snap-align%3Astart%3Btransition%3Acolor%20.25s%2Cbackground-color%20.25s%3Bwhite-space%3Anowrap%3Bwidth%3A100%25%7D.md-version__link%3Afocus%2C.md-version__link%3Ahover%7Bcolor%3Avar%28--md-accent-fg-color%29%7D.md-version__link%3Afocus%7Bbackground-color%3Avar%28--md-default-fg-color--lightest%29%7D%3Aroot%7B--md-admonition-icon--note%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M12%202C6.47%202%202%206.47%202%2012s4.47%2010%2010%2010%2010-4.47%2010-10S17.53%202%2012%202m3.1%205.07c.14%200%20.28.05.4.16l1.27%201.27c.23.22.23.57%200%20.78l-1%201-2.05-2.05%201-1c.1-.11.24-.16.38-.16m-1.97%201.74%202.06%202.06-6.06%206.06H7.07v-2.06z%22/%3E%3C/svg%3E%27%29%3B--md-admonition-icon--abstract%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M17%209H7V7h10m0%206H7v-2h10m-3%206H7v-2h7M12%203a1%201%200%200%201%201%201%201%201%200%200%201-1%201%201%201%200%200%201-1-1%201%201%200%200%201%201-1m7%200h-4.18C14.4%201.84%2013.3%201%2012%201s-2.4.84-2.82%202H5a2%202%200%200%200-2%202v14a2%202%200%200%200%202%202h14a2%202%200%200%200%202-2V5a2%202%200%200%200-2-2%22/%3E%3C/svg%3E%27%29%3B--md-admonition-icon--info%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M13%209h-2V7h2m0%2010h-2v-6h2m-1-9A10%2010%200%200%200%202%2012a10%2010%200%200%200%2010%2010%2010%2010%200%200%200%2010-10A10%2010%200%200%200%2012%202%22/%3E%3C/svg%3E%27%29%3B--md-admonition-icon--tip%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M17.66%2011.2c-.23-.3-.51-.56-.77-.82-.67-.6-1.43-1.03-2.07-1.66C13.33%207.26%2013%204.85%2013.95%203c-.95.23-1.78.75-2.49%201.32-2.59%202.08-3.61%205.75-2.39%208.9.04.1.08.2.08.33%200%20.22-.15.42-.35.5-.23.1-.47.04-.66-.12a.6.6%200%200%201-.14-.17c-1.13-1.43-1.31-3.48-.55-5.12C5.78%2010%204.87%2012.3%205%2014.47c.06.5.12%201%20.29%201.5.14.6.41%201.2.71%201.73%201.08%201.73%202.95%202.97%204.96%203.22%202.14.27%204.43-.12%206.07-1.6%201.83-1.66%202.47-4.32%201.53-6.6l-.13-.26c-.21-.46-.77-1.26-.77-1.26m-3.16%206.3c-.28.24-.74.5-1.1.6-1.12.4-2.24-.16-2.9-.82%201.19-.28%201.9-1.16%202.11-2.05.17-.8-.15-1.46-.28-2.23-.12-.74-.1-1.37.17-2.06.19.38.39.76.63%201.06.77%201%201.98%201.44%202.24%202.8.04.14.06.28.06.43.03.82-.33%201.72-.93%202.27%22/%3E%3C/svg%3E%27%29%3B--md-admonition-icon--success%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M21%207%209%2019l-5.5-5.5%201.41-1.41L9%2016.17%2019.59%205.59z%22/%3E%3C/svg%3E%27%29%3B--md-admonition-icon--question%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22m15.07%2011.25-.9.92C13.45%2012.89%2013%2013.5%2013%2015h-2v-.5c0-1.11.45-2.11%201.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41a2%202%200%200%200-2-2%202%202%200%200%200-2%202H8a4%204%200%200%201%204-4%204%204%200%200%201%204%204%203.2%203.2%200%200%201-.93%202.25M13%2019h-2v-2h2M12%202A10%2010%200%200%200%202%2012a10%2010%200%200%200%2010%2010%2010%2010%200%200%200%2010-10c0-5.53-4.5-10-10-10%22/%3E%3C/svg%3E%27%29%3B--md-admonition-icon--warning%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M13%2014h-2V9h2m0%209h-2v-2h2M1%2021h22L12%202z%22/%3E%3C/svg%3E%27%29%3B--md-admonition-icon--failure%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M19%206.41%2017.59%205%2012%2010.59%206.41%205%205%206.41%2010.59%2012%205%2017.59%206.41%2019%2012%2013.41%2017.59%2019%2019%2017.59%2013.41%2012z%22/%3E%3C/svg%3E%27%29%3B--md-admonition-icon--danger%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22m11.5%2020%204.86-9.73H13V4l-5%209.73h3.5zM12%202c2.75%200%205.1%201%207.05%202.95S22%209.25%2022%2012s-1%205.1-2.95%207.05S14.75%2022%2012%2022s-5.1-1-7.05-2.95S2%2014.75%202%2012s1-5.1%202.95-7.05S9.25%202%2012%202%22/%3E%3C/svg%3E%27%29%3B--md-admonition-icon--bug%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M11%2013h2v1h-2zm10-8v6c0%205.5-3.8%2010.7-9%2012-5.2-1.3-9-6.5-9-12V5l9-4zm-4%205h-2.2c-.2-.6-.6-1.1-1.1-1.5l1.2-1.2-.7-.7L12.8%208H12c-.2%200-.5%200-.7.1L9.9%206.6l-.8.8%201.2%201.2c-.5.3-.9.8-1.1%201.4H7v1h2v1H7v1h2v1H7v1h2.2c.4%201.2%201.5%202%202.8%202s2.4-.8%202.8-2H17v-1h-2v-1h2v-1h-2v-1h2zm-6%202h2v-1h-2z%22/%3E%3C/svg%3E%27%29%3B--md-admonition-icon--example%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M7%202v2h1v14a4%204%200%200%200%204%204%204%204%200%200%200%204-4V4h1V2zm4%2014c-.6%200-1-.4-1-1s.4-1%201-1%201%20.4%201%201-.4%201-1%201m2-4c-.6%200-1-.4-1-1s.4-1%201-1%201%20.4%201%201-.4%201-1%201m1-5h-4V4h4z%22/%3E%3C/svg%3E%27%29%3B--md-admonition-icon--quote%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M14%2017h3l2-4V7h-6v6h3M6%2017h3l2-4V7H5v6h3z%22/%3E%3C/svg%3E%27%29%7D.md-typeset%20.admonition%2C.md-typeset%20details%7Bbackground-color%3Avar%28--md-admonition-bg-color%29%3Bborder%3A.075rem%20solid%20%23448aff%3Bborder-radius%3A.2rem%3Bbox-shadow%3Avar%28--md-shadow-z1%29%3Bcolor%3Avar%28--md-admonition-fg-color%29%3Bdisplay%3Aflow-root%3Bfont-size%3A.64rem%3Bmargin%3A1.5625em%200%3Bpadding%3A0%20.6rem%3Bpage-break-inside%3Aavoid%3Btransition%3Abox-shadow%20125ms%7D%40media%20print%7B.md-typeset%20.admonition%2C.md-typeset%20details%7Bbox-shadow%3Anone%7D%7D.md-typeset%20.admonition%3Afocus-within%2C.md-typeset%20details%3Afocus-within%7Bbox-shadow%3A0%200%200%20.2rem%20%23448aff1a%7D.md-typeset%20.admonition%3E%2A%2C.md-typeset%20details%3E%2A%7Bbox-sizing%3Aborder-box%7D.md-typeset%20.admonition%20.admonition%2C.md-typeset%20.admonition%20details%2C.md-typeset%20details%20.admonition%2C.md-typeset%20details%20details%7Bmargin-bottom%3A1em%3Bmargin-top%3A1em%7D.md-typeset%20.admonition%20.md-typeset__scrollwrap%2C.md-typeset%20details%20.md-typeset__scrollwrap%7Bmargin%3A1em%20-.6rem%7D.md-typeset%20.admonition%20.md-typeset__table%2C.md-typeset%20details%20.md-typeset__table%7Bpadding%3A0%20.6rem%7D.md-typeset%20.admonition%3E.tabbed-set%3Aonly-child%2C.md-typeset%20details%3E.tabbed-set%3Aonly-child%7Bmargin-top%3A0%7Dhtml%20.md-typeset%20.admonition%3E%3Alast-child%2Chtml%20.md-typeset%20details%3E%3Alast-child%7Bmargin-bottom%3A.6rem%7D%5Bdir%3Dltr%5D%20.md-typeset%20.admonition-title%2C%5Bdir%3Dltr%5D%20.md-typeset%20summary%7Bpadding-left%3A2rem%3Bpadding-right%3A.6rem%7D%5Bdir%3Drtl%5D%20.md-typeset%20.admonition-title%2C%5Bdir%3Drtl%5D%20.md-typeset%20summary%7Bpadding-left%3A.6rem%3Bpadding-right%3A2rem%7D%5Bdir%3Dltr%5D%20.md-typeset%20.admonition-title%2C%5Bdir%3Dltr%5D%20.md-typeset%20summary%7Bborder-left-width%3A.2rem%7D%5Bdir%3Drtl%5D%20.md-typeset%20.admonition-title%2C%5Bdir%3Drtl%5D%20.md-typeset%20summary%7Bborder-right-width%3A.2rem%7D%5Bdir%3Dltr%5D%20.md-typeset%20.admonition-title%2C%5Bdir%3Dltr%5D%20.md-typeset%20summary%7Bborder-top-left-radius%3A.1rem%7D%5Bdir%3Dltr%5D%20.md-typeset%20.admonition-title%2C%5Bdir%3Dltr%5D%20.md-typeset%20summary%2C%5Bdir%3Drtl%5D%20.md-typeset%20.admonition-title%2C%5Bdir%3Drtl%5D%20.md-typeset%20summary%7Bborder-top-right-radius%3A.1rem%7D%5Bdir%3Drtl%5D%20.md-typeset%20.admonition-title%2C%5Bdir%3Drtl%5D%20.md-typeset%20summary%7Bborder-top-left-radius%3A.1rem%7D.md-typeset%20.admonition-title%2C.md-typeset%20summary%7Bbackground-color%3A%23448aff1a%3Bborder%3Anone%3Bfont-weight%3A700%3Bmargin%3A0%20-.6rem%3Bpadding-bottom%3A.4rem%3Bpadding-top%3A.4rem%3Bposition%3Arelative%7Dhtml%20.md-typeset%20.admonition-title%3Alast-child%2Chtml%20.md-typeset%20summary%3Alast-child%7Bmargin-bottom%3A0%7D%5Bdir%3Dltr%5D%20.md-typeset%20.admonition-title%3Abefore%2C%5Bdir%3Dltr%5D%20.md-typeset%20summary%3Abefore%7Bleft%3A.6rem%7D%5Bdir%3Drtl%5D%20.md-typeset%20.admonition-title%3Abefore%2C%5Bdir%3Drtl%5D%20.md-typeset%20summary%3Abefore%7Bright%3A.6rem%7D.md-typeset%20.admonition-title%3Abefore%2C.md-typeset%20summary%3Abefore%7Bbackground-color%3A%23448aff%3Bcontent%3A%22%22%3Bheight%3A1rem%3B-webkit-mask-image%3Avar%28--md-admonition-icon--note%29%3Bmask-image%3Avar%28--md-admonition-icon--note%29%3B-webkit-mask-position%3Acenter%3Bmask-position%3Acenter%3B-webkit-mask-repeat%3Ano-repeat%3Bmask-repeat%3Ano-repeat%3B-webkit-mask-size%3Acontain%3Bmask-size%3Acontain%3Bposition%3Aabsolute%3Btop%3A.625em%3Bwidth%3A1rem%7D.md-typeset%20.admonition-title%20code%2C.md-typeset%20summary%20code%7Bbox-shadow%3A0%200%200%20.05rem%20var%28--md-default-fg-color--lightest%29%7D.md-typeset%20.admonition.note%2C.md-typeset%20details.note%7Bborder-color%3A%23448aff%7D.md-typeset%20.admonition.note%3Afocus-within%2C.md-typeset%20details.note%3Afocus-within%7Bbox-shadow%3A0%200%200%20.2rem%20%23448aff1a%7D.md-typeset%20.note%3E.admonition-title%2C.md-typeset%20.note%3Esummary%7Bbackground-color%3A%23448aff1a%7D.md-typeset%20.note%3E.admonition-title%3Abefore%2C.md-typeset%20.note%3Esummary%3Abefore%7Bbackground-color%3A%23448aff%3B-webkit-mask-image%3Avar%28--md-admonition-icon--note%29%3Bmask-image%3Avar%28--md-admonition-icon--note%29%7D.md-typeset%20.note%3E.admonition-title%3Aafter%2C.md-typeset%20.note%3Esummary%3Aafter%7Bcolor%3A%23448aff%7D.md-typeset%20.admonition.abstract%2C.md-typeset%20details.abstract%7Bborder-color%3A%2300b0ff%7D.md-typeset%20.admonition.abstract%3Afocus-within%2C.md-typeset%20details.abstract%3Afocus-within%7Bbox-shadow%3A0%200%200%20.2rem%20%2300b0ff1a%7D.md-typeset%20.abstract%3E.admonition-title%2C.md-typeset%20.abstract%3Esummary%7Bbackground-color%3A%2300b0ff1a%7D.md-typeset%20.abstract%3E.admonition-title%3Abefore%2C.md-typeset%20.abstract%3Esummary%3Abefore%7Bbackground-color%3A%2300b0ff%3B-webkit-mask-image%3Avar%28--md-admonition-icon--abstract%29%3Bmask-image%3Avar%28--md-admonition-icon--abstract%29%7D.md-typeset%20.abstract%3E.admonition-title%3Aafter%2C.md-typeset%20.abstract%3Esummary%3Aafter%7Bcolor%3A%2300b0ff%7D.md-typeset%20.admonition.info%2C.md-typeset%20details.info%7Bborder-color%3A%2300b8d4%7D.md-typeset%20.admonition.info%3Afocus-within%2C.md-typeset%20details.info%3Afocus-within%7Bbox-shadow%3A0%200%200%20.2rem%20%2300b8d41a%7D.md-typeset%20.info%3E.admonition-title%2C.md-typeset%20.info%3Esummary%7Bbackground-color%3A%2300b8d41a%7D.md-typeset%20.info%3E.admonition-title%3Abefore%2C.md-typeset%20.info%3Esummary%3Abefore%7Bbackground-color%3A%2300b8d4%3B-webkit-mask-image%3Avar%28--md-admonition-icon--info%29%3Bmask-image%3Avar%28--md-admonition-icon--info%29%7D.md-typeset%20.info%3E.admonition-title%3Aafter%2C.md-typeset%20.info%3Esummary%3Aafter%7Bcolor%3A%2300b8d4%7D.md-typeset%20.admonition.tip%2C.md-typeset%20details.tip%7Bborder-color%3A%2300bfa5%7D.md-typeset%20.admonition.tip%3Afocus-within%2C.md-typeset%20details.tip%3Afocus-within%7Bbox-shadow%3A0%200%200%20.2rem%20%2300bfa51a%7D.md-typeset%20.tip%3E.admonition-title%2C.md-typeset%20.tip%3Esummary%7Bbackground-color%3A%2300bfa51a%7D.md-typeset%20.tip%3E.admonition-title%3Abefore%2C.md-typeset%20.tip%3Esummary%3Abefore%7Bbackground-color%3A%2300bfa5%3B-webkit-mask-image%3Avar%28--md-admonition-icon--tip%29%3Bmask-image%3Avar%28--md-admonition-icon--tip%29%7D.md-typeset%20.tip%3E.admonition-title%3Aafter%2C.md-typeset%20.tip%3Esummary%3Aafter%7Bcolor%3A%2300bfa5%7D.md-typeset%20.admonition.success%2C.md-typeset%20details.success%7Bborder-color%3A%2300c853%7D.md-typeset%20.admonition.success%3Afocus-within%2C.md-typeset%20details.success%3Afocus-within%7Bbox-shadow%3A0%200%200%20.2rem%20%2300c8531a%7D.md-typeset%20.success%3E.admonition-title%2C.md-typeset%20.success%3Esummary%7Bbackground-color%3A%2300c8531a%7D.md-typeset%20.success%3E.admonition-title%3Abefore%2C.md-typeset%20.success%3Esummary%3Abefore%7Bbackground-color%3A%2300c853%3B-webkit-mask-image%3Avar%28--md-admonition-icon--success%29%3Bmask-image%3Avar%28--md-admonition-icon--success%29%7D.md-typeset%20.success%3E.admonition-title%3Aafter%2C.md-typeset%20.success%3Esummary%3Aafter%7Bcolor%3A%2300c853%7D.md-typeset%20.admonition.question%2C.md-typeset%20details.question%7Bborder-color%3A%2364dd17%7D.md-typeset%20.admonition.question%3Afocus-within%2C.md-typeset%20details.question%3Afocus-within%7Bbox-shadow%3A0%200%200%20.2rem%20%2364dd171a%7D.md-typeset%20.question%3E.admonition-title%2C.md-typeset%20.question%3Esummary%7Bbackground-color%3A%2364dd171a%7D.md-typeset%20.question%3E.admonition-title%3Abefore%2C.md-typeset%20.question%3Esummary%3Abefore%7Bbackground-color%3A%2364dd17%3B-webkit-mask-image%3Avar%28--md-admonition-icon--question%29%3Bmask-image%3Avar%28--md-admonition-icon--question%29%7D.md-typeset%20.question%3E.admonition-title%3Aafter%2C.md-typeset%20.question%3Esummary%3Aafter%7Bcolor%3A%2364dd17%7D.md-typeset%20.admonition.warning%2C.md-typeset%20details.warning%7Bborder-color%3A%23ff9100%7D.md-typeset%20.admonition.warning%3Afocus-within%2C.md-typeset%20details.warning%3Afocus-within%7Bbox-shadow%3A0%200%200%20.2rem%20%23ff91001a%7D.md-typeset%20.warning%3E.admonition-title%2C.md-typeset%20.warning%3Esummary%7Bbackground-color%3A%23ff91001a%7D.md-typeset%20.warning%3E.admonition-title%3Abefore%2C.md-typeset%20.warning%3Esummary%3Abefore%7Bbackground-color%3A%23ff9100%3B-webkit-mask-image%3Avar%28--md-admonition-icon--warning%29%3Bmask-image%3Avar%28--md-admonition-icon--warning%29%7D.md-typeset%20.warning%3E.admonition-title%3Aafter%2C.md-typeset%20.warning%3Esummary%3Aafter%7Bcolor%3A%23ff9100%7D.md-typeset%20.admonition.failure%2C.md-typeset%20details.failure%7Bborder-color%3A%23ff5252%7D.md-typeset%20.admonition.failure%3Afocus-within%2C.md-typeset%20details.failure%3Afocus-within%7Bbox-shadow%3A0%200%200%20.2rem%20%23ff52521a%7D.md-typeset%20.failure%3E.admonition-title%2C.md-typeset%20.failure%3Esummary%7Bbackground-color%3A%23ff52521a%7D.md-typeset%20.failure%3E.admonition-title%3Abefore%2C.md-typeset%20.failure%3Esummary%3Abefore%7Bbackground-color%3A%23ff5252%3B-webkit-mask-image%3Avar%28--md-admonition-icon--failure%29%3Bmask-image%3Avar%28--md-admonition-icon--failure%29%7D.md-typeset%20.failure%3E.admonition-title%3Aafter%2C.md-typeset%20.failure%3Esummary%3Aafter%7Bcolor%3A%23ff5252%7D.md-typeset%20.admonition.danger%2C.md-typeset%20details.danger%7Bborder-color%3A%23ff1744%7D.md-typeset%20.admonition.danger%3Afocus-within%2C.md-typeset%20details.danger%3Afocus-within%7Bbox-shadow%3A0%200%200%20.2rem%20%23ff17441a%7D.md-typeset%20.danger%3E.admonition-title%2C.md-typeset%20.danger%3Esummary%7Bbackground-color%3A%23ff17441a%7D.md-typeset%20.danger%3E.admonition-title%3Abefore%2C.md-typeset%20.danger%3Esummary%3Abefore%7Bbackground-color%3A%23ff1744%3B-webkit-mask-image%3Avar%28--md-admonition-icon--danger%29%3Bmask-image%3Avar%28--md-admonition-icon--danger%29%7D.md-typeset%20.danger%3E.admonition-title%3Aafter%2C.md-typeset%20.danger%3Esummary%3Aafter%7Bcolor%3A%23ff1744%7D.md-typeset%20.admonition.bug%2C.md-typeset%20details.bug%7Bborder-color%3A%23f50057%7D.md-typeset%20.admonition.bug%3Afocus-within%2C.md-typeset%20details.bug%3Afocus-within%7Bbox-shadow%3A0%200%200%20.2rem%20%23f500571a%7D.md-typeset%20.bug%3E.admonition-title%2C.md-typeset%20.bug%3Esummary%7Bbackground-color%3A%23f500571a%7D.md-typeset%20.bug%3E.admonition-title%3Abefore%2C.md-typeset%20.bug%3Esummary%3Abefore%7Bbackground-color%3A%23f50057%3B-webkit-mask-image%3Avar%28--md-admonition-icon--bug%29%3Bmask-image%3Avar%28--md-admonition-icon--bug%29%7D.md-typeset%20.bug%3E.admonition-title%3Aafter%2C.md-typeset%20.bug%3Esummary%3Aafter%7Bcolor%3A%23f50057%7D.md-typeset%20.admonition.example%2C.md-typeset%20details.example%7Bborder-color%3A%237c4dff%7D.md-typeset%20.admonition.example%3Afocus-within%2C.md-typeset%20details.example%3Afocus-within%7Bbox-shadow%3A0%200%200%20.2rem%20%237c4dff1a%7D.md-typeset%20.example%3E.admonition-title%2C.md-typeset%20.example%3Esummary%7Bbackground-color%3A%237c4dff1a%7D.md-typeset%20.example%3E.admonition-title%3Abefore%2C.md-typeset%20.example%3Esummary%3Abefore%7Bbackground-color%3A%237c4dff%3B-webkit-mask-image%3Avar%28--md-admonition-icon--example%29%3Bmask-image%3Avar%28--md-admonition-icon--example%29%7D.md-typeset%20.example%3E.admonition-title%3Aafter%2C.md-typeset%20.example%3Esummary%3Aafter%7Bcolor%3A%237c4dff%7D.md-typeset%20.admonition.quote%2C.md-typeset%20details.quote%7Bborder-color%3A%239e9e9e%7D.md-typeset%20.admonition.quote%3Afocus-within%2C.md-typeset%20details.quote%3Afocus-within%7Bbox-shadow%3A0%200%200%20.2rem%20%239e9e9e1a%7D.md-typeset%20.quote%3E.admonition-title%2C.md-typeset%20.quote%3Esummary%7Bbackground-color%3A%239e9e9e1a%7D.md-typeset%20.quote%3E.admonition-title%3Abefore%2C.md-typeset%20.quote%3Esummary%3Abefore%7Bbackground-color%3A%239e9e9e%3B-webkit-mask-image%3Avar%28--md-admonition-icon--quote%29%3Bmask-image%3Avar%28--md-admonition-icon--quote%29%7D.md-typeset%20.quote%3E.admonition-title%3Aafter%2C.md-typeset%20.quote%3Esummary%3Aafter%7Bcolor%3A%239e9e9e%7D%3Aroot%7B--md-footnotes-icon%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M19%207v4H5.83l3.58-3.59L8%206l-6%206%206%206%201.41-1.42L5.83%2013H21V7z%22/%3E%3C/svg%3E%27%29%7D.md-typeset%20.footnote%7Bcolor%3Avar%28--md-default-fg-color--light%29%3Bfont-size%3A.64rem%7D%5Bdir%3Dltr%5D%20.md-typeset%20.footnote%3Eol%7Bmargin-left%3A0%7D%5Bdir%3Drtl%5D%20.md-typeset%20.footnote%3Eol%7Bmargin-right%3A0%7D.md-typeset%20.footnote%3Eol%3Eli%7Btransition%3Acolor%20125ms%7D.md-typeset%20.footnote%3Eol%3Eli%3Atarget%7Bcolor%3Avar%28--md-default-fg-color%29%7D.md-typeset%20.footnote%3Eol%3Eli%3Afocus-within%20.footnote-backref%7Bopacity%3A1%3Btransform%3AtranslateX%280%29%3Btransition%3Anone%7D.md-typeset%20.footnote%3Eol%3Eli%3Ahover%20.footnote-backref%2C.md-typeset%20.footnote%3Eol%3Eli%3Atarget%20.footnote-backref%7Bopacity%3A1%3Btransform%3AtranslateX%280%29%7D.md-typeset%20.footnote%3Eol%3Eli%3E%3Afirst-child%7Bmargin-top%3A0%7D.md-typeset%20.footnote-ref%7Bfont-size%3A.75em%3Bfont-weight%3A700%7Dhtml%20.md-typeset%20.footnote-ref%7Boutline-offset%3A.1rem%7D.md-typeset%20%5Bid%5E%3D%22fnref%3A%22%5D%3Atarget%3E.footnote-ref%7Boutline%3Aauto%7D.md-typeset%20.footnote-backref%7Bcolor%3Avar%28--md-typeset-a-color%29%3Bdisplay%3Ainline-block%3Bfont-size%3A0%3Bopacity%3A0%3Btransform%3AtranslateX%28.25rem%29%3Btransition%3Acolor%20.25s%2Ctransform%20.25s%20.25s%2Copacity%20125ms%20.25s%3Bvertical-align%3Atext-bottom%7D%40media%20print%7B.md-typeset%20.footnote-backref%7Bcolor%3Avar%28--md-typeset-a-color%29%3Bopacity%3A1%3Btransform%3AtranslateX%280%29%7D%7D%5Bdir%3Drtl%5D%20.md-typeset%20.footnote-backref%7Btransform%3AtranslateX%28-.25rem%29%7D.md-typeset%20.footnote-backref%3Ahover%7Bcolor%3Avar%28--md-accent-fg-color%29%7D.md-typeset%20.footnote-backref%3Abefore%7Bbackground-color%3Acurrentcolor%3Bcontent%3A%22%22%3Bdisplay%3Ainline-block%3Bheight%3A.8rem%3B-webkit-mask-image%3Avar%28--md-footnotes-icon%29%3Bmask-image%3Avar%28--md-footnotes-icon%29%3B-webkit-mask-position%3Acenter%3Bmask-position%3Acenter%3B-webkit-mask-repeat%3Ano-repeat%3Bmask-repeat%3Ano-repeat%3B-webkit-mask-size%3Acontain%3Bmask-size%3Acontain%3Bwidth%3A.8rem%7D%5Bdir%3Drtl%5D%20.md-typeset%20.footnote-backref%3Abefore%20svg%7Btransform%3AscaleX%28-1%29%7D%5Bdir%3Dltr%5D%20.md-typeset%20.headerlink%7Bmargin-left%3A.5rem%7D%5Bdir%3Drtl%5D%20.md-typeset%20.headerlink%7Bmargin-right%3A.5rem%7D.md-typeset%20.headerlink%7Bcolor%3Avar%28--md-default-fg-color--lighter%29%3Bdisplay%3Ainline-block%3Bopacity%3A0%3Btransition%3Acolor%20.25s%2Copacity%20125ms%7D%40media%20print%7B.md-typeset%20.headerlink%7Bdisplay%3Anone%7D%7D.md-typeset%20.headerlink%3Afocus%2C.md-typeset%20%3Ahover%3E.headerlink%2C.md-typeset%20%3Atarget%3E.headerlink%7Bopacity%3A1%3Btransition%3Acolor%20.25s%2Copacity%20125ms%7D.md-typeset%20.headerlink%3Afocus%2C.md-typeset%20.headerlink%3Ahover%2C.md-typeset%20%3Atarget%3E.headerlink%7Bcolor%3Avar%28--md-accent-fg-color%29%7D.md-typeset%20%3Atarget%7B--md-scroll-margin%3A3.6rem%3B--md-scroll-offset%3A0rem%3Bscroll-margin-top%3Acalc%28var%28--md-scroll-margin%29%20-%20var%28--md-scroll-offset%29%29%7D%40media%20screen%20and%20%28min-width%3A76.25em%29%7B.md-header--lifted~.md-container%20.md-typeset%20%3Atarget%7B--md-scroll-margin%3A6rem%7D%7D.md-typeset%20h1%3Atarget%2C.md-typeset%20h2%3Atarget%2C.md-typeset%20h3%3Atarget%7B--md-scroll-offset%3A0.2rem%7D.md-typeset%20h4%3Atarget%7B--md-scroll-offset%3A0.15rem%7D.md-typeset%20div.arithmatex%7Boverflow%3Aauto%7D%40media%20screen%20and%20%28max-width%3A44.984375em%29%7B.md-typeset%20div.arithmatex%7Bmargin%3A0%20-.8rem%7D.md-typeset%20div.arithmatex%3E%2A%7Bwidth%3Amin-content%7D%7D.md-typeset%20div.arithmatex%3E%2A%7Bmargin-left%3Aauto%21important%3Bmargin-right%3Aauto%21important%3Bpadding%3A0%20.8rem%3Btouch-action%3Aauto%7D.md-typeset%20div.arithmatex%3E%2A%20mjx-container%7Bmargin%3A0%21important%7D.md-typeset%20div.arithmatex%20mjx-assistive-mml%7Bheight%3A0%7D.md-typeset%20del.critic%7Bbackground-color%3Avar%28--md-typeset-del-color%29%7D.md-typeset%20del.critic%2C.md-typeset%20ins.critic%7B-webkit-box-decoration-break%3Aclone%3Bbox-decoration-break%3Aclone%7D.md-typeset%20ins.critic%7Bbackground-color%3Avar%28--md-typeset-ins-color%29%7D.md-typeset%20.critic.comment%7B-webkit-box-decoration-break%3Aclone%3Bbox-decoration-break%3Aclone%3Bcolor%3Avar%28--md-code-hl-comment-color%29%7D.md-typeset%20.critic.comment%3Abefore%7Bcontent%3A%22/%2A%20%22%7D.md-typeset%20.critic.comment%3Aafter%7Bcontent%3A%22%20%2A/%22%7D.md-typeset%20.critic.block%7Bbox-shadow%3Anone%3Bdisplay%3Ablock%3Bmargin%3A1em%200%3Boverflow%3Aauto%3Bpadding-left%3A.8rem%3Bpadding-right%3A.8rem%7D.md-typeset%20.critic.block%3E%3Afirst-child%7Bmargin-top%3A.5em%7D.md-typeset%20.critic.block%3E%3Alast-child%7Bmargin-bottom%3A.5em%7D%3Aroot%7B--md-details-icon%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M8.59%2016.58%2013.17%2012%208.59%207.41%2010%206l6%206-6%206z%22/%3E%3C/svg%3E%27%29%7D.md-typeset%20details%7Bdisplay%3Aflow-root%3Boverflow%3Avisible%3Bpadding-top%3A0%7D.md-typeset%20details%5Bopen%5D%3Esummary%3Aafter%7Btransform%3Arotate%2890deg%29%7D.md-typeset%20details%3Anot%28%5Bopen%5D%29%7Bbox-shadow%3Anone%3Bpadding-bottom%3A0%7D.md-typeset%20details%3Anot%28%5Bopen%5D%29%3Esummary%7Bborder-radius%3A.1rem%7D%5Bdir%3Dltr%5D%20.md-typeset%20summary%7Bpadding-right%3A1.8rem%7D%5Bdir%3Drtl%5D%20.md-typeset%20summary%7Bpadding-left%3A1.8rem%7D%5Bdir%3Dltr%5D%20.md-typeset%20summary%7Bborder-top-left-radius%3A.1rem%7D%5Bdir%3Dltr%5D%20.md-typeset%20summary%2C%5Bdir%3Drtl%5D%20.md-typeset%20summary%7Bborder-top-right-radius%3A.1rem%7D%5Bdir%3Drtl%5D%20.md-typeset%20summary%7Bborder-top-left-radius%3A.1rem%7D.md-typeset%20summary%7Bcursor%3Apointer%3Bdisplay%3Ablock%3Bmin-height%3A1rem%3Boverflow%3Ahidden%7D.md-typeset%20summary.focus-visible%7Boutline-color%3Avar%28--md-accent-fg-color%29%3Boutline-offset%3A.2rem%7D.md-typeset%20summary%3Anot%28.focus-visible%29%7B-webkit-tap-highlight-color%3Atransparent%3Boutline%3Anone%7D%5Bdir%3Dltr%5D%20.md-typeset%20summary%3Aafter%7Bright%3A.4rem%7D%5Bdir%3Drtl%5D%20.md-typeset%20summary%3Aafter%7Bleft%3A.4rem%7D.md-typeset%20summary%3Aafter%7Bbackground-color%3Acurrentcolor%3Bcontent%3A%22%22%3Bheight%3A1rem%3B-webkit-mask-image%3Avar%28--md-details-icon%29%3Bmask-image%3Avar%28--md-details-icon%29%3B-webkit-mask-position%3Acenter%3Bmask-position%3Acenter%3B-webkit-mask-repeat%3Ano-repeat%3Bmask-repeat%3Ano-repeat%3B-webkit-mask-size%3Acontain%3Bmask-size%3Acontain%3Bposition%3Aabsolute%3Btop%3A.625em%3Btransform%3Arotate%280deg%29%3Btransition%3Atransform%20.25s%3Bwidth%3A1rem%7D%5Bdir%3Drtl%5D%20.md-typeset%20summary%3Aafter%7Btransform%3Arotate%28180deg%29%7D.md-typeset%20summary%3A%3Amarker%7Bdisplay%3Anone%7D.md-typeset%20summary%3A%3A-webkit-details-marker%7Bdisplay%3Anone%7D.md-typeset%20.emojione%2C.md-typeset%20.gemoji%2C.md-typeset%20.twemoji%7B--md-icon-size%3A1.125em%3Bdisplay%3Ainline-flex%3Bheight%3Avar%28--md-icon-size%29%3Bvertical-align%3Atext-top%7D.md-typeset%20.emojione%20svg%2C.md-typeset%20.gemoji%20svg%2C.md-typeset%20.twemoji%20svg%7Bfill%3Acurrentcolor%3Bmax-height%3A100%25%3Bwidth%3Avar%28--md-icon-size%29%7D.md-typeset%20.lg%2C.md-typeset%20.xl%2C.md-typeset%20.xxl%2C.md-typeset%20.xxxl%7Bvertical-align%3Atext-bottom%7D.md-typeset%20.middle%7Bvertical-align%3Amiddle%7D.md-typeset%20.lg%7B--md-icon-size%3A1.5em%7D.md-typeset%20.xl%7B--md-icon-size%3A2.25em%7D.md-typeset%20.xxl%7B--md-icon-size%3A3em%7D.md-typeset%20.xxxl%7B--md-icon-size%3A4em%7D.highlight%20.o%2C.highlight%20.ow%7Bcolor%3Avar%28--md-code-hl-operator-color%29%7D.highlight%20.p%7Bcolor%3Avar%28--md-code-hl-punctuation-color%29%7D.highlight%20.cpf%2C.highlight%20.l%2C.highlight%20.s%2C.highlight%20.s1%2C.highlight%20.s2%2C.highlight%20.sb%2C.highlight%20.sc%2C.highlight%20.si%2C.highlight%20.ss%7Bcolor%3Avar%28--md-code-hl-string-color%29%7D.highlight%20.cp%2C.highlight%20.se%2C.highlight%20.sh%2C.highlight%20.sr%2C.highlight%20.sx%7Bcolor%3Avar%28--md-code-hl-special-color%29%7D.highlight%20.il%2C.highlight%20.m%2C.highlight%20.mb%2C.highlight%20.mf%2C.highlight%20.mh%2C.highlight%20.mi%2C.highlight%20.mo%7Bcolor%3Avar%28--md-code-hl-number-color%29%7D.highlight%20.k%2C.highlight%20.kd%2C.highlight%20.kn%2C.highlight%20.kp%2C.highlight%20.kr%2C.highlight%20.kt%7Bcolor%3Avar%28--md-code-hl-keyword-color%29%7D.highlight%20.kc%2C.highlight%20.n%7Bcolor%3Avar%28--md-code-hl-name-color%29%7D.highlight%20.bp%2C.highlight%20.nb%2C.highlight%20.no%7Bcolor%3Avar%28--md-code-hl-constant-color%29%7D.highlight%20.nc%2C.highlight%20.ne%2C.highlight%20.nf%2C.highlight%20.nn%7Bcolor%3Avar%28--md-code-hl-function-color%29%7D.highlight%20.nd%2C.highlight%20.ni%2C.highlight%20.nl%2C.highlight%20.nt%7Bcolor%3Avar%28--md-code-hl-keyword-color%29%7D.highlight%20.c%2C.highlight%20.c1%2C.highlight%20.ch%2C.highlight%20.cm%2C.highlight%20.cs%2C.highlight%20.sd%7Bcolor%3Avar%28--md-code-hl-comment-color%29%7D.highlight%20.na%2C.highlight%20.nv%2C.highlight%20.vc%2C.highlight%20.vg%2C.highlight%20.vi%7Bcolor%3Avar%28--md-code-hl-variable-color%29%7D.highlight%20.ge%2C.highlight%20.gh%2C.highlight%20.go%2C.highlight%20.gp%2C.highlight%20.gr%2C.highlight%20.gs%2C.highlight%20.gt%2C.highlight%20.gu%7Bcolor%3Avar%28--md-code-hl-generic-color%29%7D.highlight%20.gd%2C.highlight%20.gi%7Bborder-radius%3A.1rem%3Bmargin%3A0%20-.125em%3Bpadding%3A0%20.125em%7D.highlight%20.gd%7Bbackground-color%3Avar%28--md-typeset-del-color%29%7D.highlight%20.gi%7Bbackground-color%3Avar%28--md-typeset-ins-color%29%7D.highlight%20.hll%7Bbackground-color%3Avar%28--md-code-hl-color--light%29%3Bbox-shadow%3A2px%200%200%200%20var%28--md-code-hl-color%29%20inset%3Bdisplay%3Ablock%3Bmargin%3A0%20-1.1764705882em%3Bpadding%3A0%201.1764705882em%7D.highlight%20span.filename%7Bbackground-color%3Avar%28--md-code-bg-color%29%3Bborder-bottom%3A.05rem%20solid%20var%28--md-default-fg-color--lightest%29%3Bborder-top-left-radius%3A.1rem%3Bborder-top-right-radius%3A.1rem%3Bdisplay%3Aflow-root%3Bfont-size%3A.85em%3Bfont-weight%3A700%3Bmargin-top%3A1em%3Bpadding%3A.6617647059em%201.1764705882em%3Bposition%3Arelative%7D.highlight%20span.filename%2Bpre%7Bmargin-top%3A0%7D.highlight%20span.filename%2Bpre%3Ecode%7Bborder-top-left-radius%3A0%3Bborder-top-right-radius%3A0%7D.highlight%20%5Bdata-linenos%5D%3Abefore%7Bbackground-color%3Avar%28--md-code-bg-color%29%3Bbox-shadow%3A-.05rem%200%20var%28--md-default-fg-color--lightest%29%20inset%3Bcolor%3Avar%28--md-default-fg-color--light%29%3Bcontent%3Aattr%28data-linenos%29%3Bfloat%3Aleft%3Bleft%3A-1.1764705882em%3Bmargin-left%3A-1.1764705882em%3Bmargin-right%3A1.1764705882em%3Bpadding-left%3A1.1764705882em%3Bposition%3Asticky%3B-webkit-user-select%3Anone%3Buser-select%3Anone%3Bz-index%3A3%7D.highlight%20code%20a%5Bid%5D%7Bposition%3Aabsolute%3Bvisibility%3Ahidden%7D.highlight%20code%5Bdata-md-copying%5D%7Bdisplay%3Ainitial%7D.highlight%20code%5Bdata-md-copying%5D%20.hll%7Bdisplay%3Acontents%7D.highlight%20code%5Bdata-md-copying%5D%20.md-annotation%7Bdisplay%3Anone%7D.highlighttable%7Bdisplay%3Aflow-root%7D.highlighttable%20tbody%2C.highlighttable%20td%7Bdisplay%3Ablock%3Bpadding%3A0%7D.highlighttable%20tr%7Bdisplay%3Aflex%7D.highlighttable%20pre%7Bmargin%3A0%7D.highlighttable%20th.filename%7Bflex-grow%3A1%3Bpadding%3A0%3Btext-align%3Aleft%7D.highlighttable%20th.filename%20span.filename%7Bmargin-top%3A0%7D.highlighttable%20.linenos%7Bbackground-color%3Avar%28--md-code-bg-color%29%3Bborder-bottom-left-radius%3A.1rem%3Bborder-top-left-radius%3A.1rem%3Bfont-size%3A.85em%3Bpadding%3A.7720588235em%200%20.7720588235em%201.1764705882em%3B-webkit-user-select%3Anone%3Buser-select%3Anone%7D.highlighttable%20.linenodiv%7Bbox-shadow%3A-.05rem%200%20var%28--md-default-fg-color--lightest%29%20inset%3Bpadding-right%3A.5882352941em%7D.highlighttable%20.linenodiv%20pre%7Bcolor%3Avar%28--md-default-fg-color--light%29%3Btext-align%3Aright%7D.highlighttable%20.code%7Bflex%3A1%3Bmin-width%3A0%7D.linenodiv%20a%7Bcolor%3Ainherit%7D.md-typeset%20.highlighttable%7Bdirection%3Altr%3Bmargin%3A1em%200%7D.md-typeset%20.highlighttable%3Etbody%3Etr%3E.code%3Ediv%3Epre%3Ecode%7Bborder-bottom-left-radius%3A0%3Bborder-top-left-radius%3A0%7D.md-typeset%20.highlight%2B.result%7Bborder%3A.05rem%20solid%20var%28--md-code-bg-color%29%3Bborder-bottom-left-radius%3A.1rem%3Bborder-bottom-right-radius%3A.1rem%3Bborder-top-width%3A.1rem%3Bmargin-top%3A-1.125em%3Boverflow%3Avisible%3Bpadding%3A0%201em%7D.md-typeset%20.highlight%2B.result%3Aafter%7Bclear%3Aboth%3Bcontent%3A%22%22%3Bdisplay%3Ablock%7D%40media%20screen%20and%20%28max-width%3A44.984375em%29%7B.md-content__inner%3E.highlight%7Bmargin%3A1em%20-.8rem%7D.md-content__inner%3E.highlight%3E.filename%2C.md-content__inner%3E.highlight%3E.highlighttable%3Etbody%3Etr%3E.code%3Ediv%3Epre%3Ecode%2C.md-content__inner%3E.highlight%3E.highlighttable%3Etbody%3Etr%3E.filename%20span.filename%2C.md-content__inner%3E.highlight%3E.highlighttable%3Etbody%3Etr%3E.linenos%2C.md-content__inner%3E.highlight%3Epre%3Ecode%7Bborder-radius%3A0%7D.md-content__inner%3E.highlight%2B.result%7Bborder-left-width%3A0%3Bborder-radius%3A0%3Bborder-right-width%3A0%3Bmargin-left%3A-.8rem%3Bmargin-right%3A-.8rem%7D%7D.md-typeset%20.keys%20kbd%3Aafter%2C.md-typeset%20.keys%20kbd%3Abefore%7B-moz-osx-font-smoothing%3Ainitial%3B-webkit-font-smoothing%3Ainitial%3Bcolor%3Ainherit%3Bmargin%3A0%3Bposition%3Arelative%7D.md-typeset%20.keys%20span%7Bcolor%3Avar%28--md-default-fg-color--light%29%3Bpadding%3A0%20.2em%7D.md-typeset%20.keys%20.key-alt%3Abefore%2C.md-typeset%20.keys%20.key-left-alt%3Abefore%2C.md-typeset%20.keys%20.key-right-alt%3Abefore%7Bcontent%3A%22%E2%8E%87%22%3Bpadding-right%3A.4em%7D.md-typeset%20.keys%20.key-command%3Abefore%2C.md-typeset%20.keys%20.key-left-command%3Abefore%2C.md-typeset%20.keys%20.key-right-command%3Abefore%7Bcontent%3A%22%E2%8C%98%22%3Bpadding-right%3A.4em%7D.md-typeset%20.keys%20.key-control%3Abefore%2C.md-typeset%20.keys%20.key-left-control%3Abefore%2C.md-typeset%20.keys%20.key-right-control%3Abefore%7Bcontent%3A%22%E2%8C%83%22%3Bpadding-right%3A.4em%7D.md-typeset%20.keys%20.key-left-meta%3Abefore%2C.md-typeset%20.keys%20.key-meta%3Abefore%2C.md-typeset%20.keys%20.key-right-meta%3Abefore%7Bcontent%3A%22%E2%97%86%22%3Bpadding-right%3A.4em%7D.md-typeset%20.keys%20.key-left-option%3Abefore%2C.md-typeset%20.keys%20.key-option%3Abefore%2C.md-typeset%20.keys%20.key-right-option%3Abefore%7Bcontent%3A%22%E2%8C%A5%22%3Bpadding-right%3A.4em%7D.md-typeset%20.keys%20.key-left-shift%3Abefore%2C.md-typeset%20.keys%20.key-right-shift%3Abefore%2C.md-typeset%20.keys%20.key-shift%3Abefore%7Bcontent%3A%22%E2%87%A7%22%3Bpadding-right%3A.4em%7D.md-typeset%20.keys%20.key-left-super%3Abefore%2C.md-typeset%20.keys%20.key-right-super%3Abefore%2C.md-typeset%20.keys%20.key-super%3Abefore%7Bcontent%3A%22%E2%9D%96%22%3Bpadding-right%3A.4em%7D.md-typeset%20.keys%20.key-left-windows%3Abefore%2C.md-typeset%20.keys%20.key-right-windows%3Abefore%2C.md-typeset%20.keys%20.key-windows%3Abefore%7Bcontent%3A%22%E2%8A%9E%22%3Bpadding-right%3A.4em%7D.md-typeset%20.keys%20.key-arrow-down%3Abefore%7Bcontent%3A%22%E2%86%93%22%3Bpadding-right%3A.4em%7D.md-typeset%20.keys%20.key-arrow-left%3Abefore%7Bcontent%3A%22%E2%86%90%22%3Bpadding-right%3A.4em%7D.md-typeset%20.keys%20.key-arrow-right%3Abefore%7Bcontent%3A%22%E2%86%92%22%3Bpadding-right%3A.4em%7D.md-typeset%20.keys%20.key-arrow-up%3Abefore%7Bcontent%3A%22%E2%86%91%22%3Bpadding-right%3A.4em%7D.md-typeset%20.keys%20.key-backspace%3Abefore%7Bcontent%3A%22%E2%8C%AB%22%3Bpadding-right%3A.4em%7D.md-typeset%20.keys%20.key-backtab%3Abefore%7Bcontent%3A%22%E2%87%A4%22%3Bpadding-right%3A.4em%7D.md-typeset%20.keys%20.key-caps-lock%3Abefore%7Bcontent%3A%22%E2%87%AA%22%3Bpadding-right%3A.4em%7D.md-typeset%20.keys%20.key-clear%3Abefore%7Bcontent%3A%22%E2%8C%A7%22%3Bpadding-right%3A.4em%7D.md-typeset%20.keys%20.key-context-menu%3Abefore%7Bcontent%3A%22%E2%98%B0%22%3Bpadding-right%3A.4em%7D.md-typeset%20.keys%20.key-delete%3Abefore%7Bcontent%3A%22%E2%8C%A6%22%3Bpadding-right%3A.4em%7D.md-typeset%20.keys%20.key-eject%3Abefore%7Bcontent%3A%22%E2%8F%8F%22%3Bpadding-right%3A.4em%7D.md-typeset%20.keys%20.key-end%3Abefore%7Bcontent%3A%22%E2%A4%93%22%3Bpadding-right%3A.4em%7D.md-typeset%20.keys%20.key-escape%3Abefore%7Bcontent%3A%22%E2%8E%8B%22%3Bpadding-right%3A.4em%7D.md-typeset%20.keys%20.key-home%3Abefore%7Bcontent%3A%22%E2%A4%92%22%3Bpadding-right%3A.4em%7D.md-typeset%20.keys%20.key-insert%3Abefore%7Bcontent%3A%22%E2%8E%80%22%3Bpadding-right%3A.4em%7D.md-typeset%20.keys%20.key-page-down%3Abefore%7Bcontent%3A%22%E2%87%9F%22%3Bpadding-right%3A.4em%7D.md-typeset%20.keys%20.key-page-up%3Abefore%7Bcontent%3A%22%E2%87%9E%22%3Bpadding-right%3A.4em%7D.md-typeset%20.keys%20.key-print-screen%3Abefore%7Bcontent%3A%22%E2%8E%99%22%3Bpadding-right%3A.4em%7D.md-typeset%20.keys%20.key-tab%3Aafter%7Bcontent%3A%22%E2%87%A5%22%3Bpadding-left%3A.4em%7D.md-typeset%20.keys%20.key-num-enter%3Aafter%7Bcontent%3A%22%E2%8C%A4%22%3Bpadding-left%3A.4em%7D.md-typeset%20.keys%20.key-enter%3Aafter%7Bcontent%3A%22%E2%8F%8E%22%3Bpadding-left%3A.4em%7D%3Aroot%7B--md-tabbed-icon--prev%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M15.41%2016.58%2010.83%2012l4.58-4.59L14%206l-6%206%206%206z%22/%3E%3C/svg%3E%27%29%3B--md-tabbed-icon--next%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M8.59%2016.58%2013.17%2012%208.59%207.41%2010%206l6%206-6%206z%22/%3E%3C/svg%3E%27%29%7D.md-typeset%20.tabbed-set%7Bborder-radius%3A.1rem%3Bdisplay%3Aflex%3Bflex-flow%3Acolumn%20wrap%3Bmargin%3A1em%200%3Bposition%3Arelative%7D.md-typeset%20.tabbed-set%3Einput%7Bheight%3A0%3Bopacity%3A0%3Bposition%3Aabsolute%3Bwidth%3A0%7D.md-typeset%20.tabbed-set%3Einput%3Atarget%7B--md-scroll-offset%3A0.625em%7D.md-typeset%20.tabbed-set%3Einput.focus-visible~.tabbed-labels%3Abefore%7Bbackground-color%3Avar%28--md-accent-fg-color%29%7D.md-typeset%20.tabbed-labels%7B-ms-overflow-style%3Anone%3Bbox-shadow%3A0%20-.05rem%20var%28--md-default-fg-color--lightest%29%20inset%3Bdisplay%3Aflex%3Bmax-width%3A100%25%3Boverflow%3Aauto%3Bscrollbar-width%3Anone%7D%40media%20print%7B.md-typeset%20.tabbed-labels%7Bdisplay%3Acontents%7D%7D%40media%20screen%7B.js%20.md-typeset%20.tabbed-labels%7Bposition%3Arelative%7D.js%20.md-typeset%20.tabbed-labels%3Abefore%7Bbackground%3Avar%28--md-default-fg-color%29%3Bbottom%3A0%3Bcontent%3A%22%22%3Bdisplay%3Ablock%3Bheight%3A2px%3Bleft%3A0%3Bposition%3Aabsolute%3Btransform%3AtranslateX%28var%28--md-indicator-x%29%29%3Btransition%3Awidth%20225ms%2Cbackground-color%20.25s%2Ctransform%20.25s%3Btransition-timing-function%3Acubic-bezier%28.4%2C0%2C.2%2C1%29%3Bwidth%3Avar%28--md-indicator-width%29%7D%7D.md-typeset%20.tabbed-labels%3A%3A-webkit-scrollbar%7Bdisplay%3Anone%7D.md-typeset%20.tabbed-labels%3Elabel%7Bborder-bottom%3A.1rem%20solid%20%230000%3Bborder-radius%3A.1rem%20.1rem%200%200%3Bcolor%3Avar%28--md-default-fg-color--light%29%3Bcursor%3Apointer%3Bflex-shrink%3A0%3Bfont-size%3A.64rem%3Bfont-weight%3A700%3Bpadding%3A.78125em%201.25em%20.625em%3Bscroll-margin-inline-start%3A1rem%3Btransition%3Abackground-color%20.25s%2Ccolor%20.25s%3Bwhite-space%3Anowrap%3Bwidth%3Aauto%7D%40media%20print%7B.md-typeset%20.tabbed-labels%3Elabel%3Afirst-child%7Border%3A1%7D.md-typeset%20.tabbed-labels%3Elabel%3Anth-child%282%29%7Border%3A2%7D.md-typeset%20.tabbed-labels%3Elabel%3Anth-child%283%29%7Border%3A3%7D.md-typeset%20.tabbed-labels%3Elabel%3Anth-child%284%29%7Border%3A4%7D.md-typeset%20.tabbed-labels%3Elabel%3Anth-child%285%29%7Border%3A5%7D.md-typeset%20.tabbed-labels%3Elabel%3Anth-child%286%29%7Border%3A6%7D.md-typeset%20.tabbed-labels%3Elabel%3Anth-child%287%29%7Border%3A7%7D.md-typeset%20.tabbed-labels%3Elabel%3Anth-child%288%29%7Border%3A8%7D.md-typeset%20.tabbed-labels%3Elabel%3Anth-child%289%29%7Border%3A9%7D.md-typeset%20.tabbed-labels%3Elabel%3Anth-child%2810%29%7Border%3A10%7D.md-typeset%20.tabbed-labels%3Elabel%3Anth-child%2811%29%7Border%3A11%7D.md-typeset%20.tabbed-labels%3Elabel%3Anth-child%2812%29%7Border%3A12%7D.md-typeset%20.tabbed-labels%3Elabel%3Anth-child%2813%29%7Border%3A13%7D.md-typeset%20.tabbed-labels%3Elabel%3Anth-child%2814%29%7Border%3A14%7D.md-typeset%20.tabbed-labels%3Elabel%3Anth-child%2815%29%7Border%3A15%7D.md-typeset%20.tabbed-labels%3Elabel%3Anth-child%2816%29%7Border%3A16%7D.md-typeset%20.tabbed-labels%3Elabel%3Anth-child%2817%29%7Border%3A17%7D.md-typeset%20.tabbed-labels%3Elabel%3Anth-child%2818%29%7Border%3A18%7D.md-typeset%20.tabbed-labels%3Elabel%3Anth-child%2819%29%7Border%3A19%7D.md-typeset%20.tabbed-labels%3Elabel%3Anth-child%2820%29%7Border%3A20%7D%7D.md-typeset%20.tabbed-labels%3Elabel%3Ahover%7Bcolor%3Avar%28--md-default-fg-color%29%7D.md-typeset%20.tabbed-labels%3Elabel%3E%5Bhref%5D%3Afirst-child%7Bcolor%3Ainherit%7D.md-typeset%20.tabbed-labels--linked%3Elabel%7Bpadding%3A0%7D.md-typeset%20.tabbed-labels--linked%3Elabel%3Ea%7Bdisplay%3Ablock%3Bpadding%3A.78125em%201.25em%20.625em%7D.md-typeset%20.tabbed-content%7Bwidth%3A100%25%7D%40media%20print%7B.md-typeset%20.tabbed-content%7Bdisplay%3Acontents%7D%7D.md-typeset%20.tabbed-block%7Bdisplay%3Anone%7D%40media%20print%7B.md-typeset%20.tabbed-block%7Bdisplay%3Ablock%7D.md-typeset%20.tabbed-block%3Afirst-child%7Border%3A1%7D.md-typeset%20.tabbed-block%3Anth-child%282%29%7Border%3A2%7D.md-typeset%20.tabbed-block%3Anth-child%283%29%7Border%3A3%7D.md-typeset%20.tabbed-block%3Anth-child%284%29%7Border%3A4%7D.md-typeset%20.tabbed-block%3Anth-child%285%29%7Border%3A5%7D.md-typeset%20.tabbed-block%3Anth-child%286%29%7Border%3A6%7D.md-typeset%20.tabbed-block%3Anth-child%287%29%7Border%3A7%7D.md-typeset%20.tabbed-block%3Anth-child%288%29%7Border%3A8%7D.md-typeset%20.tabbed-block%3Anth-child%289%29%7Border%3A9%7D.md-typeset%20.tabbed-block%3Anth-child%2810%29%7Border%3A10%7D.md-typeset%20.tabbed-block%3Anth-child%2811%29%7Border%3A11%7D.md-typeset%20.tabbed-block%3Anth-child%2812%29%7Border%3A12%7D.md-typeset%20.tabbed-block%3Anth-child%2813%29%7Border%3A13%7D.md-typeset%20.tabbed-block%3Anth-child%2814%29%7Border%3A14%7D.md-typeset%20.tabbed-block%3Anth-child%2815%29%7Border%3A15%7D.md-typeset%20.tabbed-block%3Anth-child%2816%29%7Border%3A16%7D.md-typeset%20.tabbed-block%3Anth-child%2817%29%7Border%3A17%7D.md-typeset%20.tabbed-block%3Anth-child%2818%29%7Border%3A18%7D.md-typeset%20.tabbed-block%3Anth-child%2819%29%7Border%3A19%7D.md-typeset%20.tabbed-block%3Anth-child%2820%29%7Border%3A20%7D%7D.md-typeset%20.tabbed-block%3E.highlight%3Afirst-child%3Epre%2C.md-typeset%20.tabbed-block%3Epre%3Afirst-child%7Bmargin%3A0%7D.md-typeset%20.tabbed-block%3E.highlight%3Afirst-child%3Epre%3Ecode%2C.md-typeset%20.tabbed-block%3Epre%3Afirst-child%3Ecode%7Bborder-top-left-radius%3A0%3Bborder-top-right-radius%3A0%7D.md-typeset%20.tabbed-block%3E.highlight%3Afirst-child%3E.filename%7Bborder-top-left-radius%3A0%3Bborder-top-right-radius%3A0%3Bmargin%3A0%7D.md-typeset%20.tabbed-block%3E.highlight%3Afirst-child%3E.highlighttable%7Bmargin%3A0%7D.md-typeset%20.tabbed-block%3E.highlight%3Afirst-child%3E.highlighttable%3Etbody%3Etr%3E.filename%20span.filename%2C.md-typeset%20.tabbed-block%3E.highlight%3Afirst-child%3E.highlighttable%3Etbody%3Etr%3E.linenos%7Bborder-top-left-radius%3A0%3Bborder-top-right-radius%3A0%3Bmargin%3A0%7D.md-typeset%20.tabbed-block%3E.highlight%3Afirst-child%3E.highlighttable%3Etbody%3Etr%3E.code%3Ediv%3Epre%3Ecode%7Bborder-top-left-radius%3A0%3Bborder-top-right-radius%3A0%7D.md-typeset%20.tabbed-block%3E.highlight%3Afirst-child%2B.result%7Bmargin-top%3A-.125em%7D.md-typeset%20.tabbed-block%3E.tabbed-set%7Bmargin%3A0%7D.md-typeset%20.tabbed-button%7Balign-self%3Acenter%3Bborder-radius%3A100%25%3Bcolor%3Avar%28--md-default-fg-color--light%29%3Bcursor%3Apointer%3Bdisplay%3Ablock%3Bheight%3A.9rem%3Bmargin-top%3A.1rem%3Bpointer-events%3Aauto%3Btransition%3Abackground-color%20.25s%3Bwidth%3A.9rem%7D.md-typeset%20.tabbed-button%3Ahover%7Bbackground-color%3Avar%28--md-accent-fg-color--transparent%29%3Bcolor%3Avar%28--md-accent-fg-color%29%7D.md-typeset%20.tabbed-button%3Aafter%7Bbackground-color%3Acurrentcolor%3Bcontent%3A%22%22%3Bdisplay%3Ablock%3Bheight%3A100%25%3B-webkit-mask-image%3Avar%28--md-tabbed-icon--prev%29%3Bmask-image%3Avar%28--md-tabbed-icon--prev%29%3B-webkit-mask-position%3Acenter%3Bmask-position%3Acenter%3B-webkit-mask-repeat%3Ano-repeat%3Bmask-repeat%3Ano-repeat%3B-webkit-mask-size%3Acontain%3Bmask-size%3Acontain%3Btransition%3Abackground-color%20.25s%2Ctransform%20.25s%3Bwidth%3A100%25%7D.md-typeset%20.tabbed-control%7Bbackground%3Alinear-gradient%28to%20right%2Cvar%28--md-default-bg-color%29%2060%25%2C%230000%29%3Bdisplay%3Aflex%3Bheight%3A1.9rem%3Bjustify-content%3Astart%3Bpointer-events%3Anone%3Bposition%3Aabsolute%3Btransition%3Aopacity%20125ms%3Bwidth%3A1.2rem%7D%5Bdir%3Drtl%5D%20.md-typeset%20.tabbed-control%7Btransform%3Arotate%28180deg%29%7D.md-typeset%20.tabbed-control%5Bhidden%5D%7Bopacity%3A0%7D.md-typeset%20.tabbed-control--next%7Bbackground%3Alinear-gradient%28to%20left%2Cvar%28--md-default-bg-color%29%2060%25%2C%230000%29%3Bjustify-content%3Aend%3Bright%3A0%7D.md-typeset%20.tabbed-control--next%20.tabbed-button%3Aafter%7B-webkit-mask-image%3Avar%28--md-tabbed-icon--next%29%3Bmask-image%3Avar%28--md-tabbed-icon--next%29%7D%40media%20screen%20and%20%28max-width%3A44.984375em%29%7B%5Bdir%3Dltr%5D%20.md-content__inner%3E.tabbed-set%20.tabbed-labels%7Bpadding-left%3A.8rem%7D%5Bdir%3Drtl%5D%20.md-content__inner%3E.tabbed-set%20.tabbed-labels%7Bpadding-right%3A.8rem%7D.md-content__inner%3E.tabbed-set%20.tabbed-labels%7Bmargin%3A0%20-.8rem%3Bmax-width%3A100vw%3Bscroll-padding-inline-start%3A.8rem%7D%5Bdir%3Dltr%5D%20.md-content__inner%3E.tabbed-set%20.tabbed-labels%3Aafter%7Bpadding-right%3A.8rem%7D%5Bdir%3Drtl%5D%20.md-content__inner%3E.tabbed-set%20.tabbed-labels%3Aafter%7Bpadding-left%3A.8rem%7D.md-content__inner%3E.tabbed-set%20.tabbed-labels%3Aafter%7Bcontent%3A%22%22%7D%5Bdir%3Dltr%5D%20.md-content__inner%3E.tabbed-set%20.tabbed-labels~.tabbed-control--prev%7Bpadding-left%3A.8rem%7D%5Bdir%3Drtl%5D%20.md-content__inner%3E.tabbed-set%20.tabbed-labels~.tabbed-control--prev%7Bpadding-right%3A.8rem%7D%5Bdir%3Dltr%5D%20.md-content__inner%3E.tabbed-set%20.tabbed-labels~.tabbed-control--prev%7Bmargin-left%3A-.8rem%7D%5Bdir%3Drtl%5D%20.md-content__inner%3E.tabbed-set%20.tabbed-labels~.tabbed-control--prev%7Bmargin-right%3A-.8rem%7D.md-content__inner%3E.tabbed-set%20.tabbed-labels~.tabbed-control--prev%7Bwidth%3A2rem%7D%5Bdir%3Dltr%5D%20.md-content__inner%3E.tabbed-set%20.tabbed-labels~.tabbed-control--next%7Bpadding-right%3A.8rem%7D%5Bdir%3Drtl%5D%20.md-content__inner%3E.tabbed-set%20.tabbed-labels~.tabbed-control--next%7Bpadding-left%3A.8rem%7D%5Bdir%3Dltr%5D%20.md-content__inner%3E.tabbed-set%20.tabbed-labels~.tabbed-control--next%7Bmargin-right%3A-.8rem%7D%5Bdir%3Drtl%5D%20.md-content__inner%3E.tabbed-set%20.tabbed-labels~.tabbed-control--next%7Bmargin-left%3A-.8rem%7D.md-content__inner%3E.tabbed-set%20.tabbed-labels~.tabbed-control--next%7Bwidth%3A2rem%7D%7D%40media%20screen%7B.md-typeset%20.tabbed-set%3Einput%3Afirst-child%3Achecked~.tabbed-labels%3E%3Afirst-child%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2810%29%3Achecked~.tabbed-labels%3E%3Anth-child%2810%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2811%29%3Achecked~.tabbed-labels%3E%3Anth-child%2811%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2812%29%3Achecked~.tabbed-labels%3E%3Anth-child%2812%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2813%29%3Achecked~.tabbed-labels%3E%3Anth-child%2813%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2814%29%3Achecked~.tabbed-labels%3E%3Anth-child%2814%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2815%29%3Achecked~.tabbed-labels%3E%3Anth-child%2815%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2816%29%3Achecked~.tabbed-labels%3E%3Anth-child%2816%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2817%29%3Achecked~.tabbed-labels%3E%3Anth-child%2817%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2818%29%3Achecked~.tabbed-labels%3E%3Anth-child%2818%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2819%29%3Achecked~.tabbed-labels%3E%3Anth-child%2819%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%282%29%3Achecked~.tabbed-labels%3E%3Anth-child%282%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2820%29%3Achecked~.tabbed-labels%3E%3Anth-child%2820%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%283%29%3Achecked~.tabbed-labels%3E%3Anth-child%283%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%284%29%3Achecked~.tabbed-labels%3E%3Anth-child%284%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%285%29%3Achecked~.tabbed-labels%3E%3Anth-child%285%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%286%29%3Achecked~.tabbed-labels%3E%3Anth-child%286%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%287%29%3Achecked~.tabbed-labels%3E%3Anth-child%287%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%288%29%3Achecked~.tabbed-labels%3E%3Anth-child%288%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%289%29%3Achecked~.tabbed-labels%3E%3Anth-child%289%29%7Bcolor%3Avar%28--md-default-fg-color%29%7D.md-typeset%20.no-js%20.tabbed-set%3Einput%3Afirst-child%3Achecked~.tabbed-labels%3E%3Afirst-child%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%2810%29%3Achecked~.tabbed-labels%3E%3Anth-child%2810%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%2811%29%3Achecked~.tabbed-labels%3E%3Anth-child%2811%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%2812%29%3Achecked~.tabbed-labels%3E%3Anth-child%2812%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%2813%29%3Achecked~.tabbed-labels%3E%3Anth-child%2813%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%2814%29%3Achecked~.tabbed-labels%3E%3Anth-child%2814%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%2815%29%3Achecked~.tabbed-labels%3E%3Anth-child%2815%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%2816%29%3Achecked~.tabbed-labels%3E%3Anth-child%2816%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%2817%29%3Achecked~.tabbed-labels%3E%3Anth-child%2817%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%2818%29%3Achecked~.tabbed-labels%3E%3Anth-child%2818%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%2819%29%3Achecked~.tabbed-labels%3E%3Anth-child%2819%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%282%29%3Achecked~.tabbed-labels%3E%3Anth-child%282%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%2820%29%3Achecked~.tabbed-labels%3E%3Anth-child%2820%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%283%29%3Achecked~.tabbed-labels%3E%3Anth-child%283%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%284%29%3Achecked~.tabbed-labels%3E%3Anth-child%284%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%285%29%3Achecked~.tabbed-labels%3E%3Anth-child%285%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%286%29%3Achecked~.tabbed-labels%3E%3Anth-child%286%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%287%29%3Achecked~.tabbed-labels%3E%3Anth-child%287%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%288%29%3Achecked~.tabbed-labels%3E%3Anth-child%288%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%289%29%3Achecked~.tabbed-labels%3E%3Anth-child%289%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Afirst-child%3Achecked~.tabbed-labels%3E%3Afirst-child%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%2810%29%3Achecked~.tabbed-labels%3E%3Anth-child%2810%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%2811%29%3Achecked~.tabbed-labels%3E%3Anth-child%2811%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%2812%29%3Achecked~.tabbed-labels%3E%3Anth-child%2812%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%2813%29%3Achecked~.tabbed-labels%3E%3Anth-child%2813%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%2814%29%3Achecked~.tabbed-labels%3E%3Anth-child%2814%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%2815%29%3Achecked~.tabbed-labels%3E%3Anth-child%2815%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%2816%29%3Achecked~.tabbed-labels%3E%3Anth-child%2816%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%2817%29%3Achecked~.tabbed-labels%3E%3Anth-child%2817%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%2818%29%3Achecked~.tabbed-labels%3E%3Anth-child%2818%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%2819%29%3Achecked~.tabbed-labels%3E%3Anth-child%2819%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%282%29%3Achecked~.tabbed-labels%3E%3Anth-child%282%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%2820%29%3Achecked~.tabbed-labels%3E%3Anth-child%2820%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%283%29%3Achecked~.tabbed-labels%3E%3Anth-child%283%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%284%29%3Achecked~.tabbed-labels%3E%3Anth-child%284%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%285%29%3Achecked~.tabbed-labels%3E%3Anth-child%285%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%286%29%3Achecked~.tabbed-labels%3E%3Anth-child%286%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%287%29%3Achecked~.tabbed-labels%3E%3Anth-child%287%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%288%29%3Achecked~.tabbed-labels%3E%3Anth-child%288%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%289%29%3Achecked~.tabbed-labels%3E%3Anth-child%289%29%7Bborder-color%3Avar%28--md-default-fg-color%29%7D%7D.md-typeset%20.tabbed-set%3Einput%3Afirst-child.focus-visible~.tabbed-labels%3E%3Afirst-child%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2810%29.focus-visible~.tabbed-labels%3E%3Anth-child%2810%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2811%29.focus-visible~.tabbed-labels%3E%3Anth-child%2811%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2812%29.focus-visible~.tabbed-labels%3E%3Anth-child%2812%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2813%29.focus-visible~.tabbed-labels%3E%3Anth-child%2813%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2814%29.focus-visible~.tabbed-labels%3E%3Anth-child%2814%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2815%29.focus-visible~.tabbed-labels%3E%3Anth-child%2815%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2816%29.focus-visible~.tabbed-labels%3E%3Anth-child%2816%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2817%29.focus-visible~.tabbed-labels%3E%3Anth-child%2817%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2818%29.focus-visible~.tabbed-labels%3E%3Anth-child%2818%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2819%29.focus-visible~.tabbed-labels%3E%3Anth-child%2819%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%282%29.focus-visible~.tabbed-labels%3E%3Anth-child%282%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2820%29.focus-visible~.tabbed-labels%3E%3Anth-child%2820%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%283%29.focus-visible~.tabbed-labels%3E%3Anth-child%283%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%284%29.focus-visible~.tabbed-labels%3E%3Anth-child%284%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%285%29.focus-visible~.tabbed-labels%3E%3Anth-child%285%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%286%29.focus-visible~.tabbed-labels%3E%3Anth-child%286%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%287%29.focus-visible~.tabbed-labels%3E%3Anth-child%287%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%288%29.focus-visible~.tabbed-labels%3E%3Anth-child%288%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%289%29.focus-visible~.tabbed-labels%3E%3Anth-child%289%29%7Bcolor%3Avar%28--md-accent-fg-color%29%7D.md-typeset%20.tabbed-set%3Einput%3Afirst-child%3Achecked~.tabbed-content%3E%3Afirst-child%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2810%29%3Achecked~.tabbed-content%3E%3Anth-child%2810%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2811%29%3Achecked~.tabbed-content%3E%3Anth-child%2811%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2812%29%3Achecked~.tabbed-content%3E%3Anth-child%2812%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2813%29%3Achecked~.tabbed-content%3E%3Anth-child%2813%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2814%29%3Achecked~.tabbed-content%3E%3Anth-child%2814%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2815%29%3Achecked~.tabbed-content%3E%3Anth-child%2815%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2816%29%3Achecked~.tabbed-content%3E%3Anth-child%2816%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2817%29%3Achecked~.tabbed-content%3E%3Anth-child%2817%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2818%29%3Achecked~.tabbed-content%3E%3Anth-child%2818%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2819%29%3Achecked~.tabbed-content%3E%3Anth-child%2819%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%282%29%3Achecked~.tabbed-content%3E%3Anth-child%282%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2820%29%3Achecked~.tabbed-content%3E%3Anth-child%2820%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%283%29%3Achecked~.tabbed-content%3E%3Anth-child%283%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%284%29%3Achecked~.tabbed-content%3E%3Anth-child%284%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%285%29%3Achecked~.tabbed-content%3E%3Anth-child%285%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%286%29%3Achecked~.tabbed-content%3E%3Anth-child%286%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%287%29%3Achecked~.tabbed-content%3E%3Anth-child%287%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%288%29%3Achecked~.tabbed-content%3E%3Anth-child%288%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%289%29%3Achecked~.tabbed-content%3E%3Anth-child%289%29%7Bdisplay%3Ablock%7D%3Aroot%7B--md-tasklist-icon%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M1%2012C1%205.925%205.925%201%2012%201s11%204.925%2011%2011-4.925%2011-11%2011S1%2018.075%201%2012m16.28-2.72a.75.75%200%200%200-.018-1.042.75.75%200%200%200-1.042-.018l-5.97%205.97-2.47-2.47a.75.75%200%200%200-1.042.018.75.75%200%200%200-.018%201.042l3%203a.75.75%200%200%200%201.06%200Z%22/%3E%3C/svg%3E%27%29%3B--md-tasklist-icon--checked%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M1%2012C1%205.925%205.925%201%2012%201s11%204.925%2011%2011-4.925%2011-11%2011S1%2018.075%201%2012m16.28-2.72a.75.75%200%200%200-.018-1.042.75.75%200%200%200-1.042-.018l-5.97%205.97-2.47-2.47a.75.75%200%200%200-1.042.018.75.75%200%200%200-.018%201.042l3%203a.75.75%200%200%200%201.06%200Z%22/%3E%3C/svg%3E%27%29%7D.md-typeset%20.task-list-item%7Blist-style-type%3Anone%3Bposition%3Arelative%7D%5Bdir%3Dltr%5D%20.md-typeset%20.task-list-item%20%5Btype%3Dcheckbox%5D%7Bleft%3A-2em%7D%5Bdir%3Drtl%5D%20.md-typeset%20.task-list-item%20%5Btype%3Dcheckbox%5D%7Bright%3A-2em%7D.md-typeset%20.task-list-item%20%5Btype%3Dcheckbox%5D%7Bposition%3Aabsolute%3Btop%3A.45em%7D.md-typeset%20.task-list-control%20%5Btype%3Dcheckbox%5D%7Bopacity%3A0%3Bz-index%3A-1%7D%5Bdir%3Dltr%5D%20.md-typeset%20.task-list-indicator%3Abefore%7Bleft%3A-1.5em%7D%5Bdir%3Drtl%5D%20.md-typeset%20.task-list-indicator%3Abefore%7Bright%3A-1.5em%7D.md-typeset%20.task-list-indicator%3Abefore%7Bbackground-color%3Avar%28--md-default-fg-color--lightest%29%3Bcontent%3A%22%22%3Bheight%3A1.25em%3B-webkit-mask-image%3Avar%28--md-tasklist-icon%29%3Bmask-image%3Avar%28--md-tasklist-icon%29%3B-webkit-mask-position%3Acenter%3Bmask-position%3Acenter%3B-webkit-mask-repeat%3Ano-repeat%3Bmask-repeat%3Ano-repeat%3B-webkit-mask-size%3Acontain%3Bmask-size%3Acontain%3Bposition%3Aabsolute%3Btop%3A.15em%3Bwidth%3A1.25em%7D.md-typeset%20%5Btype%3Dcheckbox%5D%3Achecked%2B.task-list-indicator%3Abefore%7Bbackground-color%3A%2300e676%3B-webkit-mask-image%3Avar%28--md-tasklist-icon--checked%29%3Bmask-image%3Avar%28--md-tasklist-icon--checked%29%7D%40media%20print%7B.giscus%2C%5Bid%3D__comments%5D%7Bdisplay%3Anone%7D%7D%3Aroot%3E%2A%7B--md-mermaid-font-family%3Avar%28--md-text-font-family%29%2Csans-serif%3B--md-mermaid-edge-color%3Avar%28--md-code-fg-color%29%3B--md-mermaid-node-bg-color%3Avar%28--md-accent-fg-color--transparent%29%3B--md-mermaid-node-fg-color%3Avar%28--md-accent-fg-color%29%3B--md-mermaid-label-bg-color%3Avar%28--md-default-bg-color%29%3B--md-mermaid-label-fg-color%3Avar%28--md-code-fg-color%29%3B--md-mermaid-sequence-actor-bg-color%3Avar%28--md-mermaid-label-bg-color%29%3B--md-mermaid-sequence-actor-fg-color%3Avar%28--md-mermaid-label-fg-color%29%3B--md-mermaid-sequence-actor-border-color%3Avar%28--md-mermaid-node-fg-color%29%3B--md-mermaid-sequence-actor-line-color%3Avar%28--md-default-fg-color--lighter%29%3B--md-mermaid-sequence-actorman-bg-color%3Avar%28--md-mermaid-label-bg-color%29%3B--md-mermaid-sequence-actorman-line-color%3Avar%28--md-mermaid-node-fg-color%29%3B--md-mermaid-sequence-box-bg-color%3Avar%28--md-mermaid-node-bg-color%29%3B--md-mermaid-sequence-box-fg-color%3Avar%28--md-mermaid-edge-color%29%3B--md-mermaid-sequence-label-bg-color%3Avar%28--md-mermaid-node-bg-color%29%3B--md-mermaid-sequence-label-fg-color%3Avar%28--md-mermaid-node-fg-color%29%3B--md-mermaid-sequence-loop-bg-color%3Avar%28--md-mermaid-node-bg-color%29%3B--md-mermaid-sequence-loop-fg-color%3Avar%28--md-mermaid-edge-color%29%3B--md-mermaid-sequence-loop-border-color%3Avar%28--md-mermaid-node-fg-color%29%3B--md-mermaid-sequence-message-fg-color%3Avar%28--md-mermaid-edge-color%29%3B--md-mermaid-sequence-message-line-color%3Avar%28--md-mermaid-edge-color%29%3B--md-mermaid-sequence-note-bg-color%3Avar%28--md-mermaid-label-bg-color%29%3B--md-mermaid-sequence-note-fg-color%3Avar%28--md-mermaid-edge-color%29%3B--md-mermaid-sequence-note-border-color%3Avar%28--md-mermaid-label-fg-color%29%3B--md-mermaid-sequence-number-bg-color%3Avar%28--md-mermaid-node-fg-color%29%3B--md-mermaid-sequence-number-fg-color%3Avar%28--md-accent-bg-color%29%7D.mermaid%7Bline-height%3Anormal%3Bmargin%3A1em%200%7D.md-typeset%20.grid%7Bgrid-gap%3A.4rem%3Bdisplay%3Agrid%3Bgrid-template-columns%3Arepeat%28auto-fit%2Cminmax%28min%28100%25%2C16rem%29%2C1fr%29%29%3Bmargin%3A1em%200%7D.md-typeset%20.grid.cards%3Eol%2C.md-typeset%20.grid.cards%3Eul%7Bdisplay%3Acontents%7D.md-typeset%20.grid.cards%3Eol%3Eli%2C.md-typeset%20.grid.cards%3Eul%3Eli%2C.md-typeset%20.grid%3E.card%7Bborder%3A.05rem%20solid%20var%28--md-default-fg-color--lightest%29%3Bborder-radius%3A.1rem%3Bdisplay%3Ablock%3Bmargin%3A0%3Bpadding%3A.8rem%3Btransition%3Aborder%20.25s%2Cbox-shadow%20.25s%7D.md-typeset%20.grid.cards%3Eol%3Eli%3Afocus-within%2C.md-typeset%20.grid.cards%3Eol%3Eli%3Ahover%2C.md-typeset%20.grid.cards%3Eul%3Eli%3Afocus-within%2C.md-typeset%20.grid.cards%3Eul%3Eli%3Ahover%2C.md-typeset%20.grid%3E.card%3Afocus-within%2C.md-typeset%20.grid%3E.card%3Ahover%7Bborder-color%3A%230000%3Bbox-shadow%3Avar%28--md-shadow-z2%29%7D.md-typeset%20.grid.cards%3Eol%3Eli%3Ehr%2C.md-typeset%20.grid.cards%3Eul%3Eli%3Ehr%2C.md-typeset%20.grid%3E.card%3Ehr%7Bmargin-bottom%3A1em%3Bmargin-top%3A1em%7D.md-typeset%20.grid.cards%3Eol%3Eli%3E%3Afirst-child%2C.md-typeset%20.grid.cards%3Eul%3Eli%3E%3Afirst-child%2C.md-typeset%20.grid%3E.card%3E%3Afirst-child%7Bmargin-top%3A0%7D.md-typeset%20.grid.cards%3Eol%3Eli%3E%3Alast-child%2C.md-typeset%20.grid.cards%3Eul%3Eli%3E%3Alast-child%2C.md-typeset%20.grid%3E.card%3E%3Alast-child%7Bmargin-bottom%3A0%7D.md-typeset%20.grid%3E%2A%2C.md-typeset%20.grid%3E.admonition%2C.md-typeset%20.grid%3E.highlight%3E%2A%2C.md-typeset%20.grid%3E.highlighttable%2C.md-typeset%20.grid%3E.md-typeset%20details%2C.md-typeset%20.grid%3Edetails%2C.md-typeset%20.grid%3Epre%7Bmargin-bottom%3A0%3Bmargin-top%3A0%7D.md-typeset%20.grid%3E.highlight%3Epre%3Aonly-child%2C.md-typeset%20.grid%3E.highlight%3Epre%3Ecode%2C.md-typeset%20.grid%3E.highlighttable%2C.md-typeset%20.grid%3E.highlighttable%3Etbody%2C.md-typeset%20.grid%3E.highlighttable%3Etbody%3Etr%2C.md-typeset%20.grid%3E.highlighttable%3Etbody%3Etr%3E.code%2C.md-typeset%20.grid%3E.highlighttable%3Etbody%3Etr%3E.code%3E.highlight%2C.md-typeset%20.grid%3E.highlighttable%3Etbody%3Etr%3E.code%3E.highlight%3Epre%2C.md-typeset%20.grid%3E.highlighttable%3Etbody%3Etr%3E.code%3E.highlight%3Epre%3Ecode%7Bheight%3A100%25%7D.md-typeset%20.grid%3E.tabbed-set%7Bmargin-bottom%3A0%3Bmargin-top%3A0%7D%40media%20screen%20and%20%28min-width%3A45em%29%7B%5Bdir%3Dltr%5D%20.md-typeset%20.inline%7Bfloat%3Aleft%7D%5Bdir%3Drtl%5D%20.md-typeset%20.inline%7Bfloat%3Aright%7D%5Bdir%3Dltr%5D%20.md-typeset%20.inline%7Bmargin-right%3A.8rem%7D%5Bdir%3Drtl%5D%20.md-typeset%20.inline%7Bmargin-left%3A.8rem%7D.md-typeset%20.inline%7Bmargin-bottom%3A.8rem%3Bmargin-top%3A0%3Bwidth%3A11.7rem%7D%5Bdir%3Dltr%5D%20.md-typeset%20.inline.end%7Bfloat%3Aright%7D%5Bdir%3Drtl%5D%20.md-typeset%20.inline.end%7Bfloat%3Aleft%7D%5Bdir%3Dltr%5D%20.md-typeset%20.inline.end%7Bmargin-left%3A.8rem%3Bmargin-right%3A0%7D%5Bdir%3Drtl%5D%20.md-typeset%20.inline.end%7Bmargin-left%3A0%3Bmargin-right%3A.8rem%7D%7D" rel="stylesheet"/><!--URL:../assets/stylesheets/main.6f8fc17f.min.css-->
<link href="data:text/css,%40media%20screen%7B%5Bdata-md-color-scheme%3Dslate%5D%7B--md-default-fg-color%3Ahsla%28var%28--md-hue%29%2C15%25%2C90%25%2C0.82%29%3B--md-default-fg-color--light%3Ahsla%28var%28--md-hue%29%2C15%25%2C90%25%2C0.56%29%3B--md-default-fg-color--lighter%3Ahsla%28var%28--md-hue%29%2C15%25%2C90%25%2C0.32%29%3B--md-default-fg-color--lightest%3Ahsla%28var%28--md-hue%29%2C15%25%2C90%25%2C0.12%29%3B--md-default-bg-color%3Ahsla%28var%28--md-hue%29%2C15%25%2C14%25%2C1%29%3B--md-default-bg-color--light%3Ahsla%28var%28--md-hue%29%2C15%25%2C14%25%2C0.54%29%3B--md-default-bg-color--lighter%3Ahsla%28var%28--md-hue%29%2C15%25%2C14%25%2C0.26%29%3B--md-default-bg-color--lightest%3Ahsla%28var%28--md-hue%29%2C15%25%2C14%25%2C0.07%29%3B--md-code-fg-color%3Ahsla%28var%28--md-hue%29%2C18%25%2C86%25%2C0.82%29%3B--md-code-bg-color%3Ahsla%28var%28--md-hue%29%2C15%25%2C18%25%2C1%29%3B--md-code-hl-color%3A%232977ff%3B--md-code-hl-color--light%3A%232977ff1a%3B--md-code-hl-number-color%3A%23e6695b%3B--md-code-hl-special-color%3A%23f06090%3B--md-code-hl-function-color%3A%23c973d9%3B--md-code-hl-constant-color%3A%239383e2%3B--md-code-hl-keyword-color%3A%236791e0%3B--md-code-hl-string-color%3A%232fb170%3B--md-code-hl-name-color%3Avar%28--md-code-fg-color%29%3B--md-code-hl-operator-color%3Avar%28--md-default-fg-color--light%29%3B--md-code-hl-punctuation-color%3Avar%28--md-default-fg-color--light%29%3B--md-code-hl-comment-color%3Avar%28--md-default-fg-color--light%29%3B--md-code-hl-generic-color%3Avar%28--md-default-fg-color--light%29%3B--md-code-hl-variable-color%3Avar%28--md-default-fg-color--light%29%3B--md-typeset-color%3Avar%28--md-default-fg-color%29%3B--md-typeset-a-color%3Avar%28--md-primary-fg-color%29%3B--md-typeset-kbd-color%3Ahsla%28var%28--md-hue%29%2C15%25%2C90%25%2C0.12%29%3B--md-typeset-kbd-accent-color%3Ahsla%28var%28--md-hue%29%2C15%25%2C90%25%2C0.2%29%3B--md-typeset-kbd-border-color%3Ahsla%28var%28--md-hue%29%2C15%25%2C14%25%2C1%29%3B--md-typeset-mark-color%3A%234287ff4d%3B--md-typeset-table-color%3Ahsla%28var%28--md-hue%29%2C15%25%2C95%25%2C0.12%29%3B--md-typeset-table-color--light%3Ahsla%28var%28--md-hue%29%2C15%25%2C95%25%2C0.035%29%3B--md-admonition-fg-color%3Avar%28--md-default-fg-color%29%3B--md-admonition-bg-color%3Avar%28--md-default-bg-color%29%3B--md-footer-bg-color%3Ahsla%28var%28--md-hue%29%2C15%25%2C10%25%2C0.87%29%3B--md-footer-bg-color--dark%3Ahsla%28var%28--md-hue%29%2C15%25%2C8%25%2C1%29%3B--md-shadow-z1%3A0%200.2rem%200.5rem%20%230000000d%2C0%200%200.05rem%20%230000001a%3B--md-shadow-z2%3A0%200.2rem%200.5rem%20%2300000040%2C0%200%200.05rem%20%2300000040%3B--md-shadow-z3%3A0%200.2rem%200.5rem%20%230006%2C0%200%200.05rem%20%2300000059%3Bcolor-scheme%3Adark%7D%5Bdata-md-color-scheme%3Dslate%5D%20img%5Bsrc%24%3D%22%23gh-light-mode-only%22%5D%2C%5Bdata-md-color-scheme%3Dslate%5D%20img%5Bsrc%24%3D%22%23only-light%22%5D%7Bdisplay%3Anone%7D%5Bdata-md-color-scheme%3Dslate%5D%5Bdata-md-color-primary%3Dpink%5D%7B--md-typeset-a-color%3A%23ed5487%7D%5Bdata-md-color-scheme%3Dslate%5D%5Bdata-md-color-primary%3Dpurple%5D%7B--md-typeset-a-color%3A%23c46fd3%7D%5Bdata-md-color-scheme%3Dslate%5D%5Bdata-md-color-primary%3Ddeep-purple%5D%7B--md-typeset-a-color%3A%23a47bea%7D%5Bdata-md-color-scheme%3Dslate%5D%5Bdata-md-color-primary%3Dindigo%5D%7B--md-typeset-a-color%3A%235488e8%7D%5Bdata-md-color-scheme%3Dslate%5D%5Bdata-md-color-primary%3Dteal%5D%7B--md-typeset-a-color%3A%2300ccb8%7D%5Bdata-md-color-scheme%3Dslate%5D%5Bdata-md-color-primary%3Dgreen%5D%7B--md-typeset-a-color%3A%2371c174%7D%5Bdata-md-color-scheme%3Dslate%5D%5Bdata-md-color-primary%3Ddeep-orange%5D%7B--md-typeset-a-color%3A%23ff764d%7D%5Bdata-md-color-scheme%3Dslate%5D%5Bdata-md-color-primary%3Dbrown%5D%7B--md-typeset-a-color%3A%23c1775c%7D%5Bdata-md-color-scheme%3Dslate%5D%5Bdata-md-color-primary%3Dblack%5D%2C%5Bdata-md-color-scheme%3Dslate%5D%5Bdata-md-color-primary%3Dblue-grey%5D%2C%5Bdata-md-color-scheme%3Dslate%5D%5Bdata-md-color-primary%3Dgrey%5D%2C%5Bdata-md-color-scheme%3Dslate%5D%5Bdata-md-color-primary%3Dwhite%5D%7B--md-typeset-a-color%3A%235e8bde%7D%5Bdata-md-color-switching%5D%20%2A%2C%5Bdata-md-color-switching%5D%20%3Aafter%2C%5Bdata-md-color-switching%5D%20%3Abefore%7Btransition-duration%3A0ms%21important%7D%7D%5Bdata-md-color-accent%3Dred%5D%7B--md-accent-fg-color%3A%23ff1947%3B--md-accent-fg-color--transparent%3A%23ff19471a%3B--md-accent-bg-color%3A%23fff%3B--md-accent-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-accent%3Dpink%5D%7B--md-accent-fg-color%3A%23f50056%3B--md-accent-fg-color--transparent%3A%23f500561a%3B--md-accent-bg-color%3A%23fff%3B--md-accent-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-accent%3Dpurple%5D%7B--md-accent-fg-color%3A%23df41fb%3B--md-accent-fg-color--transparent%3A%23df41fb1a%3B--md-accent-bg-color%3A%23fff%3B--md-accent-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-accent%3Ddeep-purple%5D%7B--md-accent-fg-color%3A%237c4dff%3B--md-accent-fg-color--transparent%3A%237c4dff1a%3B--md-accent-bg-color%3A%23fff%3B--md-accent-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-accent%3Dindigo%5D%7B--md-accent-fg-color%3A%23526cfe%3B--md-accent-fg-color--transparent%3A%23526cfe1a%3B--md-accent-bg-color%3A%23fff%3B--md-accent-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-accent%3Dblue%5D%7B--md-accent-fg-color%3A%234287ff%3B--md-accent-fg-color--transparent%3A%234287ff1a%3B--md-accent-bg-color%3A%23fff%3B--md-accent-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-accent%3Dlight-blue%5D%7B--md-accent-fg-color%3A%230091eb%3B--md-accent-fg-color--transparent%3A%230091eb1a%3B--md-accent-bg-color%3A%23fff%3B--md-accent-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-accent%3Dcyan%5D%7B--md-accent-fg-color%3A%2300bad6%3B--md-accent-fg-color--transparent%3A%2300bad61a%3B--md-accent-bg-color%3A%23fff%3B--md-accent-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-accent%3Dteal%5D%7B--md-accent-fg-color%3A%2300bda4%3B--md-accent-fg-color--transparent%3A%2300bda41a%3B--md-accent-bg-color%3A%23fff%3B--md-accent-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-accent%3Dgreen%5D%7B--md-accent-fg-color%3A%2300c753%3B--md-accent-fg-color--transparent%3A%2300c7531a%3B--md-accent-bg-color%3A%23fff%3B--md-accent-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-accent%3Dlight-green%5D%7B--md-accent-fg-color%3A%2363de17%3B--md-accent-fg-color--transparent%3A%2363de171a%3B--md-accent-bg-color%3A%23fff%3B--md-accent-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-accent%3Dlime%5D%7B--md-accent-fg-color%3A%23b0eb00%3B--md-accent-fg-color--transparent%3A%23b0eb001a%3B--md-accent-bg-color%3A%23000000de%3B--md-accent-bg-color--light%3A%230000008a%7D%5Bdata-md-color-accent%3Dyellow%5D%7B--md-accent-fg-color%3A%23ffd500%3B--md-accent-fg-color--transparent%3A%23ffd5001a%3B--md-accent-bg-color%3A%23000000de%3B--md-accent-bg-color--light%3A%230000008a%7D%5Bdata-md-color-accent%3Damber%5D%7B--md-accent-fg-color%3A%23fa0%3B--md-accent-fg-color--transparent%3A%23ffaa001a%3B--md-accent-bg-color%3A%23000000de%3B--md-accent-bg-color--light%3A%230000008a%7D%5Bdata-md-color-accent%3Dorange%5D%7B--md-accent-fg-color%3A%23ff9100%3B--md-accent-fg-color--transparent%3A%23ff91001a%3B--md-accent-bg-color%3A%23000000de%3B--md-accent-bg-color--light%3A%230000008a%7D%5Bdata-md-color-accent%3Ddeep-orange%5D%7B--md-accent-fg-color%3A%23ff6e42%3B--md-accent-fg-color--transparent%3A%23ff6e421a%3B--md-accent-bg-color%3A%23fff%3B--md-accent-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-primary%3Dred%5D%7B--md-primary-fg-color%3A%23ef5552%3B--md-primary-fg-color--light%3A%23e57171%3B--md-primary-fg-color--dark%3A%23e53734%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-primary%3Dpink%5D%7B--md-primary-fg-color%3A%23e92063%3B--md-primary-fg-color--light%3A%23ec417a%3B--md-primary-fg-color--dark%3A%23c3185d%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-primary%3Dpurple%5D%7B--md-primary-fg-color%3A%23ab47bd%3B--md-primary-fg-color--light%3A%23bb69c9%3B--md-primary-fg-color--dark%3A%238c24a8%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-primary%3Ddeep-purple%5D%7B--md-primary-fg-color%3A%237e56c2%3B--md-primary-fg-color--light%3A%239574cd%3B--md-primary-fg-color--dark%3A%23673ab6%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-primary%3Dindigo%5D%7B--md-primary-fg-color%3A%234051b5%3B--md-primary-fg-color--light%3A%235d6cc0%3B--md-primary-fg-color--dark%3A%23303fa1%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-primary%3Dblue%5D%7B--md-primary-fg-color%3A%232094f3%3B--md-primary-fg-color--light%3A%2342a5f5%3B--md-primary-fg-color--dark%3A%231975d2%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-primary%3Dlight-blue%5D%7B--md-primary-fg-color%3A%2302a6f2%3B--md-primary-fg-color--light%3A%2328b5f6%3B--md-primary-fg-color--dark%3A%230287cf%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-primary%3Dcyan%5D%7B--md-primary-fg-color%3A%2300bdd6%3B--md-primary-fg-color--light%3A%2325c5da%3B--md-primary-fg-color--dark%3A%230097a8%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-primary%3Dteal%5D%7B--md-primary-fg-color%3A%23009485%3B--md-primary-fg-color--light%3A%2326a699%3B--md-primary-fg-color--dark%3A%23007a6c%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-primary%3Dgreen%5D%7B--md-primary-fg-color%3A%234cae4f%3B--md-primary-fg-color--light%3A%2368bb6c%3B--md-primary-fg-color--dark%3A%23398e3d%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-primary%3Dlight-green%5D%7B--md-primary-fg-color%3A%238bc34b%3B--md-primary-fg-color--light%3A%239ccc66%3B--md-primary-fg-color--dark%3A%23689f38%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-primary%3Dlime%5D%7B--md-primary-fg-color%3A%23cbdc38%3B--md-primary-fg-color--light%3A%23d3e156%3B--md-primary-fg-color--dark%3A%23b0b52c%3B--md-primary-bg-color%3A%23000000de%3B--md-primary-bg-color--light%3A%230000008a%7D%5Bdata-md-color-primary%3Dyellow%5D%7B--md-primary-fg-color%3A%23ffec3d%3B--md-primary-fg-color--light%3A%23ffee57%3B--md-primary-fg-color--dark%3A%23fbc02d%3B--md-primary-bg-color%3A%23000000de%3B--md-primary-bg-color--light%3A%230000008a%7D%5Bdata-md-color-primary%3Damber%5D%7B--md-primary-fg-color%3A%23ffc105%3B--md-primary-fg-color--light%3A%23ffc929%3B--md-primary-fg-color--dark%3A%23ffa200%3B--md-primary-bg-color%3A%23000000de%3B--md-primary-bg-color--light%3A%230000008a%7D%5Bdata-md-color-primary%3Dorange%5D%7B--md-primary-fg-color%3A%23ffa724%3B--md-primary-fg-color--light%3A%23ffa724%3B--md-primary-fg-color--dark%3A%23fa8900%3B--md-primary-bg-color%3A%23000000de%3B--md-primary-bg-color--light%3A%230000008a%7D%5Bdata-md-color-primary%3Ddeep-orange%5D%7B--md-primary-fg-color%3A%23ff6e42%3B--md-primary-fg-color--light%3A%23ff8a66%3B--md-primary-fg-color--dark%3A%23f4511f%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-primary%3Dbrown%5D%7B--md-primary-fg-color%3A%23795649%3B--md-primary-fg-color--light%3A%238d6e62%3B--md-primary-fg-color--dark%3A%235d4037%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-primary%3Dgrey%5D%7B--md-primary-fg-color%3A%23757575%3B--md-primary-fg-color--light%3A%239e9e9e%3B--md-primary-fg-color--dark%3A%23616161%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%3B--md-typeset-a-color%3A%234051b5%7D%5Bdata-md-color-primary%3Dblue-grey%5D%7B--md-primary-fg-color%3A%23546d78%3B--md-primary-fg-color--light%3A%23607c8a%3B--md-primary-fg-color--dark%3A%23455a63%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%3B--md-typeset-a-color%3A%234051b5%7D%5Bdata-md-color-primary%3Dlight-green%5D%3Anot%28%5Bdata-md-color-scheme%3Dslate%5D%29%7B--md-typeset-a-color%3A%2372ad2e%7D%5Bdata-md-color-primary%3Dlime%5D%3Anot%28%5Bdata-md-color-scheme%3Dslate%5D%29%7B--md-typeset-a-color%3A%238b990a%7D%5Bdata-md-color-primary%3Dyellow%5D%3Anot%28%5Bdata-md-color-scheme%3Dslate%5D%29%7B--md-typeset-a-color%3A%23b8a500%7D%5Bdata-md-color-primary%3Damber%5D%3Anot%28%5Bdata-md-color-scheme%3Dslate%5D%29%7B--md-typeset-a-color%3A%23d19d00%7D%5Bdata-md-color-primary%3Dorange%5D%3Anot%28%5Bdata-md-color-scheme%3Dslate%5D%29%7B--md-typeset-a-color%3A%23e68a00%7D%5Bdata-md-color-primary%3Dwhite%5D%7B--md-primary-fg-color%3Ahsla%28var%28--md-hue%29%2C0%25%2C100%25%2C1%29%3B--md-primary-fg-color--light%3Ahsla%28var%28--md-hue%29%2C0%25%2C100%25%2C0.7%29%3B--md-primary-fg-color--dark%3Ahsla%28var%28--md-hue%29%2C0%25%2C0%25%2C0.07%29%3B--md-primary-bg-color%3Ahsla%28var%28--md-hue%29%2C0%25%2C0%25%2C0.87%29%3B--md-primary-bg-color--light%3Ahsla%28var%28--md-hue%29%2C0%25%2C0%25%2C0.54%29%3B--md-typeset-a-color%3A%234051b5%7D%5Bdata-md-color-primary%3Dwhite%5D%20.md-button%7Bcolor%3Avar%28--md-typeset-a-color%29%7D%5Bdata-md-color-primary%3Dwhite%5D%20.md-button--primary%7Bbackground-color%3Avar%28--md-typeset-a-color%29%3Bborder-color%3Avar%28--md-typeset-a-color%29%3Bcolor%3Ahsla%28var%28--md-hue%29%2C0%25%2C100%25%2C1%29%7D%40media%20screen%20and%20%28min-width%3A60em%29%7B%5Bdata-md-color-primary%3Dwhite%5D%20.md-search__form%7Bbackground-color%3Ahsla%28var%28--md-hue%29%2C0%25%2C0%25%2C.07%29%7D%5Bdata-md-color-primary%3Dwhite%5D%20.md-search__form%3Ahover%7Bbackground-color%3Ahsla%28var%28--md-hue%29%2C0%25%2C0%25%2C.32%29%7D%5Bdata-md-color-primary%3Dwhite%5D%20.md-search__input%2B.md-search__icon%7Bcolor%3Ahsla%28var%28--md-hue%29%2C0%25%2C0%25%2C.87%29%7D%7D%40media%20screen%20and%20%28min-width%3A76.25em%29%7B%5Bdata-md-color-primary%3Dwhite%5D%20.md-tabs%7Bborder-bottom%3A.05rem%20solid%20%2300000012%7D%7D%5Bdata-md-color-primary%3Dblack%5D%7B--md-primary-fg-color%3Ahsla%28var%28--md-hue%29%2C15%25%2C9%25%2C1%29%3B--md-primary-fg-color--light%3Ahsla%28var%28--md-hue%29%2C15%25%2C9%25%2C0.54%29%3B--md-primary-fg-color--dark%3Ahsla%28var%28--md-hue%29%2C15%25%2C9%25%2C1%29%3B--md-primary-bg-color%3Ahsla%28var%28--md-hue%29%2C15%25%2C100%25%2C1%29%3B--md-primary-bg-color--light%3Ahsla%28var%28--md-hue%29%2C15%25%2C100%25%2C0.7%29%3B--md-typeset-a-color%3A%234051b5%7D%5Bdata-md-color-primary%3Dblack%5D%20.md-button%7Bcolor%3Avar%28--md-typeset-a-color%29%7D%5Bdata-md-color-primary%3Dblack%5D%20.md-button--primary%7Bbackground-color%3Avar%28--md-typeset-a-color%29%3Bborder-color%3Avar%28--md-typeset-a-color%29%3Bcolor%3Ahsla%28var%28--md-hue%29%2C0%25%2C100%25%2C1%29%7D%5Bdata-md-color-primary%3Dblack%5D%20.md-header%7Bbackground-color%3Ahsla%28var%28--md-hue%29%2C15%25%2C9%25%2C1%29%7D%40media%20screen%20and%20%28max-width%3A59.984375em%29%7B%5Bdata-md-color-primary%3Dblack%5D%20.md-nav__source%7Bbackground-color%3Ahsla%28var%28--md-hue%29%2C15%25%2C11%25%2C.87%29%7D%7D%40media%20screen%20and%20%28max-width%3A76.234375em%29%7Bhtml%20%5Bdata-md-color-primary%3Dblack%5D%20.md-nav--primary%20.md-nav__title%5Bfor%3D__drawer%5D%7Bbackground-color%3Ahsla%28var%28--md-hue%29%2C15%25%2C9%25%2C1%29%7D%7D%40media%20screen%20and%20%28min-width%3A76.25em%29%7B%5Bdata-md-color-primary%3Dblack%5D%20.md-tabs%7Bbackground-color%3Ahsla%28var%28--md-hue%29%2C15%25%2C9%25%2C1%29%7D%7D" rel="stylesheet"/><!--URL:../assets/stylesheets/palette.06af60db.min.css-->
<link crossorigin="" href="https://fonts.gstatic.com" rel="preconnect"/>
<link href="data:text/css; charset=utf-8;base64,QGZvbnQtZmFjZSB7CiAgZm9udC1mYW1pbHk6ICdSb2JvdG8nOwogIGZvbnQtc3R5bGU6IGl0YWxpYzsKICBmb250LXdlaWdodDogMzAwOwogIGZvbnQtZGlzcGxheTogZmFsbGJhY2s7CiAgc3JjOiB1cmwoaHR0cHM6Ly9mb250cy5nc3RhdGljLmNvbS9zL3JvYm90by92MzIvS0ZPakNucUV1OTJGcjFNdTUxVGpBU2M2Q3NFLnR0ZikgZm9ybWF0KCd0cnVldHlwZScpOwp9CkBmb250LWZhY2UgewogIGZvbnQtZmFtaWx5OiAnUm9ib3RvJzsKICBmb250LXN0eWxlOiBpdGFsaWM7CiAgZm9udC13ZWlnaHQ6IDQwMDsKICBmb250LWRpc3BsYXk6IGZhbGxiYWNrOwogIHNyYzogdXJsKGh0dHBzOi8vZm9udHMuZ3N0YXRpYy5jb20vcy9yb2JvdG8vdjMyL0tGT2tDbnFFdTkyRnIxTXU1MXhJSXpjLnR0ZikgZm9ybWF0KCd0cnVldHlwZScpOwp9CkBmb250LWZhY2UgewogIGZvbnQtZmFtaWx5OiAnUm9ib3RvJzsKICBmb250LXN0eWxlOiBpdGFsaWM7CiAgZm9udC13ZWlnaHQ6IDcwMDsKICBmb250LWRpc3BsYXk6IGZhbGxiYWNrOwogIHNyYzogdXJsKGh0dHBzOi8vZm9udHMuZ3N0YXRpYy5jb20vcy9yb2JvdG8vdjMyL0tGT2pDbnFFdTkyRnIxTXU1MVR6QmljNkNzRS50dGYpIGZvcm1hdCgndHJ1ZXR5cGUnKTsKfQpAZm9udC1mYWNlIHsKICBmb250LWZhbWlseTogJ1JvYm90byc7CiAgZm9udC1zdHlsZTogbm9ybWFsOwogIGZvbnQtd2VpZ2h0OiAzMDA7CiAgZm9udC1kaXNwbGF5OiBmYWxsYmFjazsKICBzcmM6IHVybChodHRwczovL2ZvbnRzLmdzdGF0aWMuY29tL3Mvcm9ib3RvL3YzMi9LRk9sQ25xRXU5MkZyMU1tU1U1ZkJCYzkudHRmKSBmb3JtYXQoJ3RydWV0eXBlJyk7Cn0KQGZvbnQtZmFjZSB7CiAgZm9udC1mYW1pbHk6ICdSb2JvdG8nOwogIGZvbnQtc3R5bGU6IG5vcm1hbDsKICBmb250LXdlaWdodDogNDAwOwogIGZvbnQtZGlzcGxheTogZmFsbGJhY2s7CiAgc3JjOiB1cmwoaHR0cHM6Ly9mb250cy5nc3RhdGljLmNvbS9zL3JvYm90by92MzIvS0ZPbUNucUV1OTJGcjFNdTRteFAudHRmKSBmb3JtYXQoJ3RydWV0eXBlJyk7Cn0KQGZvbnQtZmFjZSB7CiAgZm9udC1mYW1pbHk6ICdSb2JvdG8nOwogIGZvbnQtc3R5bGU6IG5vcm1hbDsKICBmb250LXdlaWdodDogNzAwOwogIGZvbnQtZGlzcGxheTogZmFsbGJhY2s7CiAgc3JjOiB1cmwoaHR0cHM6Ly9mb250cy5nc3RhdGljLmNvbS9zL3JvYm90by92MzIvS0ZPbENucUV1OTJGcjFNbVdVbGZCQmM5LnR0ZikgZm9ybWF0KCd0cnVldHlwZScpOwp9CkBmb250LWZhY2UgewogIGZvbnQtZmFtaWx5OiAnUm9ib3RvIE1vbm8nOwogIGZvbnQtc3R5bGU6IGl0YWxpYzsKICBmb250LXdlaWdodDogNDAwOwogIGZvbnQtZGlzcGxheTogZmFsbGJhY2s7CiAgc3JjOiB1cmwoaHR0cHM6Ly9mb250cy5nc3RhdGljLmNvbS9zL3JvYm90b21vbm8vdjIzL0wweG9ERjR4bFZNRi1CZlI4YlhNSWpoT3NYRy1xMm9ldUZvcUZybG5BTlc2Q3B3LnR0ZikgZm9ybWF0KCd0cnVldHlwZScpOwp9CkBmb250LWZhY2UgewogIGZvbnQtZmFtaWx5OiAnUm9ib3RvIE1vbm8nOwogIGZvbnQtc3R5bGU6IGl0YWxpYzsKICBmb250LXdlaWdodDogNzAwOwogIGZvbnQtZGlzcGxheTogZmFsbGJhY2s7CiAgc3JjOiB1cmwoaHR0cHM6Ly9mb250cy5nc3RhdGljLmNvbS9zL3JvYm90b21vbm8vdjIzL0wweG9ERjR4bFZNRi1CZlI4YlhNSWpoT3NYRy1xMm9ldUZvcUZybUFCOVc2Q3B3LnR0ZikgZm9ybWF0KCd0cnVldHlwZScpOwp9CkBmb250LWZhY2UgewogIGZvbnQtZmFtaWx5OiAnUm9ib3RvIE1vbm8nOwogIGZvbnQtc3R5bGU6IG5vcm1hbDsKICBmb250LXdlaWdodDogNDAwOwogIGZvbnQtZGlzcGxheTogZmFsbGJhY2s7CiAgc3JjOiB1cmwoaHR0cHM6Ly9mb250cy5nc3RhdGljLmNvbS9zL3JvYm90b21vbm8vdjIzL0wweHVERjR4bFZNRi1CZlI4YlhNSWhKSGc0NW13Z0dFRmwwXzN2cV9ST1c5LnR0ZikgZm9ybWF0KCd0cnVldHlwZScpOwp9CkBmb250LWZhY2UgewogIGZvbnQtZmFtaWx5OiAnUm9ib3RvIE1vbm8nOwogIGZvbnQtc3R5bGU6IG5vcm1hbDsKICBmb250LXdlaWdodDogNzAwOwogIGZvbnQtZGlzcGxheTogZmFsbGJhY2s7CiAgc3JjOiB1cmwoaHR0cHM6Ly9mb250cy5nc3RhdGljLmNvbS9zL3JvYm90b21vbm8vdjIzL0wweHVERjR4bFZNRi1CZlI4YlhNSWhKSGc0NW13Z0dFRmwwX09mMl9ST1c5LnR0ZikgZm9ybWF0KCd0cnVldHlwZScpOwp9Cg==" rel="stylesheet"/><!--URL:https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback-->
<style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
<link href="data:text/css,%0A/%2A%20%0AThe%20print-site%20banner%0A%2A/%0A%23print-site-banner%20%7B%0A%20%20%20%20border%3A2px%3B%20%0A%20%20%20%20border-style%3Asolid%3B%20%0A%20%20%20%20border-color%3A%23000000%3B%20%0A%20%20%20%20padding%3A%200em%201em%200em%201em%3B%20%0A%20%20%20%20margin-bottom%3A%202em%3B%0A%7D%0A%23print-site-banner%20h3%20%7B%0A%20%20%20%20margin-top%3A%201rem%3B%0A%7D%0A%0A%0A/%2A%20%0AEnumerate%20headings%0A%0AOnly%20displayed%20when%20set%20in%20mkdocs.yml%0A%0Aprint-site%3A%0A%20%20%20%20-%20print-site-enumerate_headings%3A%20true%0A%2A/%0A%0A/%2A%20Ensure%20that%20when%20adding%20enumeration%20to%20headings%2C%20this%20happens%20inline%20%2A/%0A.print-site-enumerate-headings%20h1%3Abefore%2C%0A.print-site-enumerate-headings%20h2%3Abefore%2C%0A.print-site-enumerate-headings%20h3%3Abefore%2C%0A.print-site-enumerate-headings%20h4%3Abefore%2C%0A.print-site-enumerate-headings%20h5%3Abefore%2C%0A.print-site-enumerate-headings%20h6%3Abefore%20%7B%0A%20%20%20%20display%3A%20inline%20%21important%3B%0A%7D%0A%0A/%2A%20Reset%20all%20enumeration%20at%20start%20of%20page%20%2A/%0Abody%20%7Bcounter-reset%3A%20chapter%20sec-top%20toc-chapter%20toc-sec-chapter%20figurecounter%3B%7D%0A%0A/%2A%20Enumerate%20headings%20of%20CHAPTERS%2C%0Athat%20are%20part%20of%20an%20original%20included%20page%20%2A/%0A.print-site-enumerate-headings%20.print-page%20h1%20%7Bcounter-reset%3A%20section%20sub-section%20composite%20detail%20last%3B%20%7D%0A.print-site-enumerate-headings%20.print-page%20h2%20%7Bcounter-reset%3A%20sub-section%20composite%20detail%20last%3B%20%7D%0A.print-site-enumerate-headings%20.print-page%20h3%20%7Bcounter-reset%3A%20composite%20detail%20last%3B%20%7D%0A.print-site-enumerate-headings%20.print-page%20h4%20%7Bcounter-reset%3A%20detail%20last%3B%20%7D%0A.print-site-enumerate-headings%20.print-page%20h5%20%7Bcounter-reset%3A%20last%3B%20%7D%0A.print-site-enumerate-headings%20.print-page%20h1%3Abefore%20%7B%0A%20%20%20%20counter-increment%3A%20chapter%3B%0A%20%20%20%20content%3A%20counter%28chapter%29%20%22%20%22%20%21important%3B%0A%7D%0A.print-site-enumerate-headings%20h1.print-page-toc-title%3Abefore%2C%0A%23print-site-cover-page%20h1%3Abefore%2C%0A%23print-site-cover-page%20h2%3Abefore%2C%0A%23print-site-cover-page%20h3%3Abefore%2C%0A%23print-site-cover-page%20h4%3Abefore%2C%0A%23print-site-cover-page%20h5%3Abefore%2C%0A%23print-site-cover-page%20h6%3Abefore%20%7B%0A%20%20%20%20content%3A%20none%20%21important%3B%0A%20%20%20%20counter-increment%3A%20none%3B%0A%7D%0A.print-site-enumerate-headings%20.print-page%20h2%3Abefore%20%7B%0A%20%20counter-increment%3A%20section%3B%0A%20%20content%3A%20counter%28chapter%29%20%22.%22%20counter%28section%29%20%22%20%22%20%21important%3B%0A%7D%0A.print-site-enumerate-headings%20.print-page%20h3%3Abefore%20%7B%0A%20%20counter-increment%3A%20sub-section%3B%0A%20%20content%3A%20counter%28chapter%29%20%22.%22%20counter%28section%29%20%22.%22%20counter%28sub-section%29%20%22%20%22%20%21important%3B%0A%7D%0A.print-site-enumerate-headings%20.print-page%20h4%3Abefore%20%7B%0A%20%20counter-increment%3A%20composite%3B%0A%20%20content%3A%20counter%28chapter%29%20%22.%22%20counter%28section%29%20%22.%22%20counter%28sub-section%29%20%22.%22%20counter%28composite%29%20%22%20%22%20%21important%3B%0A%7D%0A.print-site-enumerate-headings%20.print-page%20h5%3Abefore%20%7B%0A%20%20counter-increment%3A%20detail%3B%0A%20%20content%3A%20counter%28chapter%29%20%22.%22%20counter%28section%29%20%22.%22%20counter%28sub-section%29%20%22.%22%20counter%28composite%29%20%22.%22%20counter%28detail%29%20%22%20%22%20%21important%3B%0A%7D%0A.print-site-enumerate-headings%20.print-page%20h6%3Abefore%20%7B%0A%20%20%20%20counter-increment%3A%20last%3B%0A%20%20%20%20content%3A%20counter%28chapter%29%20%22.%22%20counter%28section%29%20%22.%22%20counter%28sub-section%29%20%22.%22%20counter%28composite%29%20%22.%22%20counter%28detail%29%20%22.%22%20counter%28last%29%20%21important%3B%0A%7D%0A%0A/%2A%20Enumerate%20headings%20of%20SECTIONS%2C%0Athat%20are%20part%20of%20an%20original%20included%20page%20%2A/%0A.print-site-enumerate-headings%20h1%20%7Bcounter-reset%3A%20sec-section%20sec-sub-section%20sec-composite%20sec-detail%20sec-last%3B%20%7D%0A.print-site-enumerate-headings%20h2.nav-section-title%20%7Bcounter-reset%3A%20sec-sub-section%20sec-composite%20sec-detail%20sec-last%3B%20%7D%0A.print-site-enumerate-headings%20h3.nav-section-title%20%7Bcounter-reset%3A%20sec-composite%20sec-detail%20sec-last%3B%20%7D%0A.print-site-enumerate-headings%20h4.nav-section-title%20%7Bcounter-reset%3A%20sec-detail%20sec-last%3B%20%7D%0A.print-site-enumerate-headings%20h5.nav-section-title%20%7Bcounter-reset%3A%20sec-last%3B%20%7D%0A.print-site-enumerate-headings%20h1.nav-section-title%3Abefore%20%7B%0A%20%20%20%20counter-increment%3A%20sec-top%3B%0A%20%20%20%20content%3A%20counter%28sec-top%2C%20upper-roman%29%20%22.%20%22%20%21important%3B%0A%7D%0A.print-site-enumerate-headings%20h2.nav-section-title%3Abefore%20%7B%0A%20%20counter-increment%3A%20sec-section%3B%0A%20%20content%3A%20counter%28sec-top%2C%20upper-roman%29%20%22.%22%20counter%28sec-section%2C%20upper-roman%29%20%22%20%22%20%21important%3B%0A%7D%0A.print-site-enumerate-headings%20h3.nav-section-title%3Abefore%20%7B%0A%20%20counter-increment%3A%20sec-sub-section%3B%0A%20%20content%3A%20counter%28sec-top%2C%20upper-roman%29%20%22.%22%20counter%28sec-section%2C%20upper-roman%29%20%22.%22%20counter%28sec-sub-section%2C%20upper-roman%29%20%22%20%22%20%21important%3B%0A%7D%0A.print-site-enumerate-headings%20h4.nav-section-title%3Abefore%20%7B%0A%20%20counter-increment%3A%20sec-composite%3B%0A%20%20content%3A%20counter%28sec-top%2C%20upper-roman%29%20%22.%22%20counter%28sec-section%2C%20upper-roman%29%20%22.%22%20counter%28sec-sub-section%2C%20upper-roman%29%20%22.%22%20counter%28sec-composite%2C%20upper-roman%29%20%22%20%22%20%21important%3B%0A%7D%0A.print-site-enumerate-headings%20h5.nav-section-title%3Abefore%20%7B%0A%20%20counter-increment%3A%20sec-detail%3B%0A%20%20content%3A%20counter%28sec-top%2C%20upper-roman%29%20%22.%22%20counter%28sec-section%2C%20upper-roman%29%20%22.%22%20counter%28sec-sub-section%2C%20upper-roman%29%20%22.%22%20counter%28sec-composite%2C%20upper-roman%29%20%22.%22%20counter%28sec-detail%2C%20upper-roman%29%20%22%20%22%20%21important%3B%0A%7D%0A.print-site-enumerate-headings%20h6.nav-section-title%3Abefore%20%7B%0A%20%20%20%20counter-increment%3A%20sec-last%3B%0A%20%20%20%20content%3A%20counter%28sec-top%2C%20upper-roman%29%20%22.%22%20counter%28sec-section%2C%20upper-roman%29%20%22.%22%20counter%28sec-sub-section%2C%20upper-roman%29%20%22.%22%20counter%28sec-composite%2C%20upper-roman%29%20%22.%22%20counter%28sec-detail%2C%20upper-roman%29%20%22.%22%20counter%28sec-last%2C%20upper-roman%29%20%21important%3B%0A%7D%0A%0A%0A/%2A%20Enumerate%20CHAPTERS%20in%20table%20of%20contents%20also%20%2A/%0A.print-site-enumerate-headings%20.print-site-toc-level-1%20%3E%20ul%20%7B%20counter-reset%3A%20toc-section%3B%20%7D%0A.print-site-enumerate-headings%20.print-site-toc-level-2%20%3E%20ul%20%7B%20counter-reset%3A%20toc-sub-section%3B%20%7D%0A.print-site-enumerate-headings%20.print-site-toc-level-3%20%3E%20ul%20%7B%20counter-reset%3A%20toc-composite%3B%20%7D%0A.print-site-enumerate-headings%20.print-site-toc-level-4%20%3E%20ul%20%7B%20counter-reset%3A%20toc-detail%3B%20%7D%0A.print-site-enumerate-headings%20.print-site-toc-level-5%20%3E%20ul%20%7B%20counter-reset%3A%20toc-last%3B%20%7D%0A.print-site-enumerate-headings%20.print-site-toc-level-1%20%3E%20li%20a%3Abefore%20%7B%0A%20%20%20%20counter-increment%3A%20toc-chapter%3B%0A%20%20%20%20content%3A%20counter%28toc-chapter%29%20%22%20%22%3B%20%0A%7D%0A.print-site-enumerate-headings%20.print-site-toc-level-2%20%3E%20li%20a%3Abefore%20%7B%0A%20%20%20%20counter-increment%3A%20toc-section%3B%20%0A%20%20%20%20content%3A%20counter%28toc-chapter%29%20%22.%22%20counter%28toc-section%29%20%22%20%22%3B%0A%7D%0A.print-site-enumerate-headings%20.print-site-toc-level-3%20%3E%20li%20a%3Abefore%20%7B%0A%20%20%20%20counter-increment%3A%20toc-sub-section%3B%0A%20%20%20%20content%3A%20counter%28toc-chapter%29%20%22.%22%20counter%28toc-section%29%20%22.%22%20counter%28toc-sub-section%29%20%22%20%22%3B%0A%7D%0A.print-site-enumerate-headings%20.print-site-toc-level-4%20%3E%20li%20a%3Abefore%20%7B%0A%20%20%20%20counter-increment%3A%20toc-composite%3B%0A%20%20%20%20content%3A%20counter%28toc-chapter%29%20%22.%22%20counter%28toc-section%29%20%22.%22%20counter%28toc-sub-section%29%20%22.%22%20counter%28toc-composite%29%20%22%20%22%3B%0A%7D%0A.print-site-enumerate-headings%20.print-site-toc-level-5%20%3E%20li%20a%3Abefore%20%7B%0A%20%20%20%20counter-increment%3A%20toc-detail%3B%0A%20%20%20%20content%3A%20counter%28toc-chapter%29%20%22.%22%20counter%28toc-section%29%20%22.%22%20counter%28toc-sub-section%29%20%22.%22%20counter%28toc-composite%29%20%22.%22%20counter%28toc-detail%29%20%22%20%22%3B%0A%7D%0A.print-site-enumerate-headings%20.print-site-toc-level-6%20%3E%20li%20a%3Abefore%20%7B%0A%20%20%20%20counter-increment%3A%20toc-last%3B%0A%20%20%20%20content%3A%20counter%28toc-chapter%29%20%22.%22%20counter%28toc-section%29%20%22.%22%20counter%28toc-sub-section%29%20%22.%22%20counter%28toc-composite%29%20%22.%22%20counter%28toc-detail%29%20%22.%22%20counter%28toc-last%29%3B%0A%7D%0A%0A/%2A%20Enumerate%20SECTIONS%20in%20table%20of%20contents%20also%20%2A/%0A.print-site-enumerate-headings%20li.toc-nav-section-title-level-1%20%7B%20counter-reset%3A%20toc-sec-section%3B%20%7D%0A.print-site-enumerate-headings%20li.toc-nav-section-title-level-2%20%7B%20counter-reset%3A%20toc-sec-sub-section%3B%20%7D%0A.print-site-enumerate-headings%20li.toc-nav-section-title-level-3%20%7B%20counter-reset%3A%20toc-sec-composite%3B%20%7D%0A.print-site-enumerate-headings%20li.toc-nav-section-title-level-4%20%7B%20counter-reset%3A%20toc-sec-detail%3B%20%7D%0A.print-site-enumerate-headings%20li.toc-nav-section-title-level-5%20%7B%20counter-reset%3A%20toc-sec-last%3B%20%7D%0A.print-site-enumerate-headings%20li.toc-nav-section-title-level-1%3Abefore%20%7B%0A%20%20%20%20counter-increment%3A%20toc-sec-chapter%3B%0A%20%20%20%20content%3A%20counter%28toc-sec-chapter%2C%20upper-roman%29%20%22%20%22%3B%20%0A%7D%0A.print-site-enumerate-headings%20li.toc-nav-section-title-level-2%3Abefore%20%7B%0A%20%20%20%20counter-increment%3A%20toc-sec-section%3B%20%0A%20%20%20%20content%3A%20counter%28toc-sec-chapter%2C%20upper-roman%29%20%22.%22%20counter%28toc-sec-section%2C%20upper-roman%29%20%22%20%22%3B%0A%7D%0A.print-site-enumerate-headings%20li.toc-nav-section-title-level-3%3Abefore%20%7B%0A%20%20%20%20counter-increment%3A%20toc-sec-sub-section%3B%0A%20%20%20%20content%3A%20counter%28toc-sec-chapter%2C%20upper-roman%29%20%22.%22%20counter%28toc-sec-section%2C%20upper-roman%29%20%22.%22%20counter%28toc-sec-sub-section%2C%20upper-roman%29%20%22%20%22%3B%0A%7D%0A.print-site-enumerate-headings%20li.toc-nav-section-title-level-4before%20%7B%0A%20%20%20%20counter-increment%3A%20toc-sec-composite%3B%0A%20%20%20%20content%3A%20counter%28toc-sec-chapter%2C%20upper-roman%29%20%22.%22%20counter%28toc-sec-section%2C%20upper-roman%29%20%22.%22%20counter%28toc-sec-sub-section%2C%20upper-roman%29%20%22.%22%20counter%28toc-sec-composite%2C%20upper-roman%29%20%22%20%22%3B%0A%7D%0A.print-site-enumerate-headings%20li.toc-nav-section-title-level-5%3Abefore%20%7B%0A%20%20%20%20counter-increment%3A%20toc-detail%3B%0A%20%20%20%20content%3A%20counter%28toc-sec-chapter%2C%20upper-roman%29%20%22.%22%20counter%28toc-sec-section%2C%20upper-roman%29%20%22.%22%20counter%28toc-sec-sub-section%2C%20upper-roman%29%20%22.%22%20counter%28toc-sec-composite%2C%20upper-roman%29%20%22.%22%20counter%28toc-sec-detail%2C%20upper-roman%29%20%22%20%22%3B%0A%7D%0A.print-site-enumerate-headings%20li.toc-nav-section-title-level-6%3Abefore%20%7B%0A%20%20%20%20counter-increment%3A%20toc-sec-last%3B%0A%20%20%20%20content%3A%20counter%28toc-sec-chapter%2C%20upper-roman%29%20%22.%22%20counter%28toc-sec-section%2C%20upper-roman%29%20%22.%22%20counter%28toc-sec-sub-section%2C%20upper-roman%29%20%22.%22%20counter%28toc-sec-composite%2C%20upper-roman%29%20%22.%22%20counter%28toc-sec-detail%2C%20upper-roman%29%20%22.%22%20counter%28toc-last%2C%20upper-roman%29%3B%0A%7D%0A%0A%23print-page-toc%20li%20a.headerlink%3Abefore%20%7B%0A%20%20%20%20content%3A%20none%20%21important%3B%0A%20%20%20%20counter-increment%3A%20none%3B%0A%7D%0A%0A%0A/%2A%20Enumerate%20figures%20%2A/%0A.print-site-enumerate-figures%20figcaption%3Abefore%20%7B%0A%20%20%20%20counter-increment%3A%20figurecounter%3B%0A%20%20%20%20content%3A%20%22Figure%20%22%20counter%28figurecounter%29%20%22%3A%20%22%3B%0A%7D%0A%0A%0A/%2A%20Print%20URLS%3A%20%0AChange%20a%20%27link%27%20to%20%27link%20%28target%29%27%20%2A/%0Adiv.print-site-add-full-url%20section.print-page%20a%5Bhref%5E%3D%22http%22%5D%3A%3Aafter%7B%0A%20%20%20%20content%3A%20%22%20%28%22%20attr%28href%29%20%22%29%20%22%3B%0A%7D%0A%0A%0A/%2A%20%0APrint%20site%20table%20of%20contents%20styling%0A%20%2A/%0A.print-page-toc-nav%20%7B%0A%20%20%20%20padding-bottom%3A%202em%3B%0A%7D%0A%0A%23print-site-page%20h1%3Atarget%2C%20%0A%23print-site-page%20h2%3Atarget%2C%20%0A%23print-site-page%20h3%3Atarget%2C%20%0A%23print-site-page%20h4%3Atarget%2C%20%0A%23print-site-page%20h5%3Atarget%2C%20%0A%23print-site-page%20h6%3Atarget%20%7B%0A%20%20%20%20animation%3A%20highlight%201s%20ease%3B%0A%7D%0A%40keyframes%20highlight%20%7B%0A%20%20%20%20from%20%7B%20background%3A%20yellow%3B%20%7D%0A%20%20%20%20to%20%7B%20background%3A%20white%3B%20%7D%0A%7D%0A%0A%23print-page-toc%20ul%20%7B%0A%20%20%20%20/%2A%20margin-left%3A%201.6em%3B%20%2A/%0A%20%20%20%20margin-top%3A%200%3B%0A%20%20%20%20margin-bottom%3A%200%3B%0A%20%20%20%20padding-left%3A%200%3B%0A%20%20%20%20list-style-position%3A%20inside%3B%0A%7D%0A%23print-page-toc%20ul.print-site-toc-level-2%2C%0A%23print-page-toc%20ul.print-site-toc-level-3%2C%0A%23print-page-toc%20ul.print-site-toc-level-4%2C%0A%23print-page-toc%20ul.print-site-toc-level-5%2C%0A%23print-page-toc%20ul.print-site-toc-level-6%20%7B%0A%20%20%20%20margin-left%3A%201.6em%3B%0A%7D%0A%23print-page-toc%20ul%20li%20%7B%0A%20%20%20%20margin-left%3A%200%3B%0A%20%20%20%20margin-bottom%3A%200.2em%3B%0A%7D%0Aul.print-site-toc-level-1%20%7B%0A%20%20%20%20list-style-type%3A%20none%3B%0A%7D%0Aul.print-site-toc-level-1%20li%20a%20%7B%0A%20%20%20%20font-weight%3A%20bold%3B%0A%20%20%20%20font-size%3A%20120%25%3B%0A%7D%0Aul.print-site-toc-level-2%20li%20a%20%7B%0A%20%20%20%20font-weight%3A%20normal%3B%0A%20%20%20%20font-size%3A%20100%25%3B%0A%20%20%20%20margin-bottom%3A%200em%3B%0A%7D%0A%23print-site-page%20ul%20li.toc-nav-section-title%20%7B%0A%20%20%20%20padding-top%3A%201em%3B%0A%20%20%20%20padding-bottom%3A%200em%3B%0A%20%20%20%20font-size%3A%20110%25%3B%0A%20%20%20%20letter-spacing%3A%201px%3B%0A%7D%0A%23print-site-page%20ul.toc-section-line-border%20%7B%20%0A%20%20%20%20border-left%3A%205px%20solid%20grey%3B%0A%20%20%20%20padding-left%3A%201.5em%3B%0A%20%20%20%20margin-top%3A%200.5em%3B%0A%20%20%20%20margin-bottom%3A%201em%3B%0A%7D%0A%0A%0A%23print-site-page%20ul%20%7B%0A%20%20%20%20margin-left%3A%200em%3B%0A%7D%0A%0A%0A%0A/%2A%20Don%27t%20display%20cover%20page%20when%20not%20in%20print%20mode%20%2A/%0A%23print-site-cover-page%20%7B%20display%3A%20none%3B%20%7D%0A%0A/%2A%20Don%27t%20display%20the%20section%20headings%20that%20we%20added%0AFor%20now%2C%20we%20added%20them%20for%20use%20only%20in%20the%20table%20of%20contents%20%2A/%0A%23print-site-page%20h1.nav-section-title%2C%0A%23print-site-page%20h2.nav-section-title%2C%0A%23print-site-page%20h3.nav-section-title%2C%0A%23print-site-page%20h4.nav-section-title%2C%0A%23print-site-page%20h5.nav-section-title%2C%0A%23print-site-page%20h6.nav-section-title%20%7B%20%0A%20%20%20%20padding-top%3A%201.5em%3B%0A%20%20%20%20padding-bottom%3A%201em%3B%0A%20%20%20%20padding-left%3A%201em%3B%0A%20%20%20%20font-size%3A%202.2em%3B%0A%20%20%20%20font-weight%3A%20300%3B%0A%20%20%20%20line-height%3A%201.3%3B%0A%20%20%20%20color%3A%20var%28--md-default-fg-color--light%29%3B%0A%7D%0A%0A%23print-site-page%20h1.nav-section-title-end%2C%0A%23print-site-page%20h2.nav-section-title-end%2C%0A%23print-site-page%20h3.nav-section-title-end%2C%0A%23print-site-page%20h4.nav-section-title-end%2C%0A%23print-site-page%20h5.nav-section-title-end%2C%0A%23print-site-page%20h6.nav-section-title-end%20%7B%20display%3A%20none%3B%20%7D%0A%0A/%2A%20In%20the%20TOC%2C%20we%20want%20lines%20that%20are%20children%20of%20a%20section%20to%20be%20displayed%20with%20a%20left%20margin%20%2A/%0A%23print-site-page%20ul%20li.toc-nav-section-child%20%7B%20padding-left%3A%201em%3B%20%7D%0A%0A/%2A%20Be%20able%20to%20not%20print%20certain%20elements%20%2A/%0A%23print-site-page%20.print-site-plugin-ignore%20%7B%20display%3A%20none%3B%7D%0A%0A%0A%0A%40media%20print%20%7B%20%20%20%20%0A%0A%20%20%20%20/%2A%20included%20bookmarks%20on%20h1%20and%20h2%0A%20%20%20%20Doesn%27t%20work%2C%20but%20included%20In%20case%20Chrome%20gets%20support%20%0A%20%20%20%20for%20these%20experimental%20CSS%20features%20that%20define%20PDF%20bookmarks%20%2A/%0A%20%20%20%20/%2A%20%23print-site-page%20h1%20%7B%0A%20%20%20%20%20%20%20%20bookmark-level%3A%201%3B%0A%20%20%20%20%20%20%20%20bookmark-label%3A%20content%28%29%3B%20%0A%20%20%20%20%20%20%20%20-ah-bookmark-level%3A%201%3B%0A%20%20%20%20%20%20%20%20-ro-pdf-bookmark-level%3A%201%3B%0A%20%20%20%20%7D%0A%20%20%20%20%23print-site-page%20h2%20%7B%0A%20%20%20%20%20%20%20%20bookmark-level%3A%202%3B%0A%20%20%20%20%20%20%20%20bookmark-label%3A%20content%28%29%3B%20%0A%20%20%20%20%20%20%20%20-ah-bookmark-level%3A%202%3B%0A%20%20%20%20%20%20%20%20-ro-pdf-bookmark-level%3A%202%3B%0A%20%20%20%20%7D%20%2A/%0A%0A%20%20%20%20/%2A%20Be%20able%20to%20not%20print%20certain%20elements%20%2A/%0A%20%20%20%20.print-site-plugin-ignore%20%7B%20display%3A%20none%3B%20%7D%0A%0A%20%20%20%20/%2A%20Remove%20print%20site%20banner%20%2A/%0A%20%20%20%20%23print-site-banner%20%7B%20display%3A%20none%3B%20%7D%0A%0A%20%20%20%20/%2A%20Ensure%20all%20tabbed%20content%20is%20displayed%20and%20printed%0A%20%20%20%20https%3A//squidfunk.github.io/mkdocs-material/reference/content-tabs/%20%2A/%0A%20%20%20%20/%2A%20%23print-site-page%20div.tabbed-content%20%7B%20display%3A%20block%20%21important%3B%20%7D%20%2A/%0A%0A%20%20%20%20/%2A%20PDF%20page%20breaks%20on%20each%20MkDocs%20page%2C%20except%20the%20first%20one%20%2A/%0A%20%20%20%20%23print-site-page%20section.print-page%20%7B%0A%20%20%20%20%20%20%20%20page-break-before%3A%20always%3B%0A%20%20%20%20%7D%0A%20%20%20%20%23print-site-page%20section.print-page%3Afirst-of-type%20%7B%0A%20%20%20%20%20%20%20%20page-break-before%3A%20avoid%3B%0A%20%20%20%20%7D%0A%20%20%20%20/%2A%20PDF%20page%20breaks%20-%20separate%20title%20page%20for%20each%20section%20%2A/%0A%20%20%20%20%23print-site-page%20.nav-section-title%20%7B%0A%20%20%20%20%20%20%20%20page-break-before%3A%20always%3B%0A%20%20%20%20%20%20%20%20page-break-after%3A%20always%3B%0A%20%20%20%20%20%20%20%20align-content%3A%20center%3B%0A%20%20%20%20%20%20%20%20text-align%3A%20center%3B%0A%20%20%20%20%20%20%20%20vertical-align%3A%20middle%3B%0A%20%20%20%20%20%20%20%20padding-top%3A%20150px%20%21important%3B%0A%20%20%20%20%20%20%20%20padding-bottom%3A%200em%3B%0A%20%20%20%20%20%20%20%20padding-left%3A%200em%3B%0A%20%20%20%20%20%20%20%20font-size%3A%202.5em%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%23print-site-page%20p%2C%20%0A%20%20%20%20%23print-site-page%20pre%2C%20%0A%20%20%20%20%23print-site-page%20blockquote%2C%20%0A%20%20%20%20%23print-site-page%20.tabbed-set%20%7B%0A%20%20%20%20%20%20%20%20page-break-inside%3A%20avoid%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20/%2A%20Avoid%20a%20page%20break%20immediately%20after%20a%20heading%20%2A/%0A%20%20%20%20/%2A%20Credits%20https%3A//stackoverflow.com/a/9238898/5525118%20%2A/%0A%20%20%20%20%23print-site-page%20h1%20%7B%0A%20%20%20%20%20%20%20%20page-break-inside%3A%20avoid%3B%0A%20%20%20%20%7D%0A%20%20%20%20%23print-site-page%20h1%3A%3Aafter%20%7B%0A%20%20%20%20%20%20%20%20content%3A%20%22%22%3B%0A%20%20%20%20%20%20%20%20display%3A%20block%3B%0A%20%20%20%20%20%20%20%20height%3A%20100px%3B%0A%20%20%20%20%20%20%20%20margin-bottom%3A%20-100px%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%23print-site-page%20footer%20%7B%20display%20%3A%20none%3B%20%7D%0A%0A%0A%20%20%20%20%0A%20%20%20%20%23print-site-cover-page%20%7B%0A%20%20%20%20%20%20%20%20display%3A%20block%3B%0A%20%20%20%20%20%20%20%20width%3A100%25%3B%20%0A%20%20%20%20%20%20%20%20text-align%3A%20center%3B%0A%20%20%20%20%7D%0A%20%20%20%20%23print-site-cover-page%20h1%20%7B%0A%20%20%20%20%20%20%20%20font-size%3A%20300%25%3B%0A%20%20%20%20%7D%0A%0A%7D%0A%0A%0A/%2A%20%40page%20%7B%20%2A/%0A%0A%20%20%20%20/%2A%20%0A%20%20%20%20%20%20%20%20Note%20this%20CSS%20file%20is%20added%20to%20all%20MkDocs%20pages%0A%20%20%20%20%20%20%20%20So%20this%20%40page%20logic%20will%20affect%20print%20of%20all%20pages%0A%20%20%20%20%2A/%0A%0A%20%20%20%20/%2A%20Prevent%20image%20page%20overflow%20%2A/%0A%20%20%20%20/%2A%20img%20%7B%20max-width%3A500px%20%21important%3B%20%7D%20%2A/%0A%0A/%2A%20%7D%20%2A/" rel="stylesheet"/><!--URL:../css/print-site.css-->
<link href="data:text/css,/%2A%20print%20styles%20for%20mkdocs%20material%20theme%20%0Ahttps%3A//github.com/squidfunk/mkdocs-material%20%2A/%0A%0A%0A/%2A%20Table%20of%20Contents%20styling%20%2A/%0A.print-page-toc-title%20%7B%0A%20%20%20%20padding-bottom%3A%200em%3B%0A%20%20%20%20margin-bottom%3A%200%3B%0A%7D%0A%0A%23print-site-page%20ul.toc-section-line-border%20%7B%20%0A%20%20%20%20border-left%3A%205px%20solid%20var%28--md-default-fg-color--lightest%29%3B%0A%7D%0A%0A%0A/%2A%20Box%20shadows%20don%27t%20do%20well%20in%20PDFs%20%2A/%0A%23print-site-page%20table%20%7B%0A%20%20%20%20border%3A%201px%20solid%20hsla%28200%2C%2018%25%2C%2026%25%2C%201%29%3B%20/%2A%20%23EFEFEF%20%2A/%0A%20%20%20%20box-shadow%3A%20none%20%21important%3B%0A%7D%0A%0A%40media%20print%20%7B%0A%20%20%20%20%23print-site-page%20td%20%7B%0A%20%20%20%20%20%20%20%20word-wrap%3A%20break-word%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%40page%20%7B%0A%0A%20%20%20%20/%2A%20%0A%20%20%20%20%20%20%20%20Note%20this%20CSS%20file%20is%20added%20to%20all%20MkDocs%20pages%0A%20%20%20%20%20%20%20%20So%20this%20%40page%20logic%20will%20affect%20print%20of%20all%20pages%0A%20%20%20%20%2A/%0A%0A%20%20%20%20size%3A%20a4%20portrait%3B%0A%20%20%20%20margin%3A%2015mm%2010mm%2025mm%2010mm%3B%0A%20%20%20%20counter-increment%3A%20page%3B%0A%0A%20%20%20%20%40bottom-center%20%7B%0A%20%20%20%20%20%20%20%20content%3A%20string%28chapter%29%3B%0A%20%20%20%20%7D%0A%20%20%20%20%40bottom-right%20%7B%0A%20%20%20%20%20%20%20%20content%3A%20%27Page%20%27%20counter%28page%29%3B%0A%20%20%20%20%7D%0A%0A%7D" rel="stylesheet"/><!--URL:../css/print-site-material.css-->
<script>__md_scope=new URL("../..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function () {
generate_toc();
})
</script>
</head>
<body data-md-color-accent="blue" data-md-color-primary="light-blue" data-md-color-scheme="default" dir="ltr">
<input autocomplete="off" class="md-toggle" data-md-toggle="drawer" id="__drawer" type="checkbox"/>
<input autocomplete="off" class="md-toggle" data-md-toggle="search" id="__search" type="checkbox"/>
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
</div>
<div data-md-component="announce">
</div>
<div data-md-color-scheme="default" data-md-component="outdated" hidden="">
</div>
<header class="md-header md-header--shadow" data-md-component="header">
<nav aria-label="En-tête" class="md-header__inner md-grid">
<a aria-label="LdapSaisie" class="md-header__button md-logo" data-md-component="logo" href="javascript:window.scrollTo(0,0)" title="LdapSaisie">
<img alt="logo" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAAAuCAYAAABtRVYBAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAZ5QAAGeUBblTa3gAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAABQqSURBVHic7Z17lBTVncc/35oZBnkjKKKODyDGB2bjK0GjCRKdh2KMm+DqbqIeo8H1GM1MDyHqbpATjQGZIWsSs2qymA3HqLhRI8r0EAMmisFoYqLGSEBFBZG3g8hrpn/7x62eru6p6tf0gOB8z7mnq6pv/X63u+t37+95W2ZGL3rRi3B4e3oAvejFhxnle3oApYCks4C5/umzZvaFPTmeUkJTWg8k0TEK84ZgrEW73mXryLV250m79sh4Yi2Xgb4PgNkca669vud4xacC9f7p962p5gc9xSsKJRMQSb8FRvmnzWZ2e6lo54FPAyP84zd3I98egRoWVqPEjcBJQH/wQLhGBQxYn1As/mewRcAiPO9Ju616624aXX+S37XnDephZgM7eTm+ux0lERBJ/YDPkVLZdvdDemLg+E+7mXfJoG8tGE2Hdw/i9BxdPeAk0ElAIwn7OnB3z4/wo4dSrSD/RLo9s7sf0qCA/Hk38y4JNHl+Pwb0eQjs+MDl9cB8sJWY1iCNwGw0YjRwClCx+wfKDoz3ALDEBz3MbBvYe/7Jjp7lFTGCUnixJF0N/Ng/3WBmw7tNNH/e+wMb/NOdwAAz2yP6eXegWHwOcJl/ahhTGFz5Y5s2fnto/ymtB5LgErCvAc3WVNO7gvQASrWCnBA43t0zeJD3S3ulcEx+voIBXJy6oFusqbop2z12W/VaYBYwS1Na94h+/lFAqQSkR1UcSQOB4bjVqS0L74JUO0mDgaHAGjMLnamLgSThxlthZqtz3jBo3TEkVJkiwP8Uwq9QA13XPzaUHX2H4m1rY+DzG23atEQh9xcDTX6+gv02jaTS2tm1eZM1T9rWo/ymT/dYd/pQ+u0cgpVtYeV7G+yBSR0F0+muiiWpAngf6ONfutjM7usWUUd3EHAd8G/AxwNvLQOagLvNzCT9ErjIf+9qM/tJFnpnAecCnwUOAfYLdFkL/BH4rpktzWN89wAH+adXmtlbkmqByUAdkHzgN+EEt8HM/hpKK9byFdAv/NOd1lRTGdavGGj64r60bZ+AdB7GBFAVWPBzb8VsKehnvN12f66HSLHWiWDX+KePWlPNjyP7NracgmkqcCruuwraqdtBL0AijiX+z5rPebHL/Q2tlyJzK6vZPdZcm/O5UqxlEugSYALQL/DWFlALZrOsuebZXHSSKMUKchwp4YASrCCSaoD/BQ4Mefso4E7gTElfwblCkwhdQSRVASvIbtQeiBOecyX9l5l9M8v4BgBfxf3gO4EtkubihDkTQ4HPA0slXWVmPw/pszFw3Eex1iprqn4ry1jzR9uOF0Fj6JwHu0yI/ZEmABOoGnSVGuf/s82auD6aoB0O1AAgrYjqpVj8Z6DLs4ysL9g40DjkjQG+0pWIfSzFy/t9FlqoYf4heBXzQKdGdBkINgkxSbF4M801jWZdv4xMlEJAgjbA+8A/ukNM0iTgXlJjWw/8zm+VOHfyObhV40VgjN+vAwidoXFqWFI4XgFeBlYCbwNDfBpfBJK6/HWSnjazeRH0gl675cD9QDXQDjwLLAS24YT3y7gIRl/gDkmtZvZOGrUEf0vPabCbgK9F8C4UydVoM7AU9AYkViJ1YByB8RnEJ/w+Z2AVv9KF884sRh1JQrGW6zOEYwniNyRYhzDQIZgdivgscHixfDr5NTwxCvX5HWaH+JcM+A3G35C9ibzRYKdhfNJ/v4H6eBnURE6CSZRaQP5iZkXrs5KOBeaQGtcvgUvMrD3QbaakK4G7gO/ih8+AV8wsSq8dDtwK3GtmL0XwHgzMA872LzX652EIfuZj/fYyUGtmb2fQrQEexglIP+AG4Btp1H5Qu5KG+J9I2VOXKxY/GmwG5TsX2YwvbIkYRz74PaKFRNuDYXq/hKiPX4z0U1/1OoOqwZdCYXZQJ73p0z0Yd4N/2oF0kc2qfjC0rxCNrWeSsIOL4eX4zeuDBj2AU5kBXiJhX7fZtc904dXQ8g3QTKAScZ2mxBfabTWPZaNfCgEpiYEuqQ/wIKlZ/E6cTdFF4MzsbkkX4HT9JCINdDP7WS7+ZvaepAtxK1YZcKwkWbiRdmLG+TPAuWa2KYRuXNJdwLX+pYlkCIgZpoaOy1DZc6TU1dNAj9Be2a6G+PNISxHPws54dhUog39TTZjal8Ybau5VQ7wy5RywqylSQGg7ZQwwwD9bEiUcKd7Vvy2KTye/QZeSUrM3kqDaZte+k9nN8aq9XQ3xIYjpACS4AcgqIN1KVpTk4dSNJLoTILwcOMY//jsRwhHATzPOu237mNlmnBMA3I8cFc8JCshaoC5MOAIICmiV79hI5+2M1Fqsi4pajvg02LWYzcUq1igW/50aW+s1eX6/TDrFwppr5uAcCgAn6Nu/GVwcIY0MnJXM2ZAF13YeGY02u6aLcKRhcOVMINnnNE1dcGi27t3N5g3OFlDkQ+qvHjcELt2ah6q2POO8VNH7oFB0iRRLqsSpVEncZNYZ7Y1C0JgtA44I62RNNYsYXPkJxFSw5wixqP37z8CsmQEVf1FD/IwcvAuAkjacx65dx2TtGoVyezVw9inn9eoZ+A/32M4L3q5Hc93jB15TXsr2ss9k699dFSs4k+7E6eHFoAao8o/fwBnpufB+4NjIIZy+5+l8nMtxLHAAMIiunq0D/Nd3zSwsvjA2cM9W4BchfdJgZlslbcfZIQCRwu//gDOBmZq68GDaE+cC4zBORhxPyuYCGIN4Ug2t51tzddaHQ42PHw5ll2M2GnQwTmcflEFvSOqGsoG5Plfo+Gees0aN8WcwfG+S/Vqx+GOYPUyFxW1G3dvZKRSAXd5pgdGvpKN8gOpbBmS5w8FTYJVJjIru2H0BKVUUOzjL3JthlEfhqMDxcjMLNWR9wbgRtxQXopJECXvwMy8ws/cj+gXHcBgp4QBYk88AbMbZq3FJiHcD6JtPjKBsVx3oRlLeO4HdoWsXPGm312UGUd0s2+7NgLILgfJ0eciCRNp4C0OCK/F4EmOYGx8TkSbSLhSLrwAWYDxGe2KR3V5XfI6Vx8jAGns4nl4vnIiypkWVcgXpjopzduD4b3neE1QBouIfhwCtpKtEbcBTONthPU7vTs7odbggYiRN0j/zMxF9MnFc4HhzxMqUE/aDz78L3KPpi++jbcdc4EsAiEMp967EBVA7oemL+9LuPUx6rGg1ZkuQtwGzDXhKTSxml5D+vRYFa655WVNaj8VocmNMC0yOBq5BXEOF964aW+ptVu0vi2OkIeFaaEFEsiZ8lnIFKdb+ECn1CvIXkOBD3+VhllQOPBLo93dgCrDQzEJnLUlBQY0SkOBnfiXPsY4NHC/O855I2LTx21W/+Aq8HWcC+wPgpWUBO2zZ2URKOFYj+xeaap+OCpApFq+jBAICnbliX9Xk+ZPpX3E2ogY4Ezg60G0EpnsVix9jTTXfKZxLYktgRXwWz6YWTKJDWVW+ogXEj04PC1wq1os0PGMcmcZ3GO9BuABcEmEPczDK/gow3szWZqF5IC4ImcTzIX3KSPfaRdLLwL8GjlvyvCcrbPb4zYq1PAeqdhd0bNdOdl7q2Dvfms5+jllZyR6V9d0iYHdO/AA3UT0CvsrXUXYBZo3AYX63G9Tw+LywdJPsxLUmoDEeZrfVLi7JoAPojhcrqGokgL8USacs43xYaK90XE3QoAwXzosCx3OyCYePSYGxbCE8I+Bo0vO3chqykuqgM4K7FfhVrnvyh4J2V5+0d65/bCiplXmzNZ/9XFZK9YuHkMot6zHYjLq3bVb1D9mVOJ7UZFiGV35WwcTUEfxMBzlHRGnRHQEJqhqvmllRxTNmtgb34CTxsWz9Je1Hqk4ZYKWZbQjpGqST/eFwtspNgUsvRAQIT8g4H52Nro9vB45/ZGbr8rgnX6QmKSNdVWgvC6ittpFcKNt5VclGlQd8h8KvA1cKXr2s6ZxluJQh/4J3TXTv4lAqAeluDOK1wPEVUZ38GMQDpCcxRql2QU9YVUSfpK1yL+nxj3wMdEhXncJo30TK6F8L3Bbar77lVMXil+jCeZmraTTthtZLgSNTFywjIu2toNOC1RG65onIlVnXPDEMK0J/D6OlfN1kQPA7T9hrWfplYxhwTKhe9Qs/Gd0589bcYy2VivWSpL4FtEy+gZmEL0v6csb7SOqPSwvIDDxFPcxBle/bvrs3k+bxuKDRZzPeysdAB5jg54Vl0vUk3QFM8y91ABdFrHRQxkjg51QNelWx1htV33JEBH80pbW/GuPXIbsrcPk9PG9usJ9fI5IMUHpUtt+pyc938dhoSutYKtufIl1lLR6x+LWKxR9SY2udy8sKh2ILxpH0wrkrfyiK386OuxAv+GdleIm4Yi2XZXv49a0Fo9XQcisN8SdzkS/KSJc0HAiG6G/1W744FQh+ITNxdRTDcUI7T9IDOHes4dLFx+N+xBeB7biabIh+mO/B2RXgPDPL/BqOFTjj8ARcgLIP8BDOTkjOyGFeMZEuID8B/h24S9J5wCJc8HI8rhYhqM/HzGxRxDiDGA12M55uViz+OtJSsFUkaMPTCEhUYTodl0KfRAKzq+y2mhAbS/8BnbU5X2LA+lcUa5kLLMcYieediNsiqR/iBYwNuO+6eCQoR3wRsy/SNu4tFzTUCmSvkeADYKTL4vXOIfn8mT3I7NqnaC6cnd1et0P1LRfg6WngYOBA0Bzq4/WKsRS0DNgIdgToSKfKeacgFJLW0wVpAiLpIOA7OMkWroDo+pBCn0xVoxC0k2HQm1mbpCtwe1slZ/oL/RbEYuBinJAkESogZva4pDtxggcwEsjcw8lwtfTTgKRtsI1w9+2RQDI/6Q2cy/hknKCe57dMbAO+kTNZ0rw1wCroTNd2/MycwAowIyTItwbjKmuufSSUbFP1/YrFq3F5bgCjQdPSaQLoRdq98ylv/xFWiIaUE1UYVWDumw4n3cLgvl/NpzYjCja79g3Vx0/G4z6S2oBL4f9Eepwkg4XoEljNRKeASDoSWIJLtUjqwnXA6ZLONbOnAvcNBnIuTxFYGZaWbmaPSDoZuAMYRyrqbf647sYVUe1PKsrd1qW2Ip3mVZKWALeQvuJ9ADwK/NDMnpZ0HK7eBGCZmYXVQqRlLfvpI+Nxxv0VpM/q63Gr0s1mlnMLJGuqXgIcqvqFn8SzcyFRB/o4dEaig/gA+BPG/fQp+4V9/6yseWDWVPM1NbQ+jLgF7FiCXkM3g85lcJ+ZNm38djXEX8S50EGEq4PSKiz529uyLu+3J+6m3FvuirBsAs7zl6mpbET2NDDTZtU+1YVG5/jsdeT5vBIrI/sBfpLi5xRrOQc0GScomWrjDpxR/zjSQwx85qlkPVYUOktuJc3HCUSY3rgOGBHh2Sk5fBsl6YVaHZVGUiDNobjinI3AO4WmxUj6HqkV6Dtm9t3Ae+W45X0YboeVVRFCVtiYp8/rw5b+I6F8uNtup30LA//4VrE15K4ufN0oyq2M7X3etR99PlwISggJEZs/jETFCKwsQXnizd2xyZ2mT/f44LSD2LVrGGXlxrayd4r5vDKzpHdoM0Tm32zG1Tss6c6g92ZIWgDU+qfnmdn8PTmeXuweJFeLAUC2GdVID5B9FBFUsV6I7NWLfQpJ3XAjLl09W7/IAv19HZJ87wgA6zLLavdW+KrhEL8NzfO1Ejp3ChZuklWO5uFc3ZtxKujGPF43dad8O8tn7lvIFk/lAP72ObOBqXRNnzDgD2b2RslGufdhr1o9/JjRobiaj7A2EvfA566d2HNISHoPZ/++ArwUaK92o7TivyXNMLO8Ek07vQtmdotft3AxzoOUlPpyoK+k/sWmae8D2JM7R6bBr748ElcPUkW4IOQql03g0v5fx83qm/y2OeM17Hg7btJMtkTGeZdmZgk/0XN/nCNjGC7mNSykBa/vjxPko3DFbknskrQMJywvkxKcFXmsOuXAEklfMsvMPgjv3AkzmyypGbc/VD9cHORm4Azgcd/dm7NAaB9EJakyzcU9zUxSX1ye15iQdhjZMyC24urqV+G2NVoVcrymJ9SXbPC9eutIxZvygu99PBpXMjAWV1uTfD0uo/s2ScnV5q+40obMGF4Cpyq2SJpsZnOy8s/lufW3w2nBxSb+iNs58SNrj5QKvhoUJgBjcKtAWFjNgNW4LNjluIDlqkB7O4/6+H0CfjbH2JCWuXq+iUtRehSX7fBn0mtSbgH+MyqEkdfWo/7euL/GpVFsxW2jeVfWm3qRrFuJEoKREbclcLP9P0gJQrKtyLL3Vy8AScmNHD6F04ROITXZbCPcG3sfcFlYIV3ee/P6OuRUXOS4Ard74A1mljWVfF+HpANw6tAougrBARG3deAiupkCsBx4LarisReFQ9IInKBM9FtUie0S4HwzS9tzrODNqyWdiMuZSpZmPobb+mafFBR/YqjCCUFYiyqa2oVTgZbTdTV4Y2/8m4a9GZJOwtmR2UoK2oBPm9nfO+8rJnvE96Rchku9OMK//BLOVmkBfm9m2eIqHyrI/YXcKMIF4HCiZ52tuFqW13BxohWkhGBlKdJNetF9SDoVN5EPzdUX5627wMyehCIFJMC4HLfL+TehcwNkcA/Ob/EFxqzIYpgSIqAKhbVspabvkBKAtFcze7cnx9yL0kDSGbgtbTv/CjXjVbg9wvbHGfU7cc+tleQv2PxBHIrLVarF/Q9H0JuwHOevXo3ztqwOHpvlURLalV8/XHT7gJDXzGvDSO35m4kdOFUouAokj18vtpS4F/sGSiYgaUTdynIqTliSmxZkKzTYjhOYdpyOmKtVkLFJQQ5swvcC0XU1WLW7YwK92HvQIwLShYn7o83DcP79g/2WeXwA0ULUkdHacVHddbha73XZjntXgV4Ui90iIPnA3/F8PzKEoXd278WexIdGQHrRiw8j/h+c20IoEFD+pgAAAABJRU5ErkJggg=="/><!--URL:../assets/images/logo.png-->
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"></path></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
LdapSaisie
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
Documentation
</span>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-content" data-md-component="content">
<article class="md-content__inner md-typeset">
<div class="print-site-enumerate-headings print-site-enumerate-figures" id="print-site-page">
<section id="print-site-cover-page">
<div style="padding-bottom: 3em">
<h1>LdapSaisie</h1>
<h2>Documentation</h2>
</div>
<p>
<small>
Auteur: Benjamin Renard
(<a href="mailto:brenard@easter-eggs.com">brenard@easter-eggs.com</a> /
<a href="mailto:brenard@zionetrix.net">brenard@zionetrix.net</a>)
</small><br/>
<small>Site web: <a href="https://ldapsaisie.org/doc/">https://ldapsaisie.org/doc/</a></small><br/>
<small>Repo: <a href="https://gitlab.easter-eggs.com/ee/ldapsaisie">https://gitlab.easter-eggs.com/ee/ldapsaisie</a></small><br/>
<small>Easter-eggs</small><br/>
</p>
</section>
<section class="print-page">
<div data-toc-depth="6" id="print-page-toc">
<nav class="print-page-toc-nav" role="navigation">
<h1 class="print-page-toc-title">Table des matières</h1>
</nav>
</div>
</section>
<section class="print-page" id="index"><h1 id="index-introduction">Introduction</h1>
<p>LdapSaisie est une application web d'administration d'annuaire LDAP développée en PHP/Javascript.
Cette application a pour but d'abstraire la complexité d'un annuaire par l'intermédiraire d'une
interface d'administration simple et intuitive. L'application a été concue avec pour objectif
premier une modularité maximum, ce qui permet l'extention ou l'adaptation facile de l'application
par l'intermédiaire de modules, d'extentions et de greffons. Cette application peut être utilisée
pour administrer le système d'information basé sur l'annuaire LDAP et également en paralèlle pour
permettre aux utilisateurs d'avoir accès aux données les concernants et éventuellement de les
modifier.</p>
<h2 id="index-fonctionnalites">Fonctionnalités</h2>
<p>De part sa modularité, LdapSaisie est facilement extensible. Cependant, voici une liste
non-exhaustive de ses fonctionnalités :</p>
<ul>
<li>Gestion d'annuaire simple et multi-branches</li>
<li>Gestion d'un nombre illimité de types d'objets</li>
<li>Gestion d'un nombre illimité de populations se connectant à l'interface</li>
<li>Gestion fine des droits des utilisateurs, permettant la maitrise des droits d'accès sur les objets
de l'annuaire et leurs atributs, tout en permettant la délégation de droits.</li>
<li>
<p>Gestion d'un grand nombre de types d'attributs :</p>
<ul>
<li>Texte (court ou long)</li>
<li>Date (format paramétrable)</li>
<li>Booléen (valeurs paramétrables)</li>
<li>Image/Photo</li>
<li>Mot de passe (génération de mot passe avec gestion d'une politique fine)</li>
<li>Adresse mail</li>
<li>Flux RSS</li>
<li>Lien web (URL)</li>
<li>Adresse XMPP</li>
<li>Maildir</li>
<li>Quota de mails</li>
<li>Clef publique SSH</li>
<li>Liste déroulante à choix simple ou multiple</li>
<li>
<p>Relation à d'autres objets de l'annuaire/ Exemple : membres d'un groupe, parrain d'un
utilisateur, ... (valeur clé paramétrable)</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Chaque type d'attribut à des fonctionnalités qui lui sont propres et qui rendent plus facile
et agréable l'utilisation de l'interface (génération automatique de mot de passe, génération
des valeurs d'un champ à partir d'autres, ...).</p>
</div>
</li>
</ul>
</li>
</ul>
<ul>
<li>Gestion d'un grand nombre de règles de vérification des valeurs des attributs :<ul>
<li>Alpha-numérique</li>
<li>Lettres uniquement</li>
<li>Longeur maximale/minimale d'une chaine de caractères</li>
<li>Valeur différente de zéro</li>
<li>Pas de signe de ponctuation</li>
<li>Valeur numérique</li>
<li>Comparaison de valeur</li>
<li>Date</li>
<li>Adresse mail</li>
<li>Poids d'une image</li>
<li>Taille d'une image</li>
<li>Type de fichiers images</li>
<li>Politique de mot de passe (longueur/caractères autorisés/caractères obligatoires)</li>
</ul>
</li>
</ul>
<ul>
<li>Gestion simplifiée des relations entre les objets de l'annuaire</li>
<li>Interface facilement personnalisable grâce à l'utilisation d'un système de template.</li>
<li>Possibilité de postionner des déclencheurs permettant d'exécuter vos propres scripts, fonctions ou
méthodes au moments précis ou l'utilisateur créé, modifie ou supprime un objet ou un de ses
attributs. Ces déclencheurs, en fonction de leur positionnement, peuvent influencer le
comportement de l'application en empêchant par exemple, la validation des données d'un formulaire.</li>
<li>Gestion fine de l'affichage des attributs en fonction de l'écran (=vue) sur lequel se trouve
l'utilisateur.</li>
<li>Gestion des dépendances entre attributs, permettant par exemple de regénérer automatiquement la
valeur d'un attribut caché lors de la modification d'un autre.</li>
<li>Possibilité de gérer des attributs entièrement cachés, dont les valeurs seront modifiées lors de
la modification d'attribut en dépendance.</li>
</ul></section><h1 class="nav-section-title">Installation</h1><section class="print-page" id="install-requirements"><h1 id="install-requirements-pre-requis">Pré-requis</h1>
<ul>
<li>Le service Apache HTTP avec le module mod_rewrite d'activé. Les règles de réécriture d'URL sont
définies dans le fichier <code>.htaccess</code> fourni avec l'application et il est donc nécessaire
d'autoriser une telle configuration à ce niveau via la directive <code>AllowOverride</code> devant inclure à
minima <code>FileInfo</code>.</li>
</ul>
<ul>
<li>L'utisateur exécutant le serveur web doit avoir les droits d'écriture sur le dossier <code>tmp</code>. En cas
d'installation à partir du paquet Debian, ce dossier est remplacé par un lien symbolique vers
le dossier <code>/var/cache/ldapsaisie/</code>.</li>
</ul>
<ul>
<li>PHP 5.6 (ou supérieur) avec <code>magic_quotes_gpc</code> et <code>register_globals</code> à <code>off</code>. L'outil CLI de PHP
est par ailleurs nécessaire pour l'utilisation des outils CLI fournis avec l'application (fourni
par le paquet <code>php-cli</code> dans Debian).</li>
</ul>
<ul>
<li>Le support LDAP dans PHP (paquet <code>php-ldap</code> dans Debian)</li>
</ul>
<ul>
<li>Le support mhash dans PHP (paquet <code>php5-mhash</code> dans Debian Lenny, intégré à <code>php-common</code> dans les
versions supérieurs)</li>
</ul>
<ul>
<li>Le support json dans PHP (<code>pear install pecl/json</code> sur RedHat, intégré au paquet <code>php5-common</code>
précédement)</li>
</ul>
<ul>
<li><a href="http://pear.php.net/package/Net_LDAP2">Net_LDAP2</a> (paquet <code>php-net-ldap2</code> dans Debian ou
<code>pear install net_ldap2</code>)</li>
</ul>
<ul>
<li>Le support mbstring dans PHP (paquet <code>php-mbstring</code> depuis Debian Stretch, intégré au paquet
<code>php-common</code> dans Debian)</li>
</ul>
<ul>
<li><a href="http://www.smarty.net/">Smarty</a> (paquet <code>smarty3</code> dans Debian)</li>
</ul>
<ul>
<li>La librairie <a href="https://pear.php.net/package/Console_Table">Console_Table</a> (nécessaire pour le
fonctionnement de l'outil CLI, paquet <code>php-console-table</code> dans Debian)</li>
</ul>
<ul>
<li>Les librairies <a href="https://pear.php.net/package/Mail">Mail</a> et
<a href="https://pear.php.net/package/Mail_Mime">PEAR_Mail_Mime</a> (nécessaire pour l'envoi de courriels,
paquets <code>php-mail</code> et <code>php-mail-mime</code> dans Debian)</li>
</ul>
<ul>
<li>L'<a href="https://www.php.net/manual/fr/intro.ftp.php">extension PHP <code>ftp</code></a> (nécessaire pour le
fonctionnement du <a href="#conf-configuration-des-lsaddons">LSaddon</a> FTP, paquet <code>php-ftp</code>
dans Debian)</li>
</ul>
<ul>
<li>La librairie <a href="https://github.com/phpseclib/phpseclib">PhpSecLib</a> (nécessaire pour le
fonctionnement du <a href="#conf-configuration-des-lsaddons">LSaddon</a> SSH, paquet
<code>php-phpseclib</code> dans Debian)</li>
</ul>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>La librairie <a href="http://pear.php.net/package/Net_LDAP2">Net_LDAP2</a> oblige le fait que la racine DSE
de l'annuaire soit lisible en anonyme sinon la connexion à l'annuaire échouera systématiquement.</p>
</div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Cette documentation est écrite à l'aide du langage Markdown et est mis en forme pour une
consultation en ligne à l'aide de <a href="https://www.mkdocs.org/">mkdocs</a> et son thème
<a href="https://squidfunk.github.io/mkdocs-material/">mkdocs-material</a>. Le dépendances pour construire
cette documentation sont listées dans le fichier <code>doc/requirements.txt</code> et sont installables à
l'aide de la commande <code>pip install -r doc/requirements.txt</code>.</p>
</div></section><section class="print-page" id="install-download"><h1 id="install-download-telechargement">Téléchargement</h1>
<h2 id="install-download-a-partir-du-paquet-debian">À partir du paquet Debian</h2>
<p>L'installation à partir du paquet Debian peut être réalisée soit en téléchargeant manuellement le
paquet, soit en déclarant le dépôt APT suivant dans votre fichier <code>/etc/apt/sources.list</code> :</p>
<div class="highlight"><pre><span></span><code><a href="#install-download-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>deb http://ldapsaisie.org/debian stable main
</code></pre></div>
<p>Il ne vous restera ensuite plus qu'a installer le paquet <code>ldapsaisie</code> avec la commande suivante :</p>
<div class="highlight"><pre><span></span><code><a href="#install-download-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a>apt-get install ldapsaisie
</code></pre></div>
<p>Le fichier <code>/etc/ldapsaisie/apache.conf</code> est un example de configuration du serveur web Apache. La
configuration du logiciel ce fera ensuite dans le dossier <code>/etc/ldapsaisie/local/</code>.</p>
<h2 id="install-download-a-partir-de-git">À partir de Git</h2>
<p>Le dépôt Git peut être récupéré anonymement en utilisant la commande suivante :</p>
<div class="highlight"><pre><span></span><code><a href="#install-download-__codelineno-2-1" id="__codelineno-2-1" name="__codelineno-2-1"></a>git clone https://gitlab.easter-eggs.com/ee/ldapsaisie.git
</code></pre></div>
<p>La racine web de l'application se trouvera alors dans le dossier <code>/ldapsaisie/src/public_html/</code>.</p>
<h2 id="install-download-a-partir-des-snapshot">À partir des snapshot</h2>
<p>Toutes les nuits, un snapshot de l'arbre Git est réalisé et est téléchargeable au format <em>tar.gz</em> à
l'adresse suivante :</p>
<p><a href="http://ldapsaisie.org/download/ldapsaisie-snapshoot.tar.gz">http://ldapsaisie.org/download/ldapsaisie-snapshoot.tar.gz</a></p></section><section class="print-page" id="install-arbo"><h1 id="install-arbo-arborescence-du-projet">Arborescence du projet</h1>
<ul>
<li>
<p><code>doc/</code></p>
<p>Les fichiers sources de la documentation (Markdown &amp; configuration Mkdocs).</p>
</li>
</ul>
<ul>
<li>
<p><code>lsexample/</code></p>
<p>Les fichiers relatifs à l'annuaire d'exemple.</p>
</li>
</ul>
<ul>
<li>
<p><code>src/</code></p>
<p>Les sources de l'application.</p>
<ul>
<li>
<p><code>public_html/</code></p>
<p>La racine web de l'application : celle-ci ne contient que les fichiers <code>.htaccess</code> et
<code>index.php</code> qui configure et déclenche la réécriture d'URL.</p>
</li>
</ul>
<ul>
<li>
<p><code>conf/</code></p>
<p>Contient les fichiers de configuration.</p>
<ul>
<li>
<p><code>LSobjects/</code></p>
<p>Configuration des <a href="#conf-configuration-lsobject">LSobjects</a>.</p>
</li>
</ul>
<ul>
<li>
<p><code>LSaddons/</code></p>
<p>Configuration des <a href="#conf-configuration-des-lsaddons">LSaddons</a>.</p>
</li>
</ul>
<ul>
<li>
<p><code>LSauth/</code></p>
<p>Configuration des <a href="#conf-configuration-des-lsauthmethods">LSauthMethod</a>.</p>
</li>
</ul>
</li>
</ul>
<ul>
<li>
<p><code>includes/</code></p>
<p>Contient les fichiers des ressources.</p>
<ul>
<li>
<p><code>addons/</code></p>
<p>Les addons au projet.</p>
</li>
</ul>
<ul>
<li>
<p><code>class/</code></p>
<p>Les fichiers de définition des classes PHP.</p>
</li>
</ul>
<ul>
<li>
<p><code>js/</code></p>
<p>Les fichiers Javascript.</p>
</li>
</ul>
<ul>
<li>
<p><code>libs/</code></p>
<p>Les librairies utilisées.</p>
</li>
</ul>
</li>
</ul>
<ul>
<li>
<p><code>lang/</code></p>
<p>Les fichiers d'internationalisation.</p>
</li>
</ul>
<ul>
<li>
<p><code>templates/</code></p>
<p>Les fichiers <em>template</em> de l'interface. Il y a un sous-dossier par template.</p>
</li>
</ul>
<ul>
<li>
<p><code>css/</code></p>
<p>Les fichiers css de l'interface. Il y a un sous-dossier par template CSS.</p>
</li>
</ul>
<ul>
<li>
<p><code>images/</code></p>
<p>Les images de l'interface. Il y a un sous-dossier par template d'image.</p>
</li>
</ul>
<ul>
<li>
<p><code>local/</code></p>
<p>Les fichiers personnalisés de l'installation.</p>
</li>
</ul>
<ul>
<li>
<p><code>tmp/</code></p>
<p>Les fichiers temporaires (y compris le cache des templates).</p>
</li>
</ul>
</li>
</ul></section><section class="print-page" id="install-howto"><h1 id="install-howto-tutoriel-dinstallation">Tutoriel d'installation</h1>
<p>Cette section décrit les différentes étapes de l'installation de LdapSaisie. Deux méthodes
d'installation sont présentées ici, l'une à partir des sources du projet et l'autre à partir du
paquet Debian.</p>
<p>Dans ce tutoriel, nous partirons du principe que vous avez pleinement la main sur votre serveur
(installation de nouveau paquet et configuration de votre serveur web). Nous partons également du
principe que votre annuaire LDAP est déjà en place. Nous utiliserons pour cette exemple de mise en
oeuvre l'annuaire correspondant au schéma et à la configuration présente dans les sources du projet
dans le dossier <code>lsexample</code>.</p>
<p>La première étape consiste à installer le locigiel en tant que tel. Pour cela, référez vous au
chapitre <a href="#install-howto-telechargement">Téléchargement</a>.</p>
<p>En cas d'installation à partir du paquet Debian, la configuration du logiciel se fera dans le
dossier <code>/etc/ldapsaisie/local/</code>. Les fichiers placés dans ce dossier prévaleront toujours aux
fichiers fournis par le paquet Debian, vous permettant facilement de modifier un composant existant
ou dans écrire de nouveaux. Ainsi, pour modifier un fichier CSS par exemple, il vous suffira de le
placer dans le dossier <code>/etc/ldapsaisie/local/css/</code>.</p>
<p>Pour une installation à partir du code source, il vous faut cloner le dépôt Git du projet dans le
dossier <code>/var/www/ldapsaisie</code>. Pour cela il vous faut avoir installés les outils de Git contenu,
dans Debian, dans le paquet <code>git-core</code>. Le dépôt Git doit ensuite être récupéré anonymement en
utilisant la commande suivante :</p>
<div class="highlight"><pre><span></span><code><a href="#install-howto-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>git clone https://gitlab.easter-eggs.com/ee/ldapsaisie.git /var/www/ldapsaisie
</code></pre></div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Pour que cette commande se déroule correctement, vous devez avoir accès au port TCP 443 du
serveur <code>gitlab.easter-eggs.com</code>. En cas de problème vérifiez votre parefeu.</p>
</div>
<p>La suite des opérations se déroulera donc maintenant dans le dossier <code>/var/www/ldapsaisie</code>. Pour
avoir plus de détails sur les élements qu'on retrouve dans ce dossier, vous pouvez consulter
<a href="#install-howto-arborescence-du-projet">la section concernée</a>. Nous allons nous instérésser plus particulièrement :</p>
<ul>
<li>au script <code>upgradeFromGit.sh</code> permettant la mise à jour de votre repos tout en concervant les
adaptations que nous ferons pour l'usage d'LdapSaisie adapté à notre annuaire ;</li>
</ul>
<ul>
<li>au dossier <code>config.local</code> dans lequel seront stockés vos fichiers et vos adaptations de
l'application ;</li>
</ul>
<ul>
<li>au dossier <code>src/public_html</code> qui correspond à la futur racine du site web de l'application.</li>
</ul>
<p>Le principe de l'adaptation est ici de mettre vos fichiers personnalisés dans le dossier
<code>config.local</code>, de les déclarer dans votre fichier <code>config.local/local.sh</code> contenant la liste des
fichiers devant être installés. Le fichier <code>local.sh</code> est la source de configuration du script
<code>upgradeFromGit.sh</code>. Il faut donc dans un premier temps créer votre fichier <code>local.sh</code> en copiant le
fichier d'example <code>local.sh.example</code>. Ce fichier est un script bash déclarant les variables de
configurations suivantes :</p>
<ul>
<li>
<p><code>LOCAL_FILES</code></p>
<p>La liste des chemins des fichiers à installer dans l'arboressence du site. Cette élément doivent
être séparés par des espaces ou des retour à la liste. Exemple :</p>
<div class="highlight"><pre><span></span><code><a href="#install-howto-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a>conf/config.inc.php
<a href="#install-howto-__codelineno-1-2" id="__codelineno-1-2" name="__codelineno-1-2"></a>lang/fr_FR.UTF8/lang.php
</code></pre></div>
</li>
</ul>
<ul>
<li>
<p><code>LOG_FILE</code></p>
<p>Nom du fichier de log des mises à jour.</p>
</li>
</ul>
<ul>
<li>
<p><code>THEME</code></p>
<p>Le nom du theme à installer (facultatif et non traité dans ce tutoriel).</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Il est possible d'utiliser dans ce fichier de configuration la variable bash <code>$ROOT_DIR</code>
correspondant au chemin du dossier d'installation, c'est à dire dans notre exemple
<code>/var/www/ldapsaisie</code>.</p>
</div>
</li>
</ul>
<p>La deuxième étape concerne la configuration globale de l'application : Cette partie est
principalement contenue dans le fichier <code>src/conf/config.inc.php</code> (ou
<code>/etc/ldapsaisie/local/conf/config.inc.php</code> en cas d'installation à partir du paquet Debian). En cas
d'installation à partir du code source, il faut donc dans un premier temps copier ce fichier dans le
dossier <code>config.local</code> et le déclarer dans la liste des fichiers à déployer lors des mises à jour
(variable <code>LOCAL_FILES</code> dans le fichier <code>local.sh</code>). Il s'agit en particulier dans ce fichier de
configurer la connexion à votre annuaire. Vous pouvez vous inspirer du fichier d'exemple fourni et
pour plus de détails, reportez-vous à <a href="#install-howto-configuration-globale">la section concernée</a>.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Notez qu'il est possible de passer l'application en mode <em>debug</em> ce qui peut être utile par la
suite.</p>
</div>
<p>La troisième étape concerne la configuration des types de
<a href="#conf-lsobject-configuration-lsobject">LSobjects</a> : Chaque type d'objet manipulé par
LdapSaisie doit correspondre avec un type de LSobject.</p>
<ol>
<li>
<p>Création du fichier de classe <em>(optionnel)</em> : Ce fichier contient la déclaration de la classe PHP
correspondant au type de LSobject. Cette classe étend la classe <code>LSldapObject</code> qui contient pour
ainsi dire toute les méthodes et proprités nécessaires pour les types de LSobject simples. Si
votre type de LSobject nécessite des méthodes ou propriétés particulières, vous pouvez implémenter
cette classe. À défaut, une classe vierge d'adaptation sera automatiquement déclarée.</p>
<p>Les fichiers des classes sont contenus dans le dossier <code>/includes/class/</code> et portent les noms
composés de la manière suivante :</p>
<div class="highlight"><pre><span></span><code><a href="#install-howto-__codelineno-2-1" id="__codelineno-2-1" name="__codelineno-2-1"></a>class.LSobjects.[nom du type d'LSobject].php
</code></pre></div>
</li>
<li>
<p>Configurer vos LSobject : Cette partie est certainement la plus longue et consiste à déclarer
l'ensemble des informations relatives aux types des objets LDAP manipulés. Les fichiers d'exemples
fournis vous seront alors d'une aide précieuse. Basez vous sur l'un de pour créer le votre. Pour
cela le fichier de configuration du type d'LSobjet <code>LSpeople</code> est le plus complet et est un bon
point de départ. Pour plus de détails sur les élements de configuration de ce fichier,
reportez-vous à <a href="#conf-lsobject-configuration-lsobject">la section concernée</a>.</p>
</li>
<li>
<p>Configurer si nécessaire les relations entre les objets appelés <a href="#install-howto-lsrelation">LSrelations</a>. Les
relations les plus simples (via un attribut de liaison) pourront être implémentées à l'aide d'un
simple paramètrage. Pour des relations, plus complexes, il sera possible d'implémenter des
méthodes personnalisées pour les gérer. Pour plus de détails, reportez-vous à
<a href="#conf-lsrelation">la section concernée</a>.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Pour avoir un exemple de fichier de classe PHP implémentant des methodes de gestion de
<a href="#install-howto-lsrelation">LSrelations</a> complexes, vous pouvez consulter le fichier de classe <code>LSgroup</code>.</p>
</div>
</li>
</ol>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>En cas d'installation à partir du code source, pensez à déclarer les fichiers que vous venez de
créer dans la variable <code>LOCAL_FILES</code> du fichier <code>local.sh</code>. Exemple pour le type d'LSobjet
portant comme nom <code>LSexample</code> :</p>
<div class="highlight"><pre><span></span><code><a href="#install-howto-__codelineno-3-1" id="__codelineno-3-1" name="__codelineno-3-1"></a>src/conf/LSobjects/config.LSobjects.LSexample.php
<a href="#install-howto-__codelineno-3-2" id="__codelineno-3-2" name="__codelineno-3-2"></a>src/includes/class/class.LSobjects.LSexample.php
</code></pre></div>
</div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Vous pouvez également personnaliser l'interface : Il est possible de personnaliser à votre goût
l'interface en écrivant votre template ou en modifiant simplement les fichiers CSS. Une partie
de cette documentation concernera bientôt cette problématique. Patience...</p>
</div>
<p>En cas d'installation à partir du code source, une dernière étape à ce niveau consiste à lancer le
script <code>upgradeFromGit.sh</code> pour qu'il installe les fichiers que vous venez de créer. Ce script est
conçu pour dire tout ce qu'il fait donc en cas de problème vous devriez rapidement comprendre où
cela coince. Dans tout les cas, n'hésitez pas à poser vos questions à la communauté sur la liste
<a href="mailto:ldapsaisie-users@lists.ldapsaisie.org">ldapsaisie-users@lists.ldapsaisie.org</a>.</p></section><h1 class="nav-section-title-end">Ended: Installation</h1><h1 class="nav-section-title">Mise à jour</h1><section class="print-page" id="upgrade"><h1 id="upgrade-mise-a-jour">Mise à jour</h1>
<p>Cette section de la documentation détaille la procédure de mise à jour d'une installation existante
et regroupe des informations pratiques et utiles pour des montées de versions spécifiques entraînant
par exemple une perte de rétrocompatibilité de la configuration.</p></section><section class="print-page" id="upgrade-method"><h1 id="upgrade-method-procedure-de-mise-a-jour">Procédure de mise à jour</h1>
<h2 id="upgrade-method-installation-via-paquet-debian">Installation via paquet Debian</h2>
<p>Lors dune installation par paquet Debian, la mise à jour est grandement facilité par le packaging :
Il vous suffit de mettre à jour le paquet <code>ldapsaisie</code> :</p>
<div class="highlight"><pre><span></span><code><a href="#upgrade-method-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>apt<span class="w"> </span>update
<a href="#upgrade-method-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a>apt<span class="w"> </span>install<span class="w"> </span>ldapsaisie
</code></pre></div>
<p>Une fois lapplication mise à jour, prêté attention aux nouveautés et point de vigilances décrite
dans la section suivante.</p>
<h2 id="upgrade-method-installation-a-partir-des-sources">Installation à partir des sources</h2>
<p>Lors dune installation par à partir des sources, le script <code>upgradeFromGit.sh</code> permet dautomatiser
la mise à jour, à condition que vous ayez suivi la procédure dinstallation à ce sujet.</p>
<p>Ce script soccupera alors de :</p>
<ul>
<li>Nettoyer <code>working-tree</code> Git des liens symboliques des fichiers locaux (et éventuellement du
thème) mis en place lors dune précédente exécution ;</li>
</ul>
<ul>
<li>Vider le cache des templates ;</li>
</ul>
<ul>
<li>Mettre à jour le <code>working-tree</code> Git via un <code>git pull</code> de la mise à jour ;</li>
</ul>
<ul>
<li>Installer des liens symboliques pour les fichiers locaux. En cas de fichier remplacant un fichier
livré avec lapplication, le script vous notifiera en cas de changement intervenu dans le fichier
fourni avec lapplication et vous permettra de le mettre à jour simplement votre fichier local
(via un <code>vim -d</code>) ;</li>
</ul>
<ul>
<li>Détecter des changements dans les fichiers <code>MO</code> (traduction) et de déclencher dans ce cas un
rechargement du serveur web pour prise en compte ;</li>
</ul>
<ul>
<li>Option : de compiler une version locale à jour de la documentation ;</li>
</ul>
<p>Une fois lapplication mise à jour, prêté attention aux nouveautés et point de vigilances décrite
dans la section suivante.</p></section><section class="print-page" id="upgrade-2_4_1-to-3_0_0"><h1 id="upgrade-2_4_1-to-3_0_0-mise-a-jour-241-300">Mise à jour 2.4.1 -&gt; 3.0.0</h1>
<p>Cette mise à jour majeure apporte de nombreuses nouveautés auxquelles il est important de prêter
attention. Cette section ne parlera pas particulièrement de ces nouveautés, mais vous pouvez
consulter le fichier
<a href="https://gitlab.easter-eggs.com/ee/ldapsaisie/-/raw/master/debian/ldapsaisie.NEWS">debian/ldapsaisie.NEWS</a>
pour cela. Cette section listera en outre les points de vigilances à avoir et les adaptations à
apporter sur votre configuration et votre code personnalisé.</p>
<h2 id="upgrade-2_4_1-to-3_0_0-fichier-configincphp">Fichier config.inc.php</h2>
<ul>
<li>ajout du paramètre <code>ConsoleTable</code> avec pour valeur par défaut sous Debian
<code>/usr/share/php/Console/Table.php</code></li>
</ul>
<ul>
<li>ajout du paramètre <code>public_root_url</code> avec pour valeur par défaut sous Debian <code>/ldapsaisie</code></li>
</ul>
<ul>
<li>paramètre <code>$GLOBALS['defaultCSSfiles']</code> : il est nécessaire de modifier les URLs des fichiers
listés : seul le nom du fichier doit rester, sa localisation sera détectée automatiquement. Par
exemple, <code>$GLOBALS['defaultCSSfiles'] = array('../light-blue.css');</code> devient
<code>$GLOBALS['defaultCSSfiles'] = array('light-blue.css');</code>.</li>
</ul>
<ul>
<li>
<p>les paramètres <code>authObjectType</code>, <code>authObjectFilter</code> et <code>authObjectTypeAttrPwd</code> sont remplacés par
le tablau <code>LSobjects</code> dans le paramètre <code>LSauth</code>.</p>
<p>Par exemple:</p>
<div class="highlight"><pre><span></span><code><a href="#upgrade-2_4_1-to-3_0_0-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>'authObjectType' =&gt; 'LSpeople',
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a>'authObjectFilter' =&gt; '(|(uid=%{user})(mail=%{user}))',
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a>'authObjectTypeAttrPwd' =&gt; 'userPassword',
</code></pre></div>
<p>Devient:</p>
<div class="highlight"><pre><span></span><code><a href="#upgrade-2_4_1-to-3_0_0-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a>'LSauth' =&gt; array (
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-1-2" id="__codelineno-1-2" name="__codelineno-1-2"></a> 'LSobjects' =&gt; array(
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-1-3" id="__codelineno-1-3" name="__codelineno-1-3"></a> 'LSpeople' =&gt; array(
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-1-4" id="__codelineno-1-4" name="__codelineno-1-4"></a> 'filter' =&gt; '(|(uid=%{user})(mail=%{user}))',
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-1-5" id="__codelineno-1-5" name="__codelineno-1-5"></a> 'password_attribute' =&gt; 'userPassword',
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-1-6" id="__codelineno-1-6" name="__codelineno-1-6"></a> ),
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-1-7" id="__codelineno-1-7" name="__codelineno-1-7"></a> ),
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-1-8" id="__codelineno-1-8" name="__codelineno-1-8"></a> [...]
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-1-9" id="__codelineno-1-9" name="__codelineno-1-9"></a>),
</code></pre></div>
</li>
</ul>
<ul>
<li>Une erreur de frappe historique a été corrigé dans le nom de la variable
<code>$GLOBALS['defaultJSscripts']</code>, à savoir un <em>"R"</em> manquant.</li>
</ul>
<ul>
<li>Les fichiers Javascript utilisés par défaut par l'application ne sont désormais plus listés dans
la variable <code>$GLOBALS['defaultJSscripts']</code>. Seul doit y demeurer vos propres fichiers. Voici la
liste des fichiers concernés et qui n'ont plus à être inclus via ce paramètre :<p>- <code>mootools-core.js</code>
- <code>mootools-more.js</code>
- <code>functions.js</code>
- <code>LSdefault.js</code>
- <code>LSinfosBox.js</code></p>
</li>
</ul>
<h2 id="upgrade-2_4_1-to-3_0_0-fichiers-css">Fichiers CSS</h2>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Les fichiers <code>light-*.css</code> ont été retravaillés pour tous <em>hériter</em> du fichier <code>light-blue.css</code>
qui défini les couleurs de l'interface au travers des variables. Ainsi, il est très simple
d'ajuster ce thème à vos couleurs. Si cela vous intéresse, vous pouvez prendre exemple sur les
autres fichiers <code>light-*.css</code>.</p>
<p>Au passage, ce thème a été retravaillé pour prendre en compte la mise en forme d'un maximum de
composants de l'application tout en profitant du côté responsive de l'interface apporter par
cette mise à jour. Si vous avez un thème personnalisé, il est conseillé de regarder si celui-ci
ne pourrait pas tirer partie du fichier <code>light-blue.css</code> en le surchargeant. À minima, vous
pouvez analyser les évolutions de ce fichier pour identifier les modifications intéressantes à
reporter sur votre thème personnel.</p>
</div>
<ul>
<li>Si vous utilisez un des fichiers <code>light-*.css</code> autre que le fichier <code>light-blue.css</code>, vous devez
désormais également charger ce dernier en premier.</li>
</ul>
<ul>
<li>
<p>corriger les URL des images : <code>url(../../images/default/find.png)</code> devient <code>url(../image/find)</code>.
Pour identifier les fichiers CSS concernés, vous pouvez utiliser les commandes suivantes :</p>
<div class="highlight"><pre><span></span><code><a href="#upgrade-2_4_1-to-3_0_0-__codelineno-2-1" id="__codelineno-2-1" name="__codelineno-2-1"></a>grep<span class="w"> </span>-Er<span class="w"> </span><span class="s1">'url\(.*images'</span><span class="w"> </span>/etc/ldapsaisie/local/css
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-2-2" id="__codelineno-2-2" name="__codelineno-2-2"></a>grep<span class="w"> </span>-Er<span class="w"> </span><span class="s1">'url\(.*\.(png|gif|jpg)'</span><span class="w"> </span>/etc/ldapsaisie/local/css
</code></pre></div>
</li>
</ul>
<ul>
<li>modification CSS page <code>fatal_error</code> (fichier <code>base.css</code>) : <code>#fatal_error</code> devient <code>#error</code></li>
</ul>
<h2 id="upgrade-2_4_1-to-3_0_0-fichiers-php">Fichiers PHP</h2>
<ul>
<li>
<p><code>LSsession :: redirect()</code> devient <code>LSurl :: redirect()</code>. Pour identifier les fichiers CSS
concernés, vous pouvez utiliser la commande suivante :</p>
<div class="highlight"><pre><span></span><code><a href="#upgrade-2_4_1-to-3_0_0-__codelineno-3-1" id="__codelineno-3-1" name="__codelineno-3-1"></a>grep<span class="w"> </span>-Er<span class="w"> </span><span class="s1">'LSsession *:: *redirect *\('</span><span class="w"> </span>/etc/ldapsaisie/local/
</code></pre></div>
</li>
</ul>
<ul>
<li>
<p>Les méthodes de gestion des Javascript et CSS additionels ont été migrées de la classe <code>LSsession</code>
vers la classe <code>LStemplate</code> :</p>
<ul>
<li>
<p><code>LSsession :: addJSscript()</code> devient <code>LStemplate :: addJSscript()</code>.</p>
<p>Par ailleurs le paramètre <code>$path</code> disparait et la méthode <code>addLibJSscript</code> a été ajoutée pour
permettre spécifiquement l'inclusion des fichiers Javascript des librairies. Voici quelques
exemples d'utilisation et leur équivalent à présent:</p>
<ul>
<li><code>LSsession :: addJSscript('../../local/includes/js/LSformElement_eetelephone.js');</code>
devient <code>LStemplate :: addJSscript('LSformElement_eetelephone.js');</code></li>
</ul>
<ul>
<li><code>LSsession :: addJSscript('../../local/includes/js/LSformElement_eetelephone.js');</code>
devient <code>LStemplate :: addJSscript('LSformElement_eetelephone.js');</code></li>
</ul>
<ul>
<li><code>LSsession :: addJSscript('click-to-dial_view.js', 'local/includes/js/');</code> devient
<code>LStemplate :: addJSscript('click-to-dial_view.js');</code></li>
</ul>
<ul>
<li><code>LSsession :: addJSscript('Picker.js',LS_LIB_DIR.'arian-mootools-datepicker/');</code>
devient <code>LStemplate :: addLibJSscript('arian-mootools-datepicker/Picker.js');</code></li>
</ul>
</li>
</ul>
<ul>
<li><code>LSsession :: addJSconfigParam()</code> devient <code>LStemplate :: addJSconfigParam()</code>.</li>
</ul>
<ul>
<li><code>LSsession :: addHelpInfos()</code> devient <code>LStemplate :: addHelpInfo()</code>.</li>
</ul>
<ul>
<li>
<p><code>LSsession :: addCssFile()</code> devient <code>LStemplate :: addCssFile()</code>.</p>
<p>Par ailleurs le paramètre <code>$path</code> disparait et la méthode <code>addLibCssFile</code> à été ajoutée pour
permettre spécifiquement l'inclusion des fichiers CSS des librairies. Voici quelques exemples
d'utilisation et leur équivalent à présent:</p>
<ul>
<li><code>LSsession :: addCssFile('test.css', '../../local/css/');</code> devient
<code>LStemplate :: addCssFile('test.css');</code>. Doit donc être conservé, que le nom du fichier CSS,
pas de chemin vers celui-ci.</li>
</ul>
<ul>
<li><code>LSsession :: addCssFile('datepicker_vista.css',LS_LIB_DIR.'arian-mootools-datepicker/datepicker_vista/');</code>
devient
<code>LStemplate :: addLibCssFile('arian-mootools-datepicker/datepicker_vista/datepicker_vista.css');</code></li>
</ul>
</li>
</ul>
<p>Pour identifier les fichiers concernés, vous pouvez utiliser les commandes suivantes :</p>
<div class="highlight"><pre><span></span><code><a href="#upgrade-2_4_1-to-3_0_0-__codelineno-4-1" id="__codelineno-4-1" name="__codelineno-4-1"></a>grep<span class="w"> </span>-Er<span class="w"> </span><span class="s1">'LSsession *:: *(addJSscript|addLibJSscript|addJSconfigParam|addHelpInfos|addCssFile|addLibCssFile) *\('</span><span class="w"> </span>/etc/ldapsaisie/local/
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-4-2" id="__codelineno-4-2" name="__codelineno-4-2"></a>grep<span class="w"> </span>-Er<span class="w"> </span><span class="s1">'(LSsession|LStemplate) *:: *addJSscript\(.*local'</span><span class="w"> </span>/etc/ldapsaisie/local/
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-4-3" id="__codelineno-4-3" name="__codelineno-4-3"></a>grep<span class="w"> </span>-Er<span class="w"> </span><span class="s1">'(LSsession|LStemplate) *:: *addJSscript\(.*\.\.\/'</span><span class="w"> </span>/etc/ldapsaisie/local/
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-4-4" id="__codelineno-4-4" name="__codelineno-4-4"></a>grep<span class="w"> </span>-Er<span class="w"> </span><span class="s1">'(LSsession|LStemplate) *:: *addCssFile\(.*local'</span><span class="w"> </span>/etc/ldapsaisie/local/
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-4-5" id="__codelineno-4-5" name="__codelineno-4-5"></a>grep<span class="w"> </span>-Er<span class="w"> </span><span class="s1">'(LSsession|LStemplate) *:: *addCssFile\(.*\.\.\/'</span><span class="w"> </span>/etc/ldapsaisie/local/
</code></pre></div>
</li>
</ul>
<ul>
<li>
<p><code>LSlog</code> vs <code>LSdebug</code> : Lutilisation de <code>LSdebug</code> est dépriorisée en faveur de <code>LSlog</code>. Ce dernier
ajoute désormais la notion de <em>logger</em>, permettant didentifier la source des logs. Ce mécanisme
permet la configuration dun niveau de log spécifique pour un <em>logger</em> donné, ainsi que la mise en
place de filtres au niveau des <em>handers</em> pour ne logger par exemple que certains <em>loggers</em>, ou à
linverse en exclure dautres.</p>
<ul>
<li>Pour vos classes personnalisées : si celles-ci héritent dune classe standard, il est fort
probable quil soit possible dutiliser des méthodes fournies par cette classe pour logguer
au travers un <em>logger</em> dédié (voir les méthodes <code>log_debug</code>, <code>log_info</code>, …). À défaut, il est
possible dutiliser la classe <code>LSlog_staticLoggerClass</code> qui facilite limplémentation.</li>
</ul>
<ul>
<li>
<p>Pour vos <a href="#conf-configuration-des-lsaddons">LSaddons</a> : il est conseillé dutiliser un
<em>logger</em> <code>LSaddon_[addon]</code> dédié. Le <em>logger</em> peut facilement être récupéré de la manière
suivante :</p>
<div class="highlight"><pre><span></span><code><a href="#upgrade-2_4_1-to-3_0_0-__codelineno-5-1" id="__codelineno-5-1" name="__codelineno-5-1"></a><span class="x">LSlog :: get_logger("LSaddon_[addon]")</span>
</code></pre></div>
<p>Cette méthode retourne une référence au <em>logger</em> et il est possible dappeler directement une
méthode de log, par exemple :</p>
<div class="highlight"><pre><span></span><code><a href="#upgrade-2_4_1-to-3_0_0-__codelineno-6-1" id="__codelineno-6-1" name="__codelineno-6-1"></a><span class="x">LSlog :: get_logger("LSaddon_[addon]") -&gt; debug("message");</span>
</code></pre></div>
</li>
</ul>
</li>
</ul>
<h2 id="upgrade-2_4_1-to-3_0_0-fichiers-templates">Fichiers templates :</h2>
<h3 id="upgrade-2_4_1-to-3_0_0-changement-de-linclusion-des-templates">Changement de linclusion des templates</h3>
<ul>
<li>
<p>Le cas des fichiers <code>top.tpl</code> et <code>bottom.tpl</code></p>
<div class="highlight"><pre><span></span><code><a href="#upgrade-2_4_1-to-3_0_0-__codelineno-7-1" id="__codelineno-7-1" name="__codelineno-7-1"></a>{include file='ls:top.tpl'}
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-7-2" id="__codelineno-7-2" name="__codelineno-7-2"></a>
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-7-3" id="__codelineno-7-3" name="__codelineno-7-3"></a>[...]
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-7-4" id="__codelineno-7-4" name="__codelineno-7-4"></a>
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-7-5" id="__codelineno-7-5" name="__codelineno-7-5"></a>{include file='ls:bottom.tpl'}
</code></pre></div>
<p>devient :</p>
<div class="highlight"><pre><span></span><code><a href="#upgrade-2_4_1-to-3_0_0-__codelineno-8-1" id="__codelineno-8-1" name="__codelineno-8-1"></a>{extends file='ls:base_connected.tpl'}
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-8-2" id="__codelineno-8-2" name="__codelineno-8-2"></a>{block name="content"}
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-8-3" id="__codelineno-8-3" name="__codelineno-8-3"></a>
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-8-4" id="__codelineno-8-4" name="__codelineno-8-4"></a>[...]
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-8-5" id="__codelineno-8-5" name="__codelineno-8-5"></a>
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-8-6" id="__codelineno-8-6" name="__codelineno-8-6"></a>{/block}
</code></pre></div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Pages à létat connecté uniquement (incluant le menu, lentête…).</p>
</div>
</li>
</ul>
<ul>
<li>
<p>Fichiers avec entête HTML :</p>
<div class="highlight"><pre><span></span><code><a href="#upgrade-2_4_1-to-3_0_0-__codelineno-9-1" id="__codelineno-9-1" name="__codelineno-9-1"></a><span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-9-2" id="__codelineno-9-2" name="__codelineno-9-2"></a> <span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-9-3" id="__codelineno-9-3" name="__codelineno-9-3"></a> [...]
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-9-4" id="__codelineno-9-4" name="__codelineno-9-4"></a> <span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-9-5" id="__codelineno-9-5" name="__codelineno-9-5"></a> <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-9-6" id="__codelineno-9-6" name="__codelineno-9-6"></a> [...]
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-9-7" id="__codelineno-9-7" name="__codelineno-9-7"></a> <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-9-8" id="__codelineno-9-8" name="__codelineno-9-8"></a><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</code></pre></div>
<p>devient :</p>
<div class="highlight"><pre><span></span><code><a href="#upgrade-2_4_1-to-3_0_0-__codelineno-10-1" id="__codelineno-10-1" name="__codelineno-10-1"></a>{extends file='ls:base.tpl'}
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-10-2" id="__codelineno-10-2" name="__codelineno-10-2"></a>{block name="body"}
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-10-3" id="__codelineno-10-3" name="__codelineno-10-3"></a>[...]
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-10-4" id="__codelineno-10-4" name="__codelineno-10-4"></a>{/block}
</code></pre></div>
<p>Au besoin, si vous avez besoin :</p>
<ul>
<li>
<p>de remplacer les fichiers CSS chargés par défaut (<code>base.css</code> par exemple) : ajouter le block
<code>css</code> :</p>
<div class="highlight"><pre><span></span><code><a href="#upgrade-2_4_1-to-3_0_0-__codelineno-11-1" id="__codelineno-11-1" name="__codelineno-11-1"></a>{block name="css"}
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-11-2" id="__codelineno-11-2" name="__codelineno-11-2"></a> &lt;link rel="stylesheet" type="text/css" href="{css name='custom.css'}" media="screen" title="Normal" /&gt;
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-11-3" id="__codelineno-11-3" name="__codelineno-11-3"></a> {include file='ls:css.tpl'}
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-11-4" id="__codelineno-11-4" name="__codelineno-11-4"></a>{/block}
</code></pre></div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Ce block contient tous les CSS, y compris ceux gérés par <code>LSsession :: addCssFile()</code>.
Pensez à ajouter <code>{include file='ls:css.tpl'}</code> pour conserver ces derniers.</p>
</div>
</li>
</ul>
<ul>
<li>
<p>dajouter des infos dans <code>&lt;head&gt;</code> : ajouter le block <code>head</code> (vide par défaut) :</p>
<div class="highlight"><pre><span></span><code><a href="#upgrade-2_4_1-to-3_0_0-__codelineno-12-1" id="__codelineno-12-1" name="__codelineno-12-1"></a>{block name="head"}
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-12-2" id="__codelineno-12-2" name="__codelineno-12-2"></a>[...]
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-12-3" id="__codelineno-12-3" name="__codelineno-12-3"></a>{/block}
</code></pre></div>
</li>
</ul>
<ul>
<li>
<p>dajouter des fichiers Javascript personnalisés : ajouter le block <code>js</code> (vide par défaut):</p>
<div class="highlight"><pre><span></span><code><a href="#upgrade-2_4_1-to-3_0_0-__codelineno-13-1" id="__codelineno-13-1" name="__codelineno-13-1"></a>{block name="js"}
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-13-2" id="__codelineno-13-2" name="__codelineno-13-2"></a>[...]
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-13-3" id="__codelineno-13-3" name="__codelineno-13-3"></a>{/block}
</code></pre></div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Ce block sera ajouté <em>APRÈS</em> les autres fichiers Javascript chargés (ceux par défaut et ceux
ajoutés via <code>LSsession :: addJSscript()</code>.</p>
</div>
</li>
</ul>
</li>
</ul>
<ul>
<li>
<p>Autres fichiers remplacés :</p>
<ul>
<li><code>blank.tpl</code> remplacé par <code>base.tpl</code></li>
<li><code>empty.tpl</code> remplacé par <code>base_connected.tpl</code></li>
<li><code>accueil.tpl</code> remplacé par <code>homepage.tpl</code></li>
</ul>
</li>
</ul>
<p>Pour identifier les fichiers concernés, vous pouvez utiliser la commande suivante :</p>
<div class="highlight"><pre><span></span><code><a href="#upgrade-2_4_1-to-3_0_0-__codelineno-14-1" id="__codelineno-14-1" name="__codelineno-14-1"></a>grep<span class="w"> </span>-Er<span class="w"> </span><span class="s1">'(accueil|blank|empty|top|bottom)\.tpl'</span><span class="w"> </span>/etc/ldapsaisie/local/
</code></pre></div>
<h3 id="upgrade-2_4_1-to-3_0_0-fichiers-templates-fournis-par-defaut">Fichiers templates fournis par défaut :</h3>
<p>Vérifier les modifications des fichiers templates fourni avec lapplication et que vous auriez
personnalisé. Pour cela, vous pouvez utiliser la commande suivante :</p>
<div class="highlight"><pre><span></span><code><a href="#upgrade-2_4_1-to-3_0_0-__codelineno-15-1" id="__codelineno-15-1" name="__codelineno-15-1"></a><span class="k">for</span><span class="w"> </span>i<span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="k">$(</span><span class="w"> </span>ls<span class="w"> </span>/etc/ldapsaisie/local/templates/*<span class="w"> </span><span class="k">)</span>
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-15-2" id="__codelineno-15-2" name="__codelineno-15-2"></a><span class="k">do</span>
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-15-3" id="__codelineno-15-3" name="__codelineno-15-3"></a><span class="w"> </span><span class="nv">default_file</span><span class="o">=</span><span class="s2">"/usr/share/ldapsaisie/templates/default/</span><span class="k">$(</span><span class="w"> </span>basename<span class="w"> </span><span class="s2">"</span><span class="nv">$i</span><span class="s2">"</span><span class="w"> </span><span class="k">)</span><span class="s2">"</span>
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-15-4" id="__codelineno-15-4" name="__codelineno-15-4"></a><span class="w"> </span><span class="o">[</span><span class="w"> </span>!<span class="w"> </span>-e<span class="w"> </span><span class="s2">"</span><span class="nv">$default_file</span><span class="s2">"</span><span class="w"> </span><span class="o">]</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="k">continue</span>
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-15-5" id="__codelineno-15-5" name="__codelineno-15-5"></a><span class="w"> </span>vi<span class="w"> </span>-d<span class="w"> </span><span class="nv">$default_file</span><span class="w"> </span><span class="nv">$i</span>
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-15-6" id="__codelineno-15-6" name="__codelineno-15-6"></a><span class="k">done</span>
</code></pre></div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Une attention particulière doit être porté aux fichiers <code>login.tpl</code> et <code>recoverpassword.tpl</code> qui
ont particulièrement changés.</p>
</div>
<h3 id="upgrade-2_4_1-to-3_0_0-corriger-les-url-des-images">Corriger les URL des images :</h3>
<p><code>../../images/default/find.png</code> devient <code>../image/find</code></p>
<p>Pour identifier les fichiers concernés, vous pouvez utiliser les commandes suivantes :</p>
<div class="highlight"><pre><span></span><code><a href="#upgrade-2_4_1-to-3_0_0-__codelineno-16-1" id="__codelineno-16-1" name="__codelineno-16-1"></a>grep<span class="w"> </span>-Er<span class="w"> </span><span class="s1">'images'</span><span class="w"> </span>/etc/ldapsaisie/local/templates
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-16-2" id="__codelineno-16-2" name="__codelineno-16-2"></a>grep<span class="w"> </span>-Er<span class="w"> </span><span class="s1">'\.(png|gif|jpg)'</span><span class="w"> </span>/etc/ldapsaisie/local/templates
</code></pre></div>
<h3 id="upgrade-2_4_1-to-3_0_0-le-cas-de-variable-de-template-lssession_css-et-lssession_js">Le cas de variable de template <code>{$LSsession_css}</code> et <code>{$LSsession_js}</code> :</h3>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Ceci est déjà géré si vous étendez bien vos templates du fichier <code>base.tpl</code> (pour les pages
non-connectées) ou <code>base_connected.tpl</code> (pour les pages connectées).</p>
</div>
<ul>
<li><code>{$LSsession_css}</code> doit être remplacé par <code>{include file='ls:css.tpl'}</code></li>
</ul>
<ul>
<li><code>{$LSsession_js}</code> doit être remplacé par <code>{include file='ls:js.tpl'}</code></li>
</ul>
<h2 id="upgrade-2_4_1-to-3_0_0-tous-les-fichiers-modification-des-urls">Tous les fichiers : Modification des URLs</h2>
<ul>
<li>
<p><code>view.php</code> :</p>
<ul>
<li>page recherche : <code>view.php?LSobject=LSpeople</code> devient <code>object/LSpeople</code></li>
</ul>
<ul>
<li>page d'un objet : <code>view.php?LSobject=LSpeople&amp;dn=$dn</code> devient <code>object/LSpeople/$dn</code></li>
</ul>
</li>
</ul>
<ul>
<li><code>addon_view.php</code> : <code>addon_view.php?LSaddon=ee&amp;view=copyContract</code> devient <code>addon/ee/copyContract</code></li>
</ul>
<ul>
<li>
<p><code>index_ajax.php</code> :</p>
<ul>
<li>
<p>Pour les méthodes Ajax de classes :</p>
<div class="highlight"><pre><span></span><code><a href="#upgrade-2_4_1-to-3_0_0-__codelineno-17-1" id="__codelineno-17-1" name="__codelineno-17-1"></a><span class="kd">var</span><span class="w"> </span><span class="nx">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span>
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-17-2" id="__codelineno-17-2" name="__codelineno-17-2"></a><span class="w"> </span><span class="nx">template</span><span class="o">:</span><span class="w"> </span><span class="s1">'LSformElement_eetelephone'</span><span class="p">,</span>
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-17-3" id="__codelineno-17-3" name="__codelineno-17-3"></a><span class="w"> </span><span class="nx">action</span><span class="o">:</span><span class="w"> </span><span class="s1">'make_call'</span><span class="p">,</span>
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-17-4" id="__codelineno-17-4" name="__codelineno-17-4"></a><span class="w"> </span><span class="nx">telephoneNumber</span><span class="o">:</span><span class="w"> </span><span class="nx">tel</span><span class="p">,</span>
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-17-5" id="__codelineno-17-5" name="__codelineno-17-5"></a><span class="w"> </span><span class="nx">name</span><span class="o">:</span><span class="w"> </span><span class="nx">name</span><span class="p">,</span>
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-17-6" id="__codelineno-17-6" name="__codelineno-17-6"></a><span class="p">};</span>
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-17-7" id="__codelineno-17-7" name="__codelineno-17-7"></a><span class="ow">new</span><span class="w"> </span><span class="nx">Request</span><span class="p">({</span><span class="nx">url</span><span class="o">:</span><span class="w"> </span><span class="s1">'index_ajax.php'</span><span class="p">,</span><span class="w"> </span><span class="nx">data</span><span class="o">:</span><span class="w"> </span><span class="nx">data</span><span class="p">,</span><span class="w"> </span><span class="nx">onSuccess</span><span class="o">:</span><span class="w"> </span><span class="p">...});</span>
</code></pre></div>
<p>Devient :</p>
<div class="highlight"><pre><span></span><code><a href="#upgrade-2_4_1-to-3_0_0-__codelineno-18-1" id="__codelineno-18-1" name="__codelineno-18-1"></a>var data = {
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-18-2" id="__codelineno-18-2" name="__codelineno-18-2"></a> telephoneNumber: tel,
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-18-3" id="__codelineno-18-3" name="__codelineno-18-3"></a> name: name,
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-18-4" id="__codelineno-18-4" name="__codelineno-18-4"></a>};
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-18-5" id="__codelineno-18-5" name="__codelineno-18-5"></a>new Request({url: 'ajax/class/LSformElement_eetelephone/make_call', data: data, onSuccess: ...});
</code></pre></div>
</li>
</ul>
<ul>
<li>
<p>Pour les méthodes Ajax d'addon :</p>
<div class="highlight"><pre><span></span><code><a href="#upgrade-2_4_1-to-3_0_0-__codelineno-19-1" id="__codelineno-19-1" name="__codelineno-19-1"></a><span class="kd">var</span><span class="w"> </span><span class="nx">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span>
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-19-2" id="__codelineno-19-2" name="__codelineno-19-2"></a><span class="w"> </span><span class="nx">addon</span><span class="o">:</span><span class="w"> </span><span class="s1">'asterisk'</span><span class="p">,</span>
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-19-3" id="__codelineno-19-3" name="__codelineno-19-3"></a><span class="w"> </span><span class="nx">action</span><span class="o">:</span><span class="w"> </span><span class="s1">'LSasterisk_make_call'</span><span class="p">,</span>
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-19-4" id="__codelineno-19-4" name="__codelineno-19-4"></a><span class="w"> </span><span class="nx">telephoneNumber</span><span class="o">:</span><span class="w"> </span><span class="nx">tel</span><span class="p">,</span>
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-19-5" id="__codelineno-19-5" name="__codelineno-19-5"></a><span class="w"> </span><span class="nx">name</span><span class="o">:</span><span class="w"> </span><span class="nx">name</span><span class="p">,</span>
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-19-6" id="__codelineno-19-6" name="__codelineno-19-6"></a><span class="w"> </span><span class="nx">nocache</span><span class="o">:</span><span class="w"> </span><span class="ow">new</span><span class="w"> </span><span class="nb">Date</span><span class="p">().</span><span class="nx">getTime</span><span class="p">()</span>
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-19-7" id="__codelineno-19-7" name="__codelineno-19-7"></a><span class="p">};</span>
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-19-8" id="__codelineno-19-8" name="__codelineno-19-8"></a><span class="ow">new</span><span class="w"> </span><span class="nx">Request</span><span class="p">({</span><span class="nx">url</span><span class="o">:</span><span class="w"> </span><span class="s1">'index_ajax.php'</span><span class="p">,</span><span class="w"> </span><span class="nx">data</span><span class="o">:</span><span class="w"> </span><span class="nx">data</span><span class="p">,</span><span class="w"> </span><span class="nx">onSuccess</span><span class="o">:</span><span class="w"> </span><span class="p">...});</span>
</code></pre></div>
<p>Devient :</p>
<div class="highlight"><pre><span></span><code><a href="#upgrade-2_4_1-to-3_0_0-__codelineno-20-1" id="__codelineno-20-1" name="__codelineno-20-1"></a>var data = {
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-20-2" id="__codelineno-20-2" name="__codelineno-20-2"></a> telephoneNumber: tel,
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-20-3" id="__codelineno-20-3" name="__codelineno-20-3"></a> name: name,
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-20-4" id="__codelineno-20-4" name="__codelineno-20-4"></a> nocache: new Date().getTime()
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-20-5" id="__codelineno-20-5" name="__codelineno-20-5"></a>};
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-20-6" id="__codelineno-20-6" name="__codelineno-20-6"></a>new Request({url: 'ajax/addon/asterisk/LSasterisk_make_call', data: data, onSuccess: ...});
</code></pre></div>
</li>
</ul>
</li>
</ul>
<ul>
<li><code>global_search.php</code> : <code>global_search.php?refresh</code> devient <code>search?refresh</code></li>
</ul>
<ul>
<li><code>index.php</code> : <code>index.php?LSsession_recoverPassword</code> devient <code>index?LSsession_recoverPassword</code></li>
</ul>
<ul>
<li><code>create.php</code> : <code>create.php?LSobject=LSpeople</code> devient <code>object/LSpeople/create</code></li>
</ul>
<ul>
<li><code>modify.php</code> : <code>modify.php?LSobject=LSpeople&amp;dn=$dn</code> devient <code>object/LSpeople/$dn/modify</code></li>
</ul>
<ul>
<li><code>import.php</code> : <code>import.php?LSobject=LSpeople</code> devient <code>object/LSpeople/import</code></li>
</ul>
<ul>
<li>
<p><code>remove.php</code> : <code>remove.php?LSobject=LSpeople&amp;dn=$dn</code> devient <code>object/LSpeople/$dn/remove</code></p>
<p>Avec validation : <code>remove.php?LSobject=LSpeople&amp;dn=$dn&amp;valid</code> devient
<code>object/LSpeople/$dn/remove?valid</code></p>
</li>
</ul>
<ul>
<li><code>select.php</code> : <code>select.php?LSobject=LSpeople</code> devient <code>object/LSpeople/select</code></li>
</ul>
<ul>
<li>
<p><code>custom_action.php</code> :
<code>custom_action.php?LSobject=LSpeople&amp;dn=$dn&amp;customAction=$customAction</code>
devient <code>object/LSpeople/$dn/customAction/$customAction</code></p>
<p>Avec validation :
<code>custom_action.php?LSobject=LSpeople&amp;dn=$dn&amp;customAction=$customAction&amp;valid</code>
devient <code>object/LSpeople/$dn/customAction/$customAction?valid</code></p>
</li>
</ul>
<ul>
<li>
<p><code>custom_search_action.php</code> :
<code>custom_search_action.php?LSobject=LSpeople&amp;customAction=$customAction</code>
devient <code>object/LSpeople/customAction/$customAction</code></p>
<p>Avec validation :
<code>custom_search_action.php?LSobject=LSpeople&amp;customAction=$customAction&amp;valid</code>
devient <code>object/LSpeople/customAction/$customAction?valid</code></p>
</li>
</ul>
<p>Pour identifier les fichiers concernés, vous pouvez utiliser la commande suivante :</p>
<div class="highlight"><pre><span></span><code><a href="#upgrade-2_4_1-to-3_0_0-__codelineno-21-1" id="__codelineno-21-1" name="__codelineno-21-1"></a>grep<span class="w"> </span>-Er<span class="w"> </span><span class="s1">'(index|global_search|view|select|create|modify|import|remove|index_ajax|custom_action|custom_search_action|addon_view)\.php'</span><span class="w"> </span>/etc/ldapsaisie/local/
</code></pre></div></section><h1 class="nav-section-title-end">Ended: Mise à jour</h1><h1 class="nav-section-title">Configuration</h1><section class="print-page" id="conf"><h1 id="conf-configuration">Configuration</h1>
<p>La configuration du projet est située principalement dans le dossier <code>conf/</code>. Les exceptions seront
détaillées par la suite.</p>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>Toute la configuration du projet se fait par l'intermédiaire de fichiers définissant des
variables PHP dont les valeurs sont utilisées par le programme. Ceci signifie que la syntaxe de
ces fichiers doit être valide avec l'interpréteur PHP utilisé.</p>
</div></section><h2 class="nav-section-title">Configuration globale</h2><section class="print-page" id="conf-global"><h1 id="conf-global-configuration-globale">Configuration globale</h1>
<p>La plus grande partie de la configuration globale se trouve dans le fichier <code>config.inc.php</code>.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-global-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>// Variables globales
<a href="#conf-global-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a>$GLOBALS['LSconfig'] = array(
<a href="#conf-global-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> // Variables globales
<a href="#conf-global-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a>);
<a href="#conf-global-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a>
<a href="#conf-global-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a>// Variables et constantes indépendantes
<a href="#conf-global-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a>$var1 = 'val1'
<a href="#conf-global-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a>$var2 = 'val2'
<a href="#conf-global-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a>...
<a href="#conf-global-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a>define('CONST1','val1')
<a href="#conf-global-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a>define('CONST2','val2')
<a href="#conf-global-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a>...
</code></pre></div>
<h2 id="conf-global-variables-globales">Variables globales</h2>
<ul>
<li>
<p><code>NetLDAP2</code></p>
<p>Chemin vers la librairie <a href="http://pear.php.net/">PEAR</a>
<a href="http://pear.php.net/package/Net_LDAP2">Net_LDAP2</a>.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-global-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a>/usr/share/php/Net/LDAP2.php
</code></pre></div>
</li>
</ul>
<ul>
<li>
<p><code>Smarty</code></p>
<p>Chemin vers le moteur de template <a href="http://www.smarty.net/">Smarty</a>.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-global-__codelineno-2-1" id="__codelineno-2-1" name="__codelineno-2-1"></a>/usr/share/php/smarty/libs/Smarty.class.php
</code></pre></div>
</li>
</ul>
<ul>
<li>
<p><code>public_root_url</code></p>
<p>URL publique de la racine web de l'application. Il peut s'agir d'une URL relative bien qu'une URL
absolue soit préférable, notament pour éviter l'auto-détection de celle-ci lorsque nécessaire
(lien dans un e-mail par exemple. Par défaut : <code>/</code>.)</p>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>Il est indispensable que ce paramètre soit configuré en adéquation avec votre environement
pour que l'application fonctionne correctement (notament en cas en cas de déploiement dans un
sous-dossier ou encore dans le cadre d'un accès à l'application au travers un
<em>reverse-proxy</em>).</p>
</div>
</li>
</ul>
<ul>
<li>
<p><code>lang</code></p>
<p>Paramètre utilisé pour l'internationalisation : code de la langue (<code>fr_FR</code> ou <code>en_US</code>)</p>
</li>
</ul>
<ul>
<li>
<p><code>encoding</code></p>
<p>Encodage de caractère (<code>UTF8</code>)</p>
</li>
</ul>
<ul>
<li>
<p><code>ldap_servers</code></p>
<p>Configuration des serveurs LDAP.
<a href="#conf-global-ldap-configuration-des-serveurs-ldap">Voir section concernée</a>.</p>
</li>
</ul>
<h3 id="conf-global-preferences-globales">Préférences globales</h3>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>Les variables globales suivantes ont une action globale, mais non-prioritaire sur le
comportement de l'application. Il peux être redéfini pour chacun des serveurs LDAP.</p>
</div>
<ul>
<li>
<p><code>cacheLSprofiles</code></p>
<p>Activation/Désactivation de la mise en cache des profils des utilisateurs connectés
(<a href="#conf-global-ldap-lsprofile-profils-dutilisateurs">LSprofiles</a>).</p>
<p>Valeurs possibles : <code>True</code> ou <code>False</code></p>
<p>Valeur recommandée : <code>True</code></p>
<p>Valeur par défaut : <code>False</code></p>
</li>
</ul>
<ul>
<li>
<p><code>cacheSubDn</code></p>
<p>Activation/Désactivation de la mise en cache des niveaux de connexion
(<a href="#conf-global-ldap-subdn-sous-niveaux-de-connexion">subDn</a>) dans l'annuaire.</p>
<p>Valeurs possibles : <code>True</code> ou <code>False</code></p>
<p>Valeur recommandée : <code>True</code></p>
<p>Valeur par défaut : <code>False</code></p>
</li>
</ul>
<ul>
<li>
<p><code>cacheSearch</code></p>
<p>Activation/Désactivation de la mise en cache du résultat des recherches dans l'annuaire.</p>
<p>Valeurs possibles : <code>True</code> ou <code>False</code></p>
<p>Valeur recommandée : <code>True</code></p>
<p>Valeur par défaut : <code>False</code></p>
</li>
</ul>
<ul>
<li>
<p><code>globalSearch</code></p>
<p>Activation/Désactivation de la recherche globale dans l'annuaire.</p>
<p>Valeurs possibles : <code>True</code> ou <code>False</code></p>
<p>Valeur par défaut : <code>True</code></p>
</li>
</ul>
<ul>
<li>
<p><code>keepLSsessionActive</code></p>
<p>Activation/Désactivation du maintient de la LSsession active.</p>
<p>Valeurs possibles : <code>True</code> ou <code>False</code></p>
<p>Valeur par défaut : <code>False</code></p>
</li>
</ul>
<h2 id="conf-global-variables-et-constantes-independantes">Variables et constantes indépendantes</h2>
<ul>
<li>
<p><code>LS_THEME</code></p>
<p>Constante déterminant le nom du theme utilisé.</p>
<p>Valeur par défaut : <em>default</em></p>
</li>
</ul>
<ul>
<li>
<p><code>LS_TEMPLATES_DIR</code></p>
<p>Constante déterminant le chemin du dossier des templates.</p>
<p>Valeur par défaut : <em>templates</em></p>
</li>
</ul>
<ul>
<li>
<p><code>LS_IMAGES_DIR</code></p>
<p>Constante déterminant le chemin du dossier des images.</p>
<p>Valeur par défaut : <em>images</em></p>
</li>
</ul>
<ul>
<li>
<p><code>LS_CSS_DIR</code></p>
<p>Constante déterminant le chemin du dossier des CSS.</p>
<p>Valeur par défaut : <em>css</em></p>
</li>
</ul>
<ul>
<li>
<p><code>LSdebug</code></p>
<p>Variable booléenne déterminant si le débogage à l'écran est activé.</p>
</li>
</ul>
<ul>
<li>
<p><code>$GLOBALS['LSlog']</code></p>
<p>Variable permettant de configurer la journalisation de l'application.
<a href="#conf-global-lslog-configuration-de-la-journalisation">Voir section concernée</a>.</p>
</li>
</ul>
<ul>
<li>
<p><code>NB_LSOBJECT_LIST</code></p>
<p>Constante déterminant le nombre d'objet affichés par page de résultat de recherche.</p>
</li>
</ul>
<ul>
<li>
<p><code>NB_LSOBJECT_LIST_SELECT</code></p>
<p>Constante déterminant le nombre d'objet affichés par page de résultat de recherche dans une
fenêtre <em>LSselect</em>.</p>
</li>
</ul>
<ul>
<li>
<p><code>$GLOBALS['NB_LSOBJECT_LIST_CHOICES']</code></p>
<p>Variable permettant de configurer la liste des choix proposés à l'utilisateur pour le nombre
maximum d'objets affichés par page de résultat de recherche.</p>
</li>
</ul>
<ul>
<li>
<p><code>MAX_SEND_FILE_SIZE</code></p>
<p>Constante déterminant la taille maximale d'un fichier envoyé à travers les formulaires.</p>
</li>
</ul>
<ul>
<li>
<p><code>$GLOBALS['defaultJSscripts']</code></p>
<p>Tableau déterminant les fichiers Javascript à charger sur toute les pages.</p>
</li>
</ul>
<ul>
<li>
<p><code>$GLOBALS['defaultCSSfiles']</code></p>
<p>Tableau déterminant les fichiers CSS à charger sur toute les pages. Ces fichiers seront chargés
dans l'ordre et en dernier permettant de surcharger tous paramètres de style.</p>
</li>
</ul></section><h3 class="nav-section-title">Connexion LDAP</h3><section class="print-page" id="conf-global-ldap"><h1 id="conf-global-ldap-configuration-des-serveurs-ldap">Configuration des serveurs LDAP</h1>
<p>Cette section décrit le tableau de configuration des différents serveurs LDAP utilisés par
l'application. Ce tableau contient lui même un tableau par serveur LDAP.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-global-ldap-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="x">$GLOBALS['LSconfig'] = array(</span>
<a href="#conf-global-ldap-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a><span class="x"> ...</span>
<a href="#conf-global-ldap-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a><span class="x"> 'ldap_servers' =&gt; array(</span>
<a href="#conf-global-ldap-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a><span class="x"> array (</span>
<a href="#conf-global-ldap-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a><span class="x"> 'name' =&gt; [nom de l'annuaire],</span>
<a href="#conf-global-ldap-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a><span class="x"> 'ldap_config'=&gt; array(</span>
<a href="#conf-global-ldap-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a><span class="x"> // Définition des paramètres de connexion à l'annuaire</span>
<a href="#conf-global-ldap-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a><span class="x"> ),</span>
<a href="#conf-global-ldap-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a><span class="x"> 'useUserCredentials' =&gt; [boolean],</span>
<a href="#conf-global-ldap-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a><span class="x"> 'useAuthzProxyControl' =&gt; [boolean],</span>
<a href="#conf-global-ldap-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a><span class="x"> 'LSauth' =&gt; array (</span>
<a href="#conf-global-ldap-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a><span class="x"> 'method' =&gt; [LSauth method],</span>
<a href="#conf-global-ldap-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a><span class="x"> 'api_method' =&gt; [LSauth method],</span>
<a href="#conf-global-ldap-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a><span class="x"> 'LSobjects' =&gt; array(</span>
<a href="#conf-global-ldap-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a><span class="x"> '[object type 1]',</span>
<a href="#conf-global-ldap-__codelineno-0-16" id="__codelineno-0-16" name="__codelineno-0-16"></a><span class="x"> '[object type 2]' =&gt; array(</span>
<a href="#conf-global-ldap-__codelineno-0-17" id="__codelineno-0-17" name="__codelineno-0-17"></a><span class="x"> 'filter' =&gt; '[LDAP filter]',</span>
<a href="#conf-global-ldap-__codelineno-0-18" id="__codelineno-0-18" name="__codelineno-0-18"></a><span class="x"> 'filter_function' =&gt; [callable],</span>
<a href="#conf-global-ldap-__codelineno-0-19" id="__codelineno-0-19" name="__codelineno-0-19"></a><span class="x"> 'password_attribute' =&gt; '[attribute name]',</span>
<a href="#conf-global-ldap-__codelineno-0-20" id="__codelineno-0-20" name="__codelineno-0-20"></a><span class="x"> 'web_access' =&gt; [booléen],</span>
<a href="#conf-global-ldap-__codelineno-0-21" id="__codelineno-0-21" name="__codelineno-0-21"></a><span class="x"> 'api_access' =&gt; [booléen],</span>
<a href="#conf-global-ldap-__codelineno-0-22" id="__codelineno-0-22" name="__codelineno-0-22"></a><span class="x"> )</span>
<a href="#conf-global-ldap-__codelineno-0-23" id="__codelineno-0-23" name="__codelineno-0-23"></a><span class="x"> )</span>
<a href="#conf-global-ldap-__codelineno-0-24" id="__codelineno-0-24" name="__codelineno-0-24"></a><span class="x"> ),</span>
<a href="#conf-global-ldap-__codelineno-0-25" id="__codelineno-0-25" name="__codelineno-0-25"></a><span class="x"> 'LSprofiles' =&gt; array (</span>
<a href="#conf-global-ldap-__codelineno-0-26" id="__codelineno-0-26" name="__codelineno-0-26"></a><span class="x"> // Définition des LSprofiles</span>
<a href="#conf-global-ldap-__codelineno-0-27" id="__codelineno-0-27" name="__codelineno-0-27"></a><span class="x"> ),</span>
<a href="#conf-global-ldap-__codelineno-0-28" id="__codelineno-0-28" name="__codelineno-0-28"></a><span class="x"> 'cacheLSprofiles' =&gt; [boolean],</span>
<a href="#conf-global-ldap-__codelineno-0-29" id="__codelineno-0-29" name="__codelineno-0-29"></a><span class="x"> 'cacheSearch' =&gt; [boolean],</span>
<a href="#conf-global-ldap-__codelineno-0-30" id="__codelineno-0-30" name="__codelineno-0-30"></a><span class="x"> 'globalSearch' =&gt; [boolean],</span>
<a href="#conf-global-ldap-__codelineno-0-31" id="__codelineno-0-31" name="__codelineno-0-31"></a><span class="x"> 'LSaccess' =&gt; array (</span>
<a href="#conf-global-ldap-__codelineno-0-32" id="__codelineno-0-32" name="__codelineno-0-32"></a><span class="x"> [Type LSobject 1],</span>
<a href="#conf-global-ldap-__codelineno-0-33" id="__codelineno-0-33" name="__codelineno-0-33"></a><span class="x"> [Type LSobject 2],</span>
<a href="#conf-global-ldap-__codelineno-0-34" id="__codelineno-0-34" name="__codelineno-0-34"></a><span class="x"> ...</span>
<a href="#conf-global-ldap-__codelineno-0-35" id="__codelineno-0-35" name="__codelineno-0-35"></a><span class="x"> ),</span>
<a href="#conf-global-ldap-__codelineno-0-36" id="__codelineno-0-36" name="__codelineno-0-36"></a><span class="x"> 'subDn' =&gt; array(</span>
<a href="#conf-global-ldap-__codelineno-0-37" id="__codelineno-0-37" name="__codelineno-0-37"></a><span class="x"> // Définition des sous-niveaux de l'annuaire</span>
<a href="#conf-global-ldap-__codelineno-0-38" id="__codelineno-0-38" name="__codelineno-0-38"></a><span class="x"> ),</span>
<a href="#conf-global-ldap-__codelineno-0-39" id="__codelineno-0-39" name="__codelineno-0-39"></a><span class="x"> 'subDnLabel' =&gt; [nom des sous-niveaux],</span>
<a href="#conf-global-ldap-__codelineno-0-40" id="__codelineno-0-40" name="__codelineno-0-40"></a><span class="x"> 'recoverPassword' =&gt; array(</span>
<a href="#conf-global-ldap-__codelineno-0-41" id="__codelineno-0-41" name="__codelineno-0-41"></a><span class="x"> // Définition des paramètres de configuration de la récupération de mot de passe</span>
<a href="#conf-global-ldap-__codelineno-0-42" id="__codelineno-0-42" name="__codelineno-0-42"></a><span class="x"> ),</span>
<a href="#conf-global-ldap-__codelineno-0-43" id="__codelineno-0-43" name="__codelineno-0-43"></a><span class="x"> 'defaultView' =&gt; [view],</span>
<a href="#conf-global-ldap-__codelineno-0-44" id="__codelineno-0-44" name="__codelineno-0-44"></a><span class="x"> 'emailSender' =&gt; [email],</span>
<a href="#conf-global-ldap-__codelineno-0-45" id="__codelineno-0-45" name="__codelineno-0-45"></a><span class="x"> 'keepLSsessionActive' =&gt; [booléen]</span>
<a href="#conf-global-ldap-__codelineno-0-46" id="__codelineno-0-46" name="__codelineno-0-46"></a><span class="x"> )</span>
<a href="#conf-global-ldap-__codelineno-0-47" id="__codelineno-0-47" name="__codelineno-0-47"></a><span class="x"> ...</span>
<a href="#conf-global-ldap-__codelineno-0-48" id="__codelineno-0-48" name="__codelineno-0-48"></a><span class="x">);</span>
<a href="#conf-global-ldap-__codelineno-0-49" id="__codelineno-0-49" name="__codelineno-0-49"></a><span class="x">...</span>
</code></pre></div>
<ul>
<li>
<p><code>name</code></p>
<p>Le nom d'affichage de ce serveur Ldap (utilisé lorsque plusieurs serveur LDAP sont déclarés).</p>
</li>
</ul>
<ul>
<li>
<p><code>ldap_config</code></p>
<p>Informations de connexion au serveur LDAP. Ces informations sont structurées selon les attentes de
la librairie <a href="http://pear.php.net/package/Net_LDAP2">Net_LDAP2</a>.
<a href="http://pear.php.net/manual/fr/package.networking.net-ldap.connecting.php">Plus d'informations</a></p>
</li>
</ul>
<ul>
<li>
<p><code>useUserCredentials</code></p>
<p>Booléen définissant si il faut utiliser les identifiants de l'utilisateur pour se connecter à
l'annuaire (<em>false</em> par défaut). Si cette option est activée, la connexion à l'annuaire LDAP sera
établie avec la configuration fournie dans le paramètre <em>ldap_config</em> en écrasant les informations
de connexion (<em>binddn</em> et <em>bindpwd</em>) par ceux de l'utilisateur. Si l'utilisateur n'est pas encore
connecté, la connexion sera étalie sans modifier la configuration fournie.</p>
</li>
</ul>
<ul>
<li>
<p><code>useAuthzProxyControl</code></p>
<p>Booléen définissant si, lorsqu'on utilise les identifiants de l'utilisateur pour se connecter à
l'annuaire, il faut utiliser une authentification via <em>proxy authorization</em>. Dans ce cas, les
identifiants de l'utilisateur ne seront pas, à proprement parlé, utilisés pour se connecter à
l'annuaire, mais une demande de <em>proxy authorization</em> en tant que l'utilisateur connecté sera
faites à l'aide des identifiants de l'application. Ce mode nécessite une configuration
particulière au niveau de l'annuaire pour autoriser le compte de l'application à faire des
demandes de <em>proxy authorization</em> en tant que les autres utilisateurs de l'annuaire.</p>
</li>
</ul>
<ul>
<li>
<p><code>LSprofiles</code></p>
<p>Définition des profils d'utilisateurs se connectant à l'annuaire.
<a href="#conf-global-ldap-lsprofile-profils-dutilisateurs">Voir la section concernée</a>.</p>
</li>
</ul>
<ul>
<li>
<p><code>LSauth</code></p>
<p>Ce tableau défini les paramètres d'authentification à l'application.</p>
<ul>
<li>
<p><code>method</code></p>
<p>Nom de la méthode d'authentification
<a href="#conf-lsauthmethod-configuration-des-lsauthmethods">LSauthMethod</a>. Exemple : pour
utiliser la classe <code>LSauthMethod_HTTP</code>, la valeur de ce paramètre sera <code>HTTP</code>.
<em>Paramètre facultatif, méthode par défaut : <code>basic</code>.</em></p>
</li>
</ul>
<ul>
<li>
<p><code>api_method</code></p>
<p>Nom de la méthode d'authentification
<a href="#conf-lsauthmethod-configuration-des-lsauthmethods">LSauthMethod</a> à utilisée lors
d'une connexion à l'API. Exemple : pour utiliser la classe <code>LSauthMethod_HTTP</code>, la valeur
de ce paramètre sera <code>HTTP</code>. <em>Paramètre facultatif, méthode par défaut : <code>HTTP</code>.</em></p>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>Toutes les <a href="#conf-lsauthmethod-configuration-des-lsauthmethods">LSauthMethod</a> ne
supportent pas forcément le mode API.</p>
</div>
</li>
</ul>
<ul>
<li>
<p><code>LSobjects</code></p>
<p>Tableau listant les types <a href="#conf-lsobject-configuration-lsobject">LSobjects</a> pouvant se
connecter à l'application. Les valeurs de ce tableau peuvent être un nom de type d'objet ou bien
tableau détaillant les paramètres de connexion de ce type d'objet.</p>
<ul>
<li>
<p><code>filter</code></p>
<p><a href="#conf-global-lsformat-format-parametrable">LSformat</a> du filtre de recherche de l'utilisateur à sa
connexion. Ce format sera composé avec l'identifiant fourni par l'utilisateur. Cela peut par
exemple permettre à l'utilisateur de se connecter en fournissant son login ou son email comme
identifiant. Exemple de valeur : <code>(|(uid=%{user})(mail=%{user}))</code>.
<em>Paramètre facultatif, filtre par défaut composé à l'aide de l'attribut RDN.</em></p>
</li>
</ul>
<ul>
<li>
<p><code>filter_function</code></p>
<p><em>Callable</em> (au sens PHP) utilisé pour filtrer les utilisateurs trouvés dans l'annuaire à
partir des autres paramètres : cette fonction, si elle est définie, sera appelée pour chaque
utilisateur trouvé, avec pour unique paramètre, une référence à l'objet LDAP correspondant
(<code>LSldapObject</code>). Cette méthode devra alors retourner <code>true</code> ou <code>false</code> pour respectivement
autoriser ou interdire l'accès à l'application à l'utilisateur.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Si un utilisateur est exclus par cette méthode et qu'aucun autre utilisateur correspondant
n'a été trouvé dans l'annuaire, une page d'erreur sera affichée et indiquera que l'accès à
l'application est refusée.</p>
</div>
</li>
</ul>
<ul>
<li>
<p><code>password_attribute</code></p>
<p>Nom de l'attribut stockant le mot de passe de ce type
d'<a href="#conf-lsobject-configuration-lsobject">LSobject</a>.
<em>Paramètre facultatif, valeur par défaut : <code>userPassword</code>.</em></p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>C'est cet attribut de l'utilisateur qui sera modifié par la fonctionnalité de récupération
de mot de passe.</p>
</div>
</li>
</ul>
<ul>
<li>
<p><code>web_access</code></p>
<p>Permet de définir si ce type d'objet à le droit d'utiliser l'interface web (facultatif, par
défaut : <code>True</code>).</p>
</li>
</ul>
<ul>
<li>
<p><code>api_access</code></p>
<p>Permet de définir si ce type d'objet à le droit d'utiliser l'API (facultatif, par défaut :
<code>False</code>).</p>
</li>
</ul>
</li>
</ul>
<ul>
<li>
<p><code>allow_multi_match</code></p>
<p>Booléen permettant de définir si un doublon d'identifiant utilisateur est autorisé. Si c'est le
cas et lorsqu'un identifiant fourni par l'utilisateur a sa connexion a permi de trouver plus
d'un utilisateur possible correspondant, l'application tentera de déterminer lequel de ces
utilisateurs correspond à la tentative d'authentification. La méthodologie employée dépendra de
la <a href="#conf-lsauthmethod-configuration-des-lsauthmethods">LSauthMethod</a> configurée. Par
exemple, la <a href="#conf-lsauthmethod-configuration-des-lsauthmethods">LSauthMethod</a> <code>basic</code>
tentera de s'identifier avec le mot de passe. Dans tous cas, si cette méthode n'a pas permis
d'identifier un seul utilisateur, l'authentification échoura. <em>Paramètre facultatif, valeur par
défaut : <code>False</code>.</em></p>
</li>
</ul>
</li>
</ul>
<ul>
<li>
<p><code>cacheLSprofiles</code></p>
<p>Activation/Désactivation de la mise en cache des <a href="#conf-global-ldap-lsprofile-profils-dutilisateurs">LSprofiles</a>
des utilisateurs connectés à ce serveur.</p>
<p>Valeur par défaut : <em>valeur de la variable globale du même nom</em></p>
</li>
</ul>
<ul>
<li>
<p><code>cacheSearch</code></p>
<p>Activation/Désactivation de la mise en cache du résultat des recherches sur ce serveur.</p>
<p>Valeur par défaut : <em>valeur de la variable globale du même nom</em></p>
</li>
</ul>
<ul>
<li>
<p><code>globalSearch</code></p>
<p>Activation/Désactivation de la recherche globale sur ce serveur en particulier. Par défaut, la
valeur du paramètre global <code>globalSearch</code> est utilisée.</p>
<p>Valeur par défaut : <em>valeur de la variable globale du même nom</em></p>
</li>
</ul>
<ul>
<li>
<p><code>LSaccess</code> <a name="LSaccess"></a></p>
<p>Définition des types d'<a href="#conf-lsobject-configuration-lsobject">LSobjects</a> devant
apparaître dans le menu de l'interface.</p>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>Ce paramètre n'est utilisé que pour les annuaires n'ayant pas de sous-niveaux
(<a href="#conf-global-ldap-subdn-sous-niveaux-de-connexion">subDn</a>).</p>
</div>
</li>
</ul>
<ul>
<li>
<p><code>subDn</code></p>
<p>Définition des sous-niveaux de connexion à l'annuaire.
<a href="#conf-global-ldap-subdn-sous-niveaux-de-connexion">Voir section concernée</a>.</p>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>Ce paramètre remplace le paramètre <a href="#conf-global-ldap-LSaccess">LSaccess</a> dans le cas d'un annuaire
multi-niveaux.</p>
</div>
</li>
</ul>
<ul>
<li>
<p><code>subDnLabel</code></p>
<p>Définition du label utilisé pour qualifier les sous-niveaux de connexion.</p>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>Ce paramètre est utile uniquement dans le cas d'un annuaire multi-niveaux.</p>
</div>
</li>
</ul>
<ul>
<li>
<p><code>recoverPassword</code></p>
<p>Définition des paramètres de la récupération de mot de passe.
<a href="#conf-global-ldap-recoverpassword-recuperation-de-mot-de-passe">Voir la section concernée</a>.</p>
</li>
</ul>
<ul>
<li>
<p><code>defaultView</code></p>
<p>Définition de la vue par défaut de l'application. Par défaut, une page blanche est affichée et il
est possible de définir à l'aide de ce paramètre la vue qui s'affichera. Ce paramètre peut prendre
comme valeur :</p>
<ul>
<li><code>SELF</code> pour la vue <em>Mon compte</em></li>
</ul>
<ul>
<li>Le nom d'un <a href="#conf-lsobject-configuration-lsobject">LSobject</a> pour afficher la liste de
ce type d'objet</li>
</ul>
<ul>
<li>Le nom d'une vue d'un <a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a> au format
<code>[addon]::[viewId]</code> pour afficher cette vue</li>
</ul>
</li>
</ul>
<ul>
<li>
<p><code>emailSender</code></p>
<p>Adresse mail utilisée par LdapSaisie pour envoyer des e-mails en relation avec cet annuaire. Cette
adresse est celle utilisée par défaut. L'adresse utilisée peut également être configurée dans le
contexte de configuration du module devant envoyer des e-mails.</p>
</li>
</ul>
<ul>
<li>
<p><code>keepLSsessionActive</code></p>
<p>Activation/Désactivation du maintient de la LSsession active.</p>
<p>Valeurs possibles : <code>True</code> ou <code>False</code></p>
<p>Valeur par défaut : <em>valeur de la variable globale du même nom</em></p>
</li>
</ul></section><section class="print-page" id="conf-global-ldap-lsprofile"><h1 id="conf-global-ldap-lsprofile-profils-dutilisateurs-lsprofile">Profils d'utilisateurs (LSprofile)</h1>
<p>Cette section décrit la manière dont sont définis les profils d'utilisateurs se connectant à
l'interface appelés <em>LSprofile</em>. Il est possible d'attribuer un profil à l'utilisateur connecté sur
tout ou partie de l'annuaire LDAP.</p>
<h2 id="conf-global-ldap-lsprofile-profils-dutilisateurs-par-defaut">Profils d'utilisateurs par défaut</h2>
<p>Il existe des profils d'utilisateurs par défaut, non liée à la configuration de l'application:</p>
<ul>
<li>
<p><code>user</code></p>
<p>Tous les utilisateurs connectés à l'utilisateur. Ce <em>LSprofile</em> est valide sur l'ensemble de
l'annuaire.</p>
</li>
</ul>
<ul>
<li>
<p><code>self</code></p>
<p>L'utilisateur connecté sur son objet correspondant dans l'annuaire. Ce <em>LSprofile</em> est utile pour
donner des droits à l'utilisateur sur lui-même.</p>
</li>
</ul>
<ul>
<li>
<p><code>nom du type de l'objet connecté</code></p>
<p>Un <em>LSprofile</em> du nom du type d'objet utilisateur connecté est automatiquement ajouté à
l'utilisateur. Ainsi, si l'utilisateur connecté est un
<a href="#conf-lsobject-configuration-lsobject">LSobject</a> <code>LSpeople</code> par exemple, il aura le
<em>LSprofile</em> <code>LSpeople</code> sur tous l'annuaire. Ce <em>LSprofile</em> est utile pour donner des droits à tous
un type d'objets pouvant se connecter à l'application (par exemple, tous les utilisateurs
applicatifs).</p>
</li>
</ul>
<h2 id="conf-global-ldap-lsprofile-profils-dutilisateurs-personalises">Profils d'utilisateurs personalisés</h2>
<p>Il est possible de définir autant de profils d'utilisateurs que l'on souhaite. Pour chaque profil
d'utilisateur personnalisé, il faudra définir dans quelles parties de l'annuaire ce profil existe
(Exemple : les admistrateurs de groupes existent uniquement dans la branche de l'annuaire stockant
les groupes). Enfin pour chaque partie de l'annuaire, il faudra définir la manière d'identifier si
l'utilisateur qui se connecte appartient à ce profil.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-global-ldap-lsprofile-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>'LSprofile' =&gt; array (
<a href="#conf-global-ldap-lsprofile-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> [nom d'un LSprofile] =&gt; array (
<a href="#conf-global-ldap-lsprofile-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> [label] =&gt; [label du LSprofile],
<a href="#conf-global-ldap-lsprofile-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> [basedn] =&gt; [dn utilisateur],
<a href="#conf-global-ldap-lsprofile-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a> [autre basedn] =&gt; array (
<a href="#conf-global-ldap-lsprofile-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a> [dn d'un utilisateur] =&gt; NULL,
<a href="#conf-global-ldap-lsprofile-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a> [autre dn] =&gt; array ( // via un listage de l'attribut d'un objet
<a href="#conf-global-ldap-lsprofile-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a> 'attr' =&gt; [nom de l'attribut clé de l'objet],
<a href="#conf-global-ldap-lsprofile-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a> 'attr_value' =&gt; [format de la valeur de l'attribut clé],
<a href="#conf-global-ldap-lsprofile-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a> 'LSobject' =&gt; [nom du type LSobject de l'objet]
<a href="#conf-global-ldap-lsprofile-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a> )
<a href="#conf-global-ldap-lsprofile-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a> ),
<a href="#conf-global-ldap-lsprofile-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a> 'LSobjects' =&gt; array ( // via une liste d'objet sur lequel l'utilisateur a des pouvoirs
<a href="#conf-global-ldap-lsprofile-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a> [nom du LSobject] =&gt; array (
<a href="#conf-global-ldap-lsprofile-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a> 'attr' =&gt; [nom de l'attribut clé],
<a href="#conf-global-ldap-lsprofile-__codelineno-0-16" id="__codelineno-0-16" name="__codelineno-0-16"></a> 'attr_value' =&gt; [format de la valeur de l'attribut clé],
<a href="#conf-global-ldap-lsprofile-__codelineno-0-17" id="__codelineno-0-17" name="__codelineno-0-17"></a> // ou
<a href="#conf-global-ldap-lsprofile-__codelineno-0-18" id="__codelineno-0-18" name="__codelineno-0-18"></a> 'filter' =&gt; [format du filtre de recherche],
<a href="#conf-global-ldap-lsprofile-__codelineno-0-19" id="__codelineno-0-19" name="__codelineno-0-19"></a>
<a href="#conf-global-ldap-lsprofile-__codelineno-0-20" id="__codelineno-0-20" name="__codelineno-0-20"></a> 'basedn' =&gt; [basedn de recherche],
<a href="#conf-global-ldap-lsprofile-__codelineno-0-21" id="__codelineno-0-21" name="__codelineno-0-21"></a> 'params' =&gt; [configuration de la recherche]
<a href="#conf-global-ldap-lsprofile-__codelineno-0-22" id="__codelineno-0-22" name="__codelineno-0-22"></a> ),
<a href="#conf-global-ldap-lsprofile-__codelineno-0-23" id="__codelineno-0-23" name="__codelineno-0-23"></a> [nom quelconque] =&gt; array (
<a href="#conf-global-ldap-lsprofile-__codelineno-0-24" id="__codelineno-0-24" name="__codelineno-0-24"></a> 'filters' =&gt; array(
<a href="#conf-global-ldap-lsprofile-__codelineno-0-25" id="__codelineno-0-25" name="__codelineno-0-25"></a> array(
<a href="#conf-global-ldap-lsprofile-__codelineno-0-26" id="__codelineno-0-26" name="__codelineno-0-26"></a> 'LSobject' =&gt; [nom du LSobject],
<a href="#conf-global-ldap-lsprofile-__codelineno-0-27" id="__codelineno-0-27" name="__codelineno-0-27"></a> 'attr' =&gt; [nom de l'attribut clé],
<a href="#conf-global-ldap-lsprofile-__codelineno-0-28" id="__codelineno-0-28" name="__codelineno-0-28"></a> 'attr_value' =&gt; [format de la valeur de l'attribut clé],
<a href="#conf-global-ldap-lsprofile-__codelineno-0-29" id="__codelineno-0-29" name="__codelineno-0-29"></a> // ou
<a href="#conf-global-ldap-lsprofile-__codelineno-0-30" id="__codelineno-0-30" name="__codelineno-0-30"></a> 'filter' =&gt; [format du filtre de recherche],
<a href="#conf-global-ldap-lsprofile-__codelineno-0-31" id="__codelineno-0-31" name="__codelineno-0-31"></a>
<a href="#conf-global-ldap-lsprofile-__codelineno-0-32" id="__codelineno-0-32" name="__codelineno-0-32"></a> 'basedn' =&gt; [basedn de recherche],
<a href="#conf-global-ldap-lsprofile-__codelineno-0-33" id="__codelineno-0-33" name="__codelineno-0-33"></a> 'params' =&gt; [configuration de la recherche]
<a href="#conf-global-ldap-lsprofile-__codelineno-0-34" id="__codelineno-0-34" name="__codelineno-0-34"></a> ),
<a href="#conf-global-ldap-lsprofile-__codelineno-0-35" id="__codelineno-0-35" name="__codelineno-0-35"></a> ),
<a href="#conf-global-ldap-lsprofile-__codelineno-0-36" id="__codelineno-0-36" name="__codelineno-0-36"></a> ),
<a href="#conf-global-ldap-lsprofile-__codelineno-0-37" id="__codelineno-0-37" name="__codelineno-0-37"></a> ...
<a href="#conf-global-ldap-lsprofile-__codelineno-0-38" id="__codelineno-0-38" name="__codelineno-0-38"></a> )
<a href="#conf-global-ldap-lsprofile-__codelineno-0-39" id="__codelineno-0-39" name="__codelineno-0-39"></a> ),
<a href="#conf-global-ldap-lsprofile-__codelineno-0-40" id="__codelineno-0-40" name="__codelineno-0-40"></a> ...
<a href="#conf-global-ldap-lsprofile-__codelineno-0-41" id="__codelineno-0-41" name="__codelineno-0-41"></a>),
<a href="#conf-global-ldap-lsprofile-__codelineno-0-42" id="__codelineno-0-42" name="__codelineno-0-42"></a>...
</code></pre></div>
<p>Le paramètre <code>LSprofiles</code> est un tableau associatif contenant, en valeur clé, le nom d'un
<em>LSprofile</em> et en valeur associée, la configuration nécessaire pour déterminer si l'utilisateur
connecté appartient à ce LSprofile pour tout ou partie de l'annuaire.</p>
<p>Dans chaque configuration de <em>LSprofile</em>, il est possible d'identifier l'appartenance ou non de
l'utilisateur connecté de deux manières :</p>
<ul>
<li>
<p>Pour une branche de l'annuaire donnée (<em>basedn</em>) : en listant les utilisateurs appartenant à ce
<em>LSprofile</em> pour tous les objets de la branche. Il sera possible de lister les utilisateurs dont
on connait le <em>DN</em> ou de lister les utilisateurs appartenant à une liste stockée dans l'annuaire
(par exemple la liste des membres d'un groupe).</p>
<ul>
<li>
<p>Liste des DNs d'utilisateurs :</p>
<div class="highlight"><pre><span></span><code><a href="#conf-global-ldap-lsprofile-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a>'LSprofile' =&gt; array (
<a href="#conf-global-ldap-lsprofile-__codelineno-1-2" id="__codelineno-1-2" name="__codelineno-1-2"></a> [nom du LSprofile] =&gt; array (
<a href="#conf-global-ldap-lsprofile-__codelineno-1-3" id="__codelineno-1-3" name="__codelineno-1-3"></a> [basedn] =&gt; [dn utilisateur],
<a href="#conf-global-ldap-lsprofile-__codelineno-1-4" id="__codelineno-1-4" name="__codelineno-1-4"></a> // ou si plusieurs DNs
<a href="#conf-global-ldap-lsprofile-__codelineno-1-5" id="__codelineno-1-5" name="__codelineno-1-5"></a> [autre basedn] =&gt; array (
<a href="#conf-global-ldap-lsprofile-__codelineno-1-6" id="__codelineno-1-6" name="__codelineno-1-6"></a> [dn d'un utilisateur] =&gt; NULL,
<a href="#conf-global-ldap-lsprofile-__codelineno-1-7" id="__codelineno-1-7" name="__codelineno-1-7"></a> [dn d'un utilisateur 2] =&gt; NULL
<a href="#conf-global-ldap-lsprofile-__codelineno-1-8" id="__codelineno-1-8" name="__codelineno-1-8"></a> ),
<a href="#conf-global-ldap-lsprofile-__codelineno-1-9" id="__codelineno-1-9" name="__codelineno-1-9"></a> ...
<a href="#conf-global-ldap-lsprofile-__codelineno-1-10" id="__codelineno-1-10" name="__codelineno-1-10"></a> ),
<a href="#conf-global-ldap-lsprofile-__codelineno-1-11" id="__codelineno-1-11" name="__codelineno-1-11"></a> ...
<a href="#conf-global-ldap-lsprofile-__codelineno-1-12" id="__codelineno-1-12" name="__codelineno-1-12"></a>),
<a href="#conf-global-ldap-lsprofile-__codelineno-1-13" id="__codelineno-1-13" name="__codelineno-1-13"></a>...
</code></pre></div>
<p>Explication : Pour un <em>LSprofile</em> et un <em>basedn</em> donnés, on définit l'utilisateur appartenant au
<em>LSprofile</em> en donnant son <em>DN</em>. Si on souhaite lister plusieurs utilisateurs, on utilise un
tableau associatif dans lequel les clés sont les <em>DNs</em> des utilisateurs et les valeurs associées
sont toutes <em>NULL</em>.</p>
</li>
</ul>
<ul>
<li>
<p>Liste d'utilisateurs stockée dans l'annuaire :</p>
<div class="highlight"><pre><span></span><code><a href="#conf-global-ldap-lsprofile-__codelineno-2-1" id="__codelineno-2-1" name="__codelineno-2-1"></a>'LSprofile' =&gt; array (
<a href="#conf-global-ldap-lsprofile-__codelineno-2-2" id="__codelineno-2-2" name="__codelineno-2-2"></a> [nom du LSprofile] =&gt; array (
<a href="#conf-global-ldap-lsprofile-__codelineno-2-3" id="__codelineno-2-3" name="__codelineno-2-3"></a> [basedn] =&gt; array (
<a href="#conf-global-ldap-lsprofile-__codelineno-2-4" id="__codelineno-2-4" name="__codelineno-2-4"></a> [DN d'un object] =&gt; array (
<a href="#conf-global-ldap-lsprofile-__codelineno-2-5" id="__codelineno-2-5" name="__codelineno-2-5"></a> 'attr' =&gt; [nom de l'attribut clé de l'objet],
<a href="#conf-global-ldap-lsprofile-__codelineno-2-6" id="__codelineno-2-6" name="__codelineno-2-6"></a> 'attr_value' =&gt; [format de la valeur de l'attribut clé],
<a href="#conf-global-ldap-lsprofile-__codelineno-2-7" id="__codelineno-2-7" name="__codelineno-2-7"></a> 'LSobject' =&gt; [nom du type LSobject de l'objet]
<a href="#conf-global-ldap-lsprofile-__codelineno-2-8" id="__codelineno-2-8" name="__codelineno-2-8"></a> )
<a href="#conf-global-ldap-lsprofile-__codelineno-2-9" id="__codelineno-2-9" name="__codelineno-2-9"></a> ),
<a href="#conf-global-ldap-lsprofile-__codelineno-2-10" id="__codelineno-2-10" name="__codelineno-2-10"></a> ...
<a href="#conf-global-ldap-lsprofile-__codelineno-2-11" id="__codelineno-2-11" name="__codelineno-2-11"></a>),
<a href="#conf-global-ldap-lsprofile-__codelineno-2-12" id="__codelineno-2-12" name="__codelineno-2-12"></a>...
</code></pre></div>
<p>Explication : Pour un <em>LSprofile</em> et un <em>basedn</em> donnés, on liste les utilisateurs du
<em>LSprofile</em> référencés dans l'attribut <code>attr</code> de l'object de type <code>LSobject</code> et selon le format
de valeur décrit dans <code>attr_value</code>.</p>
</li>
</ul>
</li>
</ul>
<ul>
<li>
<p>Pour un type de <em>LSobject</em> donné : en listant les objets pour lesquels l'utilisateur aura les
droits du LSprofile. Il sera possible, à travers une recherche paramétrable dans l'annuaire, de
lister les objets pour lesquels l'utilisateur appartiendra au <em>LSprofile</em>.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-global-ldap-lsprofile-__codelineno-3-1" id="__codelineno-3-1" name="__codelineno-3-1"></a>'LSprofile' =&gt; array (
<a href="#conf-global-ldap-lsprofile-__codelineno-3-2" id="__codelineno-3-2" name="__codelineno-3-2"></a> [nom d'un LSprofile] =&gt; array (
<a href="#conf-global-ldap-lsprofile-__codelineno-3-3" id="__codelineno-3-3" name="__codelineno-3-3"></a> 'LSobjects' =&gt; array ( // via un liste d'objet pour lequel l'utilisateur
<a href="#conf-global-ldap-lsprofile-__codelineno-3-4" id="__codelineno-3-4" name="__codelineno-3-4"></a> // appartient au LSprofile
<a href="#conf-global-ldap-lsprofile-__codelineno-3-5" id="__codelineno-3-5" name="__codelineno-3-5"></a> [nom du LSobject] =&gt; array (
<a href="#conf-global-ldap-lsprofile-__codelineno-3-6" id="__codelineno-3-6" name="__codelineno-3-6"></a> 'attr' =&gt; [nom de l'attribut clé],
<a href="#conf-global-ldap-lsprofile-__codelineno-3-7" id="__codelineno-3-7" name="__codelineno-3-7"></a> 'attr_value' =&gt; [format de la valeur de l'attribut clé],
<a href="#conf-global-ldap-lsprofile-__codelineno-3-8" id="__codelineno-3-8" name="__codelineno-3-8"></a> // or
<a href="#conf-global-ldap-lsprofile-__codelineno-3-9" id="__codelineno-3-9" name="__codelineno-3-9"></a> 'filter' =&gt; [format du filtre de recherche],
<a href="#conf-global-ldap-lsprofile-__codelineno-3-10" id="__codelineno-3-10" name="__codelineno-3-10"></a>
<a href="#conf-global-ldap-lsprofile-__codelineno-3-11" id="__codelineno-3-11" name="__codelineno-3-11"></a> 'basedn' =&gt; [format du basedn de recherche],
<a href="#conf-global-ldap-lsprofile-__codelineno-3-12" id="__codelineno-3-12" name="__codelineno-3-12"></a> 'params' =&gt; [configuration de la recherche]
<a href="#conf-global-ldap-lsprofile-__codelineno-3-13" id="__codelineno-3-13" name="__codelineno-3-13"></a> ),
<a href="#conf-global-ldap-lsprofile-__codelineno-3-14" id="__codelineno-3-14" name="__codelineno-3-14"></a> array (
<a href="#conf-global-ldap-lsprofile-__codelineno-3-15" id="__codelineno-3-15" name="__codelineno-3-15"></a> 'filters' =&gt; array(
<a href="#conf-global-ldap-lsprofile-__codelineno-3-16" id="__codelineno-3-16" name="__codelineno-3-16"></a> array(
<a href="#conf-global-ldap-lsprofile-__codelineno-3-17" id="__codelineno-3-17" name="__codelineno-3-17"></a> 'LSobject' =&gt; [nom du LSobject],
<a href="#conf-global-ldap-lsprofile-__codelineno-3-18" id="__codelineno-3-18" name="__codelineno-3-18"></a> 'attr' =&gt; [nom de l'attribut clé],
<a href="#conf-global-ldap-lsprofile-__codelineno-3-19" id="__codelineno-3-19" name="__codelineno-3-19"></a> 'attr_value' =&gt; [format de la valeur de l'attribut clé],
<a href="#conf-global-ldap-lsprofile-__codelineno-3-20" id="__codelineno-3-20" name="__codelineno-3-20"></a> // ou
<a href="#conf-global-ldap-lsprofile-__codelineno-3-21" id="__codelineno-3-21" name="__codelineno-3-21"></a> 'filter' =&gt; [format du filtre de recherche],
<a href="#conf-global-ldap-lsprofile-__codelineno-3-22" id="__codelineno-3-22" name="__codelineno-3-22"></a>
<a href="#conf-global-ldap-lsprofile-__codelineno-3-23" id="__codelineno-3-23" name="__codelineno-3-23"></a> 'basedn' =&gt; [format du basedn de recherche],
<a href="#conf-global-ldap-lsprofile-__codelineno-3-24" id="__codelineno-3-24" name="__codelineno-3-24"></a> 'params' =&gt; [configuration de la recherche]
<a href="#conf-global-ldap-lsprofile-__codelineno-3-25" id="__codelineno-3-25" name="__codelineno-3-25"></a> ),
<a href="#conf-global-ldap-lsprofile-__codelineno-3-26" id="__codelineno-3-26" name="__codelineno-3-26"></a> ),
<a href="#conf-global-ldap-lsprofile-__codelineno-3-27" id="__codelineno-3-27" name="__codelineno-3-27"></a> ),
<a href="#conf-global-ldap-lsprofile-__codelineno-3-28" id="__codelineno-3-28" name="__codelineno-3-28"></a> ...
<a href="#conf-global-ldap-lsprofile-__codelineno-3-29" id="__codelineno-3-29" name="__codelineno-3-29"></a> )
<a href="#conf-global-ldap-lsprofile-__codelineno-3-30" id="__codelineno-3-30" name="__codelineno-3-30"></a> ),
<a href="#conf-global-ldap-lsprofile-__codelineno-3-31" id="__codelineno-3-31" name="__codelineno-3-31"></a> ...
<a href="#conf-global-ldap-lsprofile-__codelineno-3-32" id="__codelineno-3-32" name="__codelineno-3-32"></a>),
<a href="#conf-global-ldap-lsprofile-__codelineno-3-33" id="__codelineno-3-33" name="__codelineno-3-33"></a>...
</code></pre></div>
<p>Explications : Dans la configuration d'un <em>LSprofile</em>, la valeur clé <em>LSobjects</em> signifie qu'on
est dans un cas de la délégation de droits sur des types d'LSobject. Dans ce tableau associatif,
il est possible de définir un ou plusieurs types de LSobject pour lesquels on délègue des droits
via des recherches simples ou enchaînées. Le fonctionnement simple consiste à partir de l'objet de
l'utilisateur et à générer un filtre et une base de recherche sur un type de LSobject. Le
fonctionnement enchainée consiste à faire un première recherche à partir de l'objet de
l'utilisateur puis à recommencer à partir des objets trouvés en construisant une liste de filtres
de recherche pour chaque objet qui seront combinés via l'opérateur booléen <em>ou</em>. Dans le cadre
d'un fonctionnement enchainée, la base de recherche est toujours générer à partir de l'objet de
l'utilisateur connecté.</p>
<p>Pour configurer une délégation de type simple on mettra le nom du LSobject dans la clé du tableau
et dans la valeur un tableau définissant la recherche. Il est possible de ne pas utiliser la clé
du tableau comme nom du LSobject grâce à la clé de configuration <em>LSobject</em>.</p>
<p>Pour configurer une délégation de type enchaîné on pourra utiliser n'importe quelle valeur unique
pour la clé du tableau et pour la valeur un tableau contenant une unique clé <em>filters</em>. La valeur
associée à cette clé est celle d'une délégation de type simple où la clé <em>LSobject</em> est devenue
obligatoire.</p>
<p>Cette configuration contient les paramètres d'une ou plusieurs recherches dans l'annuaire en
considérant que l'utilisateur connecté aura les droits du LSprofile sur les objets retournés. Les
paramètres de la recherche sont :</p>
<ul>
<li>
<p><code>LSobject</code></p>
<p>C'est le nom du LSobject recherché. <em>(Paramètre facultatif pour
une délégation de type simple)</em></p>
</li>
</ul>
<ul>
<li>
<p><code>attr</code></p>
<p>Nom de l'attribut des LSobjets contenant une valeur clé qui
permettra d'identifier l'utilisateur comme ayant droit.</p>
</li>
</ul>
<ul>
<li>
<p><code>attr_value</code></p>
<p>Le format de la valeur clé prise par l'attribut <code>attr</code>. Ce format est composé à partir des
données de l'objet de l'utilisateur connecté. Voir le paragraphe
<a href="#conf-global-lsformat-format-parametrable">Format paramètrable</a> pour plus d'informations sur
l'écriture du format.</p>
</li>
</ul>
<ul>
<li>
<p><code>filter</code></p>
<p>Ce paramètre remplace les paramètres <code>attr</code> et <code>attr_value</code>. Il est possible ici d'écrire
directement le format paramètrable du filtre recherche dans l'annuaire. Ce filtre sera
automatiquement agrémenté des conditions sur l'attribut <em>objectclass</em>. Voir le paragraphe
<a href="#conf-global-lsformat-format-parametrable">Format paramètrable</a> pour plus d'informations sur
l'écriture du format.</p>
</li>
</ul>
<ul>
<li>
<p><code>basedn</code></p>
<p>C'est le format paramétrable du <em>basedn</em> de la recherche généré à partir de l'utilisateur
connecté. Il est possible ainsi de la limiter sur les LSojects d'une branche précise de
l'annuaire. Voir le paragraphe <a href="#conf-global-lsformat-format-parametrable">Format paramètrable</a> pour
plus d'informations sur l'écriture du format. <em>(Paramètre facultatif)</em></p>
</li>
</ul>
<ul>
<li>
<p><code>params</code></p>
<p>C'est un tableau associatif contenant les paramètres étendus de la recherche. Voir le paragraphe
<a href="#conf-global-ldap_search_params-parametres-etendus-des-recherches-dans-lannuaire">Paramètres étendus des recherches dans l'annuaire</a>
pour plus de détails. <em>(Paramètre facultatif)</em></p>
</li>
</ul>
</li>
</ul>
<p>Par ailleurs, il est possible d'attribuer un label plus explicite à chaque <em>LSprofile</em> à l'aide de
la clé <code>label</code>. Ce label sera utilisé pour faire référence au <em>LSprofile</em> lorsque nécéssaire.
<em>(Paramètre facultatif)</em></p></section><section class="print-page" id="conf-global-ldap-subdn"><h1 id="conf-global-ldap-subdn-sous-niveaux-de-connexion">Sous-niveaux de connexion</h1>
<p>Cette section décrit la manière de définir des sous-niveaux de connexion à l'annuaire (<em>subDn</em>). Le
concept de sous-niveau de connexion sert à déclarer les niveaux logiques de l'annuaire. Par exemple,
dans un annuaire dans lequel sont stockés des objets concernant plusieurs organisations et que
celles-ci se distinguent grâce à la présence d'une séparation dans l'arbre, il sera alors possible
de définir des sous-niveaux de connexion pour chacune des organisations.</p>
<p><strong>Exemple d'arborescence d'annuaire utilisant le concept de sous-niveaux correspondant à des sociétés :</strong></p>
<div class="highlight"><pre><span></span><code><a href="#conf-global-ldap-subdn-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>|- o=ls
<a href="#conf-global-ldap-subdn-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a>| |- ou=companies
<a href="#conf-global-ldap-subdn-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a>| | |- ou=company1
<a href="#conf-global-ldap-subdn-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a>| | | |- ou=people
<a href="#conf-global-ldap-subdn-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a>| | | |- ou=groups
<a href="#conf-global-ldap-subdn-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a>| | |- ou=company2
<a href="#conf-global-ldap-subdn-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a>| | | |- ou=people
<a href="#conf-global-ldap-subdn-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a>| | | |- ou=groups
<a href="#conf-global-ldap-subdn-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a>| |- ou=people
<a href="#conf-global-ldap-subdn-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a>| |- ou=groups
</code></pre></div>
<p>Explications : Il est possible dans cet exemple de définir des sous-niveaux de connexion
correspondants aux sociétés. Dans chacune de ces sociétés, on retrouve les <em>OU</em> correspondant au
type d'<em>LSobjets</em>. Lors de la connexion à l'interface, l'utilisateur devra choisir dans quel
sous-niveau de l'annuaire il souhaite se connecter. Une fois connecté, l'utilisateur manipulera
uniquement les objets du sous-niveau de l'annuaire dans lequel il se trouve. Il lui sera également
possible de changer de sous-niveau de connexion à travers l'interface : une liste déroulante est
disponible pour cela dans le menu.</p>
<p>Il existe deux manières de déclarer des sous-niveaux de connexion à l'annuaire :</p>
<ul>
<li>En déclarant manuellement un <em>subDn</em> de l'annuaire et en lui donnant un nom.</li>
</ul>
<ul>
<li>En listant les <em>LSobjets</em> d'un type précis et en utilisant leurs données pour constituer le nom
des sous-niveaux. Cette liste est constituée en effectuant une recherche dans l'annuaire. Il est
possible de définir un <em>basedn</em> particulier pour cette recherche.</li>
</ul>
<p>Pour chacune de ces méthodes on définira également les types d'<em>LSobjets</em> qui sont présents dans
cette branche de l'annuaire.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-global-ldap-subdn-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a>'subDn' =&gt; array(
<a href="#conf-global-ldap-subdn-__codelineno-1-2" id="__codelineno-1-2" name="__codelineno-1-2"></a> // Déclaration manuelle
<a href="#conf-global-ldap-subdn-__codelineno-1-3" id="__codelineno-1-3" name="__codelineno-1-3"></a> '[Nom du sous-niveau]' =&gt; array(
<a href="#conf-global-ldap-subdn-__codelineno-1-4" id="__codelineno-1-4" name="__codelineno-1-4"></a> 'dn' =&gt; '[basedn du sous-niveau]',
<a href="#conf-global-ldap-subdn-__codelineno-1-5" id="__codelineno-1-5" name="__codelineno-1-5"></a> 'nologin' =&gt; true, // Désactive la connection dans ce subDn
<a href="#conf-global-ldap-subdn-__codelineno-1-6" id="__codelineno-1-6" name="__codelineno-1-6"></a> 'LSobjects' =&gt; array( // Liste des types d'LSobjets présents dans le sous-niveau
<a href="#conf-global-ldap-subdn-__codelineno-1-7" id="__codelineno-1-7" name="__codelineno-1-7"></a> [LSobject1],
<a href="#conf-global-ldap-subdn-__codelineno-1-8" id="__codelineno-1-8" name="__codelineno-1-8"></a> [LSobject2],
<a href="#conf-global-ldap-subdn-__codelineno-1-9" id="__codelineno-1-9" name="__codelineno-1-9"></a> ...
<a href="#conf-global-ldap-subdn-__codelineno-1-10" id="__codelineno-1-10" name="__codelineno-1-10"></a> )
<a href="#conf-global-ldap-subdn-__codelineno-1-11" id="__codelineno-1-11" name="__codelineno-1-11"></a> ),
<a href="#conf-global-ldap-subdn-__codelineno-1-12" id="__codelineno-1-12" name="__codelineno-1-12"></a> // Liste de LSobjets
<a href="#conf-global-ldap-subdn-__codelineno-1-13" id="__codelineno-1-13" name="__codelineno-1-13"></a> 'LSobject' =&gt; array(
<a href="#conf-global-ldap-subdn-__codelineno-1-14" id="__codelineno-1-14" name="__codelineno-1-14"></a> '[type d'LSobject]' =&gt; array( // le type d'LSobjet à lister
<a href="#conf-global-ldap-subdn-__codelineno-1-15" id="__codelineno-1-15" name="__codelineno-1-15"></a> 'basedn' =&gt; '[basedn]', // Le basedn de la recherche
<a href="#conf-global-ldap-subdn-__codelineno-1-16" id="__codelineno-1-16" name="__codelineno-1-16"></a> 'displayValue' =&gt; '[format]', // Format du nom des sous-niveaux
<a href="#conf-global-ldap-subdn-__codelineno-1-17" id="__codelineno-1-17" name="__codelineno-1-17"></a> 'nologin' =&gt; true, // Désactive la connection dans ces subDn
<a href="#conf-global-ldap-subdn-__codelineno-1-18" id="__codelineno-1-18" name="__codelineno-1-18"></a> 'onlyAccessible' =&gt; True, // Pour que seul les LSobjet accessible à l'utilisateur soit listé
<a href="#conf-global-ldap-subdn-__codelineno-1-19" id="__codelineno-1-19" name="__codelineno-1-19"></a> 'LSobjects' =&gt; array( // Liste des types d'LSobjets présents dans les sous-niveaux
<a href="#conf-global-ldap-subdn-__codelineno-1-20" id="__codelineno-1-20" name="__codelineno-1-20"></a> [LSobject1],
<a href="#conf-global-ldap-subdn-__codelineno-1-21" id="__codelineno-1-21" name="__codelineno-1-21"></a> [LSobject2],
<a href="#conf-global-ldap-subdn-__codelineno-1-22" id="__codelineno-1-22" name="__codelineno-1-22"></a> ...
<a href="#conf-global-ldap-subdn-__codelineno-1-23" id="__codelineno-1-23" name="__codelineno-1-23"></a> )
<a href="#conf-global-ldap-subdn-__codelineno-1-24" id="__codelineno-1-24" name="__codelineno-1-24"></a> )
<a href="#conf-global-ldap-subdn-__codelineno-1-25" id="__codelineno-1-25" name="__codelineno-1-25"></a> )
<a href="#conf-global-ldap-subdn-__codelineno-1-26" id="__codelineno-1-26" name="__codelineno-1-26"></a>),
<a href="#conf-global-ldap-subdn-__codelineno-1-27" id="__codelineno-1-27" name="__codelineno-1-27"></a>...
</code></pre></div></section><section class="print-page" id="conf-global-ldap-recoverpassword"><h1 id="conf-global-ldap-recoverpassword-recuperation-de-mot-de-passe">Récupération de mot de passe</h1>
<p>Cette section décrit la manière de configurer la récupération de mot de passe par les utilisateurs.
Le mécanisme de récupération de mot de passe fonctionne en deux parties :</p>
<ul>
<li>
<p>Dans un premier lieu, l'utilisateur ayant perdu son mot de passe accède à l'interface de
récupération à partir de la page de connexion. L'interface lui demande de saisir son identifiant
et éventuellement de sélectionner le serveur LDAP concerné. Une fois ces informations saisies, une
recherche de l'utilisateur est effectuée dans l'annuaire et si celui-ci est trouvé, la valeur de
l'attribut <code>recoveryHashAttr</code> de l'objet est alors redéfinie avec une valeur aléatoire.</p>
<p>Un mail est ensuite envoyé à l'utilisateur en utilisant la première valeur de l'attribut
<code>mailAttr</code> comme adresse. Ce mail est formé à partir des paramètres du tableau associatif
<code>recoveryHashMail</code>.
Celui-ci doit contenir le sujet du mail dans <code>subject</code> et le corps du message dans <code>msg</code>. Ces deux
informations sont des <a href="#conf-global-lsformat-format-parametrable">formats paramètrables</a> composés avec,
comme valeur clé, l'URL de retour à laquelle l'utilisateur devra se rendre pour accèder à la
seconde étape de la récupération de son mot de passe.</p>
</li>
</ul>
<ul>
<li>
<p>L'utilisateur doit donc se rendre sur l'interface par l'intermédiaire de l'URL qui lui aura été
fournie dans le mail de l'étape précédente. Cette URL contient la valeur de l'attribut
<code>recoveryHashAttr</code> précédement définie. A partir de cette information, une recherche est effectuée
dans l'annuaire pour retrouver l'utilisateur correspondant.</p>
<p>Si l'utilisateur est retrouvé, un nouveau mot de passe lui est généré en utilisant les paramètres
de configuration éventuellement définis dans la configuration HTML de l'attribut "mot de passe".
Pour avoir plus d'information sur ces paramètres, consulter la documentation du type d'attribut
HTML
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-lsattr_html_password"><em>LSattr_html_password</em></a>.
L'attribut <code>recoveryHashAttr</code> est quant à lui supprimé.</p>
<p>Ensuite, un mail est composé à partir des paramètres du tableau associatif <code>newPasswordMail</code> et
est envoyé à l'utilisateur. Ce tableau doit contenir le sujet du mail dans <code>subject</code> et le corps
du message dans <code>msg</code>. Ces deux informations sont des
<a href="#conf-global-lsformat-format-parametrable">formats paramètrables</a> composés avec, comme valeur clé, le
nouveau mot de passe de l'utilisateur.</p>
</li>
</ul>
<div class="highlight"><pre><span></span><code><a href="#conf-global-ldap-recoverpassword-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>'recoverPassword' =&gt; array(
<a href="#conf-global-ldap-recoverpassword-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'mailAttr' =&gt; '[attribut mail]',
<a href="#conf-global-ldap-recoverpassword-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> 'recoveryHashAttr' =&gt; '[attribut hash]',
<a href="#conf-global-ldap-recoverpassword-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> 'recoveryEmailSender' =&gt; '[adresse mail utilisée par LdapSaisie pour l'envoi des mails]',
<a href="#conf-global-ldap-recoverpassword-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a> 'recoveryHashMail' =&gt; array( // 1er mail : avec l'URL pour l'accès à la 2nde partie
<a href="#conf-global-ldap-recoverpassword-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a> 'subject' =&gt; '[sujet du mail]',
<a href="#conf-global-ldap-recoverpassword-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a> 'msg' =&gt; "[message contenant le mot clé %{url}]"
<a href="#conf-global-ldap-recoverpassword-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a> ),
<a href="#conf-global-ldap-recoverpassword-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a> 'newPasswordMail' =&gt; array( // 2nd mail : avec le mot de passe
<a href="#conf-global-ldap-recoverpassword-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a> 'subject' =&gt; '[sujet du mail]',
<a href="#conf-global-ldap-recoverpassword-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a> 'msg' =&gt; "[message contenant le mot clé %{mdp}]"
<a href="#conf-global-ldap-recoverpassword-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a> )
<a href="#conf-global-ldap-recoverpassword-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a>),
<a href="#conf-global-ldap-recoverpassword-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a>...
</code></pre></div></section><h1 class="nav-section-title-end">Ended: Connexion LDAP</h1><section class="print-page" id="conf-global-lslog"><h1 id="conf-global-lslog-configuration-de-la-journalisation-lslog">Configuration de la journalisation (LSlog)</h1>
<p>Cette section décrit le tableau de configuration de la journalisation de l'application.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-global-lslog-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="x">$GLOBALS['LSlog'] = array(</span>
<a href="#conf-global-lslog-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a><span class="x"> 'enable' =&gt; [booléen],</span>
<a href="#conf-global-lslog-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a><span class="x"> 'level' =&gt; '[niveau]',</span>
<a href="#conf-global-lslog-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a><span class="x"> 'log_errors_context' =&gt; [booléen],</span>
<a href="#conf-global-lslog-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a><span class="x"> 'log_errors_context_with_args' =&gt; [booléen],</span>
<a href="#conf-global-lslog-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a><span class="x"> 'log_errors_context_args_max_length' =&gt; [entier],</span>
<a href="#conf-global-lslog-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a><span class="x"> 'handlers' =&gt; array(</span>
<a href="#conf-global-lslog-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a><span class="x"> '[handler 1]',</span>
<a href="#conf-global-lslog-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a><span class="x"> array (</span>
<a href="#conf-global-lslog-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a><span class="x"> 'handler' =&gt; [handler 2],</span>
<a href="#conf-global-lslog-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a><span class="x"> 'enabled' =&gt; [booléen],</span>
<a href="#conf-global-lslog-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a><span class="x"> 'level' =&gt; '[niveau]',</span>
<a href="#conf-global-lslog-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a><span class="x"> 'loggers' =&gt; array('logger1', [...]),</span>
<a href="#conf-global-lslog-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a><span class="x"> 'excluded_loggers' =&gt; array('logger2', [...]),</span>
<a href="#conf-global-lslog-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a><span class="x"> 'format' =&gt; '[LSformat]',</span>
<a href="#conf-global-lslog-__codelineno-0-16" id="__codelineno-0-16" name="__codelineno-0-16"></a><span class="x"> 'cli_format' =&gt; '[LSformat]',</span>
<a href="#conf-global-lslog-__codelineno-0-17" id="__codelineno-0-17" name="__codelineno-0-17"></a><span class="x"> 'datetime_prefix' =&gt; [booléen],</span>
<a href="#conf-global-lslog-__codelineno-0-18" id="__codelineno-0-18" name="__codelineno-0-18"></a><span class="x"> 'datetime_format' =&gt; '[format date()]',</span>
<a href="#conf-global-lslog-__codelineno-0-19" id="__codelineno-0-19" name="__codelineno-0-19"></a><span class="x"> // Autres paramètres propre à ce handler</span>
<a href="#conf-global-lslog-__codelineno-0-20" id="__codelineno-0-20" name="__codelineno-0-20"></a><span class="x"> [...]</span>
<a href="#conf-global-lslog-__codelineno-0-21" id="__codelineno-0-21" name="__codelineno-0-21"></a><span class="x"> ),</span>
<a href="#conf-global-lslog-__codelineno-0-22" id="__codelineno-0-22" name="__codelineno-0-22"></a><span class="x"> [...]</span>
<a href="#conf-global-lslog-__codelineno-0-23" id="__codelineno-0-23" name="__codelineno-0-23"></a><span class="x"> ),</span>
<a href="#conf-global-lslog-__codelineno-0-24" id="__codelineno-0-24" name="__codelineno-0-24"></a><span class="x"> 'loggers' =&gt; array (</span>
<a href="#conf-global-lslog-__codelineno-0-25" id="__codelineno-0-25" name="__codelineno-0-25"></a><span class="x"> 'logger1' =&gt; array (</span>
<a href="#conf-global-lslog-__codelineno-0-26" id="__codelineno-0-26" name="__codelineno-0-26"></a><span class="x"> 'level' =&gt; 'DEBUG',</span>
<a href="#conf-global-lslog-__codelineno-0-27" id="__codelineno-0-27" name="__codelineno-0-27"></a><span class="x"> ),</span>
<a href="#conf-global-lslog-__codelineno-0-28" id="__codelineno-0-28" name="__codelineno-0-28"></a><span class="x"> 'logger2' =&gt; array (</span>
<a href="#conf-global-lslog-__codelineno-0-29" id="__codelineno-0-29" name="__codelineno-0-29"></a><span class="x"> 'enabled' =&gt; false,</span>
<a href="#conf-global-lslog-__codelineno-0-30" id="__codelineno-0-30" name="__codelineno-0-30"></a><span class="x"> ),</span>
<a href="#conf-global-lslog-__codelineno-0-31" id="__codelineno-0-31" name="__codelineno-0-31"></a><span class="x"> [...]</span>
<a href="#conf-global-lslog-__codelineno-0-32" id="__codelineno-0-32" name="__codelineno-0-32"></a><span class="x"> );</span>
<a href="#conf-global-lslog-__codelineno-0-33" id="__codelineno-0-33" name="__codelineno-0-33"></a><span class="x">);</span>
<a href="#conf-global-lslog-__codelineno-0-34" id="__codelineno-0-34" name="__codelineno-0-34"></a><span class="x">...</span>
</code></pre></div>
<ul>
<li>
<p><code>enable</code></p>
<p>Booléen permatant d'activer ou désactiver complètement la journalisation. Par défaut : <code>False</code></p>
</li>
</ul>
<ul>
<li>
<p><code>level</code></p>
<p>Ce paramètre défini le niveau minimum de la journalisation : tous les messages des niveaux
inférieurs ne seront pas inclus dans le journal de l'application. Les niveaux de journalisation
gérés par l'application sont (dans l'ordre du plus petit au plus grand) :</p>
<ul>
<li><code>TRACE</code></li>
<li><code>DEBUG</code></li>
<li><code>INFO</code></li>
<li><code>WARNING</code></li>
<li><code>ERROR</code></li>
<li><code>FATAL</code></li>
</ul>
</li>
</ul>
<ul>
<li>
<p><code>log_errors_context</code></p>
<p>Booléen permatant de définir si le contexte <em>(=backtrace)</em> doit être inclus lors de la
journalisation d'une erreurs.</p>
</li>
</ul>
<ul>
<li>
<p><code>log_errors_context_with_args</code></p>
<p>Booléen permatant de définir si les arguments des méthodes/fonctions appelées doivent être
inclus lors de la journalisation du contexte des erreurs.
<strong>Note :</strong> ce paramètre n'as aucun effet si le paramètre <code>log_errors_context</code> n'est pas activé.</p>
</li>
</ul>
<ul>
<li>
<p><code>log_errors_context_args_max_length</code></p>
<p>Ce paramètre permet de définir à partir de quelle longueur les arguments des méthodes/fonctions
appelées et journalisés seront tronqués (par défaut : <code>1000</code>). <strong>Note :</strong> pour désactiver le
troncage, mettre ce paramètre à zéro.</p>
</li>
</ul>
<ul>
<li>
<p><code>handlers</code></p>
<p>Tableau permettant de configurer les <em>handlers</em> de la journalisation. Chaque <em>handler</em> gère les
messages journalisés d'une manière qui lui est propre.</p>
<p>Plusieurs <em>handlers</em> peuvent être configurés en même temps (y compris plusieurs <em>handlers</em> du même
type).</p>
<p>Ce tableau peut contenir simplement le nom du type de <em>handler</em> à utiliser ou bien des tableaux
configurant un à un chacun des <em>handlers</em>. Dans ce second cas, la structure de la configuration
d'un <em>handler</em> est la suivante :</p>
<div class="highlight"><pre><span></span><code><a href="#conf-global-lslog-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a><span class="x">array(</span>
<a href="#conf-global-lslog-__codelineno-1-2" id="__codelineno-1-2" name="__codelineno-1-2"></a><span class="x"> 'handler' =&gt; [type],</span>
<a href="#conf-global-lslog-__codelineno-1-3" id="__codelineno-1-3" name="__codelineno-1-3"></a><span class="x"> 'level' =&gt; '[niveau]',</span>
<a href="#conf-global-lslog-__codelineno-1-4" id="__codelineno-1-4" name="__codelineno-1-4"></a><span class="x"> 'loggers' =&gt; array('logger1', [...]),</span>
<a href="#conf-global-lslog-__codelineno-1-5" id="__codelineno-1-5" name="__codelineno-1-5"></a><span class="x"> 'excluded_loggers' =&gt; array('logger2', [...]),</span>
<a href="#conf-global-lslog-__codelineno-1-6" id="__codelineno-1-6" name="__codelineno-1-6"></a><span class="x"> 'format' =&gt; '[LSformat]',</span>
<a href="#conf-global-lslog-__codelineno-1-7" id="__codelineno-1-7" name="__codelineno-1-7"></a><span class="x"> 'cli_format' =&gt; '[LSformat]',</span>
<a href="#conf-global-lslog-__codelineno-1-8" id="__codelineno-1-8" name="__codelineno-1-8"></a><span class="x"> 'datetime_prefix' =&gt; [booléen],</span>
<a href="#conf-global-lslog-__codelineno-1-9" id="__codelineno-1-9" name="__codelineno-1-9"></a><span class="x"> 'datetime_format' =&gt; '[format date()]',</span>
<a href="#conf-global-lslog-__codelineno-1-10" id="__codelineno-1-10" name="__codelineno-1-10"></a><span class="x"> // Autres paramètres propre à ce handler</span>
<a href="#conf-global-lslog-__codelineno-1-11" id="__codelineno-1-11" name="__codelineno-1-11"></a><span class="x"> [...]</span>
<a href="#conf-global-lslog-__codelineno-1-12" id="__codelineno-1-12" name="__codelineno-1-12"></a><span class="x">)</span>
<a href="#conf-global-lslog-__codelineno-1-13" id="__codelineno-1-13" name="__codelineno-1-13"></a><span class="x">...</span>
</code></pre></div>
<ul>
<li>
<p><code>handler</code></p>
<p>Type du <em>handler</em> (voir ci-dessous).</p>
</li>
</ul>
<ul>
<li>
<p><code>level</code></p>
<p>Ce paramètre défini le niveau minimum de la journalisation spécifique à cet <em>handler</em>. Si ce
paramètre est omis, le niveau global sera utilisé. Les valeurs possibles de ce paramètre sont
les mêmes que pour le paramètre <code>$GLOBALS['LSlog']['level']</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>enabled</code></p>
<p>Booléen permettant d'activer ou désactiver cet <em>handler</em> (paramètre facultatif, par défaut :
<code>True</code>).</p>
</li>
</ul>
<ul>
<li>
<p><code>loggers</code></p>
<p>Liste exhautive des composants dont les messages doivent être traités par ce handler (paramètre
facultatif, par défaut : tous les composants).</p>
</li>
</ul>
<ul>
<li>
<p><code>excluded_loggers</code></p>
<p>Liste exhautive des composants dont les messages ne doivent pas être traités par ce handler
(paramètre facultatif, par défaut : aucun composant).</p>
</li>
</ul>
<ul>
<li>
<p><code>format</code></p>
<p><a href="#conf-global-lsformat-format-parametrable">LSformat</a> des messages de cet journalisé par ce handler. Ce
format est composé à partir des informations décritent ci-dessous. Par défaut :</p>
<div class="highlight"><pre><span></span><code><a href="#conf-global-lslog-__codelineno-2-1" id="__codelineno-2-1" name="__codelineno-2-1"></a>%{requesturi} - %{remoteaddr} - %{ldapservername} - %{authuser} - %{logger} - %{level} - %{message}
</code></pre></div>
<ul>
<li>
<p><code>level</code></p>
<p>Le niveau du message.</p>
</li>
</ul>
<ul>
<li>
<p><code>message</code></p>
<p>Le message.</p>
</li>
</ul>
<ul>
<li>
<p><code>logger</code></p>
<p>Le composant ayant déchenché cette journalisation.</p>
</li>
</ul>
<ul>
<li>
<p><code>clibinpath</code></p>
<p>Le nom du script ayant déclenché cette jounalisation (uniquement en cas d'exécution en ligne
de commande).</p>
</li>
</ul>
<ul>
<li>
<p><code>requesturi</code></p>
<p>L'URL de la page courante (uniquement dans un contexte Web).</p>
</li>
</ul>
<ul>
<li>
<p><code>remoteaddr</code></p>
<p>L'adresse IP du client (uniquement dans un contexte Web).</p>
</li>
</ul>
<ul>
<li>
<p><code>ldapservername</code></p>
<p>Le nom du serveur LDAP courant.</p>
</li>
</ul>
<ul>
<li>
<p><code>authuser</code></p>
<p>Le DN de l'utilisateur connecté (uniquement dans un contexte Web).</p>
</li>
</ul>
</li>
</ul>
<ul>
<li>
<p><code>cli_format</code></p>
<p><a href="#conf-global-lsformat-format-parametrable">LSformat</a> des messages de cet journalisé par ce handler dans
le cas d'une exécution en ligne de commande. Ce format est composé à partir des même
informations que le paramètre <code>format</code> (voir ci-dessus). Par défaut :
</p><div class="highlight"><pre><span></span><code><a href="#conf-global-lslog-__codelineno-3-1" id="__codelineno-3-1" name="__codelineno-3-1"></a>%{clibinpath} - %{logger} - %{level} - %{message}
</code></pre></div><p></p>
</li>
</ul>
<ul>
<li>
<p><code>datetime_format</code></p>
<p>Booléen permettant de définir si le message doit être préfixé de la date et heure courante. La
valeur par défaut dépends de l'handler (en règle général, toujours actif sauf lorsque le canal
de journalisation l'ajoute déjà).</p>
</li>
</ul>
<ul>
<li>
<p><code>datetime_format</code></p>
<p>Format de la date et heure lorsque celle-ci est ajoutée en préfixe du message (voir paramètre
<code>datetime_format</code>). Le format correspond à celui attendu par la function <code>date()</code> de
<a href="http://www.php.net/">PHP</a>. Consultez la <a href="http://php.net/date">documentation officielle</a> pour
plus de détails (Par défaut : <code>Y/m/d H:i:s</code>).</p>
</li>
</ul>
<p>Il existe plusieurs types d'<em>handlers</em> gérés par l'application :</p>
<ul>
<li>
<p><code>file</code></p>
<p>Journalisation dans un simple fichier texte. Le chemin du fichier peut être configuré via le
paramètre <code>path</code>. Si ce paramètre est omis, le chemin du fichier par défaut est soit la
valeur de la variable <code>$GLOBALS['LSlog']['filename']</code> (pour la rétro-compatibilité avec les
anciennes versions d'LdapSaisie) ou à défaut : <code>tmp/LS.log</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>syslog</code></p>
<p>Journalisation via le service <em>syslog</em>. Il est possible de configurer une priorité
systématique pour les messages journalisés. À défaut, la priorité sera déterminée
automatiquement en fonction du niveau du message. Les valeurs
possibles de ce paramètre sont : <code>EMERG, ALERT, CRITICAL,ERROR, WARNING, NOTICE, INFO, DEBUG</code></p>
</li>
</ul>
<ul>
<li>
<p><code>system</code></p>
<p>Journalisation via le gestionnaire d'erreurs PHP. Cet <em>handler</em> utilise la fonction
<a href="http://www.php.net/">PHP</a> <code>error_log</code>. Pour plus d'informations sur comment configurer le
gestionnaire d'erreurs PHP, consulter la
<a href="https://www.php.net/error_log">documentation officielle</a>.</p>
</li>
</ul>
<ul>
<li>
<p><code>email</code></p>
<p>Journalisation via l'envoi d'un email : chaque message journalisé déclenchera l'envoi d'un email
au destinataire configuré. L'adresse email du destinataire peut-être configurée via le paramètre
<code>recipient</code>.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Il est conseillé d'utiliser ce type d'<em>handler</em> avec un niveau minimum de journalisation
important (<code>FATAL</code> recommandé) pour ne pas déclencher un nombre trop important d'envois
d'emails.</p>
</div>
</li>
</ul>
</li>
</ul>
<ul>
<li>
<p><code>loggers</code></p>
<p>Tableau permettant de configurer la journalisation composant par composant. Chaque composant peut
avoir son propre <code>logger</code> ce qui permet alors, par exemple, de configurer le niveau de log
spécifiquement pour ce composant.</p>
<p>Le nom des composant correspond en général au nom de la classe PHP correspondante, ou bien encore
le nom d'une commande (lors d'une exécution en ligne de commande).</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Par défaut, le nom du composant ayant déclenché un message journalisé est affiché juste avant
le niveau de log.</p>
</div>
<ul>
<li>
<p><code>enabled</code></p>
<p>Booléen permettant de désactiver complètement les logs du composant (par défaut: <code>True</code>).</p>
</li>
</ul>
<ul>
<li>
<p><code>level</code></p>
<p>Niveau de log spécifique pour ce composant (par défaut: le niveau de log global).</p>
</li>
</ul>
</li>
</ul></section><section class="print-page" id="conf-global-lsformat"><h1 id="conf-global-lsformat-format-parametrable-lsfomat">Format paramétrable (LSfomat)</h1>
<p>Un <em>format paramétrable</em> est une chaîne de caractères contenant des mots clés formés comme dans
l'exemple suivant :</p>
<div class="highlight"><pre><span></span><code><a href="#conf-global-lsformat-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>%{[nom du mot clé][:A][:B][! ou _][~][%]}
</code></pre></div>
<p>Le nom du mot clé peut contenir des lettres de "a" à "z", de "A" à "Z" et des chiffres de 0 à 9. Ces
mots clés seront remplacés par les valeurs passées en paramètres et liées au contexte d'utilisation.
Les paramètres <em>:A</em> et <em>:B</em> permettent d'extraire une partie de la chaîne complète avant la
substitution.</p>
<p>Le paramètre <code>A</code> correspond, lorsque <code>B</code> n'est pas défini, au nombre maximum de caractères à
extraire de la chaîne de substitution. <em>A</em> doit être un entier dont le signe influ, comme expliqué
ci-dessous :</p>
<ul>
<li>Si <code>A</code> est positif, les <code>A</code> premiers caractères de la chaîne de substitution seront extraits.</li>
</ul>
<ul>
<li>Si <code>A</code> est négatif, les <code>|A|</code> derniers caractères de la chaîne de substitution seront extraits.</li>
</ul>
<p>Lorsque le paramètre <code>B</code> est défini, <code>A</code> correspond au rang du premier caractère à partir duquel la
chaîne de substitution sera découpée et <code>B</code> le nombre maximum de caractères à extraire. Le signe de
<code>B</code> influera comme expliqué dans le premier cas. Si <code>B</code> vaut zéro, la totalité de la longeur de la
chaîne sera retournée en tenant compte de <code>A</code> pour le rang du premier caractère.</p>
<p>Il existe par ailleurs des paramètres permettant de modifier la valeur de substitution avant son
utilisation :</p>
<ul>
<li>Les paramètres <em>!</em> ou <em>_</em> permettre respectivement de forcer la mise en majuscule ou en minuscule ;</li>
</ul>
<ul>
<li>Le paramètre <em>~</em> permet de forcer la suppression des accents ;</li>
</ul>
<ul>
<li>Le paramètre <em>%</em> permet de protéger les caractères éligibles en entités HTML.</li>
</ul>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>Lorsque qu'une seule valeur clé est disponible pour la substitution, le nom du mot clé n'importe
pas. Tous les mots clés trouvés dans le format seront remplacés par cette seule valeur.</p>
</div></section><section class="print-page" id="conf-global-ldap_search_params"><h1 id="conf-global-ldap_search_params-parametres-etendus-des-recherches-dans-lannuaire">Paramètres étendus des recherches dans l'annuaire</h1>
<p>Les paramètres des recherches sont ceux supportés par
<a href="http://pear.php.net/package/Net_LDAP2">Net_LDAP2</a>. Ces paramètres sont passés sous la forme d'un
tableau associatif. Les paramètres supportés sont détaillés ci-dessous :</p>
<table>
<thead>
<tr class="header">
<th>Nom</th>
<th>Description</th>
<th>Valeur par défaut</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code>scope</code></td>
<td><p>Définition de l'étendue de la recherche :</p>
<ul>
<li><p><code>base</code> - Sur une entrée seulement</p></li>
<li><p><code>one</code> - Sur les entrées imédiatement contenu par le <code>basedn</code> de la recherche</p></li>
<li><p><code>sub</code> - Sur l'arbre entier</p></li>
</ul></td>
<td><code>sub</code></td>
</tr>
<tr class="even">
<td><code>sizelimit</code></td>
<td>Le nombre maximum d'entrées retournées par la recherche.</td>
<td><code>0</code> (illimité)</td>
</tr>
<tr class="odd">
<td><code>timelimit</code></td>
<td>Le délai d'attente maximum de la réponse du serveur en secondes.</td>
<td><code>0</code> (illimité)</td>
</tr>
<tr class="even">
<td><code>attrsonly</code></td>
<td>Si <em>vrai</em>, seuls les noms des atttributs seront retournés.</td>
<td><code>false</code></td>
</tr>
<tr class="odd">
<td><code>attributes</code></td>
<td>Tableau contenant les noms des attributs que les entrées retournées peuvent contenir et que l'on souhaite récupérer.</td>
<td><code>array()</code>(tous)</td>
</tr>
</tbody>
</table>
<p>Pour plus d'information sur le sujet, vous pouvez consulter la documentation officiel du projet
<a href="http://pear.php.net/package/Net_LDAP2">Net_LDAP2</a>.</p></section><h1 class="nav-section-title-end">Ended: Configuration globale</h1><h2 class="nav-section-title">Objets de l'annuaire</h2><section class="print-page" id="conf-lsobject"><h1 id="conf-lsobject-configuration-lsobject">Configuration LSobject</h1>
<p>Cette partie décrit la manière de configurer les différents types de LSobjets manipulés par
LdapSaisie.</p>
<p>La configuration des LSobjects est stockée dans le dossier <code>/conf/LSobjects</code>. Dans ce dossier, on
retrouve un fichier par type d'LSobject, nommé de la manière suivante :</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>config.LSobjects.[nom du type d'LSobject].php
</code></pre></div>
<p>Ce fichier contient la déclaration de la configuration du type d'LSobject qui est stocké dans la
variable globale <code>$GLOBALS['LSobjects']['[nom du type d'LSobject]']</code>.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a><span class="x">$GLOBALS['LSobjects']['[nom du type d'LSobject]'] = array (</span>
<a href="#conf-lsobject-__codelineno-1-2" id="__codelineno-1-2" name="__codelineno-1-2"></a><span class="x"> 'objectclass' =&gt; array(</span>
<a href="#conf-lsobject-__codelineno-1-3" id="__codelineno-1-3" name="__codelineno-1-3"></a><span class="x"> 'objetclass1',</span>
<a href="#conf-lsobject-__codelineno-1-4" id="__codelineno-1-4" name="__codelineno-1-4"></a><span class="x"> 'objetclass2',</span>
<a href="#conf-lsobject-__codelineno-1-5" id="__codelineno-1-5" name="__codelineno-1-5"></a><span class="x"> ...</span>
<a href="#conf-lsobject-__codelineno-1-6" id="__codelineno-1-6" name="__codelineno-1-6"></a><span class="x"> ),</span>
<a href="#conf-lsobject-__codelineno-1-7" id="__codelineno-1-7" name="__codelineno-1-7"></a><span class="x"> 'filter' =&gt; '[filtre LDAP]',</span>
<a href="#conf-lsobject-__codelineno-1-8" id="__codelineno-1-8" name="__codelineno-1-8"></a>
<a href="#conf-lsobject-__codelineno-1-9" id="__codelineno-1-9" name="__codelineno-1-9"></a><span class="x"> 'rdn' =&gt; 'attr1',</span>
<a href="#conf-lsobject-__codelineno-1-10" id="__codelineno-1-10" name="__codelineno-1-10"></a>
<a href="#conf-lsobject-__codelineno-1-11" id="__codelineno-1-11" name="__codelineno-1-11"></a><span class="x"> 'LSaddons' =&gt; [LSaddon(s)],</span>
<a href="#conf-lsobject-__codelineno-1-12" id="__codelineno-1-12" name="__codelineno-1-12"></a>
<a href="#conf-lsobject-__codelineno-1-13" id="__codelineno-1-13" name="__codelineno-1-13"></a><span class="x"> 'container_dn' =&gt; 'ou=people',</span>
<a href="#conf-lsobject-__codelineno-1-14" id="__codelineno-1-14" name="__codelineno-1-14"></a><span class="x"> 'generate_container_dn' =&gt; '[callable]',</span>
<a href="#conf-lsobject-__codelineno-1-15" id="__codelineno-1-15" name="__codelineno-1-15"></a><span class="x"> 'container_auto_create' =&gt; array(</span>
<a href="#conf-lsobject-__codelineno-1-16" id="__codelineno-1-16" name="__codelineno-1-16"></a><span class="x"> // Information des configurations pour la création du conteneur du type d'LSobjet</span>
<a href="#conf-lsobject-__codelineno-1-17" id="__codelineno-1-17" name="__codelineno-1-17"></a><span class="x"> // lors de la création nouveau subDn</span>
<a href="#conf-lsobject-__codelineno-1-18" id="__codelineno-1-18" name="__codelineno-1-18"></a><span class="x"> ),</span>
<a href="#conf-lsobject-__codelineno-1-19" id="__codelineno-1-19" name="__codelineno-1-19"></a>
<a href="#conf-lsobject-__codelineno-1-20" id="__codelineno-1-20" name="__codelineno-1-20"></a><span class="x"> 'disable_creation' =&gt; [boolean]',</span>
<a href="#conf-lsobject-__codelineno-1-21" id="__codelineno-1-21" name="__codelineno-1-21"></a>
<a href="#conf-lsobject-__codelineno-1-22" id="__codelineno-1-22" name="__codelineno-1-22"></a><span class="x"> 'before_modify' =&gt; 'function1',</span>
<a href="#conf-lsobject-__codelineno-1-23" id="__codelineno-1-23" name="__codelineno-1-23"></a><span class="x"> 'after_modify' =&gt; 'function2',</span>
<a href="#conf-lsobject-__codelineno-1-24" id="__codelineno-1-24" name="__codelineno-1-24"></a><span class="x"> 'after_create' =&gt; 'function3',</span>
<a href="#conf-lsobject-__codelineno-1-25" id="__codelineno-1-25" name="__codelineno-1-25"></a><span class="x"> 'after_delete' =&gt; 'function4',</span>
<a href="#conf-lsobject-__codelineno-1-26" id="__codelineno-1-26" name="__codelineno-1-26"></a>
<a href="#conf-lsobject-__codelineno-1-27" id="__codelineno-1-27" name="__codelineno-1-27"></a><span class="x"> 'label' =&gt; 'objet1',</span>
<a href="#conf-lsobject-__codelineno-1-28" id="__codelineno-1-28" name="__codelineno-1-28"></a><span class="x"> 'display_name_format' =&gt; '[format]',</span>
<a href="#conf-lsobject-__codelineno-1-29" id="__codelineno-1-29" name="__codelineno-1-29"></a><span class="x"> 'displayAttrName' =&gt; '[booleen]',</span>
<a href="#conf-lsobject-__codelineno-1-30" id="__codelineno-1-30" name="__codelineno-1-30"></a>
<a href="#conf-lsobject-__codelineno-1-31" id="__codelineno-1-31" name="__codelineno-1-31"></a><span class="x"> //Custom Actions</span>
<a href="#conf-lsobject-__codelineno-1-32" id="__codelineno-1-32" name="__codelineno-1-32"></a><span class="x"> 'customActions' =&gt; array (</span>
<a href="#conf-lsobject-__codelineno-1-33" id="__codelineno-1-33" name="__codelineno-1-33"></a><span class="x"> // Configuration des customActions pour ce type d'objet</span>
<a href="#conf-lsobject-__codelineno-1-34" id="__codelineno-1-34" name="__codelineno-1-34"></a><span class="x"> ),</span>
<a href="#conf-lsobject-__codelineno-1-35" id="__codelineno-1-35" name="__codelineno-1-35"></a>
<a href="#conf-lsobject-__codelineno-1-36" id="__codelineno-1-36" name="__codelineno-1-36"></a><span class="x"> // LSrelation</span>
<a href="#conf-lsobject-__codelineno-1-37" id="__codelineno-1-37" name="__codelineno-1-37"></a><span class="x"> 'LSrelation' =&gt; array(</span>
<a href="#conf-lsobject-__codelineno-1-38" id="__codelineno-1-38" name="__codelineno-1-38"></a><span class="x"> // Configuration des LSrelations entre ce type d'objet et les autres</span>
<a href="#conf-lsobject-__codelineno-1-39" id="__codelineno-1-39" name="__codelineno-1-39"></a><span class="x"> ),</span>
<a href="#conf-lsobject-__codelineno-1-40" id="__codelineno-1-40" name="__codelineno-1-40"></a>
<a href="#conf-lsobject-__codelineno-1-41" id="__codelineno-1-41" name="__codelineno-1-41"></a><span class="x"> // LSform</span>
<a href="#conf-lsobject-__codelineno-1-42" id="__codelineno-1-42" name="__codelineno-1-42"></a><span class="x"> 'LSform' =&gt; array (</span>
<a href="#conf-lsobject-__codelineno-1-43" id="__codelineno-1-43" name="__codelineno-1-43"></a><span class="x"> // Configuration des formulaires de l'objet</span>
<a href="#conf-lsobject-__codelineno-1-44" id="__codelineno-1-44" name="__codelineno-1-44"></a><span class="x"> ), // fin LSform</span>
<a href="#conf-lsobject-__codelineno-1-45" id="__codelineno-1-45" name="__codelineno-1-45"></a>
<a href="#conf-lsobject-__codelineno-1-46" id="__codelineno-1-46" name="__codelineno-1-46"></a><span class="x"> // LSsearch</span>
<a href="#conf-lsobject-__codelineno-1-47" id="__codelineno-1-47" name="__codelineno-1-47"></a><span class="x"> 'LSsearch' =&gt; array (</span>
<a href="#conf-lsobject-__codelineno-1-48" id="__codelineno-1-48" name="__codelineno-1-48"></a><span class="x"> // Configuration des recherches de l'objet</span>
<a href="#conf-lsobject-__codelineno-1-49" id="__codelineno-1-49" name="__codelineno-1-49"></a><span class="x"> ), // fin LSsearch</span>
<a href="#conf-lsobject-__codelineno-1-50" id="__codelineno-1-50" name="__codelineno-1-50"></a>
<a href="#conf-lsobject-__codelineno-1-51" id="__codelineno-1-51" name="__codelineno-1-51"></a><span class="x"> 'globalSearch' =&gt; [booleen],</span>
<a href="#conf-lsobject-__codelineno-1-52" id="__codelineno-1-52" name="__codelineno-1-52"></a><span class="x"> 'globalSearch_extraDisplayedColumns' =&gt; [booleen],</span>
<a href="#conf-lsobject-__codelineno-1-53" id="__codelineno-1-53" name="__codelineno-1-53"></a>
<a href="#conf-lsobject-__codelineno-1-54" id="__codelineno-1-54" name="__codelineno-1-54"></a><span class="x"> // ioFormat</span>
<a href="#conf-lsobject-__codelineno-1-55" id="__codelineno-1-55" name="__codelineno-1-55"></a><span class="x"> 'ioFormat' =&gt; array (</span>
<a href="#conf-lsobject-__codelineno-1-56" id="__codelineno-1-56" name="__codelineno-1-56"></a><span class="x"> // Configuration des formats d'import/export de l'objet</span>
<a href="#conf-lsobject-__codelineno-1-57" id="__codelineno-1-57" name="__codelineno-1-57"></a><span class="x"> ),</span>
<a href="#conf-lsobject-__codelineno-1-58" id="__codelineno-1-58" name="__codelineno-1-58"></a>
<a href="#conf-lsobject-__codelineno-1-59" id="__codelineno-1-59" name="__codelineno-1-59"></a><span class="x"> // Attributs</span>
<a href="#conf-lsobject-__codelineno-1-60" id="__codelineno-1-60" name="__codelineno-1-60"></a><span class="x"> 'attrs' =&gt; array (</span>
<a href="#conf-lsobject-__codelineno-1-61" id="__codelineno-1-61" name="__codelineno-1-61"></a><span class="x"> // Configuration des attributs du type d'LSobjet</span>
<a href="#conf-lsobject-__codelineno-1-62" id="__codelineno-1-62" name="__codelineno-1-62"></a><span class="x"> )</span>
<a href="#conf-lsobject-__codelineno-1-63" id="__codelineno-1-63" name="__codelineno-1-63"></a><span class="x">);</span>
<a href="#conf-lsobject-__codelineno-1-64" id="__codelineno-1-64" name="__codelineno-1-64"></a><span class="x">...</span>
</code></pre></div>
<ul>
<li>
<p><code>objectclass</code></p>
<p>La liste des <em>objectclass</em> des objets.</p>
</li>
</ul>
<ul>
<li>
<p><code>filter</code></p>
<p>Filtre de recherche LDAP applicable à tout les objets de ce type et qui sera utilisé lors de
chaque recherche de ce type d'objet.</p>
</li>
</ul>
<ul>
<li>
<p><code>rdn</code></p>
<p>Nom de l'attribut correspondant au <em>RDN</em> des objets LDAP.</p>
</li>
</ul>
<ul>
<li>
<p><code>LSaddons</code></p>
<p>LSaddon(s) dont le type d'objet dépend. Ce peut être un tableau de chaînes de caractères ou une
simpe chaîne de caractères correspondant au(x) nom(s) du/des LSaddon(s) en dépendance.</p>
</li>
</ul>
<ul>
<li>
<p><code>container_dn</code></p>
<p>Elément pour construire le <em>basedn</em> de stockage de ce type d'objet. Par exemple, si le <em>basedn</em> de
l'annuaire est <code>o=ls</code> et que les objets <em>utilisateurs</em> sont stockés dans la branche de l'annuaire
<code>ou=people,o=ls</code>, alors <code>container_dn</code> devra valoir <code>ou=people</code>.</p>
<p>Lorsque l'annuaire possède des <a href="#conf-global-ldap-subdn-sous-niveaux-de-connexion">subDn</a>, les
objets seront cherchés dans le <em>basedn</em> résultant de la concaténation du paramètre <code>container_dn</code>,
d'une virgule et du <em>basedn</em> correspondant au
<a href="#conf-global-ldap-subdn-sous-niveaux-de-connexion">subDn</a> courant.</p>
</li>
</ul>
<ul>
<li>
<p><code>generate_container_dn</code></p>
<p><em>Callable</em> (au sens PHP), utilisé pour générer la valeur du paramètre <code>container_dn</code>
dynamiquement. Ce <em>callable</em> prend en paramètre l'objet LSobject à
créer et retourne la valeur du paramètre <code>container_dn</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>container_auto_create</code></p>
<p>Tableau associatif contenant les paramètres de configuration nécessaires à la création des
<code>container_dn</code> dans les nouveaux objets utilisés comme
<a href="#conf-global-ldap-subdn-sous-niveaux-de-connexion">subDn</a>.
<a href="#conf-lsobject-container_auto_create-creation-automatique-du-conteneur-des-lsobjets-dans-un-subdn">Voir la section concernée</a>.</p>
</li>
</ul>
<ul>
<li>
<p><code>disable_creation</code></p>
<p>Booléen permetant de desactiver la creation de ce type d'objet de manière globale.</p>
</li>
</ul>
<ul>
<li>
<p><code>before_modify</code></p>
<p>Chaîne de caractères (ou tableau de chaine de caractères) correspondant au nom d'une ou plusieurs
fonctions qui seront exécutées avant la modification d'un objet.
<a href="#conf-lsobject-triggers-declencheurs_1">Voir la section concernée</a>.</p>
</li>
</ul>
<ul>
<li>
<p><code>after_modify</code></p>
<p>Chaîne de caractères (ou tableau de chaine de caractères) correspondant au nom d'une ou plusieurs
fonctions qui seront exécutées après la modification d'un objet.
<a href="#conf-lsobject-triggers-declencheurs_1">Voir la section concernée</a>.</p>
</li>
</ul>
<ul>
<li>
<p><code>after_create</code></p>
<p>Chaîne de caractères (ou tableau de chaine de caractères) correspondant au nom d'une ou plusieurs
fonctions qui seront exécutées après la création d'un objet.
<a href="#conf-lsobject-triggers-declencheurs_1">Voir la section concernée</a>.</p>
</li>
</ul>
<ul>
<li>
<p><code>after_delete</code></p>
<p>Chaîne de caractères (ou tableau de chaine de caractères) correspondant au nom d'une ou plusieurs
fonctions qui seront exécutées après la suppression d'un objet.
<a href="#conf-lsobject-triggers-declencheurs_1">Voir la section concernée</a>.</p>
</li>
</ul>
<ul>
<li>
<p><code>label</code></p>
<p>Nom générique au pluriel qualifiant le type d'objet. Exemple : <em>Utilisateurs</em>.</p>
</li>
</ul>
<ul>
<li>
<p><code>display_name_format</code></p>
<p><a href="#conf-global-lsformat-format-parametrable">Format paramètrable</a> du nom des objets composés à
partir des valeurs d'affichage des attributs de l'objet.</p>
</li>
</ul>
<ul>
<li>
<p><code>displayAttrName</code></p>
<p>Booléen définissant si le nom des attributs doit être affiché en préfixe de leur message d'aide
(paramètre <code>help_info</code>).</p>
</li>
</ul>
<ul>
<li>
<p><code>customActions</code></p>
<p>Tableau associatif contenant les paramètres de configuration des
<a href="#conf-lsobject-customactions-customactions">customActions</a>.
<a href="#conf-lsobject-customactions-customactions">Voir la section concernée</a>.</p>
</li>
</ul>
<ul>
<li>
<p><code>LSrelation</code></p>
<p>Tableau associatif contenant les paramètres de configuration des
<a href="#conf-lsobject-lsrelation-lsrelation">LSrelations</a>. <a href="#conf-lsobject-lsrelation-lsrelation">Voir la section concernée</a>.</p>
</li>
</ul>
<ul>
<li>
<p><code>LSform</code></p>
<p>Tableau associatif contenant les paramètres de configuration des <a href="#conf-lsobject-lsform-lsform">LSforms</a> des
LSobjects. <a href="#conf-lsobject-lsform-lsform">Voir la section concernée</a>.</p>
</li>
</ul>
<ul>
<li>
<p><code>LSsearch</code></p>
<p>Tableau associatif contenant les paramètres de configuration des recherches de
LSobject de ce type dans l'annuaire.
<a href="#conf-lsobject-lssearch-lssearch">Voir la section concernée</a>.</p>
</li>
</ul>
<ul>
<li>
<p><code>globalSearch</code></p>
<p>Inclure ou non ce type d'objet dans le résultat des recherches globales (Par défaut : <code>True</code>).</p>
</li>
</ul>
<ul>
<li>
<p><code>globalSearch_extraDisplayedColumns</code></p>
<p>Afficher ou non les colonnes supplémentaires pour ce type d'objet dans le résultat des recherches
globales (Par défaut : <code>True</code>). Pour plus de détails les colonnes supplémentaires,
<a href="#conf-lsobject-lssearch-lssearch">voir la section dédiée</a>.</p>
</li>
</ul>
<ul>
<li>
<p><code>ioFormat</code></p>
<p>Tableau associatif contenant les paramètres de configuration des formats de fichiers
d'import/export de ce type d'LSobject.
<a href="#conf-lsobject-ioformat-ioformat">Voir la section concernée</a>.</p>
</li>
</ul>
<ul>
<li>
<p><code>attrs</code></p>
<p>Tableau associatif contenant les paramètres de configuration des attributs des objets.
<a href="#conf-lsobject-lsattribute-configuration-des-attributs">Voir la section concernée</a>.</p>
</li>
</ul></section><h3 class="nav-section-title">Attributs</h3><section class="print-page" id="conf-lsobject-lsattribute"><h1 id="conf-lsobject-lsattribute-configuration-des-attributs">Configuration des attributs</h1>
<p>Cette section décrit les options de configuration des attributs des
<a href="#conf-lsobject-configuration-lsobject">LSobjects</a>. Les attributs sont définis dans le tableau
associatif <code>attrs</code> de la configuration des <a href="#conf-lsobject-configuration-lsobject">LSobjects</a>. Dans ce
tableau, les clé les noms des attributs et les valeurs liés sont la configuration des attributs.</p>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>Contrairement à ce qui existe dans le standard LDAP, les noms des attributs sont sensibles à la
casse. Il faut que le nom des attributs dans LdapSaisie soient scrupuleusement les mêmes que
ceux retourné par <a href="http://pear.php.net/package/Net_LDAP2">Net_LDAP2</a></p>
</div>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>'attrs' =&gt; array (
<a href="#conf-lsobject-lsattribute-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> /* ----------- start -----------*/
<a href="#conf-lsobject-lsattribute-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> 'attr1' =&gt; array (
<a href="#conf-lsobject-lsattribute-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> 'label' =&gt; '[label de l'attr1',
<a href="#conf-lsobject-lsattribute-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a> 'displayAttrName' =&gt; '[booleen]',
<a href="#conf-lsobject-lsattribute-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a> 'help_info' =&gt; '[Message d'aide sur l'attribut attr1]',
<a href="#conf-lsobject-lsattribute-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a> 'help_info_in_view' =&gt; '[booleen]',
<a href="#conf-lsobject-lsattribute-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a> 'ldap_type' =&gt; 'ldaptype1',
<a href="#conf-lsobject-lsattribute-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a> 'ldap_options' =&gt; array(
<a href="#conf-lsobject-lsattribute-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a> // Options LDAP liées au type LDAP de l'attribut
<a href="#conf-lsobject-lsattribute-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a> ),
<a href="#conf-lsobject-lsattribute-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a> 'html_type' =&gt; 'htmltype1',
<a href="#conf-lsobject-lsattribute-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a> 'html_options' =&gt; array(
<a href="#conf-lsobject-lsattribute-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a> // Options HTML liées au type HTML de l'attribut
<a href="#conf-lsobject-lsattribute-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a> ),
<a href="#conf-lsobject-lsattribute-__codelineno-0-16" id="__codelineno-0-16" name="__codelineno-0-16"></a> 'no_value_label' =&gt; '[No set value label]',
<a href="#conf-lsobject-lsattribute-__codelineno-0-17" id="__codelineno-0-17" name="__codelineno-0-17"></a> 'multiple' =&gt; 0,
<a href="#conf-lsobject-lsattribute-__codelineno-0-18" id="__codelineno-0-18" name="__codelineno-0-18"></a> 'required' =&gt; 1,
<a href="#conf-lsobject-lsattribute-__codelineno-0-19" id="__codelineno-0-19" name="__codelineno-0-19"></a> 'generate_function' =&gt; 'fonction1',
<a href="#conf-lsobject-lsattribute-__codelineno-0-20" id="__codelineno-0-20" name="__codelineno-0-20"></a> 'generate_value_format' =&gt; '[LSformat]',
<a href="#conf-lsobject-lsattribute-__codelineno-0-21" id="__codelineno-0-21" name="__codelineno-0-21"></a> 'default_value' =&gt; 'valeur1',
<a href="#conf-lsobject-lsattribute-__codelineno-0-22" id="__codelineno-0-22" name="__codelineno-0-22"></a> 'set_default_value_on_creation_if_empty' =&gt; [booleen],
<a href="#conf-lsobject-lsattribute-__codelineno-0-23" id="__codelineno-0-23" name="__codelineno-0-23"></a> 'force_generation_if_empty' =&gt; [booleen],
<a href="#conf-lsobject-lsattribute-__codelineno-0-24" id="__codelineno-0-24" name="__codelineno-0-24"></a> 'check_data' =&gt; array (
<a href="#conf-lsobject-lsattribute-__codelineno-0-25" id="__codelineno-0-25" name="__codelineno-0-25"></a> // Régle de vérification syntaxique des données saisies
<a href="#conf-lsobject-lsattribute-__codelineno-0-26" id="__codelineno-0-26" name="__codelineno-0-26"></a> ),
<a href="#conf-lsobject-lsattribute-__codelineno-0-27" id="__codelineno-0-27" name="__codelineno-0-27"></a> 'validation' =&gt; array (
<a href="#conf-lsobject-lsattribute-__codelineno-0-28" id="__codelineno-0-28" name="__codelineno-0-28"></a> // Règle de vérification d'intégrité des données saisies
<a href="#conf-lsobject-lsattribute-__codelineno-0-29" id="__codelineno-0-29" name="__codelineno-0-29"></a> ),
<a href="#conf-lsobject-lsattribute-__codelineno-0-30" id="__codelineno-0-30" name="__codelineno-0-30"></a> 'rights' =&gt; array(
<a href="#conf-lsobject-lsattribute-__codelineno-0-31" id="__codelineno-0-31" name="__codelineno-0-31"></a> 'LSprofile1' =&gt; 'droit1',
<a href="#conf-lsobject-lsattribute-__codelineno-0-32" id="__codelineno-0-32" name="__codelineno-0-32"></a> 'LSprofile2' =&gt; 'droit2',
<a href="#conf-lsobject-lsattribute-__codelineno-0-33" id="__codelineno-0-33" name="__codelineno-0-33"></a> ...
<a href="#conf-lsobject-lsattribute-__codelineno-0-34" id="__codelineno-0-34" name="__codelineno-0-34"></a> ),
<a href="#conf-lsobject-lsattribute-__codelineno-0-35" id="__codelineno-0-35" name="__codelineno-0-35"></a> 'view' =&gt; 1,
<a href="#conf-lsobject-lsattribute-__codelineno-0-36" id="__codelineno-0-36" name="__codelineno-0-36"></a> 'form' =&gt; array (
<a href="#conf-lsobject-lsattribute-__codelineno-0-37" id="__codelineno-0-37" name="__codelineno-0-37"></a> 'create' =&gt; 1,
<a href="#conf-lsobject-lsattribute-__codelineno-0-38" id="__codelineno-0-38" name="__codelineno-0-38"></a> 'modify' =&gt; 0,
<a href="#conf-lsobject-lsattribute-__codelineno-0-39" id="__codelineno-0-39" name="__codelineno-0-39"></a> ...
<a href="#conf-lsobject-lsattribute-__codelineno-0-40" id="__codelineno-0-40" name="__codelineno-0-40"></a> ),
<a href="#conf-lsobject-lsattribute-__codelineno-0-41" id="__codelineno-0-41" name="__codelineno-0-41"></a> 'dependAttrs' =&gt; array(
<a href="#conf-lsobject-lsattribute-__codelineno-0-42" id="__codelineno-0-42" name="__codelineno-0-42"></a> // Attributs en dépendance
<a href="#conf-lsobject-lsattribute-__codelineno-0-43" id="__codelineno-0-43" name="__codelineno-0-43"></a> ),
<a href="#conf-lsobject-lsattribute-__codelineno-0-44" id="__codelineno-0-44" name="__codelineno-0-44"></a> 'onDisplay' =&gt; 'fonction2'
<a href="#conf-lsobject-lsattribute-__codelineno-0-45" id="__codelineno-0-45" name="__codelineno-0-45"></a>
<a href="#conf-lsobject-lsattribute-__codelineno-0-46" id="__codelineno-0-46" name="__codelineno-0-46"></a> 'before_modify' =&gt; 'function1',
<a href="#conf-lsobject-lsattribute-__codelineno-0-47" id="__codelineno-0-47" name="__codelineno-0-47"></a> 'after_modify' =&gt; 'function2'
<a href="#conf-lsobject-lsattribute-__codelineno-0-48" id="__codelineno-0-48" name="__codelineno-0-48"></a> ),
<a href="#conf-lsobject-lsattribute-__codelineno-0-49" id="__codelineno-0-49" name="__codelineno-0-49"></a> /* ----------- end -----------*/
<a href="#conf-lsobject-lsattribute-__codelineno-0-50" id="__codelineno-0-50" name="__codelineno-0-50"></a> ...
<a href="#conf-lsobject-lsattribute-__codelineno-0-51" id="__codelineno-0-51" name="__codelineno-0-51"></a>);
<a href="#conf-lsobject-lsattribute-__codelineno-0-52" id="__codelineno-0-52" name="__codelineno-0-52"></a>...
</code></pre></div>
<ul>
<li>
<p><code>label</code></p>
<p>Le label de l'attribut.</p>
</li>
</ul>
<ul>
<li>
<p><code>displayAttrName</code></p>
<p>Booléen définissant si le nom de l'attribut doit être affiché en préfixe du message d'aide
(paramètre <code>help_info</code>).</p>
</li>
</ul>
<ul>
<li>
<p><code>help_info</code></p>
<p>Message d'aide qui sera affiché dans une bulle d'aide à côté du nom de l'attribut dans les
formulaires.</p>
</li>
</ul>
<ul>
<li>
<p><code>help_info_in_view</code></p>
<p>Booléen définissant si le message d'aide doit être affiché sur la vue de visualisation de l'objet.</p>
<p>Valeurs possibles : <em>0</em> ou <em>1</em></p>
<p>Valeur par défaut : <em>0</em></p>
</li>
</ul>
<ul>
<li>
<p><code>ldap_type</code></p>
<p>Le type LDAP de l'attribut (facultatif, par défaut:
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_ascii-lsattr_ldap_ascii">LSattr_ldap_ascii</a>).
<a href="#conf-lsobject-lsattribute-lsattr_ldap-configuration-des-attributs-ldap">Voir la section concernée.</a></p>
</li>
</ul>
<ul>
<li>
<p><code>ldap_options</code></p>
<p>Tableau associatif contenant les paramètres de configuration du type LDAP de l'attribut.
<a href="#conf-lsobject-lsattribute-lsattr_ldap-configuration-des-attributs-ldap">Voir la section concernée.</a></p>
</li>
</ul>
<ul>
<li>
<p><code>html_type</code></p>
<p>Le type HTML de l'attribut (facultatif, par défaut:
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-lsattr_html_text">LSattr_html_text</a>).
<a href="#conf-lsobject-lsattribute-lsattr_html-configuration-des-attributs-html">Voir la section concernée.</a></p>
</li>
</ul>
<ul>
<li>
<p><code>html_options</code></p>
<p>Tableau associatif contenant les paramètres de configuration du type HTML de l'attribut.
<a href="#conf-lsobject-lsattribute-lsattr_html-configuration-des-attributs-html">Voir la section concernée.</a></p>
</li>
</ul>
<ul>
<li>
<p><code>no_value_label</code></p>
<p>Label affiché lorsque l'attribut n'a pas de valeur (facultatif).</p>
</li>
</ul>
<ul>
<li>
<p><code>multiple</code></p>
<p>Booléen définissant si cet attribut peut stocker plusieurs valeurs.</p>
<p>Valeurs possibles : <em>0</em> ou <em>1</em></p>
<p>Valeur par défaut : <em>0</em></p>
</li>
</ul>
<ul>
<li>
<p><code>required</code></p>
<p>Booléen définissant si cet attribut doit obligatoirement être défini.</p>
<p>Valeurs possibles : <em>0</em> ou <em>1</em></p>
<p>Valeur par défaut : <em>0</em></p>
</li>
</ul>
<ul>
<li>
<p><code>generate_function</code></p>
<p>Nom de la fonction permettant de générer la valeur de l'attribut. Cette fonction sera éxecutée, en
passant en premier paramètre, l'objet <a href="#conf-lsobject-configuration-lsobject">LSobject</a> courant.</p>
</li>
</ul>
<ul>
<li>
<p><code>generate_value_format</code></p>
<p><a href="#conf-global-lsformat-format-parametrable">LSformat</a> permettant la génération de l'attribut.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Cette méthode de génération est utilisée uniquement si aucune fonction de génération de la
valeur n'est définie (paramètre <code>generate_function</code>).</p>
</div>
</li>
</ul>
<ul>
<li>
<p><code>default_value</code></p>
<p>Valeur par défaut de l'attribut.</p>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>Il doit s'agir de la valeur telque retournée par le formulaire web. Ainsi, par exemple dans le
cas d'un attribut booléen, les valeurs possibles sont <code>yes</code> ou <code>no</code>.</p>
</div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Cette valeur est également utilisée dans le cadre de la génération automatique de la valeur de
l'attribut si aucune autre méthode n'est disponible (via une fonction ou un
<a href="#conf-global-lsformat-format-parametrable">LSformat</a>).</p>
</div>
</li>
</ul>
<ul>
<li>
<p><code>set_default_value_on_creation_if_empty</code></p>
<p>Booléen permettant de définir si la valeur de l'attribut doit être initialisée avec sa valeur par
défaut à la création de l'objet si aucune autre valeur n'as été fournie dans le contexte de
création (par défaut : <em>1</em>).</p>
</li>
</ul>
<ul>
<li>
<p><code>force_generation_if_empty</code></p>
<p>Booléen permettant de définir si la valeur de l'attribut doit être générée si elle est vide, que
ce soit à la création ou la modification de l'objet (par défaut : <em>0</em>).</p>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>Si la génération échoue, cela bloquera l'action. Par ailleurs, cette génération est
prioritaire sur l'utilisation de la valeur par défaut de l'attribut induit par le paramètre
<code>set_default_value_on_creation_if_empty</code>.</p>
</div>
</li>
</ul>
<ul>
<li>
<p><code>check_data</code></p>
<p>Tableau associatif contenant les règles de vérification syntaxique des données de l'attribut.
<a href="#conf-lsobject-lsattribute-check_data-configuration-des-regles-de-verification-syntaxique">Voir la section concernée.</a></p>
</li>
</ul>
<ul>
<li>
<p><code>validation</code></p>
<p>Tableau associatif contenant les règles de vérification d'intégrité des données de l'attribut.
<a href="#conf-lsobject-lsattribute-validation-configuration-des-regles-de-verification-dintegrite">Voir la section concernée.</a></p>
</li>
</ul>
<ul>
<li>
<p><code>rights</code></p>
<p>Tableau associatif dont les clés sont les noms des
<a href="#conf-global-ldap-lsprofile-profils-dutilisateurs">LSprofiles</a> ayant des droits sur cet
attribut et les valeurs associées sont les droits correspondants. La valeur des droits d'un
<a href="#conf-global-ldap-lsprofile-profils-dutilisateurs">LSprofile</a> peut être <code>r</code> pour le droit de
lecture ou <code>w</code> pour le droit de lecture-écriture. Par défaut, un
<a href="#conf-global-ldap-lsprofile-profils-dutilisateurs">LSprofile</a> n'a aucun droit.</p>
</li>
</ul>
<ul>
<li>
<p><code>view</code></p>
<p>Booléen définissant si l'attribut est, ou non, affiché lors de la visualisation des objets du type
courant.</p>
<p>Valeurs possibles : <em>0</em> ou <em>1</em></p>
<p>Valeur par défaut : <em>0</em></p>
</li>
</ul>
<ul>
<li>
<p><code>form</code></p>
<p>Tableau associatif dont les clés sont les noms des <a href="#conf-lsobject-lsform-lsform">LSforms</a> et les valeurs
associées la définition de l'affichage dans ce <a href="#conf-lsobject-lsform-lsform">LSform</a>. Si cette valeur vaut
<code>0</code>, alors l'attribut sera lecture-seule et si cette valeur vaut <code>1</code>, cet attribut sera affiché
en lecture-écriture.</p>
</li>
</ul>
<ul>
<li>
<p><code>dependAttrs</code></p>
<p>Tableau associatif listant les attributs dépendants de celui-ci. Les attributs listés ici seront
regénérés lors de chaque modification de l'attribut courant. Cette génération sera effectuée avec
la fonction définie dans le paramètre <code>generate_function</code> de l'attribut.</p>
</li>
</ul>
<ul>
<li>
<p><code>onDisplay</code></p>
<p>Nom ou liste de nom des fonctions retournant les valeurs d'affichages de l'attribut. Si c'est une
liste, chacune des fonctions seront executée les unes après les autres. Ces fonctions seront
éxecutées, en passant en premier paramètre, le tableau des valeurs de l'objet.</p>
</li>
</ul>
<ul>
<li>
<p><code>before_modify</code></p>
<p>Chaîne de caractères (ou tableau de chaine de caractères) correspondant au nom d'une ou plusieurs
fonctions qui seront exécutées avant toutes modifications de la valeur de l'attribut.
<a href="#conf-lsobject-lsattribute-triggers-declencheurs">Voir la section concernée</a></p>
</li>
</ul>
<ul>
<li>
<p><code>after_modify</code></p>
<p>Chaîne de caractères (ou tableau de chaine de caractères) correspondant au nom d'une ou plusieurs
fonctions qui seront exécutées après toutes modifications de la valeur de l'attribut.
<a href="#conf-lsobject-lsattribute-triggers-declencheurs">Voir la section concernée</a></p>
</li>
</ul></section><h4 class="nav-section-title">Types d'attribut LDAP (LSattr_ldap)</h4><section class="print-page" id="conf-lsobject-lsattribute-lsattr_ldap"><h1 id="conf-lsobject-lsattribute-lsattr_ldap-configuration-des-attributs-ldap-lsattr_ldap">Configuration des attributs LDAP (LSattr_ldap)</h1>
<p>Cette section décrit les options propres à chacun des types d'attributs LDAP supportés par
LdapSaisie.</p></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_ascii"><h1 id="conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_ascii-lsattr_ldap_ascii">LSattr_ldap_ascii</h1>
<p>Ce type est utilisé pour la gestion des attributs dont la valeur est une chaine de caractère. Ce
type est le type par défaut.</p></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_boolean"><h1 id="conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_boolean-lsattr_ldap_boolean">LSattr_ldap_boolean</h1>
<p>Ce type est utilisé pour la gestion des attributs dont la valeur est une booléen. On attend ici par
booléen, tout attribut ne pouvant prendre que deux valeurs pré-définies correspond pour l'un à <em>Oui</em>
et l'autre à <em>Non</em></p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_boolean-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>'ldap_options' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_boolean-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'true_value' =&gt; '[valeur correspondant à Vrai]',
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_boolean-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> 'false_value' =&gt; '[valeur correspondant à Faux]'
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_boolean-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a>),
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_boolean-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a>...
</code></pre></div>
<ul>
<li>
<p><code>true_value</code></p>
<p>La valeur de l'attribut correspondant à <em>Vrai</em>­. (Par défaut : <code>TRUE</code>)</p>
</li>
</ul>
<ul>
<li>
<p><code>false_value</code></p>
<p>La valeur de l'attribut correspondant à <code>False</code>­. (Par défaut : <code>FALSE</code>)</p>
</li>
</ul>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>Les valeurs possibles pour le paramètre <code>default_value</code> sont <code>yes</code> et <code>no</code>.</p>
</div></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_compositevaluetojson"><h1 id="conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_compositevaluetojson-lsattr_ldap_compositevaluetojson">LSattr_ldap_compositeValueToJSON</h1>
<p>Ce type est utilisé pour la gestion des attributs composites dont les valeurs respectent le format
suivant : <code>[key1=value1][key2=value2][...]</code></p>
<p>Ce type d'attribut LDAP sera utilisé pour convertir la valeur en son équivalent <code>JSON</code> pour pouvoir
être traité à l'aide du type d' attribut HTML
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-lsattr_html_jsoncompositeattribute">LSattr_html_jsonCompositeAttribute</a>.</p></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_date"><h1 id="conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_date-lsattr_ldap_date">LSattr_ldap_date</h1>
<p>Ce type est utilisé pour la gestion des attributs dont la valeur est une date.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Au sein d'LdapSaisie, les dates manipulées au travers ce type d'attribut LDAP, sont au format
<em>timestamp</em>. Il s'agit donc de nombres entiers correpondants au nombre de secondes depuis le 1
janvier 1970.</p>
<p>Le type d'attribut HTML utilisé conjointement avec ce type d'attribut LDAP devra être prévu pour
recevoir et fournir des dates au format <em>timestamp</em>, comme c'est le cas pour le <a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_date-lsattr_html_date">type d'attribut
HTML <em>date</em></a>.</p>
</div>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_date-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>'ldap_options' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_date-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'timestamp' =&gt; [Booléen], // Si la date est stockée au format timestamp
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_date-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> 'formats' =&gt; array(
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_date-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> '[Format de stockage principal]', // Par défaut : "YmdHisO"
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_date-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a> '[Formats de stockage alternatifs]', // Par défaut : "YmdHis.vO" &amp; "YmdHis.uO"
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_date-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a> [...]
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_date-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a> ),
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_date-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a> 'timezone' =&gt; '[Fuseau horaire]', // Default : "UTC"
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_date-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a>),
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_date-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a>...
</code></pre></div>
<ul>
<li>
<p><code>timestamp</code></p>
<p>Booléen définissant si la date est stockée sous la forme d'un timestamp Unix (nombre de secondes
depuis le 1er janvier 1970 à 00:00:00 UTC)­.</p>
<p>Si <code>timestamp</code> est vrai, LdapSaisie ne tient pas compte du paramètre format.</p>
</li>
</ul>
<ul>
<li>
<p><code>formats</code></p>
<p>Formats de stockage de la date dans l'annuaire. Ces formats sont composés à partir des motifs clés
gérés par la fonction <code>date()</code> de PHP. Pour plus d'information, consulter
<a href="http://www.php.net/date">la documentation officielle</a>. Plusieurs formats peuvent être définis,
mais en cas de stockage d'une nouvelle valeur, se sera le premier format défini qui sera utilisé.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>La valeur par défaut est <em>["YmdHisO", "YmdHis.vO", "YmdHis.uO"]</em>, correspondant à la syntaxe
<code>Generalized Time</code> (sans et avec les milli-secondes ou micro-secondes) telle que définie dans
la <a href="https://tools.ietf.org/html/rfc4517">RFC4517</a>.
Exemples : <code>20091206230506Z</code> <em>(=2009/12/06 23:05:66 UTC)</em>, <code>20190613143537+0200</code>
<em>(=2019/06/13 14:35:37 UTC+0200)</em> ou <code>20230818121005.307+0200</code>
<em>(=2023/08/18 12:10:05.307 UTC+0200)</em>.</p>
</div>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>Si vous exploitez un attribut stockant une date incluant les milli-secondes ou les
micro-secondes, ce type d'attribut LDAP sera capable de gérer l'interpratation des valeurs
stockées, en outre le type d'attribut
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_date-lsattr_html_date">LSattr_html_date</a>, s'appuyant sur les
méthodes standards <code>strftime()</code> et <code>strptime()</code>, ne permettra pas aujourd'hui leur saisie et
affichage.</p>
</div>
</li>
</ul>
<ul>
<li>
<p><code>timezone</code></p>
<p>Fuseau horaire de stockage des dates dans l'annuaire LDAP. Les valeurs possibles sont documentées
dans <a href="https://www.php.net/timezones">la documentation officielle de PHP</a>. (Par défaut : <code>UTC</code>)</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_image"><h1 id="conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_image-lsattr_ldap_image">LSattr_ldap_image</h1>
<p>Ce type est utilisé pour la gestion des attributs dont la valeur est une image. Pour le moment,
aucun traitement particulier n'est appliqué pour le stockage.</p></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_naivedate"><h1 id="conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_naivedate-lsattr_ldap_naivedate">LSattr_ldap_naiveDate</h1>
<p>Ce type est utilisé pour la gestion des attributs dont la valeur est une date dont la <em>timezone</em>
doit être ignorée. Côté LDAP, les dates seront stockées au format UTC étant donnée que la syntaxe
LDAP exige une <em>timezone</em>, cependant celle-ci sera complètement ignorée. Ce type peut-être utilisé
à la place du type <a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_date-lsattr_ldap_date">LSattr_ldap_date</a>.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_naivedate-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>'ldap_options' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_naivedate-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'format' =&gt; '[Format de stockage]', // Default : "%Y%m%d%H%M%SZ"
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_naivedate-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a>),
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_naivedate-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a>...
</code></pre></div>
<ul>
<li>
<p><code>format</code></p>
<p>Format de stockage de la date dans l'annuaire. Ce format est composé à partir des motifs clés
gérés par la fonction <code>strftime()</code> de PHP. Pour plus d'information, consulter
<a href="http://www.php.net/strftime">la documentation officielle</a>.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>La valeur par défaut est <em>%Y%m%d%H%M%SZ</em>, correspondant à la syntaxe <code>Generalized Time</code> (sans
les micro-secondes) telle que définie dans la <a href="https://tools.ietf.org/html/rfc4517">RFC4517</a>.
Exemple : <code>20091206230506Z</code> <em>(=2009/12/06 23:05:66 UTC)</em>.</p>
</div>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_numeric"><h1 id="conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_numeric-lsattr_ldap_numeric">LSattr_ldap_numeric</h1>
<p>Ce type est utilisé pour la gestion des attributs dont la valeur est un nombre. Pour le moment,
aucun traitement particulier est n'appliqué pour le stockage.</p></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_password"><h1 id="conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_password-lsattr_ldap_password">LSattr_ldap_password</h1>
<p>Ce type est utilisé pour la gestion des attributs dont la valeur est un mot de passe.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_password-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>'ldap_options' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_password-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'encode' =&gt; '[Type d'encodage du mot de passe]',
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_password-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> 'encode_function' =&gt; '[Nom de la fonction d'encodage]',
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_password-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> 'verify_function' =&gt; '[Nom de la fonction de vérification]',
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_password-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a> 'no_random_crypt_salt' =&gt; '[Booléen]', // Désactivation de l'utilisation d'une salt aléatoire
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_password-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a> 'wildcardPassword' =&gt; '[mot de passe(s) en clair]',
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_password-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a> 'encodedWildcardPassword' =&gt; '[mot de passe(s) encodé(s)]'
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_password-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a>),
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_password-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a>...
</code></pre></div>
<ul>
<li>
<p><code>encode</code></p>
<p>Nom du type d'encodage du mot de passe utilisé. Les types d'encodages supportés sont les
suivants :</p>
<ul>
<li><code>argon2</code> (ou <code>argon2i</code>, PHP &gt;= 7.2)</li>
<li><code>argon2id</code> (PHP &gt;= 7.3)</li>
<li><code>md5crypt</code></li>
<li><code>crypt</code></li>
<li><code>ext_des</code></li>
<li><code>blowfish</code></li>
<li><code>sha</code></li>
<li><code>sha256</code></li>
<li><code>sha512</code></li>
<li><code>ssha</code></li>
<li><code>ssha256</code></li>
<li><code>ssha512</code></li>
<li><code>smd5</code></li>
<li><code>md5</code></li>
<li><code>clear</code></li>
</ul>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Valeur par défaut : <code>md5crypt</code></p>
</div>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>Si le type d'encodage est inconnu, ou qu'il n'est pas supporté par le serveur web, un message
d'erreur alertera l'utilisateur et le mot de passe sera stocké en clair.</p>
</div>
</li>
</ul>
<ul>
<li>
<p><code>encode_function</code></p>
<p>Nom d'une function qui sera utilisée afin d'encoder le mot de passe. Cette fonction recevra deux
paramètres : le <code>LSldapObject</code> et le mot de passe en clair.</p>
</li>
</ul>
<ul>
<li>
<p><code>verify_function</code></p>
<p>Nom d'une function qui sera utilisée afin de valider un mot de passe soumis par l'utilisateur par
rapport à celui stocké dans l'annuaire. Cette fonction recevra trois paramètres : le
<code>LSldapObject</code>,le mot de passe en clair et le mot de passe hashé. Si ce paramètre est omis et que
le paramètre <code>encode_function</code> est défini, le mot de passe à tester sera encodé à nouveau à l'aide
de la fonction <code>encode_function</code> et le résultat sera comparé avec le mot de passe stocké dans
l'annuaire.</p>
</li>
</ul>
<ul>
<li>
<p><code>no_random_crypt_salt</code></p>
<p>Désactivation de l'utilisation d'une salt générée aléatoirement au profit de l'utilisation des
deux premiers caractères du mot de passe. Ce paramètre impacte uniquement le type de cryptage
<code>crypt</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>wildcardPassword</code></p>
<p>Mot de passe (ou tableau de mot de passe) qui sera ajouté systématiquement, en plus du mot de
passe choisi. Il sera encodé de la même manière que pour le mot de passe choisi avant
enregistrement.</p>
</li>
</ul>
<ul>
<li>
<p><code>encodedWildcardPassword</code></p>
<p>Mot de passe (ou tableau de mot de passe) qui sera ajouté systématiquement, en plus du mot de
passe choisi. Contrairement à la directive <code>wildcardPassword</code>, le mot de passe ne sera pas encodé
avant enregistrement.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Cette directive peut cohabiter avec sa cousine <code>wildcardPassword</code>. Les mot de passes contenus
dans les deux directives seront alors ajoutés.</p>
</div>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_postaladdress"><h1 id="conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_postaladdress-lsattr_ldap_postaladdress">LSattr_ldap_postaladdress</h1>
<p>Ce type est utilisé pour la gestion des attributs dont la valeur est construite sur le modèle de
l'attribut standard <em>postalAddress</em>, c'est à dire dont les lignes sont séparées à l'aide du
caractère de délimiteur <code>$</code>.</p>
<p>Lors de la lecture des valeurs de ce type d'attribut dans l'annuaire, les caractères <code>$</code> seront
remplacés par des caractères <code>\n</code> et, à l'inverse, lors de l'écriture des valeurs de ce type
d'attribut dans l'annuaire, les caractères <code>\n</code> seront remplacés par des caractères <code>$</code>.</p></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory"><h1 id="conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-lsattr_ldap_pwdhistory">LSattr_ldap_pwdHistory</h1>
<p>Ce type est utilisé pour la gestion de l'attribut standard <em>pwdHistory</em>. Cet attribut, accessible en
lecture uniquement, stocke dans un format prédéfini l'historique des mots de passe d'une utilisateur
avec pour chaque entrée :</p>
<ul>
<li>la date et heure de l'ajout du mot de passe dans l'historique</li>
<li>l'OID de la syntaxe du mot de passe</li>
<li>la longueur du mot de passe</li>
<li>le mot de passe (hâché)</li>
</ul>
<p>Ce type d'attribut LDAP permettra de convertir la valeur en son équivalent <code>JSON</code> pour pouvoir être
traité à l'aide du type d'attribut HTML
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-lsattr_html_jsoncompositeattribute">LSattr_html_jsonCompositeAttribute</a>.</p>
<p><strong>Exemple de valeur de l'attribut pwdHistory :</strong></p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>20201202144718Z#1.3.6.1.4.1.1466.115.121.1.40#105#{SSHA512}XDSiR6Sh6W7gyVIk6Rr2OUv8rNPr+0rHF99d9lcirE/TnnEdkjkncIi5iPubErL5lpfgh8gXLgSfmqvmFcMqXLToC25xIqyk
</code></pre></div>
<p><strong>Exemple de valeur tranformée :</strong></p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a>{"time":1606920438,"syntaxOID":"1.3.6.1.4.1.1466.115.121.1.40","length":105,"hashed_password":"{SSHA512}XDSiR6Sh6W7gyVIk6Rr2OUv8rNPr+0rHF99d9lcirE/TnnEdkjkncIi5iPubErL5lpfgh8gXLgSfmqvmFcMqXLToC25xIqyk"}
</code></pre></div>
<p><strong>Exemple de configuration complète de l'attribut :</strong></p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-1" id="__codelineno-2-1" name="__codelineno-2-1"></a>'pwdHistory' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-2" id="__codelineno-2-2" name="__codelineno-2-2"></a> 'label' =&gt; 'Passwords in history',
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-3" id="__codelineno-2-3" name="__codelineno-2-3"></a> 'ldap_type' =&gt; 'pwdHistory',
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-4" id="__codelineno-2-4" name="__codelineno-2-4"></a> 'html_type' =&gt; 'jsonCompositeAttribute',
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-5" id="__codelineno-2-5" name="__codelineno-2-5"></a> 'html_options' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-6" id="__codelineno-2-6" name="__codelineno-2-6"></a> 'components' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-7" id="__codelineno-2-7" name="__codelineno-2-7"></a> 'time' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-8" id="__codelineno-2-8" name="__codelineno-2-8"></a> 'label' =&gt; 'Date added to history',
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-9" id="__codelineno-2-9" name="__codelineno-2-9"></a> 'type' =&gt; 'text',
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-10" id="__codelineno-2-10" name="__codelineno-2-10"></a> 'required' =&gt; true,
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-11" id="__codelineno-2-11" name="__codelineno-2-11"></a> 'multiple' =&gt; false,
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-12" id="__codelineno-2-12" name="__codelineno-2-12"></a> ),
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-13" id="__codelineno-2-13" name="__codelineno-2-13"></a> 'syntaxOID' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-14" id="__codelineno-2-14" name="__codelineno-2-14"></a> 'label' =&gt; 'Syntax OID',
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-15" id="__codelineno-2-15" name="__codelineno-2-15"></a> 'type' =&gt; 'text',
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-16" id="__codelineno-2-16" name="__codelineno-2-16"></a> 'required' =&gt; true,
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-17" id="__codelineno-2-17" name="__codelineno-2-17"></a> 'multiple' =&gt; false,
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-18" id="__codelineno-2-18" name="__codelineno-2-18"></a> ),
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-19" id="__codelineno-2-19" name="__codelineno-2-19"></a> 'length' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-20" id="__codelineno-2-20" name="__codelineno-2-20"></a> 'label' =&gt; 'Length',
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-21" id="__codelineno-2-21" name="__codelineno-2-21"></a> 'type' =&gt; 'text',
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-22" id="__codelineno-2-22" name="__codelineno-2-22"></a> 'required' =&gt; true,
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-23" id="__codelineno-2-23" name="__codelineno-2-23"></a> 'multiple' =&gt; false,
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-24" id="__codelineno-2-24" name="__codelineno-2-24"></a> ),
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-25" id="__codelineno-2-25" name="__codelineno-2-25"></a> 'hashed_password' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-26" id="__codelineno-2-26" name="__codelineno-2-26"></a> 'label' =&gt; 'Hashed password',
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-27" id="__codelineno-2-27" name="__codelineno-2-27"></a> 'type' =&gt; 'text',
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-28" id="__codelineno-2-28" name="__codelineno-2-28"></a> 'required' =&gt; true,
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-29" id="__codelineno-2-29" name="__codelineno-2-29"></a> 'multiple' =&gt; false,
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-30" id="__codelineno-2-30" name="__codelineno-2-30"></a> ),
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-31" id="__codelineno-2-31" name="__codelineno-2-31"></a> ),
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-32" id="__codelineno-2-32" name="__codelineno-2-32"></a> ),
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-33" id="__codelineno-2-33" name="__codelineno-2-33"></a> 'no_value_label' =&gt; 'History is empty.',
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-34" id="__codelineno-2-34" name="__codelineno-2-34"></a> 'multiple' =&gt; 1,
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-35" id="__codelineno-2-35" name="__codelineno-2-35"></a> 'rights' =&gt; array(
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-36" id="__codelineno-2-36" name="__codelineno-2-36"></a> 'admin' =&gt; 'r',
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-37" id="__codelineno-2-37" name="__codelineno-2-37"></a> ),
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-38" id="__codelineno-2-38" name="__codelineno-2-38"></a> 'view' =&gt; 1,
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-39" id="__codelineno-2-39" name="__codelineno-2-39"></a>),
</code></pre></div>
<p>La date et heure de l'ajout du mot de passe dans l'historique est convertie dans un format lisible.
Par défaut, ce format est <code>AAAA/MM/JJ HH:MM:SS</code>, mais il peut aussi est personnalisé via le
paramètre <code>date_format</code>. Ce format est composé à partir des motifs clés gérés par la fonction
<code>date()</code> de PHP. Pour plus d'information, consulter
<a href="http://www.php.net/date">la documentation officielle</a>.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>La valeur par défaut est <em>YmdHisO</em>, correspondant à la syntaxe <code>Generalized Time</code> telle que
définie dans la <a href="https://tools.ietf.org/html/rfc4517">RFC4517</a> et prévu par le
<a href="http://tools.ietf.org/id/draft-behera-ldap-password-policy-10.txt">Draft-behera-ldap-password-policy</a>
spécifiant cet attribut standard.</p>
</div></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_sambaacctflags"><h1 id="conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_sambaacctflags-lsattr_ldap_sambaacctflags">LSattr_ldap_sambaAcctFlags</h1>
<p>Ce type est prévu pour gérer l'attribut <em>sambaAcctFlags</em> du schéma Samba, qui au travers d'une seule
et unique valeur, respectant un format prévu, liste l'ensemble des drapeaux actifs d'un compte
Samba. Il transforme l'unique valeur de l'attribut LDAP en une liste de drapeaux actuellement
activés sur le compte. Il est conçu pour être utilisé conjointement avec le type d'attribut HTML
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_sambaacctflags-lsattr_html_sambaacctflags">LSattr_html_sambaAcctFlags</a>.</p></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_shadowexpire"><h1 id="conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_shadowexpire-lsattr_ldap_shadowexpire">LSattr_ldap_shadowExpire</h1>
<p>Ce type est prévu pour gérer l'attribut <code>shadowExpire</code> du schéma POSIX, qui une stocke une date sous
la forme d'un entier correspondant au nombre de jours depuis le premier 1er 1970. Il est prévu pour
être utilisé conjointement avec le type d'attribut HTML
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_date-lsattr_html_date">LSattr_html_date</a>.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Malgrés son nom, ce type d'attribut LDAP peux être utilisé pour d'autres attributs stockant ce
même format de date, tel-que l'attribut <code>shadowLastChange</code>.</p>
</div></section><h1 class="nav-section-title-end">Ended: Types d'attribut LDAP (LSattr_ldap)</h1><h4 class="nav-section-title">Types d'attribut HTML (LSattr_html)</h4><section class="print-page" id="conf-lsobject-lsattribute-lsattr_html"><h1 id="conf-lsobject-lsattribute-lsattr_html-configuration-des-attributs-html-lsattr_html">Configuration des attributs HTML (LSattr_html)</h1>
<p>Cette section décrit les options propres à chacun des types d'attributs HTML supportés par
LdapSaisie.</p></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_boolean"><h1 id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_boolean-lsattr_html_boolean">LSattr_html_boolean</h1>
<p>Ce type est utilisé pour la gestion des attributs dont la valeur est un booléen.</p>
<p>La valeur retournée est l'une des chaînes de caractères suivantes :</p>
<ul>
<li><code>yes</code> pour <em>Vrai</em></li>
</ul>
<ul>
<li><code>no</code> pour <code>False</code></li>
</ul>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_boolean-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>'html_options' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_boolean-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'true_label' =&gt; '[label]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_boolean-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> 'false_label' =&gt; '[label]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_boolean-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a>),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_boolean-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a>...
</code></pre></div>
<ul>
<li>
<p><code>true_label</code></p>
<p>Label affiché pour désigner la valeur <code>True</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>false_label</code></p>
<p>Label affiché pour désigner la valeur <code>False</code>.</p>
</li>
</ul>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Pour le moment, les attributs à valeurs multiples ne sont pas gérés.</p>
</div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Pour maîtriser les valeurs stockées dans l'annuaire, il faut coupler ce type d'attribut HTML
avec le type d'attribut LDAP <a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_boolean-lsattr_ldap_boolean">boolean</a></p>
</div>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>La définition de la valeur par défaut d'un attribut utilisant ce type HTML (paramètre
<code>default_value</code>), doit se faire à l'aide des valeurs <code>yes</code> ou <code>no</code>.</p>
</div></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_date"><h1 id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_date-lsattr_html_date">LSattr_html_date</h1>
<p>Ce type est utilisé pour la gestion des attributs dont la valeur est une date. L'outil de sélection
de date <a href="http://mootools.net/forge/p/mootools_datepicker">MooTools-DatePicker</a> est utilisé pour la
sélection graphique de la date et de l'heure.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_date-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>'html_options' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_date-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'format' =&gt; '[Format d'affichage de la date]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_date-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> 'time' =&gt; '[Booleen pour le choix ou non de l heure]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_date-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> 'manual' =&gt; '[Booleen pour l edition manuelle ou non]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_date-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a> 'showNowButton' =&gt; '[Booleen]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_date-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a> 'showTodayButton' =&gt; '[Booleen]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_date-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a> 'style' =&gt; '[Nom du style utilise]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_date-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a> 'special_values' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_date-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a> '[value]' =&gt; '[label]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_date-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a> [...]
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_date-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a> ),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_date-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a>),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_date-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a>...
</code></pre></div>
<ul>
<li>
<p><code>format</code></p>
<p>Format d'affichage de la date dans le champ de saisie. Ce format est composé à partir des motifs
clés suivants :</p>
<table>
<thead>
<tr>
<th>Mot clé</th>
<th>Valeur de substitution</th>
<th>Exemple de valeur</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>%a</code></td>
<td>Nom abrégé du jour de la semaine</td>
<td>De Sun à Sat</td>
</tr>
<tr>
<td><code>%A</code></td>
<td>Nom complet du jour de la semaine</td>
<td>De Sunday à Saturday</td>
</tr>
<tr>
<td><code>%b</code></td>
<td>Nom du mois, abrégé, suivant la locale</td>
<td>De Jan à Dec</td>
</tr>
<tr>
<td><code>%B</code></td>
<td>Nom complet du mois, suivant la locale</td>
<td>De January à December</td>
</tr>
<tr>
<td><code>%c</code></td>
<td>Date et heure préférées, basées sur la locale</td>
<td>Exemple : Tue Feb 5 00:45:10 2009 pour le 5 Février 2009 à 12:45:10 AM</td>
</tr>
<tr>
<td><code>%d</code></td>
<td>Jour du mois en numérique, sur 2 chiffres (avec le zéro initial)</td>
<td>De 01 à 31</td>
</tr>
<tr>
<td><code>%e</code></td>
<td>Jour du mois, avec un espace précédant le premier chiffre. L'implémentation Windows est différente, voyez après pour plus d'informations.</td>
<td>De 1 à 31</td>
</tr>
<tr>
<td><code>%H</code></td>
<td>L'heure, sur 2 chiffres, au format 24 heures</td>
<td>De 00 à 23</td>
</tr>
<tr>
<td><code>%I</code></td>
<td>Heure, sur 2 chiffres, au format 12 heures</td>
<td>De 01 à 12</td>
</tr>
<tr>
<td><code>%j</code></td>
<td>Jour de l'année, sur 3 chiffres avec un zéro initial</td>
<td>001 à 366</td>
</tr>
<tr>
<td><code>%m</code></td>
<td>Mois, sur 2 chiffres</td>
<td>De 01 (pour Janvier) à 12 (pour Décembre)</td>
</tr>
<tr>
<td><code>%M</code></td>
<td>Minute, sur 2 chiffres</td>
<td>De 00 à 59</td>
</tr>
<tr>
<td><code>%p</code></td>
<td>'AM' ou 'PM', en majuscule, basé sur l'heure fournie</td>
<td>Exemple : AM pour 00:31, PM pour 22:23</td>
</tr>
<tr>
<td><code>%s</code></td>
<td>Timestamp de l'époque Unix (identique à la fonction time())</td>
<td>Exemple : 305815200 pour le 10 Septembre 1979 08:40:00 AM</td>
</tr>
<tr>
<td><code>%S</code></td>
<td>Seconde, sur 2 chiffres</td>
<td>De 00 à 59</td>
</tr>
<tr>
<td><code>%T</code></td>
<td>Identique à "%H:%M:%S" Exemple : 21:34:17 pour 09:34:17 PM</td>
<td></td>
</tr>
<tr>
<td><code>%U</code></td>
<td>Numéro de la semaine de l'année donnée, en commençant par le premier Lundi comme première semaine</td>
<td>13 (pour la 13ème semaine pleine de l'année)</td>
</tr>
<tr>
<td><code>%w</code></td>
<td>Représentation numérique du jour de la semaine</td>
<td>De 0 (pour Dimanche) à 6 (pour Samedi)</td>
</tr>
<tr>
<td><code>%y</code></td>
<td>L'année, sur 2 chiffres</td>
<td>Exemple : 09 pour 2009, 79 pour 1979</td>
</tr>
<tr>
<td><code>%Y</code></td>
<td>L'année, sur 4 chiffres</td>
<td>Exemple : 2038</td>
</tr>
<tr>
<td><code>%z</code></td>
<td>Soit le décalage horaire depuis UTC, ou son abréviation (suivant le système d'exploitation)</td>
<td>Exemple : -0500 ou EST pour l'heure de l'Est</td>
</tr>
<tr>
<td><code>%Z</code></td>
<td>Le décalage horaire ou son abréviation NON fournie par %z (suivant le système d'exploitation)</td>
<td>Exemple : -0500 ou EST pour l'heure de l'Est</td>
</tr>
<tr>
<td><code>%%</code></td>
<td>Le caractère de pourcentage ("%")</td>
<td>---</td>
</tr>
</tbody>
</table>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>La valeur par défaut est <em>%d/%m/%Y, %T</em>. Exemple : <em>23/04/2009, 23:03:04</em></p>
</div>
</li>
</ul>
<ul>
<li>
<p><code>time</code></p>
<p>Booléen définissant si l'outil de sélection permetra ou non le choix de l'heure en plus de la date</p>
</li>
</ul>
<ul>
<li>
<p><code>manual</code></p>
<p>Booléen autorisant ou non l'édition manuelle du champs. Si ce paramètre vaut <code>False</code>, la sélection
se fera uniquement à l'aide de l'outil graphique</p>
</li>
</ul>
<ul>
<li>
<p><code>showNowButton</code></p>
<p>Booléen définissant si le bouton <em>Maintenant</em> est affiché ou non. Par défaut, il est affiché.</p>
</li>
</ul>
<ul>
<li>
<p><code>showTodayButton</code></p>
<p>Booléen définissant si le bouton <em>Aujourd'hui</em> est affiché ou non. Par défaut, il est affiché.</p>
</li>
</ul>
<ul>
<li>
<p><code>style</code></p>
<p>Nom du style d'affichage de l'outil de sélection. Les valeurs possibles sont par défaut :</p>
<ul>
<li><code>default</code></li>
<li><code>dashboard</code></li>
<li><code>vista</code></li>
<li><code>jqui</code></li>
</ul>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>La création de nouveau thème est possible. Pour plus d'information, consulter
<a href="http://mootools.net/forge/p/mootools_datepicker">l'aide de l'outil de sélection de date</a>.</p>
</div>
</li>
</ul>
<ul>
<li>
<p><code>special_values</code></p>
<p>Tableau listant les valeurs spéciales que peut prendre l'attribut. Dans ce tableau associatif, la
clé doit correspondre à la valeur de l'attribut (telle que fournie par
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_date-lsattr_ldap_date">l'attribut LDAP</a>) et la valeur associée au
label associé.</p>
<p>Ces valeurs spéciales seront proposées à l'utilisateur sous la forme de cases à cocher dans le
formulaire. Elles peuvent permettre par exemple de données une signification particulière au zéro
pour un attribut LDAP stockant un <em>timestamp</em>.</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_gpg_pub_key"><h1 id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_gpg_pub_key-lsattr_html_gpg_pub_key">LSattr_html_gpg_pub_key</h1>
<p>Ce type est utilisé pour la gestion des attributs dont la valeur est une clef publique GPG. Il
permet dans l'interface, d'avoir un affichage adapté à ce type de donnée.</p></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_image"><h1 id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_image-lsattr_html_image">LSattr_html_image</h1>
<p>Ce type est utilisé pour la gestion des attributs dont la valeur est une image. Pour le moment, les
attributs à valeurs multiples ne sont pas gérés.</p></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute"><h1 id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-lsattr_html_jsoncompositeattribute">LSattr_html_jsonCompositeAttribute</h1>
<p>Ce type est utilisé pour la gestion des attributs dont les valeurs sont des dictionnaires de valeurs
encodées aux formats <em>JSON</em>.</p>
<p>Exemple de valeur gérée :</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="p">{</span><span class="nt">"component1"</span><span class="p">:</span><span class="w"> </span><span class="s2">"value1"</span><span class="p">,</span><span class="w"> </span><span class="nt">"component2"</span><span class="p">:</span><span class="w"> </span><span class="s2">"value2"</span><span class="p">,</span><span class="w"> </span><span class="nt">"component3"</span><span class="p">:</span><span class="w"> </span><span class="s2">"value3"</span><span class="p">}</span>
</code></pre></div>
<p>Le principe est que ces dictionnaires contienent plusieurs composants référencés par leur clé et
stockant une valeur dont le type peut être un texte libre ou bien être issue d'une liste déroulante
configurable selon le même principe que le type d'attribut
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-lsattr_html_select_list">LSattr_html_select_list</a>.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a>'html_options' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-1-2" id="__codelineno-1-2" name="__codelineno-1-2"></a> 'components' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-1-3" id="__codelineno-1-3" name="__codelineno-1-3"></a> '[clé composant 1]' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-1-4" id="__codelineno-1-4" name="__codelineno-1-4"></a> 'label' =&gt; '[Label du composant]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-1-5" id="__codelineno-1-5" name="__codelineno-1-5"></a> 'help_info' =&gt; '[Message d'aide sur le composant]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-1-6" id="__codelineno-1-6" name="__codelineno-1-6"></a> 'type' =&gt; '[Type de la valeur stocké]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-1-7" id="__codelineno-1-7" name="__codelineno-1-7"></a> 'required' =&gt; [Booléen],
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-1-8" id="__codelineno-1-8" name="__codelineno-1-8"></a> 'multiple' =&gt; [Booléen],
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-1-9" id="__codelineno-1-9" name="__codelineno-1-9"></a> 'check_data' =&gt; =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-1-10" id="__codelineno-1-10" name="__codelineno-1-10"></a> // Régle de vérification syntaxique des données saisies
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-1-11" id="__codelineno-1-11" name="__codelineno-1-11"></a> ),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-1-12" id="__codelineno-1-12" name="__codelineno-1-12"></a> ),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-1-13" id="__codelineno-1-13" name="__codelineno-1-13"></a> '[clé composant 2]' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-1-14" id="__codelineno-1-14" name="__codelineno-1-14"></a> 'label' =&gt; '[Label du composant 2]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-1-15" id="__codelineno-1-15" name="__codelineno-1-15"></a> 'type' =&gt; 'select_list',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-1-16" id="__codelineno-1-16" name="__codelineno-1-16"></a> 'required' =&gt; [Booléen],
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-1-17" id="__codelineno-1-17" name="__codelineno-1-17"></a> 'options' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-1-18" id="__codelineno-1-18" name="__codelineno-1-18"></a> [Configuration équivalente à un attribut LSattr_html_select_list]
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-1-19" id="__codelineno-1-19" name="__codelineno-1-19"></a> )
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-1-20" id="__codelineno-1-20" name="__codelineno-1-20"></a> ),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-1-21" id="__codelineno-1-21" name="__codelineno-1-21"></a> [...]
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-1-22" id="__codelineno-1-22" name="__codelineno-1-22"></a> ),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-1-23" id="__codelineno-1-23" name="__codelineno-1-23"></a> 'fullWidth' =&gt; [booléen],
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-1-24" id="__codelineno-1-24" name="__codelineno-1-24"></a>),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-1-25" id="__codelineno-1-25" name="__codelineno-1-25"></a>...
</code></pre></div>
<ul>
<li>
<p><code>components</code></p>
<p>Tableau associatif obligatoire contenant en valeur clé, l'identifiant des composants,
correspondant à la clé dans le dictionnaire <em>JSON</em>, et en valeurs associés, la configuration du
composant.</p>
<ul>
<li>
<p><code>label</code></p>
<p>Le label du composant.</p>
</li>
</ul>
<ul>
<li>
<p><code>help_info</code></p>
<p>Message d'aide sur le composant (affiché uniquement en mode édition).</p>
</li>
</ul>
<ul>
<li>
<p><code>type</code></p>
<p>Le type de valeur du composant. Les types possibles sont <code>text</code> ou <code>select_list</code> pour
respectivement soit une valeur saisie librement, soit une valeur sélectionnée parmis une liste
déroulante.</p>
</li>
</ul>
<ul>
<li>
<p><code>options</code></p>
<p>Dans le cadre d'un composant de type <code>select_list</code>, cela correspond à la configuration de la
liste déroulante. Cette configuration utilise la même syntaxe de configuration que celle du type
d'attribut <a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-lsattr_html_select_list">LSattr_html_select_list</a> et son
paramètre <code>html_options</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>multiple</code></p>
<p>Booléen définissant si ce composant peut stocker plusieurs valeurs (Par défaut : <code>False</code>).</p>
</li>
</ul>
<ul>
<li>
<p><code>required</code></p>
<p>Booléen définissant si ce composant doit obligatoirement être défini (Par défaut : <code>False</code>).</p>
</li>
</ul>
<ul>
<li>
<p><code>check_data</code></p>
<p>Tableau associatif contenant les règles de vérification syntaxique des données du composant. Ces
règles sont configurables de la même manière que les celles des valeurs attributs.
<a href="#conf-lsobject-lsattribute-check_data-configuration-des-regles-de-verification-syntaxique">Voir la section concernée.</a></p>
</li>
</ul>
</li>
</ul>
<ul>
<li>
<p><code>fullWidth</code></p>
<p>Booléen permettant de définir si l'affichage dans le formulaire doit se faire sur toute la largeur
disponible de la page (Par défaut : <code>False</code>).</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_labeledvalue"><h1 id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_labeledvalue-lsattr_html_labeledvalue">LSattr_html_labeledValue</h1>
<p>Ce type est utilisé pour la gestion des attributs dont la valeur est prefixé d'un <code>label</code> et qui
respecte le format suivant : <code>[label]valeur</code>.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_labeledvalue-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>'html_options' =&gt; array(
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_labeledvalue-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'labels' =&gt; array ( // Liste des labels possible
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_labeledvalue-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> 'label1' =&gt; 'Libellé label1',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_labeledvalue-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> 'label2' =&gt; 'Libellé label2',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_labeledvalue-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a> [...]
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_labeledvalue-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a> ),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_labeledvalue-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a> 'translate_labels' =&gt; [booléen],
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_labeledvalue-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a>),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_labeledvalue-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a>...
</code></pre></div>
<ul>
<li>
<p><code>labels</code></p>
<p>Tableau associatif obligatoire contenant en valeur clé, le <code>label</code> utilisé dans la valeur stockée
et en valeur associée, le valeur d'affichage du <code>label</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>translate_labels</code></p>
<p>Booléen permettant d'activer/désactiver la traduction des labels (Par défaut : <code>True</code>).</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_mail"><h1 id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_mail-lsattr_html_mail">LSattr_html_mail</h1>
<p>Ce type est utilisé pour la gestion des attributs dont la valeur est une adresse e-mail. En plus
d'un affichage adapté, il offre la possibilité d'envoyer des mails directement depuis l'interface de
l'application.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_mail-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>'html_options' =&gt; array(
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_mail-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'disableMailSending' =&gt; [booléen],
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_mail-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a>),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_mail-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a>...
</code></pre></div>
<ul>
<li>
<p><code>disableMailSending</code></p>
<p>Désactive l'envoi de mail depuis l'interface pour cet attribut.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Ceci ne désactive pas pour autant le lien HTML de type <em>mailto:</em>. Pour cela, utilisez plutôt
le type d'attribut HTML <a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-lsattr_html_text">text</a>.</p>
</div>
</li>
</ul>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>Ce type d'attribut HTML est dérivé du type <a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-lsattr_html_text">text</a>. Il
profite donc de toutes les fonctionnalités d'un champ de ce type (autogénération, ...).</p>
</div></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_maildir"><h1 id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_maildir-lsattr_html_maildir">LSattr_html_maildir</h1>
<p>Ce type est utilisé pour la gestion des attributs dont la valeur est le chemin d'une maildir.
Typiquement, ce type attribut HTML est utile dans le cas de l'attribut <em>mailbox</em> utilisé par
maildrop pour stocker le chemin des boites mails. Ce type d'attribut offre la possibilité de gérér
un niveau de l'attribut et à travers les déclencheurs gérés par LdapSaisie la création, la
modification et ou la suppression de la boite mails.
Le <a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a>
<a href="#conf-lsaddon-lsaddon_maildir-lsaddon_maildir">maildir</a> est utilisé pour manipuler la boite
mail à distance.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Actuellement, cet <a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a> ne gérant que l'accès via FTP
au serveur distant, l'API d'accès via FTP est attaquée directement.</p>
</div>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_maildir-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>'html_options' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_maildir-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'LSform' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_maildir-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> '[LSform1]' =&gt; [booléen],
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_maildir-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> '[LSform2]' =&gt; [booléen],
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_maildir-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a> ...
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_maildir-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a> ),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_maildir-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a> 'remoteRootPathRegex' =&gt; "[Expression régulière pour matcher le dossier à créer]",
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_maildir-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a> 'archiveNameFormat' =&gt; "[LSformat du chemin/nom du fichier une fois archiver]"
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_maildir-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a> ),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_maildir-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a>...
</code></pre></div>
<ul>
<li>
<p><code>LSform</code></p>
<p>Tableau associatif obligatoire contenant en valeur clé le nom des <a href="#conf-lsobject-lsform-lsform">LSforms</a>
dans lesquels la fonctionnalité de modification de la boite mail sera présente. Les valeurs
attachées sont des booléens définissant si la modification est active par défaut.</p>
</li>
</ul>
<ul>
<li>
<p><code>remoteRootPathRegex</code></p>
<p>Expression régulière (compatible Perl) facultative dont le but est de <em>matcher</em> dans la valeur
complète du chemin distant de la <em>maildir</em>, le chemin de la <em>maildir</em> à créer une fois connecté
sur le serveur.</p>
<p>Exemple : Si le chemin complet de la <em>maildir</em> est <code>/home/vmail/user</code>, mais que l'utilisateur FTP
lorsqu'il se connecte arrive directement dans <code>/home/vmail</code>, et faut définir le paramètre
<code>remoteRootPathRegex</code> de la manière suivante :</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_maildir-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a>/^\/home\/vmail\/([^\/]*)\/+$/
</code></pre></div>
</li>
</ul>
<ul>
<li>
<p><code>archiveNameFormat</code></p>
<p><a href="#conf-global-lsformat-format-parametrable">LSformat</a> du nom du dossier de la <em>maildir</em> une
fois archivée. Si ce format est défini, le dossier ne sera pas supprimé mais déplacé ou rénommé.
Le format sera construit avec pour seul mot clé, le nom de l'ancien dossier. Exemple : Si le
dossier de la maildir est <code>/home/vmail/user</code> et le paramètre <code>archiveNameFormat</code> vaut
<code>%{old}.bckp</code>, le dossier sera renommé en <code>/home/vmail/user.bckp</code>.</p>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>Ce format est interprété après application de la routine liée au paramètre
<code>remoteRootPathRegex</code>. Ainsi, dans l'exemple précédent, si le paramètre <code>remoteRootPathRegex</code>
tronquait uniquement le nom du dossier final, c'est à dire <code>user</code>, le format une fois
interprété donnerai <code>user.bckp</code>.</p>
</div>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_mailquota"><h1 id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_mailquota-lsattr_html_mailquota">LSattr_html_mailQuota</h1>
<p>Ce type est utilisé pour la gestion des attributs dont la valeur est le quota d'une boite mail. Le
format de la valeur générée correspondant au format attendu par le serveur de mail
<a href="http://www.courier-mta.org/">Courier</a>] par défaut. Exemple : <em>50000000S</em> correspond à un quota de
50Mio.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_mailquota-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>'html_options' =&gt; array(
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_mailquota-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'suffix' =&gt; '[suffix]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_mailquota-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> )
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_mailquota-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a>),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_mailquota-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a>...
</code></pre></div>
<ul>
<li>
<p><code>suffix</code></p>
<p>Chaine de caractères suffixant la valeur du quota (Par défaut : <code>S</code>).</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_password"><h1 id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-lsattr_html_password">LSattr_html_password</h1>
<p>Ce type est utilisé pour la gestion des attributs dont la valeur est un mot de passe.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>'html_options' =&gt; array(
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'isLoginPassword' =&gt; [booleen],
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> 'generationTool' =&gt; [booleen],
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> 'autoGenerate' =&gt; [booleen],
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a> 'length' =&gt; [nombre de caractères],
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a> 'chars' =&gt; array ( // Caractères que peut contenir le mot de passe
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a> array( // Liste caractère avec un nombre mininum d'apparition supérieur à 1
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a> 'nb' =&gt; [nb caractères],
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a> 'chars' =&gt; '[liste de caractères possibles]'
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a> ),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a> '[autre liste de caractères possibles]', // Liste caractère avec un nombre
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a> // d'apparitions égal à 1
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a> ...
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a> ),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a> 'use_pwgen' =&gt; [booléen], // Utiliser pwgen pour la génération du mot de passe
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-16" id="__codelineno-0-16" name="__codelineno-0-16"></a> 'pwgen_path' =&gt; "/path/to/pwgen",
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-17" id="__codelineno-0-17" name="__codelineno-0-17"></a> 'pwgen_opts' =&gt; "[options à passer à pwgen]",
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-18" id="__codelineno-0-18" name="__codelineno-0-18"></a> 'verify' =&gt; [booléen], // Activation de l'outil de vérification du mot de passe
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-19" id="__codelineno-0-19" name="__codelineno-0-19"></a> 'viewHash' =&gt; [booléen], // Activation de l'outil de visualisation du mot de passe haché
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-20" id="__codelineno-0-20" name="__codelineno-0-20"></a> 'confirmChange' =&gt; [booléen], // Activation de la confirmation en cas de changement du mot de passe
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-21" id="__codelineno-0-21" name="__codelineno-0-21"></a> 'confirmChangeQuestion' =&gt; "[LSformat]", // LSformat de la question de confirmation du changement du mot de passe
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-22" id="__codelineno-0-22" name="__codelineno-0-22"></a> 'mail' =&gt; array( // Configuration de l'envoi du mot de passe par mail
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-23" id="__codelineno-0-23" name="__codelineno-0-23"></a> 'subject' =&gt; "[LSformat du sujet du mail]",
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-24" id="__codelineno-0-24" name="__codelineno-0-24"></a> 'msg' =&gt; "[LSformat du message du mail]",
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-25" id="__codelineno-0-25" name="__codelineno-0-25"></a> 'mail_attr' =&gt; 'mail', // Attribut mail de l'objet
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-26" id="__codelineno-0-26" name="__codelineno-0-26"></a> 'get_mail_attr_function' =&gt; '[function]', // Fonction retournant l'attribut mail de l'objet
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-27" id="__codelineno-0-27" name="__codelineno-0-27"></a> 'send' =&gt; 1, // Activation par défaut de l'envoi du mot de passe
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-28" id="__codelineno-0-28" name="__codelineno-0-28"></a> 'ask' =&gt; 1, // Laisser le choix à l'utilisateur
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-29" id="__codelineno-0-29" name="__codelineno-0-29"></a> 'canEdit' =&gt; 1, // Activation de l'édition du LSformat du message par l'utilisateur
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-30" id="__codelineno-0-30" name="__codelineno-0-30"></a> 'checkDomain' =&gt; false, // Désactivation de la vérification du domaine de l'adresse email
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-31" id="__codelineno-0-31" name="__codelineno-0-31"></a> 'domain' =&gt; '[nom de domaine]', // Nom de domaine obligatoire lors de la validation de l'adresse email
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-32" id="__codelineno-0-32" name="__codelineno-0-32"></a> )
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-33" id="__codelineno-0-33" name="__codelineno-0-33"></a>),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-34" id="__codelineno-0-34" name="__codelineno-0-34"></a>...
</code></pre></div>
<ul>
<li>
<p><code>isLoginPassword</code></p>
<p>Booléen définissant si le mot de passe est celui utilisé par l'utilisateur pour se logguer à
l'annuaire LDAP. Si c'est le cas, pour vérifier si le mot de passe correspond avec un autre, une
tentative de connexion de l'utilisateur à l'annuaire sera faite. (Par défaut : <code>False</code>)</p>
</li>
</ul>
<ul>
<li>
<p><code>generationTool</code></p>
<p>Booléen définissant si l'outil de génération de mot de passe est activé.</p>
</li>
</ul>
<ul>
<li>
<p><code>autoGenerate</code></p>
<p>Active la génération automatique du mot de passe lorsque l'attribut n'a encore aucune valeur de
définie. Il faut également que l'outil de génération soit activé (<code>generationTool</code>).</p>
</li>
</ul>
<ul>
<li>
<p><code>length</code></p>
<p>Nombre de caractères que devront contenir les mots de passe générés.</p>
</li>
</ul>
<ul>
<li>
<p><code>chars</code></p>
<p>Tableau contenant une liste de listes de caractères possibles pour composer le mot de passe. Dans
chacune de ces listes, au moins un caractère sera utilisé dans le nouveau mot de passe. Il est
possible de définir un nombre supérieur de caractères d'une liste devant apparaître dans les mots
de passe générés en spécifiant un tableau associatif dont la clé <em>nb</em> associra le nombre entier de
caractères et la clé <em>chars</em> la liste de caractères. Une liste de caractères est un chaîne.</p>
</li>
</ul>
<ul>
<li>
<p><code>use_pwgen</code></p>
<p>Booléen définissant si la commande <code>pwgen</code> doit être utilisé pour générer le mot de passe.</p>
</li>
</ul>
<ul>
<li>
<p><code>pwgen_path</code></p>
<p>Chemin d'accès au binaire <code>pwgen</code>. (Par défaut : <code>pwgen</code>).</p>
</li>
</ul>
<ul>
<li>
<p><code>pwgen_opts</code></p>
<p>Options à passer à la commande <code>pwgen</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>verify</code></p>
<p>Booléen définissant si l'outil de vérification du mot de passe est activé. Si celui-ci est activé,
l'utilisateur pourra entrer un mot de passe dans le champ et cliquer sur un bouton qui lancera une
procédure de vérification du mot de passe via un test de connexion à l'annuaire.</p>
</li>
</ul>
<ul>
<li>
<p><code>viewHash</code></p>
<p>Booléen définissant si l'utilisateur aura accès à la fonctionnalité de visualisation du mot de
passe haché.</p>
</li>
</ul>
<ul>
<li>
<p><code>confirmInput</code></p>
<p>Booléen définissant si un second champ mot de passe sera affiché dans le formulaire pour que
l'utilisateur confirme la saisie du nouveau mot de passe.</p>
</li>
</ul>
<ul>
<li>
<p><code>confirmInputError</code></p>
<p><a href="#conf-global-lsformat-format-parametrable">LSformat</a> du message d'erreur affiché à
l'utilisateur si le mot de passe saisie dans le champs de confirmation ne correspond pas au
nouveau mot de passe. <em>Paramètre facultatif.</em></p>
</li>
</ul>
<ul>
<li>
<p><code>confirmChange</code></p>
<p>Booléen définissant si l'utilisateur devra confirmer le changement de ce mot de passe. Lorsque
cette fonctionnalité est activée, l'utilisateur verra apparaître une popup de confirmation à la
validation du formulaire s'il a saisi un nouveau mot de passe.</p>
</li>
</ul>
<ul>
<li>
<p><code>confirmChangeQuestion</code></p>
<p><a href="#conf-global-lsformat-format-parametrable">LSformat</a> de la question posée à l'utilisateur
en cas de changement du mot de passe et si la fonctionnalité est activée. Il sera composé à l'aide
du <em>label</em> de l'attribut. <em>Paramètre facultatif.</em></p>
</li>
</ul>
<ul>
<li>
<p><code>clearView</code></p>
<p>Booléen définissant si l'utilisateur pourra voir le mot de passe en clair par défaut (y comris en
mode visualisation uniquement).</p>
</li>
</ul>
<ul>
<li>
<p><code>clearEdit</code></p>
<p>Booléen définissant si l'utilisateur éditera le mot de passe au travers un champs HTML de type
<em>text</em> et donc lisible ou au travers un champs HTML de type <em>password</em>.</p>
</li>
</ul>
<ul>
<li>
<p><code>mail</code></p>
<p>Paramètres de configuration de l'envoi par mail du mot de passe à l'utilisateur. Lorsque cet outil
est activé, lors de la modification/création du mot de passe, l'utilisateur pourra recevoir un
mail lui spécifiant son nouveau mot de passe.</p>
<ul>
<li>
<p><code>send</code></p>
<p>Booléen définissant si l'envoi du mot de passe est activé par défaut.</p>
</li>
</ul>
<ul>
<li>
<p><code>ask</code></p>
<p>Booléen définissant si on laisse le choix à l'utilisateur d'activer ou non l'envoi du mot de
passe par mail.</p>
</li>
</ul>
<ul>
<li>
<p><code>canEdit</code></p>
<p>Booléen définissant si on laisse la possibilité à l'utilisateur d'éditer le
<a href="#conf-global-lsformat-format-parametrable">LSformat</a> du message et du sujet.</p>
</li>
</ul>
<ul>
<li>
<p><code>subject</code></p>
<p><a href="#conf-global-lsformat-format-parametrable">LSformat</a> du sujet du mail. Ce format sera
composé avec la valeur du nouveau mot de passe de l'utilisateur.</p>
</li>
</ul>
<ul>
<li>
<p><code>msg</code></p>
<p><a href="#conf-global-lsformat-format-parametrable">LSformat</a> du message du mail. Ce format sera
composé avec les informations de l'object LDAP, y compris le mot clé <em>%{password}</em> correspondant
à la valeur du nouveau mot de passe de l'utilisateur.</p>
</li>
</ul>
<ul>
<li>
<p><code>mail_attr</code></p>
<p>Le nom de l'attribut listant les mails possibles de l'utilisateur. Par défaut, la première
valeur de l'attribut sera utilisée comme adresse mail destinatrice. Cet attribut peut également
être un tableau de plusieurs noms d'attributs. Dans ce cas, la première valeur correcte sera
retenue. Si <code>canEdit</code> est activé, l'utilisateur pourra choisir l'adresse mail destinatrice parmi
la liste des valeurs de l'attribut.</p>
</li>
</ul>
<ul>
<li>
<p><code>get_mail_attr_function</code></p>
<p>Nom de la fonction (ou <code>callable</code> au sens PHP) qui sera utilisé pour récupérer le nom de
l'attribut listant les mails possibles de l'utilisateur. Cette fonction prendra en paramètre,
l'objet <code>LSformElement</code> courant et devra retourner une valeur équivalente au paramètre de
configuration <code>mail_attr</code>. Si ce paramètre est défini, il prévalera toujours sur le paramètre
<code>mail_attr</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>bcc</code></p>
<p>Mettre en <em>BCC</em> un mail systématiquement (ou plusieurs en les séparant par des virgules).</p>
</li>
</ul>
<ul>
<li>
<p><code>headers</code></p>
<p>Un tableau de type clé/valeur ou la clé est le nom d'un header à ajouter au mail et la valeur
est la valeur de l'header en question.</p>
</li>
</ul>
<ul>
<li>
<p><code>checkDomain</code></p>
<p>Booléen définissant si le domaine de l'adresse mail doit être validée. *Paramètre facultatif,
par défaut: <code>True</code></p>
</li>
</ul>
<ul>
<li>
<p><code>domain</code></p>
<p>Nom de domaine obligatoire lors de la validation de l'adresse mail. Ce paramètre peut être une
simple chaine correspondant au domaine ou un tableau listant plusieurs domaines valides.
<em>Paramètre facultatif, par défaut tous les domaines sont acceptés.</em></p>
</li>
</ul>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_postaladdress"><h1 id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_postaladdress-lsattr_html_postaladdress">LSattr_html_postaladdress</h1>
<p>Ce type est utilisé pour la gestion des attributs du type de l'attribut standard <em>postalAddress</em>.
Ce type d'attribut permet d'afficher, en plus de l'adresse, un lien composé à partir d'informations
de l'objet permettant par exemple d'afficher un lien vers une carte géocalisant l'adresse postale.</p>
<p>Par défaut, le lien ajouté sera un lien de recherche de l'adresse postale générée à partir de la
valeur de l'attribut (en remplaçant les retours à la ligne (<code>\n</code>) par des espaces) via le service
<a href="http://nominatim.openstreetmap.org/">Nominatim d'OpenStreetMap</a>.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Dans le cadre du fonctionnement par défaut et pour maîtriser les valeurs stockées dans
l'annuaire, il faut coupler ce type d'attribut HTML avec le type d'attribut LDAP
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_postaladdress-lsattr_ldap_postaladdress">postaladdress</a></p>
</div>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_postaladdress-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>'html_options' =&gt; array(
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_postaladdress-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'map_url_pattern_format' =&gt; '[LSformat]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_postaladdress-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> 'map_url_pattern_generate_function' =&gt; '[callable]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_postaladdress-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> 'map_url_format' =&gt; '[LSformat]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_postaladdress-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a>),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_postaladdress-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a>...
</code></pre></div>
<ul>
<li>
<p><code>map_url_pattern_format</code></p>
<p>Ce <a href="#conf-global-lsformat-format-parametrable">LSformat</a> doit permettre de générer la valeur
de l'adresse postale qui sera insérée dans l'URL du lien ajouté dans l'interface.</p>
</li>
</ul>
<ul>
<li>
<p><code>map_url_pattern_generate_function</code></p>
<p>Ce paramètre permet de définir une fonction qui sera utilisée à la place du paramètre
<code>map_url_pattern_format</code> pour générer la valeur de l'adresse postale qui sera insérée dans l'URL
du lien ajouté dans l'interface. Cette fonction prendra en paramètre l'objet <em>LSformElement</em>
courant et devra retourner une chaîne de caractères correspondant à l'adresse postale à insérer
dans le lien de l'interface. Par défaut, la fonction
<code>LSformElement_postaladdress__generate_pattern</code> est utilisée.</p>
</li>
</ul>
<ul>
<li>
<p><code>map_url_format</code></p>
<p>Ce <a href="#conf-global-lsformat-format-parametrable">LSformat</a> doit permettre de générer l'URL du
lien ajouté dans l'interface. Il sera composé avec les informations de l'objet LDAP, y compris le
mot clé <code>%{pattern}</code> correspondant à la valeur de l'adresse postale générée à l'aide des
paramètres précédents. Par défaut, la format suivant sera utilisé :
<code>http://nominatim.openstreetmap.org/search.php?q=%{pattern}</code></p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_pre"><h1 id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_pre-lsattr_html_pre">LSattr_html_pre</h1>
<p>Ce type est dérivé du type <a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_textarea-lsattr_html_textarea">LSattr_html_textarea</a> et
permet simplement que lors de l'affichage de la valeur, celle-ci soit affichée en respectant les
retours à la ligne et en utilisant une police de caractères <code>monospace</code>. Cela reproduit l'affichage
d'une balise HTML <code>pre</code>.</p></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_rss"><h1 id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_rss-lsattr_html_rss">LSattr_html_rss</h1>
<p>Ce type est utilisé pour la gestion des attributs dont la valeur est l'URL d'un flux RSS. Il propose
directement dans l'interface, la possibilité d'accèder au flux RSS.</p>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>Ce type d'attribut HTML est dérivé du type <a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-lsattr_html_text">text</a>. Il
profite donc de toutes les fonctionnalités d'un champ de ce type (autogénération, ...).</p>
</div></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_sambaacctflags"><h1 id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_sambaacctflags-lsattr_html_sambaacctflags">LSattr_html_sambaAcctFlags</h1>
<p>Ce type est prévu pour gérer l'attribut <em>sambaAcctFlags</em> du schéma Samba, qui au travers d'une seule
et unique valeur, respectant un format prévu, liste l'ensemble des drapeaux actifs d'un compte
Samba. Il est conçu pour être utilisé conjointement avec le type d'attribut LDAP
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_sambaacctflags-lsattr_ldap_sambaAcctFlags">LSattr_ldap_sambaAcctFlags</a>.</p>
<p>Pour définir la valeur par défaut de cet attribut, il faut définir paramètre <code>default_value</code> comme
un tableau des drapeaux telque prévu par Samba :</p>
<p>- <code>U</code></p>
<div class="highlight"><pre><span></span><code>Compte utilisateur standard
</code></pre></div>
<p>- <code>W</code></p>
<div class="highlight"><pre><span></span><code>Compte de poste de travail approuvé
</code></pre></div>
<p>- <code>S</code></p>
<div class="highlight"><pre><span></span><code>Compte de serveur approuvé
</code></pre></div>
<p>- <code>I</code></p>
<div class="highlight"><pre><span></span><code>Compte de domaine approuvé
</code></pre></div>
<p>- <code>M</code></p>
<div class="highlight"><pre><span></span><code>Compte de connexion Majority Node Set (MNS)
</code></pre></div>
<p>- <code>H</code></p>
<div class="highlight"><pre><span></span><code>Dossier personnel requis
</code></pre></div>
<p>- <code>N</code></p>
<div class="highlight"><pre><span></span><code>Compte sans mot de passe
</code></pre></div>
<p>- <code>X</code></p>
<div class="highlight"><pre><span></span><code>Le mot de passe n'expire jamais
</code></pre></div>
<p>- <code>D</code></p>
<div class="highlight"><pre><span></span><code>Compte désactivé
</code></pre></div>
<p>- <code>T</code></p>
<div class="highlight"><pre><span></span><code>Copie temporaire d'un autre compte
</code></pre></div>
<p>- <code>L</code></p>
<div class="highlight"><pre><span></span><code>Compte automatiquement bloqué
</code></pre></div>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_sambaacctflags-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a> Exemple de valeur par défaut...
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_sambaacctflags-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a>'default_value' =&gt; array('U', 'X'),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_sambaacctflags-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a>...
</code></pre></div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Ce type d'attribut est implémenté en dérivant le type <em>LSattr_html_select_box</em> dont les valeurs
possibles sont pré-configurées (paramètre <code>possible_values</code>). Même si cela n'est pas forcément
utiles, les autres paramètres du type parent restent utilisables.</p>
</div></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_box"><h1 id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_box-lsattr_html_select_box">LSattr_html_select_box</h1>
<p>Ce type est identique au type <em>LSattr_html_select_list</em> excepté qu'il utilise en lieu et place d'une
balise HTML <code>select</code>, plusieurs balises HTML <code>input</code> de type <code>checkbox</code> en cas de valeurs multiples
ou de type <code>radio</code> en cas de valeur unique. Les paramètres de configuration de la classe
<em>LSattr_html_select_list</em> sont tous hérités et fonctionnent donc de la même manière. Par ailleurs,
ce type dispose également de paramètres qui lui sont propre (voir ci-dessous).</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_box-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>'html_options' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_box-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'inline' =&gt; [Booléen],
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_box-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a>),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_box-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a>...
</code></pre></div>
<ul>
<li>
<p><code>inline</code></p>
<p>Booléen définissant si les valeurs possibles doivent être affichées sur une même ligne ou non
(Faux par défaut).</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list"><h1 id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-lsattr_html_select_list">LSattr_html_select_list</h1>
<p>Ce type est utilisé pour la gestion des attributs dont les valeurs font partie d'une liste statique
ou dynamique. Il est possible de lister des valeurs statiques et également des références à d'autres
<a href="#conf-configuration-lsobject">LSobjects</a>. La référence à un objet correspond à une
valeur clé, référente à un objet précis, qui peut être soit la valeur d'un de ses attributs, soit
son <em>DN</em>.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>'html_options' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'possible_values' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> '[LSformat de la valeur clé]' =&gt; '[LSformat du nom d'affichage]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> ...
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a> 'OTHER_OBJECT' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a> 'object_type' =&gt; '[Type d'LSobject]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a> 'display_name_format' =&gt; '[LSformat du nom d'affichage des LSobjects]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a> 'value_attribute' =&gt; '[Nom de l'attribut clé]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a> 'values_attribute' =&gt; '[Nom de l'attribut clé multi-valeur]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a> 'filter' =&gt; '[Filtre de recherche des LSobject]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a> 'scope' =&gt; '[Scope de la recherche]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a> 'basedn' =&gt; '[Basedn de la recherche]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a> 'onlyAccessible' =&gt; '[Booléen]'
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a> ),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a> 'OTHER_ATTRIBUTE' =&gt; '[attr]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-16" id="__codelineno-0-16" name="__codelineno-0-16"></a> // Or :
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-17" id="__codelineno-0-17" name="__codelineno-0-17"></a> 'OTHER_ATTRIBUTE' =&gt; array(
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-18" id="__codelineno-0-18" name="__codelineno-0-18"></a> '[attr1]' =&gt; '[label1]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-19" id="__codelineno-0-19" name="__codelineno-0-19"></a> '[attr2]' =&gt; '[label2]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-20" id="__codelineno-0-20" name="__codelineno-0-20"></a> [...]
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-21" id="__codelineno-0-21" name="__codelineno-0-21"></a> ),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-22" id="__codelineno-0-22" name="__codelineno-0-22"></a> // Or :
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-23" id="__codelineno-0-23" name="__codelineno-0-23"></a> 'OTHER_ATTRIBUTE' =&gt; array(
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-24" id="__codelineno-0-24" name="__codelineno-0-24"></a> 'attr' =&gt; [attr],
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-25" id="__codelineno-0-25" name="__codelineno-0-25"></a> 'json_component_key' =&gt; '[Composant JSON clé]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-26" id="__codelineno-0-26" name="__codelineno-0-26"></a> 'json_component_label' =&gt; '[Composant JSON label]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-27" id="__codelineno-0-27" name="__codelineno-0-27"></a> ),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-28" id="__codelineno-0-28" name="__codelineno-0-28"></a> array (
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-29" id="__codelineno-0-29" name="__codelineno-0-29"></a> 'label' =&gt; '[LSformat du nom du groupe de valeurs]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-30" id="__codelineno-0-30" name="__codelineno-0-30"></a> 'possible_values' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-31" id="__codelineno-0-31" name="__codelineno-0-31"></a> '[LSformat de la valeur clé]' =&gt; '[LSformat du nom d'affichage]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-32" id="__codelineno-0-32" name="__codelineno-0-32"></a> ...
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-33" id="__codelineno-0-33" name="__codelineno-0-33"></a> 'OTHER_OBJECT' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-34" id="__codelineno-0-34" name="__codelineno-0-34"></a> ...
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-35" id="__codelineno-0-35" name="__codelineno-0-35"></a> )
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-36" id="__codelineno-0-36" name="__codelineno-0-36"></a> )
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-37" id="__codelineno-0-37" name="__codelineno-0-37"></a> )
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-38" id="__codelineno-0-38" name="__codelineno-0-38"></a> ),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-39" id="__codelineno-0-39" name="__codelineno-0-39"></a> 'get_possible_values' =&gt; [callable],
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-40" id="__codelineno-0-40" name="__codelineno-0-40"></a> 'translate_labels' =&gt; [booléen],
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-41" id="__codelineno-0-41" name="__codelineno-0-41"></a> 'sort' =&gt; [Booléen],
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-42" id="__codelineno-0-42" name="__codelineno-0-42"></a> 'sortDirection' =&gt; '[ASC|DESC]'
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-43" id="__codelineno-0-43" name="__codelineno-0-43"></a>),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-__codelineno-0-44" id="__codelineno-0-44" name="__codelineno-0-44"></a>...
</code></pre></div>
<ul>
<li>
<p><code>possible_values</code></p>
<p>Tableau associatif obligatoire contenant en valeur clé le
<a href="#conf-global-lsformat-format-parametrable">LSformat</a> des valeurs clés prisent par
l'attribut et en valeurs associées, le <a href="#conf-global-lsformat-format-parametrable">LSformat</a>
des noms d'affichage de ces valeurs. Ces <a href="#conf-global-lsformat-format-parametrable">LSformats</a>
sont composés à partir des valeurs de l'objet courant (attributs, dn, ...).</p>
<p>Si la valeur clé est égale à <code>OTHER_OBJECT</code>, une liste
d'<a href="#conf-configuration-lsobject">LSobject</a> sera insérée dans la liste des valeurs
possibles. La valeur associée est alors un tableau associatif dont les valeurs clés sont les noms
des paramètres de configuration de la recherche de ces
<a href="#conf-configuration-lsobject">LSobjects</a> et les valeurs associées, les valeurs des
paramètres.</p>
<p>Il est possible de regrouper des valeurs de l'attribut en plaçant leur déclaration dans un
sous-tableau. Ce sous-tableau devra contenir la clé <code>label</code> dont la valeur associé sera le
<a href="#conf-global-lsformat-format-parametrable">LSformat</a> du nom du groupe de valeurs. Ce
<a href="#conf-global-lsformat-format-parametrable">LSformat</a> est composé à partir des valeurs de
l'objet courant (attributs, dn, ...). Une seconde clé <code>possible_values</code> regroupera les valeurs
possibles du groupe. Comme pour le tableau principal, la clé <code>OTHER_OBJECT</code> permet d'imcorporer
une liste d'<a href="#conf-configuration-lsobject">LSobject</a>.</p>
<ul>
<li>
<p><code>object_type</code></p>
<p>Nom du type d'<a href="#conf-configuration-lsobject">LSobject</a> en référence.</p>
</li>
</ul>
<ul>
<li>
<p><code>display_name_format</code></p>
<p><a href="#conf-global-lsformat-format-parametrable">LSformat</a> du nom d'affichage des objets lors
de leur sélection.</p>
</li>
</ul>
<ul>
<li>
<p><code>value_attribute</code></p>
<p>Nom de l'attribut des <a href="#conf-configuration-lsobject">LSobjects</a> en référence servant
de valeur clé et permettant de les identifier (Exemple : <code>dn</code> ou <code>uid</code>).</p>
</li>
</ul>
<ul>
<li>
<p><code>values_attribute</code></p>
<p>Nom de l'attribut des <a href="#conf-configuration-lsobject">LSobjects</a> en référence servant
de catalogue de valeurs. Dans ce mode, la valeur n'a pas de label et est affichée directement
dans l'interface. Ce paramètre peut-être utilisé en complément ou non du paramètre
<code>value_attribute</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>filter</code></p>
<p>Filtre falcultatif de la recherche des LSobjets. Il sera dans tous les cas agrémenté des valeurs
des <em>objectclass</em> du type d'<a href="#conf-configuration-lsobject">LSobject</a>.</p>
</li>
</ul>
<ul>
<li>
<p><code>scope</code></p>
<p>Scope falcultatif de la recherche des LSobjets.</p>
</li>
</ul>
<ul>
<li>
<p><code>basedn</code></p>
<p>Basedn falcultatif de la recherche des LSobjets.</p>
</li>
</ul>
<ul>
<li>
<p><code>onlyAccessible</code></p>
<p>Booléen falcultatif définissant si seul les LSobjets auxquels l'utilisateur connecté à accès
doivent être considérés comme sélectionnables (Faux par défaut).</p>
</li>
</ul>
<p>Si la valeur clé est égale à <code>OTHER_ATTRIBTE</code>, une liste de valeur possible sera composée à l'aide
des valeurs d'un (ou plusieurs) autre attribut de l'objet courant. La valeur associée peut être
alors :</p>
<ul>
<li>soit le nom d'un attribut dont les valeurs seront utilisées comme valeurs possibles (la valeur
affichée est égale à la valeur stockée).</li>
</ul>
<ul>
<li>soit un tableau associatif dont les valeurs clés sont les noms des attributs dont les valeurs
seront utilisés comme valeurs possibles et dont les valeurs associés seront les labels sous
lesquels ces valeurs seront regroupées (la valeur affichée est égale à la valeur stockée).</li>
</ul>
<ul>
<li>soit un tableau associatif référençant un attribut sous la clé <code>attr</code> dont les valeurs seront
utilisées comme valeurs possibles. Cet attribut peut-être du type
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-lsattr_html_jsoncompositeattribute">LSattr_html_jsonCompositeAttribute</a>.
Il sera alors possible d'utiliser les valeurs d'un composant en particulier en le référençant à
l'aide de la clé <code>json_component_key</code>. Il est également possible de référencer un autre
composant à l'aide de la clé <code>json_component_label</code> et dont les valeurs seront utilisées comme
valeurs affichées lors de la sélection. À défaut, les valeurs affichées seront identiques à
celles stockées.</li>
</ul>
</li>
</ul>
<ul>
<li>
<p><code>get_possible_values</code></p>
<p>Paramètre permettant de spécifier un <em>callable</em> qui sera utilisé pour lister les valeurs possibles
de l'attribut. Il recevra en paramètres les informations suivantes:</p>
<ul>
<li>
<p><code>$options</code></p>
<p>Les options HTML de l'attribut.</p>
</li>
</ul>
<ul>
<li>
<p><code>$name</code></p>
<p>Le nom de l'attribut.</p>
</li>
</ul>
<ul>
<li>
<p><code>&amp;$ldapObject</code></p>
<p>Une référence à l'objet <code>LSldapObject</code>.</p>
</li>
</ul>
<p>La valeur de retour attendue est un tableau associatif des valeurs possibles de l'attribut avec la
valeur que prendra l'attribut en tant que clé et le label correspondant en tant que valeur. Tout
autre retour sera considéré comme un échec et déclenchera une erreur.</p>
<p>Il est également possible de regrouper des valeurs possibles de l'attribut: pour cela, le tableau
retourné devra lui-même contenir un tableau associatif contenant la label traduit du groupe sous
la clé <code>label</code> et les valeurs possibles du groupe sous la clé <code>possible_values</code>.</p>
<p>Les valeurs retournées pourront être combinées avec les autres valeurs possibles configurées de
l'attribut. La prise en charge du tri des valeurs possibles est assurée par la fonction appelante
sauf dans le cas des sous-groupes de valeurs possibles. Dans ce cas, la méthode
<code>LSattr_html_select_list :: _sort()</code> pourra être utilisée pour trier les valeurs du sous-groupe :
cette méthode accepte en paramètre une référence du tableau des valeurs possibles ainsi que les
options HTML de l'attribut.</p>
<p>Si la traduction des labels des valeurs possibles de l'attribut est activées (voir ci-dessous),
celle-ci doit être prise en charge par la fonction configurée.</p>
</li>
</ul>
<ul>
<li>
<p><code>translate_labels</code></p>
<p>Booléen permettant d'activer/désactiver la traduction des labels (Par défaut : <code>True</code>).</p>
</li>
</ul>
<ul>
<li>
<p><code>sort</code></p>
<p>Booléen définissant si les valeurs possibles doivent être triées ou non (Vrai par défaut). Le trie
est effectué sur les libellés des valeurs possibles.</p>
</li>
</ul>
<ul>
<li>
<p><code>sortDirection</code></p>
<p>Mot clé déterminant le sens du trie des valeurs possibles.</p>
<p>Valeurs possibles : <code>ASC</code> ou <code>DESC</code> (<code>ASC</code> par défaut).</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_object"><h1 id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_object-lsattr_html_select_object">LSattr_html_select_object</h1>
<p>Ce type est utilisé pour la gestion des attributs dont les valeurs sont des références à d'autres
<a href="#conf-configuration-lsobject">LSobjects</a>. Chaque référence à un objet correspond à une
valeur prise par l'attribut. Les valeurs clés référant à un
<a href="#conf-configuration-lsobject">LSobject</a> sont soit la valeur d'un de leurs attributs,
soit leur <em>DN</em>.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_object-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>'html_options' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_object-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> selectable_object =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_object-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> array (
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_object-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> 'object_type' =&gt; '[Type d'LSobject selectionnable]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_object-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a> 'display_name_format' =&gt; '[LSformat du nom d'affichage des LSobjects]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_object-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a> 'value_attribute' =&gt; '[Nom de l'attribut clé des LSobjects]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_object-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a> 'filter' =&gt; '[Filtre de recherche]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_object-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a> 'onlyAccessible' =&gt; '[Booléen]'
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_object-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a> ),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_object-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a> [...]
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_object-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a> ),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_object-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a> 'ordered' =&gt; [Booléen],
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_object-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a> 'sort' =&gt; [Booléen],
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_object-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a> 'sortDirection' =&gt; '[ASC|DESC]'
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_object-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a>),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_object-__codelineno-0-16" id="__codelineno-0-16" name="__codelineno-0-16"></a>...
</code></pre></div>
<ul>
<li>
<p><code>selectable_object</code></p>
<p>Tableau dont chaque valeur correspond à un tableau associatif spécifiant un type
d'<a href="#conf-configuration-lsobject">LSobject</a> sélectionnable. Pour chaque type d'objet
sélectionnable, les paramètres suivants doivent être renseignés :</p>
<ul>
<li>
<p><code>object_type</code></p>
<p>Nom du type d'<a href="#conf-configuration-lsobject">LSobject</a> en référence
<em>(Paramètre obligatoire)</em>.</p>
</li>
</ul>
<ul>
<li>
<p><code>display_name_format</code></p>
<p><a href="#conf-global-lsformat-format-parametrable">LSformat</a> du nom d'affichage des objets lors
de leur sélection <em>(Paramètre facultatif)</em>.</p>
</li>
</ul>
<ul>
<li>
<p><code>value_attribute</code></p>
<p>Nom de l'attribut des <a href="#conf-configuration-lsobject">LSobjects</a> en référence servant
de valeur clé et permettant de les identifier <em>(Paramètre obligatoire, exemples : <code>dn</code> ou <code>uid</code>)</em>.</p>
</li>
</ul>
<ul>
<li>
<p><code>filter</code></p>
<p>Filtre de recherche qui sera ajouter au filtre par défaut lors de la sélection des objets
<em>(Paramètre facultatif)</em>.</p>
</li>
</ul>
<ul>
<li>
<p><code>onlyAccessible</code></p>
<p>Booléen définissant si seul les LSobjets auxquels l'utilisateur connecté à accès doivent être
considérés comme sélectionnables <em>(Paramètre facultatif, par défaut: <code>False</code>)</em>.</p>
</li>
</ul>
</li>
</ul>
<ul>
<li>
<p><code>ordered</code></p>
<p>Booléen définissant si la liste des objets choisis doit être ordonnable ou non <em>(Paramètre
facultatif, par défaut: <code>False</code>)</em>. Cela aura pour effet d'activer une fonctionnalité dynamique de
l'interface permettant de remonter ou descendre dans la liste les objets choisis.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Cette fonctionnalité désactive automatiquement le trie des objets à l'affichage.</p>
</div>
</li>
</ul>
<ul>
<li>
<p><code>sort</code></p>
<p>Booléen définissant si la liste des objets choisis doit être triée ou non <em>(Paramètre facultatif,
par défaut: <code>True</code>)</em>. Le trie est effectué sur les libellés des objets choisis.</p>
</li>
</ul>
<ul>
<li>
<p><code>sortDirection</code></p>
<p>Mot clé déterminant le sens du trie des objets choisis.</p>
<p>Valeurs possibles : <code>ASC</code> ou <code>DESC</code> (<code>ASC</code> par défaut).</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_ssh_key"><h1 id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_ssh_key-lsattr_html_ssh_key">LSattr_html_ssh_key</h1>
<p>Ce type est utilisé pour la gestion des attributs dont la valeur est une clef publique SSH. Il
permet dans l'interface, d'avoir un affichage adapté à ce type de donnée.</p></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_tel"><h1 id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_tel-lsattr_html_tel">LSattr_html_tel</h1>
<p>Ce type est utilisé pour la gestion des attributs dont la valeur est un numéro de téléphone. Lors de
l'affichage, un lien hypertexte avec une URI de type <code>tel:~~</code> est affiché.</p>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>Ce type d'attribut HTML est dérivé du type <a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-lsattr_html_text">text</a>. Il
profite donc de toutes les fonctionnalités d'un champ de ce type (autogénération, ...).</p>
</div></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_text"><h1 id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-lsattr_html_text">LSattr_html_text</h1>
<p>Ce type est utilisé pour la gestion des attributs dont la valeur est une chaîne de caractères devant
être affichée dans un champ <em>input</em> HTML de type <em>text</em>.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>'html_options' =&gt; array(
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'generate_value_format' =&gt; '[LSformat pour la génération de la valeur]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> 'autoGenerateOnCreate' =&gt; [booléen],
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> 'autoGenerateOnModify' =&gt; [booléen],
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a> 'withoutAccent' =&gt; [booleen],
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a> 'replaceSpaces' =&gt; "[chaîne de remplacement]",
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a> 'upperCase' =&gt; [booleen],
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a> 'lowerCase' =&gt; [booleen],
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a>
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a> // Autocomplétion
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a> 'autocomplete' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a> 'object_type' =&gt; '[Type d'LSobject]', // facultatif (voir ci-dessous)
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a> 'value_attributes' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a> '[attr1]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a> '[attr2]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-__codelineno-0-16" id="__codelineno-0-16" name="__codelineno-0-16"></a> [...]
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-__codelineno-0-17" id="__codelineno-0-17" name="__codelineno-0-17"></a> ),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-__codelineno-0-18" id="__codelineno-0-18" name="__codelineno-0-18"></a> 'filter' =&gt; '[filtre LDAP]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-__codelineno-0-19" id="__codelineno-0-19" name="__codelineno-0-19"></a> 'basedn' =&gt; '[base DN spécifique]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-__codelineno-0-20" id="__codelineno-0-20" name="__codelineno-0-20"></a> 'scope' =&gt; '[scope de recherche]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-__codelineno-0-21" id="__codelineno-0-21" name="__codelineno-0-21"></a> 'displayFormat' =&gt; '[LSformat]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-__codelineno-0-22" id="__codelineno-0-22" name="__codelineno-0-22"></a> 'onlyAccessible' =&gt; [booléen],
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-__codelineno-0-23" id="__codelineno-0-23" name="__codelineno-0-23"></a> ),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-__codelineno-0-24" id="__codelineno-0-24" name="__codelineno-0-24"></a>
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-__codelineno-0-25" id="__codelineno-0-25" name="__codelineno-0-25"></a>),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-__codelineno-0-26" id="__codelineno-0-26" name="__codelineno-0-26"></a>...
</code></pre></div>
<ul>
<li>
<p><code>generate_value_format</code></p>
<p><a href="#conf-global-lsformat-format-parametrable">LSformat</a> de la valeur utilisée pour la
génération automatique de celle-ci à partir des informations saisies dans le formulaire. Les
valeurs clefs du format sont les noms des attributs de l'objet. Seuls les attributs affichés au
moins en lecture seule dans le formulaire peuvent être utilisés dans le format. Une seule valeur
par attribut sera utilisée pour la génération : celle du premier champ (dans l'ordre d'apparition
dans le formulaire).</p>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>Seuls les éléments du formulaire de type HTML <em>input</em>, <em>select</em> ou <em>textarea</em> peuvent être
utilisés.</p>
</div>
</li>
</ul>
<ul>
<li>
<p><code>autoGenerateOnCreate</code></p>
<p>Activation de la génération automatique lorsque celui-ci est vide au moment du chargement du
formulaire (par défaut : <code>False</code>).</p>
</li>
</ul>
<ul>
<li>
<p><code>autoGenerateOnModify</code></p>
<p>Activation de la génération automatique lors de chaque modification de la valeur des champs du
formulaire lié (par défaut : <code>False</code>).</p>
</li>
</ul>
<ul>
<li>
<p><code>withoutAccent</code></p>
<p>Activation de la suppression des accents dans la chaîne de caractères générée automatiquement
(par défaut : <code>False</code>).</p>
</li>
</ul>
<ul>
<li>
<p><code>withoutAccent</code></p>
<p>Activation du remplacement des accents dans la chaîne de caractères générée automatiquement. La
valeur de remplacement est celle du paramètre (par défaut : <code>False</code>).</p>
</li>
</ul>
<ul>
<li>
<p><code>upperCase</code></p>
<p>Activation de la mise en majuscule de la valeur générée automatiquement (par défaut : <code>False</code>).</p>
</li>
</ul>
<ul>
<li>
<p><code>lowerCase</code></p>
<p>Activation de la mise en minuscule de la valeur générée automatiquement (par défaut : <code>False</code>).</p>
</li>
</ul>
<ul>
<li>
<p><code>autocomplete</code></p>
<p>Paramètrage de l'autocomplétion des valeurs saisies : on paramètre ici la recherche des valeurs
possibles de l'attribut dans l'annuaire qui peut se faire :</p>
<ul>
<li>Sur la base d'un type d'<a href="#conf-configuration-lsobject">LSobject</a> donné :
l'autocomplétion se fera alors comme n'importe quelle recherche d'un type d'objet donné.</li>
</ul>
<ul>
<li>Sur la base d'une recherche brute dans l'annuaire : l'autocomplétion se fera alors au travers
une recherche brute dans l'annuaire sur n'importe quels objets ayant un des attributs spécifiés
dans le paramètre <code>value_attributes</code> correspondant.</li>
</ul>
<p>Les paramètres associés à ces deux cas de figure sont décrits ci-dessous :</p>
<ul>
<li>
<p><code>object_type</code></p>
<p>Le type d'<a href="#conf-configuration-lsobject">LSobject</a> recherché.</p>
</li>
</ul>
<ul>
<li>
<p><code>value_attributes</code></p>
<p>Le(s) nom de l'attribut stockant les valeurs possibles recherchées. Il peut s'agir d'une chaîne
de caractères ou d'un tableau s'il y a plusieurs attributs.</p>
</li>
</ul>
<ul>
<li>
<p><code>pattern_filter</code></p>
<p>Le <a href="#conf-global-lsformat-format-parametrable">LSformat</a> du filtre de recherche à partir
du mot clé recherché. Ce paramètre est facultatif et utile que dans le cas d'une recherche sans
type d'<a href="#conf-configuration-lsobject">LSobject</a> précis. S'il est défini, ce
<a href="#conf-global-lsformat-format-parametrable">LSformat</a> sera composé à l'aide du mot clé
recherché. À défaut, le filtre de recherche sera composé à l'aide des différents
<code>value_attributes</code> configurés.</p>
</li>
</ul>
<ul>
<li>
<p><code>filter</code></p>
<p>Un filtre de recherche facultatif venant en plus de celui calculé automatiquement à partir du
mot clé de recherche.</p>
</li>
</ul>
<ul>
<li>
<p><code>basedn</code></p>
<p>Le <em>basedn</em> de la recherche. <em>Paramètre facultatif.</em></p>
</li>
</ul>
<ul>
<li>
<p><code>scope</code></p>
<p>Le <em>scope</em> de la recherche. <em>Paramètre facultatif, par défaut : <code>sub</code>.</em></p>
</li>
</ul>
<ul>
<li>
<p><code>display_name_format</code></p>
<p>Le <a href="#conf-global-lsformat-format-parametrable">LSformat</a> d'affichage des objets trouvés.
Ce paramètre est facultatif et par défaut, il s'agira du format d'affichage propre au type
d'<a href="#conf-configuration-lsobject">LSobject</a> (si défini) et à défaut, la valeur
possible trouvée sera affichée. Si est configuré, ce
<a href="#conf-global-lsformat-format-parametrable">LSformat</a> sera composé à l'aide des valeurs
brutes des attributs des objets correspondants avec en plus la valeur possible trouvée dans le
mot clé <code>value</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>only_accessible</code></p>
<p>Booléen falcultatif définissant si seul les
<a href="#conf-configuration-lsobject">LSobjects</a> auxquels l'utilisateur connecté à accès
doivent être considérés comme sélectionnables (Faux par défaut). Ce paramètre n'est appliqué que
dans le cas d'une recherche pour un type d'<a href="#conf-configuration-lsobject">LSobject</a>
donné.</p>
</li>
</ul>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_textarea"><h1 id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_textarea-lsattr_html_textarea">LSattr_html_textarea</h1>
<p>Ce type est utilisé pour la gestion des attributs dont la valeur est une chaine de caractères trop
longue pour être saisie dans un champs HTML <em>imput</em> de type <em>text</em> et est plus adapté à un champ
HTML <em>textarea</em>.</p></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_url"><h1 id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_url-lsattr_html_url">LSattr_html_url</h1>
<p>Ce type est utilisé pour la gestion des attributs dont la valeur est une URL. Il propose directement
dans l'interface, la possibilité d'accèder au site ou encore de l'ajouter dans ses favoris
(lorsque le navigateur le supporte).</p>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>Ce type d'attribut HTML est dérivé du type <a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-lsattr_html_text">text</a>. Il
profite donc de toutes les fonctionnalités d'un champ de ce type (autogénération, ...).</p>
</div></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_valuewithunit"><h1 id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_valuewithunit-lsattr_html_valuewithunit">LSattr_html_valueWithUnit</h1>
<p>Ce type est utilisé pour la gestion des attributs dont la valeur est un entier auxquel un facteur
peut s'appliquer (par exemple : <code>Kilo, Méga, ...</code>).</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_valuewithunit-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>'html_options' =&gt; array(
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_valuewithunit-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'units' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_valuewithunit-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> '[facteur1]' =&gt; '[label unit1]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_valuewithunit-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> '[facteur2]' =&gt; '[label unit2]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_valuewithunit-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a> [...]
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_valuewithunit-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a> ),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_valuewithunit-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a> 'translate_labels' =&gt; [booléen],
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_valuewithunit-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a> 'nb_decimals' =&gt; [number of decimals],
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_valuewithunit-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a> 'dec_point' =&gt; '[decimals point]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_valuewithunit-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a> 'thousands_sep' =&gt; '[thousands separator]',
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_valuewithunit-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a> 'store_integer' =&gt; [booléen],
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_valuewithunit-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a> 'round_down' =&gt; [booléen],
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_valuewithunit-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a> )
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_valuewithunit-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a>),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_valuewithunit-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a>...
</code></pre></div>
<ul>
<li>
<p><code>units</code></p>
<p>Tableau associatif dont la clé est un entier correspondant au facteur et la valeur est le label de
l'unité. (Par exemple : <code>1 =&gt; Octet, 1024 =&gt; Kilo-octet, ...</code>).</p>
</li>
</ul>
<ul>
<li>
<p><code>translate_labels</code></p>
<p>Booléen permettant d'activer/désactiver la traduction des labels (Par défaut : <code>True</code>).</p>
</li>
</ul>
<ul>
<li>
<p><code>nb_decimals</code></p>
<p>Le nombre de décimals à afficher en cas de nombre non-entier (Par défaut : <code>2</code>).</p>
</li>
</ul>
<ul>
<li>
<p><code>dec_point</code></p>
<p>Le caractère à utiliser comme séparateur de décimal (Par défaut, une virgule).</p>
</li>
</ul>
<ul>
<li>
<p><code>thousands_sep</code></p>
<p>Le caractère à utiliser comme séparateur de milliers (Par défaut, un espace).</p>
</li>
</ul>
<ul>
<li>
<p><code>store_integer</code></p>
<p>Booléen permettant d'activer/désactiver le stockage de valeurs entières (Par défaut : <code>True</code>).</p>
</li>
</ul>
<ul>
<li>
<p><code>round_down</code></p>
<p>Booléen permettant d'arrondir à l'entier inférieur (et non à l'entier supérieur par défaut) en cas
de stockage de valeurs entières.</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_wysiwyg"><h1 id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_wysiwyg-lsattr_html_wysiwyg">LSattr_html_wysiwyg</h1>
<p>Ce type est utilisé pour la gestion des attributs dont la valeur est du code HTML et dont l'édition
doit être fait à l'aide d'un éditeur <em>WYSIWYG</em>. La librairie <a href="https://www.tinymce.com">TinyMCE</a>
est utilisée pour cela.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_wysiwyg-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>'html_options' =&gt; array(
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_wysiwyg-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'extra_options' =&gt; array (
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_wysiwyg-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> [Options à passer à TinyMCE]
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_wysiwyg-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> ),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_wysiwyg-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a>),
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_wysiwyg-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a>...
</code></pre></div>
<ul>
<li>
<p><code>extra_options</code></p>
<p>Ce paramètre permet de passer des options à <a href="https://www.tinymce.com">TinyMCE</a> pour personnaliser
son comportement. Par exemple, il est possible d'utiliser le paramètre <code>valid_styles</code> pour définir
quels styles CSS sont autorisés. Pour plus d'informations, consultez la documentation de
<a href="https://www.tinymce.com">TinyMCE</a> .</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_xmpp"><h1 id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_xmpp-lsattr_html_xmpp">LSattr_html_xmpp</h1>
<p>Ce type est utilisé pour la gestion des attributs dont la valeur est une adresse XMPP. Il propose
directement dans l'interface, la possibilité de lancer une fenêtre de dialogue avec l'interlocuteur
de son client XMPP préféré.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Cette fonctionnalité n'est supporté uniquement par les navigateurs web supportant les URI de
type <code>xmpp://</code>.</p>
</div>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>Ce type d'attribut HTML est dérivé du type <a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-lsattr_html_text">text</a>. Il
profite donc de toutes les fonctionnalités d'un champ de ce type (autogénération, ...).</p>
</div></section><h1 class="nav-section-title-end">Ended: Types d'attribut HTML (LSattr_html)</h1><h4 class="nav-section-title">Règles de vérification syntaxique (LSformRule)</h4><section class="print-page" id="conf-lsobject-lsattribute-check_data"><h1 id="conf-lsobject-lsattribute-check_data-configuration-des-regles-de-verification-syntaxique">Configuration des règles de vérification syntaxique</h1>
<p>Cette section décrit la manière de configuer des règles de vérification syntaxique sur les données
des attributs. Ces règles seront utilisées pour vérifier que les valeurs saisies par un utilisateur
dans un formulaire sont correctes.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-check_data-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>'check_data' =&gt; array (
<a href="#conf-lsobject-lsattribute-check_data-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> '[regle1]' =&gt; array(
<a href="#conf-lsobject-lsattribute-check_data-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> 'msg' =&gt; "[Message d'erreur]",
<a href="#conf-lsobject-lsattribute-check_data-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> 'params' =&gt; array(
<a href="#conf-lsobject-lsattribute-check_data-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a> // Paramètres de la règle
<a href="#conf-lsobject-lsattribute-check_data-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a> )
<a href="#conf-lsobject-lsattribute-check_data-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a> ),
<a href="#conf-lsobject-lsattribute-check_data-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a> ...
<a href="#conf-lsobject-lsattribute-check_data-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a>),
<a href="#conf-lsobject-lsattribute-check_data-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a>...
</code></pre></div>
<p>Le paramètre <code>check_data</code> est un tableau associatif dont les clés sont les noms des règles de
vérification syntaxique actives et les valeurs associées sont des tableaux associatifs contenant les
paramètres des règles.</p>
<ul>
<li>
<p><code>msg</code></p>
<p>Le message d'erreur à afficher lors que la règle n'est pas respectée (optionnel).</p>
</li>
</ul>
<ul>
<li>
<p><code>params</code></p>
<p>Tableau associatif contenant les paramètres de la règle. Les paramètres possibles sont propres à
chaque type de règle. Les clès sont les noms des paramètres et les valeurs associés, les valeurs
des paramètres.</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-alphanumeric"><h1 id="conf-lsobject-lsattribute-check_data-alphanumeric-alphanumeric">alphanumeric</h1>
<p>Cette règle vérifie que la valeur est une chaîne de caractères composée uniquement de lettres
non-accuentées, en minuscule ou en majuscule et/ou de chiffres.</p>
<ul>
<li>
<p><code>withAccents</code></p>
<p>Si le paramètre est à <em>true</em>, les lettres accentuées seront acceptées.</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-callable"><h1 id="conf-lsobject-lsattribute-check_data-callable-callable">callable</h1>
<p>Cette règle vérifie que la valeur saisie est correcte en utilisant une fonction personnalisée. Cette
fonction devra prendre en paramètres la valeur à valider, le tableau des paramètres de la règle
ainsi qu'un pointeur sur l'objet <em>LSformElement</em>. Sur la base de ses informations, elle devra
valider la valeur et retourner <code>True</code> si la valeur est valide et <code>False</code> sinon.</p>
<ul>
<li>
<p><code>callable</code></p>
<p>Le nom de la fonction (ou tout autre <code>callable</code> au sens PHP) de validation.</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-date"><h1 id="conf-lsobject-lsattribute-check_data-date-date">date</h1>
<p>Cette règle vérifie que la valeur saisie est bien une date et qu'elle respecte un format précis.</p>
<ul>
<li>
<p><code>format</code></p>
<p>Format de la date à respecter. Ce format doit être compatible avec la fonction <code>strftime()</code> de
PHP. <a href="http://www.php.net/strftime">Voir la documentation de la fonction</a></p>
</li>
</ul>
<ul>
<li>
<p><code>special_values</code></p>
<p>Tableau listant les valeurs spéciales que peut prendre l'attribut. Dans ce tableau, seules les
valeurs sont utilisées et les clés n'ont pas d'importance. Ces valeurs spéciales n'auront pas
forcément besoin de respecter le format attendu.</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-differentpassword"><h1 id="conf-lsobject-lsattribute-check_data-differentpassword-differentpassword">differentPassword</h1>
<p>Cette règle vérifie que la valeur saisie ne correspond pas à un des mots de passe stockés dans
d'autres attributs du même objet.</p>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>Les autres attributs doivent utiliser le type d'attribut <em>LDAP</em>
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_password-lsattr_ldap_password">LSattr_ldap_password</a>.</p>
</div>
<ul>
<li>
<p><code>otherPasswordAttributes</code></p>
<p>La liste des autres attributs dont les mots de passe doivent être différent.</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-email"><h1 id="conf-lsobject-lsattribute-check_data-email-email">email</h1>
<p>Cette règle vérifie que la valeur saisie est bien une adresse e-mail. Il est possible de vérifier si
elle appartient bien à un domaine en particulier ou encore de vérifier si le domaine existe et qu'il
possède un serveur de mail(MX).</p>
<ul>
<li>
<p><code>domain</code></p>
<p>Nom de domaine obligatoire. Ce paramètre peut être une simple chaine correspondant au domaine ou
un tableau listant plusieurs domaines possibles.</p>
</li>
</ul>
<ul>
<li>
<p><code>checkDomain</code></p>
<p>Booléen définissant si le domaine de l'adresse mail doit être validée.</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-filesize"><h1 id="conf-lsobject-lsattribute-check_data-filesize-filesize">filesize</h1>
<p>Cette règle vérifie que la valeur est un fichier dont la taille en octets respecte les limites
passées en paramètre.</p>
<ul>
<li>
<p><code>minSize</code></p>
<p>Taille minimum.</p>
</li>
</ul>
<ul>
<li>
<p><code>maxSize</code></p>
<p>Taille maximum.</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-gpg_pub_key"><h1 id="conf-lsobject-lsattribute-check_data-gpg_pub_key-gpg_pub_key">gpg_pub_key</h1>
<p>Cette règle vérifie que la valeur est une clé publique GPG. Pour cela, la clé est importée dans un
<em>keyring</em> GnuPG.</p></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-imagefile"><h1 id="conf-lsobject-lsattribute-check_data-imagefile-imagefile">imagefile</h1>
<p>Cette règle vérifie que la valeur est bien un fichier et que le type mime de celui-ci est bien une
image. Cette règle utilise la règle mimetype en spécifiant si l'utilisateur ne le fait pas que le
type mime doit respecter la regex suivante : <code>/image\/.*/</code></p>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>Cette règle est une simple interface à la règle mimetype, il est donc possible de passer
d'autres paramètres propres à ce type.</p>
</div></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-imagesize"><h1 id="conf-lsobject-lsattribute-check_data-imagesize-imagesize">imagesize</h1>
<p>Cette règle vérifie que la valeur est une image dont la taille en pixels respecte les limites
passées en paramètre.</p>
<ul>
<li>
<p><code>minWidth</code></p>
<p>Largeur minimum.</p>
</li>
</ul>
<ul>
<li>
<p><code>maxWitdh</code></p>
<p>Largeur maximum.</p>
</li>
</ul>
<ul>
<li>
<p><code>minHeight</code></p>
<p>Hauteur minimum.</p>
</li>
</ul>
<ul>
<li>
<p><code>maxHeight</code></p>
<p>Hauteur maximum.</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-inarray"><h1 id="conf-lsobject-lsattribute-check_data-inarray-inarray">inarray</h1>
<p>Cette règle vérifie que la valeur saisie fait partie d'une liste de valeurs autorisées
(ou interdites).</p>
<ul>
<li>
<p><code>possible_values</code></p>
<p>Tableau listant les valeurs autorisées.</p>
</li>
</ul>
<ul>
<li>
<p><code>reverse</code></p>
<p>Booléen permettant d'inverser la logique de validation : si <code>reverse</code> est vrai, la valeur testée
sera acceptée si elle ne fait pas partie des valeurs possibles (Paramètre facultatif, par défaut :
<code>False</code>).</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-integer"><h1 id="conf-lsobject-lsattribute-check_data-integer-integer">integer</h1>
<p>Cette règle vérifie que la valeur saisie est un entier. Les paramètres permettent de spécifier
éventuellement si la valeur doit être positive ou négative et également de borner les valeurs
valides.</p>
<ul>
<li>
<p><code>positive</code></p>
<p>Booléen définissant si la valeur doit être positive.</p>
</li>
</ul>
<ul>
<li>
<p><code>negative</code></p>
<p>Booléen définissant si la valeur doit être negative.</p>
</li>
</ul>
<ul>
<li>
<p><code>min</code></p>
<p>Valeur minimale (supérieur ou égale).</p>
</li>
</ul>
<ul>
<li>
<p><code>max</code></p>
<p>Valeur maximale (inférieur ou égale).</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-ldapsearchuri"><h1 id="conf-lsobject-lsattribute-check_data-ldapsearchuri-ldapsearchuri">ldapSearchURI</h1>
<p>Cette règle vérifie que la valeur est une URI de recherche LDAP valide, c'est à dire, par exemple,
<code>ldaps://ldap.example.com:636/o=example?attr1,attr2?one?(gidNumber=100)</code></p>
<p>Cette vérification commence par découper la valeur à l'aide du sépérateur <code>?</code> et elle s'assure
ensuite :</p>
<ul>
<li>Que la première partie est bien une URI LDAP valide. Si l'hôte LDAP est spécifié, elle s'assure
qu'il soit une adresse IP ou un nom de domaine valide. Si le port LDAP est spécifié, elle s'assure
également qu'il soit correct et que l'hôte est également bien spécifié.</li>
</ul>
<ul>
<li>Si la base de recherche est spécifiée, elle s'assure qu'elle soit compatible avec la racine de
l'annuaire connecté.</li>
</ul>
<ul>
<li>Si un ou plusieurs attributs sont spécifiés, elle les vérifie un à un afin de vérifier qu'il
s'agit de nom d'attribut valide.</li>
</ul>
<ul>
<li>Que le scope de recherche soit bien spécifié et valide.</li>
</ul>
<ul>
<li>Si le filtre de recherche est spécifié, elle vérifie qu'il soit valide.</li>
</ul>
<p><strong>Paramêtres de configuration :</strong></p>
<ul>
<li>
<p><code>check_resolving_ldap_host</code></p>
<p>Si l'hôte du serveur LDAP est spécifié et qu'il s'agit d'un nom de domaine valide, un tentative de
résolution DNS sera également faite (optionnel, par défaut : <code>True</code>).</p>
</li>
</ul>
<ul>
<li>
<p><code>host_required</code></p>
<p>Booléen détermintant si une erreur est relevée en cas d'absence de l'hôte LDAP. (optionnel,
par défaut : <code>False</code>)</p>
</li>
</ul>
<ul>
<li>
<p><code>basedn_required</code></p>
<p>Booléen détermintant si une erreur est relevée en cas d'absence de base de recherche. (optionnel,
par défaut : <code>False</code>)</p>
</li>
</ul>
<ul>
<li>
<p><code>scope_required</code></p>
<p>Booléen détermintant si une erreur est relevée en cas d'absence de portée de recherche.
(optionnel, par défaut : <code>True</code>)</p>
</li>
</ul>
<ul>
<li>
<p><code>attr_required</code></p>
<p>Booléen détermintant si une erreur est relevée en cas d'absence d'attribut recherché. (optionnel,
par défaut : <code>False</code>)</p>
</li>
</ul>
<ul>
<li>
<p><code>max_attrs_count</code></p>
<p>Nombre maximum d'attribut recherchés. (optionnel, par défaut : pas de limite)</p>
</li>
</ul>
<ul>
<li>
<p><code>filter_required</code></p>
<p>Booléen détermintant si une erreur est relevée en cas d'absence de filtre de recherche.
(optionnel, par défaut : <code>False</code>)</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-lettersonly"><h1 id="conf-lsobject-lsattribute-check_data-lettersonly-lettersonly">lettersonly</h1>
<p>Cette règle vérifie que la valeur est une chaîne de caractères composée uniquement de lettres
non-accuentées, en minuscule ou en majuscule.</p></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-maxlength"><h1 id="conf-lsobject-lsattribute-check_data-maxlength-maxlength">maxlength</h1>
<p>Cette règle vérifie que la valeur saisie est une chaine de caractères dont la longueur est inférieur
ou égale à la valeur passées en paramètre.</p>
<ul>
<li>
<p><code>limit</code></p>
<p>Limite supérieur (ou égale) de la longueur de la chaîne de caratères.</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-mimetype"><h1 id="conf-lsobject-lsattribute-check_data-mimetype-mimetype">mimetype</h1>
<p>Cette règle vérifie que la valeur est bien un fichier et que le type mime de celui-ci est correct.
Il est possible de vérifier si le type mime fait partie d'une liste ou encore s'il valide une
expression régulière.</p>
<ul>
<li>
<p><code>mimeType</code></p>
<p>Type mime obligatoire. Ce paramètre peut être une simple chaine correspondant au type mime ou un
tableau listant plusieurs possibilités.</p>
</li>
</ul>
<ul>
<li>
<p><code>mimeTypeRegEx</code></p>
<p>Expression régulière que doit respecter le type mime.</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-minlength"><h1 id="conf-lsobject-lsattribute-check_data-minlength-minlength">minlength</h1>
<p>Cette règle vérifie que la valeur saisie est une chaine de caractères dont la longueur est supérieur
ou égale à la valeur passée en paramètre.</p>
<ul>
<li>
<p><code>limit</code></p>
<p>Limite inférieure (ou égale) de la longueur de la chaîne de caratères.</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-nonzero"><h1 id="conf-lsobject-lsattribute-check_data-nonzero-nonzero">nonzero</h1>
<p>Cette régle vérifie que la valeur est une valeur numérique non nulle.</p></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-nopunctuation"><h1 id="conf-lsobject-lsattribute-check_data-nopunctuation-nopunctuation">nopunctuation</h1>
<p>Cette régle vérifie que la valeur est une chaîne de caractères ne contenant pas de signe de
ponctuation. Les caractères suivants sont actuellement exclus :
<code>( ) . \ / \ * \ ^ \ ? # ! @ $ % + = , " ' &gt; &lt; ~ [ ] { }</code></p></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-numberofvalues"><h1 id="conf-lsobject-lsattribute-check_data-numberofvalues-numberofvalues">numberOfValues</h1>
<p>Cette règle vérifie que le nombre de valeurs de l'attribut est comprise entre les limites passées en
paramètre.</p>
<ul>
<li>
<p><code>min</code></p>
<p>Nombre minimum de valeurs (paramètre optionnel).</p>
</li>
</ul>
<ul>
<li>
<p><code>max</code></p>
<p>Nombre maximum de valeurs (paramètre optionnel).</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-numeric"><h1 id="conf-lsobject-lsattribute-check_data-numeric-numeric">numeric</h1>
<p>Cette régle vérifie que la valeur est une valeur numérique.</p></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-password"><h1 id="conf-lsobject-lsattribute-check_data-password-password">password</h1>
<p>Cette règle vérifie que la valeur est un mot de passe respectant la politique de sécurité définie
par les paramètres de la règle.</p>
<ul>
<li>
<p><code>minlength</code></p>
<p>Longueur minimale du mot de passe.</p>
</li>
</ul>
<ul>
<li>
<p><code>maxlength</code></p>
<p>Longueur maximale du mot de passe.</p>
</li>
</ul>
<ul>
<li>
<p><code>prohibitedValues</code></p>
<p>Tableau de valeurs interdites.</p>
</li>
</ul>
<ul>
<li>
<p><code>regex</code></p>
<p>Expression(s) régulière(s) que doit respecter le mot de passe. Ce paramètre peut être une
expression régulière au format <a href="http://php.net/pcre.pattern">PCRE</a> ou un tableau d'expressions
régulières.</p>
</li>
</ul>
<ul>
<li>
<p><code>minValidRegex</code></p>
<p>Le nombre minimum d'expression régulière qui doivent être validées pour que le mot de passe soit
considéré comme correct. Ce paramètre est optionnel, par défaut, toutes les expressions régulières
doivent être validées.</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-rangelength"><h1 id="conf-lsobject-lsattribute-check_data-rangelength-rangelength">rangelength</h1>
<p>Cette règle vérifie que la valeur saisie est une chaine de caractères dont la longueur est comprise
entre deux valeurs passées en paramètre.</p>
<ul>
<li>
<p><code>limits</code></p>
<p>Tableau contenant deux valeurs, la première étant la limite inférieure ou égale et la seconde la
limite supérieure ou égale.</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-regex"><h1 id="conf-lsobject-lsattribute-check_data-regex-regex">regex</h1>
<p>Cette règle vérifie que la valeur saisie respecte bien l'expression régulière passée en paramètre.</p>
<ul>
<li>
<p><code>regex</code></p>
<p>L'expression régulière devant être respectée. Cette expression régulière doit être au format
<a href="http://php.net/pcre.pattern">PCRE</a>.</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-required"><h1 id="conf-lsobject-lsattribute-check_data-required-required">required</h1>
<p>Cette régle vérifie que la valeur n'est pas une chaîne de caractères de longueur nulle.</p></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-ssh_pub_key"><h1 id="conf-lsobject-lsattribute-check_data-ssh_pub_key-ssh_pub_key">ssh_pub_key</h1>
<p>Cette règle vérifie que la valeur est une clé publique SSH.</p>
<p>Cette vérification utilise tout d'abord une expression régulière pour valider la forme syntaxique de
la clé publique (<code>ssh-[type] [clé au format base64] [commentaire]</code>) puis tente de décoder la partie
en base64 de la clé pour vérifier qu'il s'agit bien d'une chaine de caractères.</p></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-telephonenumber"><h1 id="conf-lsobject-lsattribute-check_data-telephonenumber-telephonenumber">telephonenumber</h1>
<p>Cette régle vérifie que la valeur est un numéro de téléphone français. Celui-ci doit respecter
l'expression regulière suivante : <code>/^(01|02|03|04|05|06|08|09)[0-9]{8}$/</code></p></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-zxcvbn"><h1 id="conf-lsobject-lsattribute-check_data-zxcvbn-zxcvbn">zxcvbn</h1>
<p>Cette règle vérifie la sécurité d'un mot de passe en utilisant la librairie
<a href="https://gitlab.easter-eggs.com/ee/zxcvbn-php">ZxcvbnPhp</a>. Cette librairie s'appuie sur un ensemble
de vérifications permettant de déterminer à quel point le mot de passe choisi est commun, prévisible
et plus globalement, estime en combien de temps il pourra être cassé par une personne malveillante.
Sur la base de l'analyse du mot de passe saisi, des conseils seront donnés à l'utilisateur pour le
guider dans le choix d'un mot de passe sûre.</p>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>La librairie <code>ZxcvbnPhp</code> n'est compatible qu'avec PHP 7 et supérieur.</p>
</div>
<ul>
<li>
<p><code>minScore</code></p>
<p>Le score minimal pour que le mot de passe soit accepté. Il doit s'agir d'un entier compris entre
0 (le plus faible) et 4 (le plus sécurisé). Paramètre facultatif valant 4 par défaut.</p>
</li>
</ul>
<ul>
<li>
<p><code>minGuessesLog10</code></p>
<p>Permet de définir le logarithme en base 10 du nombre minimum estimé de tentative pour deviner le
mot de passe. Par exemple, si <code>minGuessesLog10</code> est égal à 6, cela signifie que le mot de passe
ne sera accepté que si <code>Zxcvbn</code> estime qu'il faut au moins 1 million (10^6) de tentatives pour le
deviner. Paramètre facultatif valant 10 par défaut.</p>
</li>
</ul>
<ul>
<li>
<p><code>userDataAttrs</code></p>
<p>Liste d'attributs de l'objet dont les valeurs seront passées à la librairie <code>Zxcvbn</code> qui les
considérera comme associés à l'utilisateur. Ainsi, par exemple, si l'utilisateur utilise son nom
de famille ou encore son prénom dans son mot de passe, la librairie pourra lui indiqué que cela ne
le protège que peut des attaques ciblées. Paramètre facultatif, mais il est fortement conseillé de
renseigner un maximum d'attributs contenant des informations personnelles relatives à l'utilisteur.</p>
</li>
</ul>
<ul>
<li>
<p><code>banPersonalInfo</code></p>
<p>Booléen permettant d'interdire toutes utilisations d'informations personnelles dans le choix du mot
de passe. Paramètre facultatif et vrai par défaut.</p>
</li>
</ul>
<ul>
<li>
<p><code>showWarning</code></p>
<p>Booléen définissant si les messages d'alertes retournés par la librairie <code>Zxcvbn</code> doivent être
affichés à l'utilisateur. Paramètre facultatif et vrai par défaut.</p>
</li>
</ul>
<ul>
<li>
<p><code>showSuggestions</code></p>
<p>Booléen définissant si les messages de suggestions retournés par la librairie <code>Zxcvbn</code> doivent
être affichés à l'utilisateur. Paramètre facultatif et vrai par défaut.</p>
</li>
</ul>
<ul>
<li>
<p><code>customDictionaries</code></p>
<p>Tableau associatif permettant de configurer des dictionnaires personnalisés : les clés contiennent
le nom de la collection de dictionnaires et les valeurs associées, le chemin vers un fichier JSON
contenant la collection de dictionnaires. Ces fichiers doivent contenir un objet racine dont les
clés sont des chaînes de caractères correspondant au nom des dictionnaires et les valeurs
associés sont des listes de mots <strong>en minuscule</strong> triées par ordre décroissant de fréquence
d'utilisation.</p>
<p>Exemple:</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-check_data-zxcvbn-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="p">{</span>
<a href="#conf-lsobject-lsattribute-check_data-zxcvbn-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a><span class="w"> </span><span class="nt">"dictionnaire1"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"mot1"</span><span class="p">,</span><span class="w"> </span><span class="s2">"mot2"</span><span class="p">],</span>
<a href="#conf-lsobject-lsattribute-check_data-zxcvbn-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a><span class="w"> </span><span class="nt">"dictionnaire2"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"mot3"</span><span class="p">,</span><span class="w"> </span><span class="s2">"mot4"</span><span class="p">]</span>
<a href="#conf-lsobject-lsattribute-check_data-zxcvbn-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a><span class="p">}</span>
</code></pre></div>
</li>
</ul>
<ul>
<li>
<p><code>banDictionaries</code></p>
<p>Ce paramètre permet d'interdire tous mots issues de certains dictionnaires. Il s'agit d'un
tableau devant contenir les noms des dictionaires interdits. La librairie <code>Zxcvbn</code> fournis
les dictionnaires suivant :</p>
<ul>
<li><code>us_tv_and_film</code> : les mots les plus courrament utilisés dans les séries et films américains</li>
<li><code>passwords</code> : les mot de passse les plus courrament utilisés</li>
<li><code>male_names</code> : les prénoms masculins les plus courrant</li>
<li><code>female_names</code> : les prénoms féminins les plus courrant</li>
<li><code>surnames</code> : les nom de familles les plus courrant aux États Unis</li>
<li><code>english_wikipedia</code> : les mots les plus courrament utilisés dans les articles en anglais de
Wikipédia</li>
<li><code>french_wikipedia</code> : les mots les plus courrament utilisés dans les articles en français de
Wikipédia</li>
<li>
<p><code>user_inputs</code> : les informations personnelles fournis lors de la validation du mot de passe</p>
<p><strong>Note :</strong> lister ce dictionnaire dans se paramètre à le même effet que le paramètre
<code>banPersonalInfo</code> documenté ci-dessus.</p>
</li>
</ul>
<p>Vous pouvez également lister ici tout dictionnaires personnalisés que vous auriez ajouté grâce
au paramètre <code>customDictionaries</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>zxcvbn_autoload_path</code></p>
<p>Le chemin vers le fichier de chargement automatique des classes de la librairie <em>ZxcvbnPhp</em>. Ce
paramètre est facultatif et vaut par défaut <code>Zxcvbn/autoload.php</code>, ce qui est adapté si vous
utiliser le paquet Debian <code>php-zxcvbn</code> disponible sur le dépôt Debian du projet LdapSaisie.</p>
</li>
</ul></section><h1 class="nav-section-title-end">Ended: Règles de vérification syntaxique (LSformRule)</h1><section class="print-page" id="conf-lsobject-lsattribute-validation"><h1 id="conf-lsobject-lsattribute-validation-configuration-des-regles-de-verification-dintegrite">Configuration des règles de vérification d'intégrité</h1>
<p>Cette section décrit la manière de configurer des règles de vérification d'intégrité sur les données
des attributs. Il est possible de valider la valeur de l'attribut par l'intermédiraire de la
vérification de résultat d'une recherche paramètrable dans l'annuaire ou encore d'appeler une
fonction de votre choix pour effectuer la vérification voulue.</p>
<h2 id="conf-lsobject-lsattribute-validation-validation-par-lanalyse-du-resultat-dune-recherche-dans-lannuaire">Validation par l'analyse du résultat d'une recherche dans l'annuaire</h2>
<p>Une telle règle permet de vérifier si les valeurs des attributs n'entrent pas en conflit avec
d'autres objets de l'annuaire. Ce test peut également permetre de vérifier si les valeurs devant
faire référence à d'autres objets de l'annuaire sont correctes.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-validation-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>'validation' =&gt; array (
<a href="#conf-lsobject-lsattribute-validation-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> ...
<a href="#conf-lsobject-lsattribute-validation-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> array(
<a href="#conf-lsobject-lsattribute-validation-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> 'msg' =&gt; "[LSformat du message d'erreur]",
<a href="#conf-lsobject-lsattribute-validation-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a> 'filter' =&gt; '[LSformat du filtre de la recherche]',
<a href="#conf-lsobject-lsattribute-validation-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a> 'object_type' =&gt; '[Type d'LSobject recherché]',
<a href="#conf-lsobject-lsattribute-validation-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a> 'basedn' =&gt; '[BaseDn de la recherche]',
<a href="#conf-lsobject-lsattribute-validation-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a> 'scope' =&gt; '[Scope de la recherche]',
<a href="#conf-lsobject-lsattribute-validation-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a> 'result' =&gt; '[Résultat positif de la recherche]',
<a href="#conf-lsobject-lsattribute-validation-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a> 'except_current_object' =&gt; '[Exclure l'objet courant]'
<a href="#conf-lsobject-lsattribute-validation-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a> ),
<a href="#conf-lsobject-lsattribute-validation-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a> ...
<a href="#conf-lsobject-lsattribute-validation-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a>),
<a href="#conf-lsobject-lsattribute-validation-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a>...
</code></pre></div>
<ul>
<li>
<p><code>msg</code></p>
<p><a href="#conf-global-lsformat-format-parametrable">LSformat</a> du message d'erreur à afficher lorsque la
validation échoue. Ce format est construit avec les valeurs du
<a href="#conf-lsobject-configuration-lsobject">LSobject</a>.</p>
</li>
</ul>
<ul>
<li>
<p><code>filter</code></p>
<p><a href="#conf-global-lsformat-format-parametrable">LSformat</a> du filtre de la recherche. Ce format peut
être construit avec toutes les valeurs du LSobject (attributs, DN, ...) et également avec la
valeur à valider en utilisant pour mot clé <code>%{val}</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>object_type</code></p>
<p>Le nom du type d'LSobject recherché. Si un type est spécifié, le filtre de la recherche sera une
combinaison de celui du paramètre <code>filter</code> et du filtre composé à partir des <em>objectClass</em> du type
d'<a href="#conf-lsobject-configuration-lsobject">LSobject</a>. <em>Paramètre facultatif.</em></p>
</li>
</ul>
<ul>
<li>
<p><code>basedn</code></p>
<p>Le <em>basedn</em> de la recherche <em>(Paramètre facultatif, par défaut : racine de l'annuaire)</em>.</p>
</li>
</ul>
<ul>
<li>
<p><code>scope</code></p>
<p>Le <em>scope</em> de la recherche <em>(Paramètre facultatif, par défaut : <code>sub</code>)</em>.</p>
</li>
</ul>
<ul>
<li>
<p><code>result</code></p>
<p>Le résultat de la recherche : si <code>result</code> vaut zéro, la recherche ne devra retourner aucun objet
pour que la validation soit réussie. Sinon, la recherche devra retourner au moins un objet.</p>
</li>
</ul>
<ul>
<li>
<p><code>except_current_object</code></p>
<p>Booléen définissant si l'objet courrant doit être exclu du résultat de la recherche. Ce paramètre
n'est évalué quand cas de création (formulaire <code>create</code>).</p>
</li>
</ul>
<h2 id="conf-lsobject-lsattribute-validation-validation-par-lexecution-dune-fonction">Validation par l'exécution d'une fonction</h2>
<p>Il est possible d'effectuer la validation de l'attribut par l'exécution d'une fonction de votre
choix. Il lui sera passé en paramètre une référence à l'objet <code>LSldapObject</code> courant. Si la fonction
ne retourne pas <em>true</em>, la validation échouera.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-validation-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a>'validation' =&gt; array (
<a href="#conf-lsobject-lsattribute-validation-__codelineno-1-2" id="__codelineno-1-2" name="__codelineno-1-2"></a> ..
<a href="#conf-lsobject-lsattribute-validation-__codelineno-1-3" id="__codelineno-1-3" name="__codelineno-1-3"></a> array(
<a href="#conf-lsobject-lsattribute-validation-__codelineno-1-4" id="__codelineno-1-4" name="__codelineno-1-4"></a> 'msg' =&gt; "[LSformat du message d'erreur]",
<a href="#conf-lsobject-lsattribute-validation-__codelineno-1-5" id="__codelineno-1-5" name="__codelineno-1-5"></a> 'function' =&gt; '[Nom de la fonction de validation]'
<a href="#conf-lsobject-lsattribute-validation-__codelineno-1-6" id="__codelineno-1-6" name="__codelineno-1-6"></a> ),
<a href="#conf-lsobject-lsattribute-validation-__codelineno-1-7" id="__codelineno-1-7" name="__codelineno-1-7"></a> ...
<a href="#conf-lsobject-lsattribute-validation-__codelineno-1-8" id="__codelineno-1-8" name="__codelineno-1-8"></a>),
<a href="#conf-lsobject-lsattribute-validation-__codelineno-1-9" id="__codelineno-1-9" name="__codelineno-1-9"></a>...
</code></pre></div>
<ul>
<li>
<p><code>msg</code></p>
<p><a href="#conf-global-lsformat-format-parametrable">LSformat</a> du message d'erreur à afficher lorsque la
validation échoue. Ce format est construit avec les valeurs du
<a href="#conf-lsobject-configuration-lsobject">LSobject</a>.</p>
</li>
</ul>
<ul>
<li>
<p><code>function</code></p>
<p>Le nom de la fonction à exécuter. Si cette fonction n'existe pas, un message d'erreur sera affiché
et la validation échouera.</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-triggers"><h1 id="conf-lsobject-lsattribute-triggers-declencheurs">Déclencheurs</h1>
<p>Cette section décrit la manière de paramétrer des déclencheurs afin que LdapSaisie exécute durant
ses processus, et à des moments bien précis des traitements d'un
<a href="#conf-lsobject-lsattribute-configuration-des-attributs">LSattributes</a>, des fonctions que vous pourrez développer vous
même. De plus, le résultat de l'exécution de vos fonctions pourra influer sur le déroulement des
processus.</p>
<p>Actuellement, les évènements suivant sont gérés :</p>
<table>
<thead>
<tr>
<th>Nom</th>
<th>Description</th>
<th>Bloquant</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>before_create</code></td>
<td>Avant la création du LSobject, lorsque l'attribut a au moins une valeur.</td>
<td>Oui</td>
</tr>
<tr>
<td><code>after_create</code></td>
<td>Après la création du LSobject, lorsque l'attribut a au moins une valeur.</td>
<td>Non</td>
</tr>
<tr>
<td><code>before_modify</code></td>
<td>Avant la modification de la valeur de l'attribut.</td>
<td>Oui</td>
</tr>
<tr>
<td><code>after_modify</code></td>
<td>Après la modification de la valeur de l'attribut.</td>
<td>Non</td>
</tr>
<tr>
<td><code>before_delete</code></td>
<td>Avant la suppression du LSobject contenant l'attribut.</td>
<td>Oui</td>
</tr>
<tr>
<td><code>after_delete</code></td>
<td>Après la suppression du LSobject contenant l'attribut.</td>
<td>Non</td>
</tr>
</tbody>
</table>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Si un événement est dit <em>bloquant</em>, lors de l'exécution des actions liées, si une des fonctions
retourne <code>false</code>, le processus s'arrêtera.</p>
</div>
<h2 id="conf-lsobject-lsattribute-triggers-configuration">Configuration</h2>
<p>La configuration des déclencheurs se fait dans la définition des
<a href="#conf-lsobject-lsattribute-configuration-des-attributs">LSattributes</a>. Par exemple, pour définir les fonctions à
exécuter après la modification de la valeur de l'attribut <em>mail</em> du type de
<a href="#conf-lsobject-configuration-lsobject">LSobject</a> <em>LSpeople</em>, c'est à dire lors de leur évenement
<code>after_modify</code>, il faut définir la variable suivante :</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-triggers-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>$GLOBALS['LSobjects']['LSpeople']['attrs']['mail']['after_modify']
</code></pre></div>
<p>Cette variable peut contenir soit une chaine de caractères correspondant au nom de la fonction à
exécuter, soit un tableau de chaînes de caractères correspondant aux noms des fonctions à exécuter.</p>
<h2 id="conf-lsobject-lsattribute-triggers-ecriture-dune-fonction">Écriture d'une fonction</h2>
<p>Une fonction exécuté par un déclencheur d'un LSattribute se déclare de la manière suivante :</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-triggers-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a><span class="x">/*</span>
<a href="#conf-lsobject-lsattribute-triggers-__codelineno-1-2" id="__codelineno-1-2" name="__codelineno-1-2"></a><span class="x"> * Ma fonction à exécuter lors de l'évènement [event]</span>
<a href="#conf-lsobject-lsattribute-triggers-__codelineno-1-3" id="__codelineno-1-3" name="__codelineno-1-3"></a><span class="x"> *</span>
<a href="#conf-lsobject-lsattribute-triggers-__codelineno-1-4" id="__codelineno-1-4" name="__codelineno-1-4"></a><span class="x"> * Paramètre :</span>
<a href="#conf-lsobject-lsattribute-triggers-__codelineno-1-5" id="__codelineno-1-5" name="__codelineno-1-5"></a><span class="x"> * - $object : Le LSobject contenant le LSattribute sur lequel l'évenement</span>
<a href="#conf-lsobject-lsattribute-triggers-__codelineno-1-6" id="__codelineno-1-6" name="__codelineno-1-6"></a><span class="x"> * survient</span>
<a href="#conf-lsobject-lsattribute-triggers-__codelineno-1-7" id="__codelineno-1-7" name="__codelineno-1-7"></a><span class="x"> *</span>
<a href="#conf-lsobject-lsattribute-triggers-__codelineno-1-8" id="__codelineno-1-8" name="__codelineno-1-8"></a><span class="x"> * Valeurs retournées :</span>
<a href="#conf-lsobject-lsattribute-triggers-__codelineno-1-9" id="__codelineno-1-9" name="__codelineno-1-9"></a><span class="x"> * - True : Tout s'est bien passé</span>
<a href="#conf-lsobject-lsattribute-triggers-__codelineno-1-10" id="__codelineno-1-10" name="__codelineno-1-10"></a><span class="x"> * - False : Une erreur est survenue ou la fonction souhaite bloquer le</span>
<a href="#conf-lsobject-lsattribute-triggers-__codelineno-1-11" id="__codelineno-1-11" name="__codelineno-1-11"></a><span class="x"> * processus lors d'un évènement bloquant.</span>
<a href="#conf-lsobject-lsattribute-triggers-__codelineno-1-12" id="__codelineno-1-12" name="__codelineno-1-12"></a><span class="x"> */</span>
<a href="#conf-lsobject-lsattribute-triggers-__codelineno-1-13" id="__codelineno-1-13" name="__codelineno-1-13"></a><span class="x">function maFonction ($object) {</span>
<a href="#conf-lsobject-lsattribute-triggers-__codelineno-1-14" id="__codelineno-1-14" name="__codelineno-1-14"></a>
<a href="#conf-lsobject-lsattribute-triggers-__codelineno-1-15" id="__codelineno-1-15" name="__codelineno-1-15"></a><span class="x"> // Actions</span>
<a href="#conf-lsobject-lsattribute-triggers-__codelineno-1-16" id="__codelineno-1-16" name="__codelineno-1-16"></a>
<a href="#conf-lsobject-lsattribute-triggers-__codelineno-1-17" id="__codelineno-1-17" name="__codelineno-1-17"></a><span class="x">}</span>
</code></pre></div>
<p>Cette fonction doit prendre pour seul paramètre, le LSobject contenant le LSattribute sur lequel
l'évenement survient et doit retourner soit <code>True</code> si tout s'est bien passé, soit <code>False</code> en cas de
problème. Dans le cas d'un événement bloquant, si la fonction retourne <code>False</code>, le processus est
arrêté.</p></section><h1 class="nav-section-title-end">Ended: Attributs</h1><section class="print-page" id="conf-lsobject-container_auto_create"><h1 id="conf-lsobject-container_auto_create-creation-automatique-du-conteneur-des-lsobjets-dans-un-subdn">Création automatique du conteneur des LSobjets dans un subDn</h1>
<p>Cette section décrit la manière de configurer la création automatique des conteneurs des LSobjets.
Si le <em>basedn</em> correspondant à la branche de stockage des <a href="#conf-lsobject-configuration-lsobject">LSobjects</a>
n'existe pas, LdapSaisie tentera de le créer à partir de la configuration de la variable
<code>$GLOBALS['LSobjects']['[nom du type d'LSobject]']['container_auto_create']</code>.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-container_auto_create-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>$GLOBALS['LSobjects']['[nom du type d'LSobject]']['container_auto_create'] = array (
<a href="#conf-lsobject-container_auto_create-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'objectclass' =&gt; array(
<a href="#conf-lsobject-container_auto_create-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> 'objectclass1',
<a href="#conf-lsobject-container_auto_create-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> 'objectclass2',
<a href="#conf-lsobject-container_auto_create-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a> ...
<a href="#conf-lsobject-container_auto_create-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a> ),
<a href="#conf-lsobject-container_auto_create-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a> 'attrs' =&gt; array(
<a href="#conf-lsobject-container_auto_create-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a> 'attr1' =&gt; 'val1',
<a href="#conf-lsobject-container_auto_create-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a> 'attr2' =&gt; array(
<a href="#conf-lsobject-container_auto_create-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a> 'val2',
<a href="#conf-lsobject-container_auto_create-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a> 'val3',
<a href="#conf-lsobject-container_auto_create-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a> ...
<a href="#conf-lsobject-container_auto_create-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a> ),
<a href="#conf-lsobject-container_auto_create-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a> ...
<a href="#conf-lsobject-container_auto_create-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a> )
<a href="#conf-lsobject-container_auto_create-__codelineno-0-16" id="__codelineno-0-16" name="__codelineno-0-16"></a>);
</code></pre></div>
<ul>
<li>
<p><code>objectclass</code></p>
<p>La liste des <em>objectclass</em> de l'objet conteneur.</p>
</li>
</ul>
<ul>
<li>
<p><code>attrs</code></p>
<p>Un tableau associatif dont les clés sont les noms des attributs de l'objet conteneur à définir et
dont les valeurs associées sont la/les valeur(s) de ces attributs.</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-triggers"><h1 id="conf-lsobject-triggers-declencheurs">Déclencheurs</h1>
<p>Cette section décrit la manière de paramétrer des déclencheurs afin que LdapSaisie exécute durant
ses processus, et à des moments bien précis des traitements d'un
<a href="#conf-lsobject-configuration-lsobject">LSobject</a>, des fonctions que vous pourrez développer vous même. De
plus, le résultat de l'exécution de vos fonctions pourra influer sur le déroulement des processus.</p>
<p>Actuellement, les évenements suivant sont gérés :</p>
<table>
<thead>
<tr>
<th>Nom</th>
<th>Description</th>
<th>Bloquant</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>before_create</code></td>
<td>Avant la création du LSobject.</td>
<td>Oui</td>
</tr>
<tr>
<td><code>after_create</code></td>
<td>Après la création du LSobject.</td>
<td>Non</td>
</tr>
<tr>
<td><code>before_modify</code></td>
<td>Avant la modification du LSobject</td>
<td>Oui</td>
</tr>
<tr>
<td><code>after_modify</code></td>
<td>Après la modification du LSobject</td>
<td>Non</td>
</tr>
<tr>
<td><code>before_rename</code></td>
<td>Avant de renommer le LSobject</td>
<td>Oui</td>
</tr>
<tr>
<td><code>after_rename</code></td>
<td>Après avoir renommé le LSobject</td>
<td>Non</td>
</tr>
<tr>
<td><code>before_delete</code></td>
<td>Avant la suppression du LSobject</td>
<td>Oui</td>
</tr>
<tr>
<td><code>after_delete</code></td>
<td>Après la suppression du LSobject</td>
<td>Non</td>
</tr>
</tbody>
</table>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Si un événement est dit <em>bloquant</em>, lors de l'exécution des actions liées, si une des fonctions
retourne <code>false</code>, le processus s'arrêtera.</p>
</div>
<h2 id="conf-lsobject-triggers-configuration">Configuration</h2>
<p>La configuration des déclencheurs se fait dans la définition des types
d'<a href="#conf-lsobject-configuration-lsobject">LSobjects</a>. Par exemple, pour définir les fonctions à exécuter
après la modification des LSobjects de type <em>LSpeople</em>, c'est à dire lors de leur évènement
<code>after_modify</code>, il faut définir la variable suivante :</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-triggers-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="x">$GLOBALS['LSobjects']['[nom du type d'LSobject]']['after_modify']</span>
</code></pre></div>
<p>Cette variable peut contenir soit une chaine de caractères correspondant au nom de la fonction à
exécuter, soit un tableau de chaînes de caractères correspondant aux noms des fonctions à exécuter.</p>
<h2 id="conf-lsobject-triggers-ecriture-dune-fonction">Écriture d'une fonction</h2>
<p>Une fonction exécuté par un déclencheur d'un LSobject se déclare de la manière suivante :</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-triggers-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a><span class="x">/*</span>
<a href="#conf-lsobject-triggers-__codelineno-1-2" id="__codelineno-1-2" name="__codelineno-1-2"></a><span class="x"> * Ma fonction à exécuter lors de l'evenement [event]</span>
<a href="#conf-lsobject-triggers-__codelineno-1-3" id="__codelineno-1-3" name="__codelineno-1-3"></a><span class="x"> *</span>
<a href="#conf-lsobject-triggers-__codelineno-1-4" id="__codelineno-1-4" name="__codelineno-1-4"></a><span class="x"> * Paramètre :</span>
<a href="#conf-lsobject-triggers-__codelineno-1-5" id="__codelineno-1-5" name="__codelineno-1-5"></a><span class="x"> * - $object : Le LSobject sur lequel l'évènement survient</span>
<a href="#conf-lsobject-triggers-__codelineno-1-6" id="__codelineno-1-6" name="__codelineno-1-6"></a><span class="x"> *</span>
<a href="#conf-lsobject-triggers-__codelineno-1-7" id="__codelineno-1-7" name="__codelineno-1-7"></a><span class="x"> * Valeurs retournées :</span>
<a href="#conf-lsobject-triggers-__codelineno-1-8" id="__codelineno-1-8" name="__codelineno-1-8"></a><span class="x"> * - True : Tout s'est bien passé</span>
<a href="#conf-lsobject-triggers-__codelineno-1-9" id="__codelineno-1-9" name="__codelineno-1-9"></a><span class="x"> * - False : Une erreur est survenue ou la fonction souhaite bloquer le</span>
<a href="#conf-lsobject-triggers-__codelineno-1-10" id="__codelineno-1-10" name="__codelineno-1-10"></a><span class="x"> * processus lors d'un évènement bloquant.</span>
<a href="#conf-lsobject-triggers-__codelineno-1-11" id="__codelineno-1-11" name="__codelineno-1-11"></a><span class="x"> */</span>
<a href="#conf-lsobject-triggers-__codelineno-1-12" id="__codelineno-1-12" name="__codelineno-1-12"></a><span class="x">function maFonction ($object) {</span>
<a href="#conf-lsobject-triggers-__codelineno-1-13" id="__codelineno-1-13" name="__codelineno-1-13"></a>
<a href="#conf-lsobject-triggers-__codelineno-1-14" id="__codelineno-1-14" name="__codelineno-1-14"></a><span class="x"> // Actions</span>
<a href="#conf-lsobject-triggers-__codelineno-1-15" id="__codelineno-1-15" name="__codelineno-1-15"></a>
<a href="#conf-lsobject-triggers-__codelineno-1-16" id="__codelineno-1-16" name="__codelineno-1-16"></a><span class="x">}</span>
</code></pre></div>
<p>Cette fonction doit prendre pour seul paramètre, le LSobject sur lequel l'évènement survient et doit
retourner soit <code>True</code> si tout s'est bien passé, soit <code>False</code> en cas de problème. Dans le cas d'un
événement bloquant, si la fonction retourne <code>False</code>, le processus est arrêté.</p></section><section class="print-page" id="conf-lsobject-customactions"><h1 id="conf-lsobject-customactions-actions-personnalisees-customactions">Actions personnalisées (customActions)</h1>
<p>Cette section décrit la manière de configurer les actions personnalisées exécutables sur les
<a href="#conf-lsobject-configuration-lsobject">LSobjects</a> appelées <em>customActions</em>.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-customactions-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>$GLOBALS['LSobjects']['[nom du type d'LSobject]']['customActions'] = array (
<a href="#conf-lsobject-customactions-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'action1' =&gt; array(
<a href="#conf-lsobject-customactions-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> 'label' =&gt; '[label l'action]',
<a href="#conf-lsobject-customactions-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> 'hideLabel' =&gt; '[booléen]',
<a href="#conf-lsobject-customactions-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a> 'helpInfo' =&gt; '[label d'aide]',
<a href="#conf-lsobject-customactions-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a> 'icon' =&gt; '[nom de l'icône de l'action]',
<a href="#conf-lsobject-customactions-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a> 'function' =&gt; '[fonction à exécuter]',
<a href="#conf-lsobject-customactions-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a> 'question_format' =&gt; '[LSformat de la question de confirmation]',
<a href="#conf-lsobject-customactions-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a> 'onSuccessMsgFormat' =&gt; '[LSformat du message à afficher en cas de succès de l'action]',
<a href="#conf-lsobject-customactions-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a> 'disableOnSuccessMsg' =&gt; '[booléen]',
<a href="#conf-lsobject-customactions-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a> 'noConfirmation' =&gt; '[booléen]',
<a href="#conf-lsobject-customactions-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a> 'redirectToObjectList' =&gt; '[booléen]',
<a href="#conf-lsobject-customactions-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a> 'noRedirect' =&gt; '[booléen]',
<a href="#conf-lsobject-customactions-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a> 'accessMethods' =&gt; array(
<a href="#conf-lsobject-customactions-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a> 'web',
<a href="#conf-lsobject-customactions-__codelineno-0-16" id="__codelineno-0-16" name="__codelineno-0-16"></a> 'api',
<a href="#conf-lsobject-customactions-__codelineno-0-17" id="__codelineno-0-17" name="__codelineno-0-17"></a> ),
<a href="#conf-lsobject-customactions-__codelineno-0-18" id="__codelineno-0-18" name="__codelineno-0-18"></a> 'rights' =&gt; array(
<a href="#conf-lsobject-customactions-__codelineno-0-19" id="__codelineno-0-19" name="__codelineno-0-19"></a> 'LSprofile1',
<a href="#conf-lsobject-customactions-__codelineno-0-20" id="__codelineno-0-20" name="__codelineno-0-20"></a> 'LSprofile2',
<a href="#conf-lsobject-customactions-__codelineno-0-21" id="__codelineno-0-21" name="__codelineno-0-21"></a> ...
<a href="#conf-lsobject-customactions-__codelineno-0-22" id="__codelineno-0-22" name="__codelineno-0-22"></a> )
<a href="#conf-lsobject-customactions-__codelineno-0-23" id="__codelineno-0-23" name="__codelineno-0-23"></a> )
<a href="#conf-lsobject-customactions-__codelineno-0-24" id="__codelineno-0-24" name="__codelineno-0-24"></a>);
</code></pre></div>
<ul>
<li>
<p><code>label</code></p>
<p>Le label de l'action.</p>
</li>
</ul>
<ul>
<li>
<p><code>hideLabel</code></p>
<p>Cache le label dans le bouton de l'action.</p>
</li>
</ul>
<ul>
<li>
<p><code>helpInfo</code></p>
<p>Le label du message d'aide qui sera affiché au survole du bouton de l'action.</p>
</li>
</ul>
<ul>
<li>
<p><code>icon</code></p>
<p>Nom de l'îcone à afficher dans le bouton de l'action. Ce nom correspond au nom du fichier de
l'image (sans l'extention) qui devra se trouver dans le dossier
<code>src/images/[nom du theme d'images]/</code> ou dans le dossier <code>src/local/images</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>function</code></p>
<p>Le nom de la fonction à exécuter qui implémente l'action personnalisée Cette fonction prendra en
seule paramètre le <a href="#conf-lsobject-configuration-lsobject">LSobject</a> sur lequel l'action devra être
exécutée et retournera <code>True</code> en cas de succès ou <code>False</code> en cas d'échec d'exécution de la fonction.</p>
</li>
</ul>
<ul>
<li>
<p><code>question_format</code></p>
<p>Le <a href="#conf-global-lsformat-format-parametrable">LSformat</a> de la question de confirmation
d'exécution de l'action. Ce <a href="#conf-global-lsformat-format-parametrable">LSformat</a> sera composé à
l'aide du nom de l'objet.</p>
</li>
</ul>
<ul>
<li>
<p><code>onSuccessMsgFormat</code></p>
<p>Le <a href="#conf-global-lsformat-format-parametrable">LSformat</a> du message à afficher en cas de succès
d'exécution de l'action. Ce <a href="#conf-global-lsformat-format-parametrable">LSformat</a> sera composé à
l'aide du nom de l'objet.</p>
</li>
</ul>
<ul>
<li>
<p><code>disableOnSuccessMsg</code></p>
<p>Booléen permetant de désactiver le message afficher en cas de succès d'exécution de l'action.</p>
</li>
</ul>
<ul>
<li>
<p><code>noConfirmation</code></p>
<p>Booléen permetant de désactiver la confirmation de l'exécution de l'action.</p>
</li>
</ul>
<ul>
<li>
<p><code>redirectToObjectList</code></p>
<p>Booléen permetant de rediriger l'utilisateur vers la liste des objets plutôt que sur la fiche de
l'objet après l'execution de l'action.</p>
</li>
</ul>
<ul>
<li>
<p><code>noRedirect</code></p>
<p>Booléen permetant de désactiver la redirection de l'utilisateur après l'execution de l'action.
Cela permet à la fonction de définir son propre fichier de template de retour et donc d'afficher
une page personnalisable.</p>
</li>
</ul>
<ul>
<li>
<p><code>rights</code></p>
<p>Tableau contenant la liste des noms des
<a href="#conf-global-ldap-lsprofile-profils-dutilisateurs">LSprofiles</a> ayant le droit d'exécuter cette
action.</p>
</li>
</ul>
<ul>
<li>
<p><code>accessMethods</code></p>
<p>Tableau permetant de restreindre les moyens d'accès possibles à cette action. Par défaut, tous les
moyens d'accès possibles sont autorisés. Valeurs possibles : <code>web</code> pour les accès via l'interface
web et <code>api</code> pour les accès via l'API.</p>
</li>
</ul>
<h2 id="conf-lsobject-customactions-ecriture-dune-fonction-implementant-une-customaction">Écriture d'une fonction implémentant une customAction</h2>
<p>Une fonction implémentant une <em>customAction</em> se déclare de la manière suivante :</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-customactions-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a>/*
<a href="#conf-lsobject-customactions-__codelineno-1-2" id="__codelineno-1-2" name="__codelineno-1-2"></a> * Ma fonction implémentant ma customAction
<a href="#conf-lsobject-customactions-__codelineno-1-3" id="__codelineno-1-3" name="__codelineno-1-3"></a> *
<a href="#conf-lsobject-customactions-__codelineno-1-4" id="__codelineno-1-4" name="__codelineno-1-4"></a> * Paramètre :
<a href="#conf-lsobject-customactions-__codelineno-1-5" id="__codelineno-1-5" name="__codelineno-1-5"></a> * - $object : Le LSobject sur lequel mon action doit être exécutée
<a href="#conf-lsobject-customactions-__codelineno-1-6" id="__codelineno-1-6" name="__codelineno-1-6"></a> *
<a href="#conf-lsobject-customactions-__codelineno-1-7" id="__codelineno-1-7" name="__codelineno-1-7"></a> * Valeurs retournées :
<a href="#conf-lsobject-customactions-__codelineno-1-8" id="__codelineno-1-8" name="__codelineno-1-8"></a> * - True : Tout s'est bien passé
<a href="#conf-lsobject-customactions-__codelineno-1-9" id="__codelineno-1-9" name="__codelineno-1-9"></a> * - False : Une erreur est survenue
<a href="#conf-lsobject-customactions-__codelineno-1-10" id="__codelineno-1-10" name="__codelineno-1-10"></a> * - Cas particulier pour une exécution via l'API : un tableau des données
<a href="#conf-lsobject-customactions-__codelineno-1-11" id="__codelineno-1-11" name="__codelineno-1-11"></a> * à retourner. Exemple :
<a href="#conf-lsobject-customactions-__codelineno-1-12" id="__codelineno-1-12" name="__codelineno-1-12"></a> * ["success" =&gt; true, "extra_info1" =&gt; "...", "extra_info2" =&gt; "..."]
<a href="#conf-lsobject-customactions-__codelineno-1-13" id="__codelineno-1-13" name="__codelineno-1-13"></a> */
<a href="#conf-lsobject-customactions-__codelineno-1-14" id="__codelineno-1-14" name="__codelineno-1-14"></a>function maFonction ($object) {
<a href="#conf-lsobject-customactions-__codelineno-1-15" id="__codelineno-1-15" name="__codelineno-1-15"></a>
<a href="#conf-lsobject-customactions-__codelineno-1-16" id="__codelineno-1-16" name="__codelineno-1-16"></a> // Actions
<a href="#conf-lsobject-customactions-__codelineno-1-17" id="__codelineno-1-17" name="__codelineno-1-17"></a>
<a href="#conf-lsobject-customactions-__codelineno-1-18" id="__codelineno-1-18" name="__codelineno-1-18"></a>}
</code></pre></div>
<p>Cette fonction doit prendre pour seul paramètre, le <a href="#conf-lsobject-configuration-lsobject">LSobject</a> sur
lequel l'action personnalisée doit être exécutée et doit retourner soit <code>True</code> si tout s'est bien
passé, soit <code>False</code> en cas de problème.</p>
<p>Une <em>customAction</em> pourra également être appelé via l'API. Dans ce cas, il est possible de
retourner un tableau associatif et non un simple booléen. Le résultat retourné sera alors
fusionné avec les données retournées par la requête. Ce tableau devra contenir à minima la clé
<code>success</code> qui indiquera via un booléen si l'exécution est un succès ou non. Il est possible de
détecter si la méthode est appelée via l'API en appelant la méthode
<code>LSsession :: get('api_mode')</code>. Vous pouvez prendre exemple sur le code de la méthode
<code>showTechInfo()</code> fournie par le LSaddon <a href="#conf-lsaddon-lsaddon_showtechinfo">showTechInfo</a>.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Ces fonctions sont le plus couramment définies au sein d'
<a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a>.</p>
</div></section><section class="print-page" id="conf-lsobject-lsrelation"><h1 id="conf-lsobject-lsrelation-les-relations-entre-les-objets-de-lannuire-lsrelation">Les relations entre les objets de l'annuire (LSrelation)</h1>
<p>Cette section décrit la manière de configurer les relations entre les
<a href="#conf-lsobject-configuration-lsobject">LSobjects</a> appelées <em>LSrelation</em>.</p>
<p>Dans le cadre d'une liaison dîte <em>simple</em>, c'est à dire une liaison au travers la valeur d'un
attribut qui fera directement référence à un autre objet (<em>DN</em> ou la première valeur d'un attribut
de référence), pourra être configurée simplement en spécifiant l'attribut de liaison et le type de
valeur qu'il contient. Dans le cas d'une liaison plus complexe, il sera possible de développer vous
même des méthodes de mise en relation.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsrelation-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="x">$GLOBALS['LSobjects']['[nom du type d'LSobject]']['LSrelation'] = array (</span>
<a href="#conf-lsobject-lsrelation-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a><span class="x"> 'relation1' =&gt; array(</span>
<a href="#conf-lsobject-lsrelation-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a><span class="x"> 'label' =&gt; '[label de la relation]',</span>
<a href="#conf-lsobject-lsrelation-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a><span class="x"> 'emptyText' =&gt; "[texte affiché si aucune relation avec d'autres objets</span>
<a href="#conf-lsobject-lsrelation-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a><span class="x"> n'existe pour l'objet courant]",</span>
<a href="#conf-lsobject-lsrelation-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a><span class="x"> 'LSobject' =&gt; '[le type d'LSobjet en relation]',</span>
<a href="#conf-lsobject-lsrelation-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a><span class="x"> 'display_name_format' =&gt; '[LSformat du nom d'affichage des LSobjet en relation]',</span>
<a href="#conf-lsobject-lsrelation-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a><span class="x"> 'canEdit_attribute' =&gt; '[nom d'attribut]',</span>
<a href="#conf-lsobject-lsrelation-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a>
<a href="#conf-lsobject-lsrelation-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a><span class="x"> // Liaison simple</span>
<a href="#conf-lsobject-lsrelation-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a><span class="x"> 'linkAttribute' =&gt; '[attribut de liaison]',</span>
<a href="#conf-lsobject-lsrelation-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a><span class="x"> 'linkAttributeValue' =&gt; '[valeur de l'attribut de liaison]',</span>
<a href="#conf-lsobject-lsrelation-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a><span class="x"> 'linkAttributeOtherValues' =&gt; array('[autres valeurs possible de l'attribut de liaison]', [...]),</span>
<a href="#conf-lsobject-lsrelation-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a>
<a href="#conf-lsobject-lsrelation-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a><span class="x"> // Liaison complexe</span>
<a href="#conf-lsobject-lsrelation-__codelineno-0-16" id="__codelineno-0-16" name="__codelineno-0-16"></a><span class="x"> 'list_function' =&gt; '[méthode1]',</span>
<a href="#conf-lsobject-lsrelation-__codelineno-0-17" id="__codelineno-0-17" name="__codelineno-0-17"></a><span class="x"> 'getkeyvalue_function' =&gt; '[methode2]',</span>
<a href="#conf-lsobject-lsrelation-__codelineno-0-18" id="__codelineno-0-18" name="__codelineno-0-18"></a><span class="x"> 'update_function' =&gt; '[methode3]',</span>
<a href="#conf-lsobject-lsrelation-__codelineno-0-19" id="__codelineno-0-19" name="__codelineno-0-19"></a><span class="x"> 'remove_function' =&gt; '[methode4]',</span>
<a href="#conf-lsobject-lsrelation-__codelineno-0-20" id="__codelineno-0-20" name="__codelineno-0-20"></a><span class="x"> 'rename_function' =&gt; '[methode5]',</span>
<a href="#conf-lsobject-lsrelation-__codelineno-0-21" id="__codelineno-0-21" name="__codelineno-0-21"></a><span class="x"> 'canEdit_function' =&gt; '[methode6]',</span>
<a href="#conf-lsobject-lsrelation-__codelineno-0-22" id="__codelineno-0-22" name="__codelineno-0-22"></a>
<a href="#conf-lsobject-lsrelation-__codelineno-0-23" id="__codelineno-0-23" name="__codelineno-0-23"></a><span class="x"> 'rights' =&gt; array(</span>
<a href="#conf-lsobject-lsrelation-__codelineno-0-24" id="__codelineno-0-24" name="__codelineno-0-24"></a><span class="x"> 'LSprofile1' =&gt; 'r',</span>
<a href="#conf-lsobject-lsrelation-__codelineno-0-25" id="__codelineno-0-25" name="__codelineno-0-25"></a><span class="x"> 'LSprofile2' =&gt; 'w',</span>
<a href="#conf-lsobject-lsrelation-__codelineno-0-26" id="__codelineno-0-26" name="__codelineno-0-26"></a><span class="x"> ...</span>
<a href="#conf-lsobject-lsrelation-__codelineno-0-27" id="__codelineno-0-27" name="__codelineno-0-27"></a><span class="x"> )</span>
<a href="#conf-lsobject-lsrelation-__codelineno-0-28" id="__codelineno-0-28" name="__codelineno-0-28"></a><span class="x"> )</span>
<a href="#conf-lsobject-lsrelation-__codelineno-0-29" id="__codelineno-0-29" name="__codelineno-0-29"></a><span class="x">);</span>
</code></pre></div>
<ul>
<li>
<p><code>label</code></p>
<p>Le label de la relation.</p>
</li>
</ul>
<ul>
<li>
<p><code>emptyText</code></p>
<p>Le texte à afficher pour décrire le fait que l'objet courant n'a aucune relation d'établie avec
d'autres <a href="#conf-lsobject-configuration-lsobject">LSobjects</a>. Exemple (au sujet d'un utilisateur) :
<em>N'appartient à aucun groupe.</em></p>
</li>
</ul>
<ul>
<li>
<p><code>LSobject</code></p>
<p>Le type d'<a href="#conf-lsobject-configuration-lsobject">LSobject</a> en relation avec le type courant.
<em>(Facultatif en cas de liaison complexe)</em></p>
</li>
</ul>
<ul>
<li>
<p><code>display_name_format</code></p>
<p><a href="#conf-global-lsformat-format-parametrable">LSformat</a> du nom d'affichage des objets en relation.</p>
</li>
</ul>
<ul>
<li>
<p><code>canEdit_attribute</code></p>
<p>Le nom de l'attibut du type d'<a href="#conf-lsobject-configuration-lsobject">LSobject</a> en relation devant être
éditable par l'utilisateur pour que celui-ci puisse modifier la relation. Dans le cadre d'une
relation simple, celui-ci peut, si nécessaire, être différent du paramètre <code>linkAttribute</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>linkAttribute</code></p>
<p>Dans le cadre d'une relation simple, il s'agit de l'attribut de liaison du type
d'<a href="#conf-lsobject-configuration-lsobject">LSobject</a> en relation avec le type courant, c'est à dire
l'attribut dans lequel on retrouve une valeur en relation avec l'objet courant.
<em>(Facultatif en cas de liaison complexe)</em></p>
</li>
</ul>
<ul>
<li>
<p><code>linkAttributeValue</code></p>
<p>Dans le cadre d'une relation simple, il s'agit du type de valeur prisent par l'attribut de liaison
du type d'<a href="#conf-lsobject-configuration-lsobject">LSobject</a> en relation avec le type courant. Il peut
s'agir du mot clé <code>dn</code> si l'attribut de liaison contient le <em>DN</em> de l'objet courant ou bien le nom
d'un attribut du type d'objet courant dont la première valeur sera stockée par l'attribut de
liaison. <em>(Facultatif en cas de liaison complexe)</em></p>
</li>
</ul>
<ul>
<li>
<p><code>linkAttributeOtherValues</code></p>
<p>Dans le cadre d'une relation simple, il s'agit d'autres types de valeur possiblement prisent par
l'attribut en plus de celui défini par le paramètre <code>linkAttributeValue</code>. Ce paramètre ne sert
qu'a détecter des liaisons établies à l'aide de valeurs autres que celle relative au paramètre
<code>linkAttributeValue</code> : en cas de nouvelle liaison, c'est la valeur associée à ce dernier qui sera
utilisée pour établir la liaison. <em>(Facultatif en cas de liaison complexe)</em></p>
</li>
</ul>
<ul>
<li>
<p><code>list_function</code></p>
<p>La méthode de la classe du type d'<a href="#conf-lsobject-configuration-lsobject">LSobject</a> en relation,
permettant de lister les objets de ce type en relation avec l'objet courant.
<em>(Facultatif en cas de liaison simple)</em></p>
</li>
</ul>
<ul>
<li>
<p><code>getkeyvalue_function</code></p>
<p>La méthode de la classe du type d'<a href="#conf-lsobject-configuration-lsobject">LSobject</a> en relation,
permettant d'obtenir la valeur clé à stocker pour établir la relation entre l'objet courant et
d'autres objets du type concerné. <em>(Facultatif en cas de liaison simple)</em></p>
</li>
</ul>
<ul>
<li>
<p><code>update_function</code></p>
<p>La méthode de la classe du type d'<a href="#conf-lsobject-configuration-lsobject">LSobject</a> en relation,
permettant de mettre à jour les relations existantes entre l'objet courant et les objets du type
concerné. Cette liste d'objets en relation est établie par l'utilisateur à travers l'interface.
<em>(Facultatif en cas de liaison simple)</em></p>
</li>
</ul>
<ul>
<li>
<p><code>remove_function</code></p>
<p>La méthode de la classe du type d'<a href="#conf-lsobject-configuration-lsobject">LSobject</a> en relation
permettant de supprimer une relation existante entre l'objet courant et un objet du type concerné.
<em>(Facultatif en cas de liaison simple)</em></p>
</li>
</ul>
<ul>
<li>
<p><code>rename_function</code></p>
<p>La méthode de la classe du type d'<a href="#conf-lsobject-configuration-lsobject">LSobject</a> en relation
permettant d'effectuer les actions nécessaires lorsque l'objet courant est renommé dans le but
de maintenir les valeurs clés permettant d'établir les relations entre l'objet courant et les
objets en relation avec lui. <em>(Facultatif en cas de liaison simple)</em></p>
</li>
</ul>
<ul>
<li>
<p><code>canEdit_function</code></p>
<p>La méthode de la classe du type d'<a href="#conf-lsobject-configuration-lsobject">LSobject</a> en relation
permettant de vérifier que l'utilisateur à le droit de modifier la relation avec un objet
en particulier. <em>(Facultatif en cas de liaison simple)</em></p>
</li>
</ul>
<ul>
<li>
<p><code>rights</code></p>
<p>Tableau associatif dont les clés sont les noms des
<a href="#conf-global-ldap-lsprofile-profils-dutilisateurs">LSprofiles</a> ayant des droits sur cette
relation et dont les valeurs associées sont les droits correspondants. La valeur des droits d'un
<a href="#conf-global-ldap-lsprofile-profils-dutilisateurs">LSprofile</a> peut être <code>r</code> pour le droit de
lecture ou <code>w</code> pour le droit de lecture-écriture.Par défaut, un
<a href="#conf-global-ldap-lsprofile-profils-dutilisateurs">LSprofile</a> n'a aucun droit.</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lsform"><h1 id="conf-lsobject-lsform-les-formulaires-lsform">Les formulaires (LSform)</h1>
<p>Cette section décrit la manière de paramétrer les formulaires d'LdapSaisie pour un type
<a href="#conf-lsobject-configuration-lsobject">LSobject</a> donné. Pour chaque type
d'<a href="#conf-lsobject-configuration-lsobject">LSobject</a>, il faut configurer plusieurs formulaires
correspondant aux vues gérées par LdapSaisie (création, modification, ...). Les formulaires se
configurent par plusieurs biais :</p>
<ul>
<li>Via la configuration des attributs : La configuration des attributs détermine la présence ou non
des attributs dans les formulaires. Elle permet également de définir si on souhaite bloquer leur
présence en lecture seulement.</li>
</ul>
<ul>
<li>Via les droits de l'utilisateur connecté sur les attributs de l'objet à éditer : en fonction des
droits de l'utilisateur sur un attribut, celui-ci apparaîtra en lecture-écriture ou en lecture
uniquement voir pas du tout.</li>
</ul>
<ul>
<li>
<p>Via la configuration au niveau de chaque type d'<a href="#conf-lsobject-configuration-lsobject">LSobject</a> : il
y est possible de définir le comportement globale du formulaire comme la validation via Ajax ou
encore la disposition logique des attributs dans le formulaire.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsform-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>$GLOBALS['LSobjects']['[nom du type d'LSobject]']['LSform'] = array (
<a href="#conf-lsobject-lsform-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'ajaxSubmit' =&gt; [booléen],
<a href="#conf-lsobject-lsform-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> 'layout' =&gt; array (
<a href="#conf-lsobject-lsform-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> // Configuration de la disposition logique des attributs
<a href="#conf-lsobject-lsform-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a> ),
<a href="#conf-lsobject-lsform-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a> 'dataEntryForm' =&gt; array (
<a href="#conf-lsobject-lsform-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a> // Configuration des masques de saisie
<a href="#conf-lsobject-lsform-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a> )
<a href="#conf-lsobject-lsform-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a>
<a href="#conf-lsobject-lsform-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a>);
</code></pre></div>
<ul>
<li>
<p><code>ajaxSubmit</code></p>
<p>Booléen définissant si le formulaire sera envoyé via une requête Ajax plutôt qu'à travers un
rafraîchissement de la page. Par défaut : <code>True</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>layout</code></p>
<p>Tableau contenant la configuration de l'affichage du formulaire : il est possible de définir la
disposition des attributs dans le formulaire en les regroupant dans des onglets et en les
faisant apparaître dans un ordre logique.
<a href="#conf-lsobject-lsform-configuration-de-laffichage">Voir la section concernée.</a></p>
</li>
</ul>
<ul>
<li>
<p><code>dataEntryForm</code></p>
<p>Tableau contenant la configuration des masques de saisie : il est possible de définir des
masques de saisie pour faire en sorte que lors de la création d'un objet, seul un certain nombre
d'élements soit demandé à l'utilisateur.
<a href="#conf-lsobject-lsform-configuration-des-masques-de-saisie">Voir la section concernée.</a></p>
</li>
</ul>
</li>
</ul>
<h2 id="conf-lsobject-lsform-configuration-de-laffichage">Configuration de l'affichage</h2>
<p>La configuration des <em>layout</em> se situe dans la configuration des
<a href="#conf-lsobject-configuration-lsobject">LSobjects</a>, dans la variable <code>layout</code>
(<code>$GLOBALS['LSobjects']['[nom du type d'LSobject]']['LSform']['layout']</code>). Cette variable est un
tableau associatif dont la clé est l'identifiant de l'onglet et dont la valeur associée est la
configuration de l'onglet.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsform-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a><span class="x">$GLOBALS['LSobjects']['[nom du type d'LSobject]']['LSform']['layout'] = array (</span>
<a href="#conf-lsobject-lsform-__codelineno-1-2" id="__codelineno-1-2" name="__codelineno-1-2"></a><span class="x"> 'onglet1' =&gt; array(</span>
<a href="#conf-lsobject-lsform-__codelineno-1-3" id="__codelineno-1-3" name="__codelineno-1-3"></a><span class="x"> 'label' =&gt; '[label de l'onglet]',</span>
<a href="#conf-lsobject-lsform-__codelineno-1-4" id="__codelineno-1-4" name="__codelineno-1-4"></a><span class="x"> 'img' =&gt; 1, // Valeur possible 1 ou 0</span>
<a href="#conf-lsobject-lsform-__codelineno-1-5" id="__codelineno-1-5" name="__codelineno-1-5"></a><span class="x"> 'args' =&gt; array (</span>
<a href="#conf-lsobject-lsform-__codelineno-1-6" id="__codelineno-1-6" name="__codelineno-1-6"></a><span class="x"> 'arg1',</span>
<a href="#conf-lsobject-lsform-__codelineno-1-7" id="__codelineno-1-7" name="__codelineno-1-7"></a><span class="x"> 'arg2',</span>
<a href="#conf-lsobject-lsform-__codelineno-1-8" id="__codelineno-1-8" name="__codelineno-1-8"></a><span class="x"> ...</span>
<a href="#conf-lsobject-lsform-__codelineno-1-9" id="__codelineno-1-9" name="__codelineno-1-9"></a><span class="x"> )</span>
<a href="#conf-lsobject-lsform-__codelineno-1-10" id="__codelineno-1-10" name="__codelineno-1-10"></a><span class="x"> ),</span>
<a href="#conf-lsobject-lsform-__codelineno-1-11" id="__codelineno-1-11" name="__codelineno-1-11"></a><span class="x"> ...</span>
<a href="#conf-lsobject-lsform-__codelineno-1-12" id="__codelineno-1-12" name="__codelineno-1-12"></a><span class="x">);</span>
</code></pre></div>
<ul>
<li>
<p><code>label</code></p>
<p>Le label de l'onglet.</p>
</li>
</ul>
<ul>
<li>
<p><code>img</code></p>
<p>Affiche ou non l'image d'un éventuel attribut de type HTML
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_image-lsattr_html_image">LSattr_html_image</a>.</p>
</li>
</ul>
<ul>
<li>
<p><code>args</code></p>
<p>Tableau associatif contenant une liste ordonnée des attributs qui apparaîtront dans l'onglet.</p>
</li>
</ul>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>Lorsqu'un <em>layout</em> est défini, celui-ci est <em>"suivi à la lettre"</em> pour l'affichage du
<a href="#conf-lsobject-lsform-lsform">LSform</a>. Ainsi, si un attribut est défini dans la configuration de l'objet comme
présent dans le <a href="#conf-lsobject-lsform-lsform">LSform</a> courant, mais que celui-ci n'est pas présent dans le <em>layout</em>,
il ne sera pas du tout affiché.</p>
</div>
<h3 id="conf-lsobject-lsform-configuration-des-masques-de-saisie">Configuration des masques de saisie</h3>
<p>La configuration des masques de saisie (<em>dataEntryForm</em>) se situe dans la configuration des
<a href="#conf-lsobject-configuration-lsobject">LSobjects</a>, dans la variable <code>dataEntryForm</code>
(<code>$GLOBALS['LSobjects']['[nom du type d'LSobject]']['LSform']['dataEntryForm']</code>). Cette variable est
un tableau associatif dont la clé est l'identifiant du masque de saisie et dont la valeur associée
est sa configuration.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsform-__codelineno-2-1" id="__codelineno-2-1" name="__codelineno-2-1"></a><span class="x">$GLOBALS['LSobjects']['[nom du type d'LSobject]']['LSform']['dataEntryForm'] = array (</span>
<a href="#conf-lsobject-lsform-__codelineno-2-2" id="__codelineno-2-2" name="__codelineno-2-2"></a><span class="x"> 'masque1' =&gt; array(</span>
<a href="#conf-lsobject-lsform-__codelineno-2-3" id="__codelineno-2-3" name="__codelineno-2-3"></a><span class="x"> 'label' =&gt; '[label du masque de saisie]',</span>
<a href="#conf-lsobject-lsform-__codelineno-2-4" id="__codelineno-2-4" name="__codelineno-2-4"></a><span class="x"> 'disabledLayout' =&gt; [booleen],</span>
<a href="#conf-lsobject-lsform-__codelineno-2-5" id="__codelineno-2-5" name="__codelineno-2-5"></a><span class="x"> 'displayedElements' =&gt; array (</span>
<a href="#conf-lsobject-lsform-__codelineno-2-6" id="__codelineno-2-6" name="__codelineno-2-6"></a><span class="x"> 'attr1',</span>
<a href="#conf-lsobject-lsform-__codelineno-2-7" id="__codelineno-2-7" name="__codelineno-2-7"></a><span class="x"> 'attr2',</span>
<a href="#conf-lsobject-lsform-__codelineno-2-8" id="__codelineno-2-8" name="__codelineno-2-8"></a><span class="x"> ...</span>
<a href="#conf-lsobject-lsform-__codelineno-2-9" id="__codelineno-2-9" name="__codelineno-2-9"></a><span class="x"> ),</span>
<a href="#conf-lsobject-lsform-__codelineno-2-10" id="__codelineno-2-10" name="__codelineno-2-10"></a><span class="x"> 'defaultValues' =&gt; array (</span>
<a href="#conf-lsobject-lsform-__codelineno-2-11" id="__codelineno-2-11" name="__codelineno-2-11"></a><span class="x"> 'attr3' =&gt; [value],</span>
<a href="#conf-lsobject-lsform-__codelineno-2-12" id="__codelineno-2-12" name="__codelineno-2-12"></a><span class="x"> 'attr4' =&gt; [value],</span>
<a href="#conf-lsobject-lsform-__codelineno-2-13" id="__codelineno-2-13" name="__codelineno-2-13"></a><span class="x"> ...</span>
<a href="#conf-lsobject-lsform-__codelineno-2-14" id="__codelineno-2-14" name="__codelineno-2-14"></a><span class="x"> ),</span>
<a href="#conf-lsobject-lsform-__codelineno-2-15" id="__codelineno-2-15" name="__codelineno-2-15"></a><span class="x"> 'requiredAllAttributes' =&gt; [booleen],</span>
<a href="#conf-lsobject-lsform-__codelineno-2-16" id="__codelineno-2-16" name="__codelineno-2-16"></a><span class="x"> 'requiredAttributes' =&gt; array (</span>
<a href="#conf-lsobject-lsform-__codelineno-2-17" id="__codelineno-2-17" name="__codelineno-2-17"></a><span class="x"> 'attr1',</span>
<a href="#conf-lsobject-lsform-__codelineno-2-18" id="__codelineno-2-18" name="__codelineno-2-18"></a><span class="x"> 'attr2',</span>
<a href="#conf-lsobject-lsform-__codelineno-2-19" id="__codelineno-2-19" name="__codelineno-2-19"></a><span class="x"> ...</span>
<a href="#conf-lsobject-lsform-__codelineno-2-20" id="__codelineno-2-20" name="__codelineno-2-20"></a><span class="x"> ),</span>
<a href="#conf-lsobject-lsform-__codelineno-2-21" id="__codelineno-2-21" name="__codelineno-2-21"></a><span class="x"> 'forceGeneration' =&gt; array (</span>
<a href="#conf-lsobject-lsform-__codelineno-2-22" id="__codelineno-2-22" name="__codelineno-2-22"></a><span class="x"> 'attr1',</span>
<a href="#conf-lsobject-lsform-__codelineno-2-23" id="__codelineno-2-23" name="__codelineno-2-23"></a><span class="x"> 'attr2',</span>
<a href="#conf-lsobject-lsform-__codelineno-2-24" id="__codelineno-2-24" name="__codelineno-2-24"></a><span class="x"> ...</span>
<a href="#conf-lsobject-lsform-__codelineno-2-25" id="__codelineno-2-25" name="__codelineno-2-25"></a><span class="x"> ),</span>
<a href="#conf-lsobject-lsform-__codelineno-2-26" id="__codelineno-2-26" name="__codelineno-2-26"></a><span class="x"> ),</span>
<a href="#conf-lsobject-lsform-__codelineno-2-27" id="__codelineno-2-27" name="__codelineno-2-27"></a><span class="x"> ...</span>
<a href="#conf-lsobject-lsform-__codelineno-2-28" id="__codelineno-2-28" name="__codelineno-2-28"></a><span class="x">);</span>
</code></pre></div>
<ul>
<li>
<p><code>label</code></p>
<p>Le label du masque de saisie.</p>
</li>
</ul>
<ul>
<li>
<p><code>disabledLayout</code></p>
<p>Active ou non les <a href="#conf-lsobject-lsform-configuration-de-laffichage">layouts</a> pour ce masque de saisie.</p>
</li>
</ul>
<ul>
<li>
<p><code>displayedElements</code></p>
<p>Tableau contenant la liste des attributs qui devront être saisie dans le masque de saisie.</p>
</li>
</ul>
<ul>
<li>
<p><code>defaultValues</code></p>
<p>Tableau associatif contenant la liste des valeurs par défaut des attributs. Les valeurs multiples
sont possibles en utilisant des tableaux.</p>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>Les valeurs seront vue comme des valeurs retournées par le formulaire et non comme des valeurs
des attribus LDAP eux-même. Ainsi et par exemple, un attribut traité comme un booléen dans un
formulaire pourra prendre comme valeur par défaut <code>yes</code> ou <code>no</code>.</p>
</div>
</li>
</ul>
<ul>
<li>
<p><code>requiredAttributes</code></p>
<p>Tableau contenant la liste des attributs obligatoires du masque de saisie. Cette liste d'attributs
obligatoires viendra en complément de la configuration des attributs. Il est ainsi possible de
rendre des attributs obligatoires durant la saisie d'un masque tout en les laissant facultatif le
reste du temps.</p>
</li>
</ul>
<ul>
<li>
<p><code>requiredAllAttributes</code></p>
<p>Si ce parametre vaut <code>True</code>, tout les attributs du masque de saisie seront tous obligatoires de la
même manière qu'avec le paramètre <code>requiredAttributes</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>forceGeneration</code></p>
<p>Tableau contenant la liste des attributs dont la génération sera forcée lors de la validation du
formation.</p>
</li>
</ul></section><section class="print-page" id="conf-lsobject-lssearch"><h1 id="conf-lsobject-lssearch-recherche-des-objets-dans-lannuaire-lssearch">Recherche des objets dans l'annuaire (LSsearch)</h1>
<p>Cette section décrit la manière de paramétrer les recherches dans l'annuaire pour un type
d'<a href="#conf-lsobject-configuration-lsobject">LSobject</a> donné.</p>
<p>La configuration des <em>LSsearch</em> se situe dans la configuration des
<a href="#conf-lsobject-configuration-lsobject">LSobjects</a>, dans la variable <code>LSsearch</code>
(<code>$GLOBALS['LSobjects']['[nom du type d'LSobject]']['LSsearch']</code>).</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lssearch-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="x">$GLOBALS['LSobjects']['[nom du type d'LSobject]']['LSsearch'] = array (</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a><span class="x"> 'attrs' =&gt; array(</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a><span class="x"> 'attr1',</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a><span class="x"> 'attr2',</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a><span class="x"> ...</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a><span class="x"> 'attr3' =&gt; array(</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a><span class="x"> 'searchLSformat' =&gt; '[LSformat]',</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a><span class="x"> 'approxLSformat' =&gt; '[LSformat]',</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a><span class="x"> ),</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a><span class="x"> ...</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a><span class="x"> ),</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a><span class="x"> 'params' =&gt; array(</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a><span class="x"> // Paramètres de la recherche</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a><span class="x"> 'pattern' =&gt; '[string]',</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a><span class="x"> 'sizelimit' =&gt; [integer],</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-16" id="__codelineno-0-16" name="__codelineno-0-16"></a><span class="x"> 'recursive' =&gt; [boolean],</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-17" id="__codelineno-0-17" name="__codelineno-0-17"></a><span class="x"> 'approx' =&gt; [boolean],</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-18" id="__codelineno-0-18" name="__codelineno-0-18"></a><span class="x"> 'withoutCache' =&gt; [boolean],</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-19" id="__codelineno-0-19" name="__codelineno-0-19"></a><span class="x"> 'onlyAccessible' =&gt; [boolean],</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-20" id="__codelineno-0-20" name="__codelineno-0-20"></a><span class="x"> // Paramètres de tri</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-21" id="__codelineno-0-21" name="__codelineno-0-21"></a><span class="x"> 'sortBy' =&gt; [displayName|subDn],</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-22" id="__codelineno-0-22" name="__codelineno-0-22"></a><span class="x"> 'sortDirection' =&gt; [ASC|DESC],</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-23" id="__codelineno-0-23" name="__codelineno-0-23"></a><span class="x"> 'sortlimit' =&gt; [integer],</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-24" id="__codelineno-0-24" name="__codelineno-0-24"></a><span class="x"> // Paramètre d'affichage</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-25" id="__codelineno-0-25" name="__codelineno-0-25"></a><span class="x"> 'displayFormat' =&gt; [LSformat],</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-26" id="__codelineno-0-26" name="__codelineno-0-26"></a><span class="x"> 'nbObjectsByPage' =&gt; [integer],</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-27" id="__codelineno-0-27" name="__codelineno-0-27"></a><span class="x"> 'nbObjectsByPageChoices' =&gt; array([integer], [integer], ...),</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-28" id="__codelineno-0-28" name="__codelineno-0-28"></a><span class="x"> 'validPatternRegex' =&gt; '[regex]'</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-29" id="__codelineno-0-29" name="__codelineno-0-29"></a><span class="x"> ),</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-30" id="__codelineno-0-30" name="__codelineno-0-30"></a><span class="x"> 'predefinedFilters' =&gt; array(</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-31" id="__codelineno-0-31" name="__codelineno-0-31"></a><span class="x"> 'filter1' =&gt; 'label filter1',</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-32" id="__codelineno-0-32" name="__codelineno-0-32"></a><span class="x"> 'filter2' =&gt; 'label filter2'</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-33" id="__codelineno-0-33" name="__codelineno-0-33"></a><span class="x"> ),</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-34" id="__codelineno-0-34" name="__codelineno-0-34"></a><span class="x"> 'extraDisplayedColumns' =&gt; array(</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-35" id="__codelineno-0-35" name="__codelineno-0-35"></a><span class="x"> 'col1' =&gt; array(</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-36" id="__codelineno-0-36" name="__codelineno-0-36"></a><span class="x"> 'label' =&gt; 'label column 1',</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-37" id="__codelineno-0-37" name="__codelineno-0-37"></a><span class="x"> 'LSformat' =&gt; '[LSformat]'</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-38" id="__codelineno-0-38" name="__codelineno-0-38"></a><span class="x"> ),</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-39" id="__codelineno-0-39" name="__codelineno-0-39"></a><span class="x"> 'col2' =&gt; array(</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-40" id="__codelineno-0-40" name="__codelineno-0-40"></a><span class="x"> 'label' =&gt; 'label column 2',</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-41" id="__codelineno-0-41" name="__codelineno-0-41"></a><span class="x"> 'generateFunction' =&gt; '[fonction de génération]',</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-42" id="__codelineno-0-42" name="__codelineno-0-42"></a><span class="x"> 'additionalAttrs' =&gt; array('[attr1]', '[attr2]', ...),</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-43" id="__codelineno-0-43" name="__codelineno-0-43"></a><span class="x"> 'escape' =&gt; [booléen],</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-44" id="__codelineno-0-44" name="__codelineno-0-44"></a><span class="x"> ),</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-45" id="__codelineno-0-45" name="__codelineno-0-45"></a><span class="x"> 'col3' =&gt; array(</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-46" id="__codelineno-0-46" name="__codelineno-0-46"></a><span class="x"> 'label' =&gt; 'label column 3',</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-47" id="__codelineno-0-47" name="__codelineno-0-47"></a><span class="x"> 'LSformat' =&gt; '[LSformat]',</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-48" id="__codelineno-0-48" name="__codelineno-0-48"></a><span class="x"> 'alternativeLSformats' =&gt; array (</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-49" id="__codelineno-0-49" name="__codelineno-0-49"></a><span class="x"> '[LSformat 1]',</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-50" id="__codelineno-0-50" name="__codelineno-0-50"></a><span class="x"> '[LSformat 2]'</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-51" id="__codelineno-0-51" name="__codelineno-0-51"></a><span class="x"> ),</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-52" id="__codelineno-0-52" name="__codelineno-0-52"></a><span class="x"> 'formaterLSformat' =&gt; '[LSformat]',</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-53" id="__codelineno-0-53" name="__codelineno-0-53"></a><span class="x"> 'formaterFunction' =&gt; '[fonction de formatage]',</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-54" id="__codelineno-0-54" name="__codelineno-0-54"></a><span class="x"> 'cssStyle' =&gt; '[CSS style]',</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-55" id="__codelineno-0-55" name="__codelineno-0-55"></a><span class="x"> 'visibleTo' =&gt; array (</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-56" id="__codelineno-0-56" name="__codelineno-0-56"></a><span class="x"> '[LSprofile 1]',</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-57" id="__codelineno-0-57" name="__codelineno-0-57"></a><span class="x"> '[LSprofile 2]'</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-58" id="__codelineno-0-58" name="__codelineno-0-58"></a><span class="x"> )</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-59" id="__codelineno-0-59" name="__codelineno-0-59"></a><span class="x"> ),</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-60" id="__codelineno-0-60" name="__codelineno-0-60"></a><span class="x"> ),</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-61" id="__codelineno-0-61" name="__codelineno-0-61"></a><span class="x"> 'customActions' =&gt; array (</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-62" id="__codelineno-0-62" name="__codelineno-0-62"></a><span class="x"> // Configuration des customActions pour les recherches de ce type d'objet</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-63" id="__codelineno-0-63" name="__codelineno-0-63"></a><span class="x"> ),</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-64" id="__codelineno-0-64" name="__codelineno-0-64"></a><span class="x"> 'showSelectionBoxes' =&gt; [boolean],</span>
<a href="#conf-lsobject-lssearch-__codelineno-0-65" id="__codelineno-0-65" name="__codelineno-0-65"></a><span class="x">);</span>
</code></pre></div>
<ul>
<li>
<p><code>attrs</code></p>
<p>Tableau listant les attributs pouvant être utilisés dans les filtres de recherche LDAP employés
par LdapSaisie. Lorsqu'un motif de recherche est passé par l'utilisateur, LdapSaisie composera un
filtre LDAP à partir de cette liste.</p>
<p>Lors d'une recherche non-approximative, le filtre de recherche sera composé (par défaut) de la
manière suivante :</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lssearch-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a>(|(attr1=*motif*)(attr2=*motif*)...)
</code></pre></div>
<p>Lors d'une recherche approximative, le filtre de recherche sera composé (par défaut) de la manière
suivante :</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lssearch-__codelineno-2-1" id="__codelineno-2-1" name="__codelineno-2-1"></a>(|(attr1=~motif)(attr2~=motif)...)
</code></pre></div>
<p>Il est également possible de paramétrer la manière dont sera composé le filtre de recherche
attribut par attribut à l'aide des paramètres <code>searchLSformat</code> et <code>approxLSformat</code>.</p>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>Ces filtres, une fois composés, sont insérés dans un autre, filtrant en plus sur les
<em>ObjectClass</em> du type d'<a href="#conf-lsobject-configuration-lsobject">LSobject</a> de la manière suivante :</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lssearch-__codelineno-3-1" id="__codelineno-3-1" name="__codelineno-3-1"></a>(&amp; (&amp;(objectclass=oc1)(objectclass=oc2)) (filtre) )
</code></pre></div>
</div>
<ul>
<li>
<p><code>searchLSformat</code></p>
<p>Ce paramètre est un <a href="#conf-global-lsformat-format-parametrable">LSformat</a> permettant de définir,
attribut par attribut, comment le filtre de recherche LDAP est composé à partir d'un motif de
recherche et en cas de recherche non-approximative.</p>
<p>Ce <a href="#conf-global-lsformat-format-parametrable">LSformat</a> est composé à l'aide des éléments
<code>name</code>, le nom de l'attribut et <code>pattern</code>, le motif de recherche.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lssearch-__codelineno-4-1" id="__codelineno-4-1" name="__codelineno-4-1"></a>(%{name}=%{pattern})
</code></pre></div>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>Le filtre déduit doit obligatoirement commencer par <code>(</code> et se terminer par <code>)</code>.</p>
</div>
</li>
</ul>
<ul>
<li>
<p><code>approxLSformat</code></p>
<p>Ce paramètre est un <a href="#conf-global-lsformat-format-parametrable">LSformat</a> permettant de définir,
attribut par attribut, comment le filtre de recherche LDAP est composé à partir d'un motif de
recherche et en cas de recherche approximative.</p>
<p>Ce <a href="#conf-global-lsformat-format-parametrable">LSformat</a> est composé à l'aide des éléments
<code>name</code>, le nom de l'attribut et <code>pattern</code>, le motif de recherche.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lssearch-__codelineno-5-1" id="__codelineno-5-1" name="__codelineno-5-1"></a>(%{name}=~%{pattern})
</code></pre></div>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>Le filtre déduit doit obligatoirement commencer par <code>(</code> et se terminer par <code>)</code>.</p>
</div>
</li>
</ul>
</li>
</ul>
<ul>
<li>
<p><code>params</code></p>
<p>Tableau des paramètres par défaut d'une recherche. Ce tableau contient les paramètres qui seront
utilisés pour initialisé une recherche. Ces paramètres pourront être redéfini par l'utilisateur
ou par l'application en fonction du contexte dans lequel cette recherche est effectuée.</p>
<ul>
<li>
<p><code>pattern</code></p>
<p>Mot clé de la recherche.</p>
</li>
</ul>
<ul>
<li>
<p><code>sizelimit</code></p>
<p>Entier determinant le nombre maximum d'objet pouvant être retournés dans une recherche.</p>
</li>
</ul>
<ul>
<li>
<p><code>recursive</code></p>
<p>Booléen déterminant si la recherche récursive est activée.</p>
</li>
</ul>
<ul>
<li>
<p><code>approx</code></p>
<p>Booléen déterminant si la recherche approximative est activée.</p>
</li>
</ul>
<ul>
<li>
<p><code>withoutCache</code></p>
<p>Booléen déterminant si le cache de recherche doit être utilisé.</p>
</li>
</ul>
<ul>
<li>
<p><code>onlyAccessible</code></p>
<p>Booléen déterminant si seul les objets accessibles à l'utilisateur connecté doivent être
retournés par la recherche.</p>
</li>
</ul>
<ul>
<li>
<p><code>sortBy</code></p>
<p>Mot clé déterminant sur quel valeur/colonne le résultat de recherche sera trié.</p>
<p>Valeurs possibles : <code>displayName</code>, <code>subDn</code> ou <code>NULL</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>sortDirection</code></p>
<p>Mot clé déterminant le sens du trie du résultat de la recherche.</p>
<p>Valeurs possibles : <code>ASC</code>, <code>DESC</code> ou <code>NULL</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>sortlimit</code></p>
<p>Entier determinant le nombre maximum d'objet pouvant être triés dans le résultat d'une
recherche.</p>
</li>
</ul>
<ul>
<li>
<p><code>displayFormat</code></p>
<p><a href="#conf-global-lsformat-format-parametrable">LSformat</a> d'affichage du nom de l'objet dans le
résultat de la recherche.</p>
</li>
</ul>
<ul>
<li>
<p><code>nbObjectsByPage</code></p>
<p>Entier déterminant le nombre d'objet maximum affichés dans une page de résultat de la recherche.</p>
</li>
</ul>
<ul>
<li>
<p><code>nbObjectsByPageChoices</code></p>
<p>Tableau des choix proposés à l'utilisateur pour le nombre d'objets maximum affichés dans une
page de résultat de la recherche.</p>
</li>
</ul>
<ul>
<li>
<p><code>validPatternRegex</code></p>
<p>Expression régulière de validation des mots clés de recherche pour ce type
d'<a href="#conf-lsobject-configuration-lsobject">LSobject</a>.</p>
<p>(Par défaut : <code>/^[\w\-_\\\'\"^[]\(\){}\=\+\£\%\$\€\.\:\;\,\?\/\@]+$/iu</code>)</p>
</li>
</ul>
</li>
</ul>
<ul>
<li>
<p><code>predefinedFilters</code></p>
<p>Tableau associatif contenant des filtres prédéfinis pour la recherche. Les clés sont les filtres
au format LDAP et les valeurs sont les labels associés.</p>
</li>
</ul>
<ul>
<li>
<p><code>extraDisplayedColumns</code></p>
<p>Tableau associatif contenant des colonnes supplémentaires à afficher dans les résultats de
recherche. Les clés sont les identifiants des colonnes supplémentaires et les valeurs sont leur
configuration définie à partir des paramètres suivant :</p>
<ul>
<li>
<p><code>label</code></p>
<p>Le label de la colonne.</p>
</li>
</ul>
<ul>
<li>
<p><code>LSformat</code></p>
<p>Le <a href="#conf-global-lsformat-format-parametrable">LSformat</a> d'affichage de la colonne. Ce format
est composé à partir des attributs des objets LDAP dans leur format brut.</p>
</li>
</ul>
<ul>
<li>
<p><code>alternativeLSformats</code></p>
<p>Tableau des <a href="#conf-global-lsformat-format-parametrable">LSformats</a> alternatifs à utiliser si le
résultat du format principal est vide. Les formats définis dans cette liste sont essayés les uns
après les autres et le premier <a href="#conf-global-lsformat-format-parametrable">LSformat</a> retournant
une valeur non-vide est utilisé.</p>
</li>
</ul>
<ul>
<li>
<p><code>formaterLSformat</code></p>
<p><a href="#conf-global-lsformat-format-parametrable">LSformat</a> optionnel permettant de mettre en forme le
résultat obtenu des <a href="#conf-global-lsformat-format-parametrable">LSformats</a> précédents. Ce
<a href="#conf-global-lsformat-format-parametrable">LSformat</a> ne sera utilisé que si le résultat obtenu
précédement n'est pas vide. Il est ainsi possible d'utiliser les paramètres <code>LSformat</code> et
<code>alternativeLSformats</code> afin de récupérer la valeur à afficher, puis de la mettre en forme grâce
à ce <a href="#conf-global-lsformat-format-parametrable">LSformat</a>. Ce format est composé à partir des
attributs des objets LDAP dans leur format brut et de la valeur retournés précedement accessible
via la variable <code>val</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>formaterFunction</code></p>
<p>Le nom d'une fonction optionnelle à exécuter pour mettre en forme le résultat obtenu des
<a href="#conf-global-lsformat-format-parametrable">LSformats</a> précédents. Cette fonction ne sera
appelée que si le résultat obtenu précédement n'est pas vide. La fonction prendra en paramètre
la valeur à mettre en forme et retournera la valeur mise en forme.</p>
</li>
</ul>
<ul>
<li>
<p><code>generateFunction</code></p>
<p>Le nom d'une fonction qui sera utilisée pour générer la valeur d'affichage de cette colonne. La
fonction prendra en paramètre une référence de l'objet <code>LSsearchEntry</code> et retournera la valeur
de la colonne.</p>
</li>
</ul>
<ul>
<li>
<p><code>additionalAttrs</code></p>
<p>Un tableau de nom d'attributs à inclure dans le resultat de la recherche LDAP. Ce tableau permet
notamment d'inclure les attributs nécessaires au bon fonctionnement de la fonction
<code>generateFunction</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>escape</code></p>
<p>Ce paramètre booléen permet de définir si, lors de l'affichage, le contenu de la colonne doit
être transformé pour protéger les caractères éligibles en entités HTML. Par défaut, ce paramètre
est <code>True</code>.</p>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>Cette fonctionnalité existe pour des raisons de sécurité et notamment en protection des
failles <code>XSS</code>. Si vous désactivez cette fonctionnalité, il est important de gérer la
problématique de sécurité par ailleurs.</p>
</div>
</li>
</ul>
<ul>
<li>
<p><code>cssStyle</code></p>
<p>Ce paramètre permet de définir un style CSS personnalisé pour la colonne. S'il est défini, le
contenu de ce paramètre sera ajouté en tant qu'attribut <code>style</code> des balises <code>th</code> et <code>td</code> de la
colone.</p>
</li>
</ul>
<ul>
<li>
<p><code>visibleTo</code></p>
<p>Ce paramètre permet de restreindre la visibilité de cette colonne aux seuls
<a href="#conf-global-ldap-lsprofile-profils-dutilisateurs">LSprofiles</a> spécifiés. S'il est omis, la
colonne sera visible pour tous.</p>
</li>
</ul>
</li>
</ul>
<ul>
<li>
<p><code>customActions</code></p>
<p>Tableau associatif contenant les paramètres de configuration des
<a href="#conf-lsobject-lssearch-customactions">customActions</a>. <a href="#conf-lsobject-lssearch-customactions">Voir la section concernée</a>.</p>
</li>
</ul>
<ul>
<li>
<p><code>showSelectionBoxes</code></p>
<p>Booléen permettant de définir si les cases à cocher de sélections des objets doivent être
affichées. Lorsqu'elles sont affichées, l'utilisateur pourra sélectionner un ou plusieurs objets
dans la liste avant de déclencher une <a href="#conf-lsobject-lssearch-customsactions">customAction</a>. Dans ce cas, les DNs de ces
objets seront passés à la page d'exécution de la <a href="#conf-lsobject-lssearch-customsactions">customAction</a> via le paramètre
<code>selected</code>.</p>
</li>
</ul>
<h2 id="conf-lsobject-lssearch-les-actions-personnalisees-customactions">Les actions personnalisées (customActions)</h2>
<p>Cette section décrit la manière de configurer les actions personnalisées exécutables sur les
recherches d'<a href="#conf-lsobject-configuration-lsobject">LSobjects</a> appelées <a href="#conf-lsobject-lssearch-customactions">customActions</a>.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lssearch-__codelineno-6-1" id="__codelineno-6-1" name="__codelineno-6-1"></a>$GLOBALS['LSobjects']['[nom du type d'LSobject]']['LSsearch']['customActions'] = array (
<a href="#conf-lsobject-lssearch-__codelineno-6-2" id="__codelineno-6-2" name="__codelineno-6-2"></a> 'action1' =&gt; array(
<a href="#conf-lsobject-lssearch-__codelineno-6-3" id="__codelineno-6-3" name="__codelineno-6-3"></a> 'label' =&gt; '[label l'action]',
<a href="#conf-lsobject-lssearch-__codelineno-6-4" id="__codelineno-6-4" name="__codelineno-6-4"></a> 'hideLabel' =&gt; '[booléen]',
<a href="#conf-lsobject-lssearch-__codelineno-6-5" id="__codelineno-6-5" name="__codelineno-6-5"></a> 'icon' =&gt; '[nom de l'icône de l'action]',
<a href="#conf-lsobject-lssearch-__codelineno-6-6" id="__codelineno-6-6" name="__codelineno-6-6"></a> 'function' =&gt; '[fonction à exécuter]',
<a href="#conf-lsobject-lssearch-__codelineno-6-7" id="__codelineno-6-7" name="__codelineno-6-7"></a> 'question_format' =&gt; '[LSformat de la question de confirmation]',
<a href="#conf-lsobject-lssearch-__codelineno-6-8" id="__codelineno-6-8" name="__codelineno-6-8"></a> 'onSuccessMsgFormat' =&gt; '[LSformat du message à afficher en cas de succès de l'action]',
<a href="#conf-lsobject-lssearch-__codelineno-6-9" id="__codelineno-6-9" name="__codelineno-6-9"></a> 'disableOnSuccessMsg' =&gt; '[booléen]',
<a href="#conf-lsobject-lssearch-__codelineno-6-10" id="__codelineno-6-10" name="__codelineno-6-10"></a> 'noConfirmation' =&gt; '[booléen]',
<a href="#conf-lsobject-lssearch-__codelineno-6-11" id="__codelineno-6-11" name="__codelineno-6-11"></a> 'redirectToObjectList' =&gt; '[booléen]',
<a href="#conf-lsobject-lssearch-__codelineno-6-12" id="__codelineno-6-12" name="__codelineno-6-12"></a> 'rights' =&gt; array(
<a href="#conf-lsobject-lssearch-__codelineno-6-13" id="__codelineno-6-13" name="__codelineno-6-13"></a> 'LSprofile1',
<a href="#conf-lsobject-lssearch-__codelineno-6-14" id="__codelineno-6-14" name="__codelineno-6-14"></a> 'LSprofile2',
<a href="#conf-lsobject-lssearch-__codelineno-6-15" id="__codelineno-6-15" name="__codelineno-6-15"></a> ...
<a href="#conf-lsobject-lssearch-__codelineno-6-16" id="__codelineno-6-16" name="__codelineno-6-16"></a> )
<a href="#conf-lsobject-lssearch-__codelineno-6-17" id="__codelineno-6-17" name="__codelineno-6-17"></a> )
<a href="#conf-lsobject-lssearch-__codelineno-6-18" id="__codelineno-6-18" name="__codelineno-6-18"></a>);
</code></pre></div>
<ul>
<li>
<p><code>label</code></p>
<p>Le label de l'action.</p>
</li>
</ul>
<ul>
<li>
<p><code>hideLabel</code></p>
<p>Cache le label dans le bouton de l'action.</p>
</li>
</ul>
<ul>
<li>
<p><code>icon</code></p>
<p>Nom de l'îcone à afficher dans le bouton de l'action. Ce nom correspond au nom du fichier de
l'image (sans l'extention) qui devra se trouver dans le dossier
<code>/src/images/[nom du theme d'images]/</code> ou dans le dossier <code>src/local/images</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>function</code></p>
<p>Le nom de la fonction à exécuter qui implémente l'action personnalisée Cette fonction prendra en
seule paramètre l'objet <a href="#conf-lsobject-lssearch-lssearch">LSsearch</a>. sur lequel l'action devra être exécutée et
retournera <code>True</code> en cas de succès ou <code>False</code> en cas d'échec d'exécution de la fonction.</p>
</li>
</ul>
<ul>
<li>
<p><code>question_format</code></p>
<p>Le <a href="#conf-global-lsformat-format-parametrable">LSformat</a> de la question de confirmation
d'exécution de l'action. Ce <a href="#conf-global-lsformat-format-parametrable">LSformat</a> sera composé à
l'aide du label de l'action.</p>
</li>
</ul>
<ul>
<li>
<p><code>onSuccessMsgFormat</code></p>
<p>Le <a href="#conf-global-lsformat-format-parametrable">LSformat</a> du message à afficher en cas de succès
d'exécution de l'action. Ce <a href="#conf-global-lsformat-format-parametrable">LSformat</a> sera composé à
l'aide du label de l'action.</p>
</li>
</ul>
<ul>
<li>
<p><code>disableOnSuccessMsg</code></p>
<p>Booléen permetant de désactiver le message afficher en cas de succès d'exécution de l'action.</p>
</li>
</ul>
<ul>
<li>
<p><code>noConfirmation</code></p>
<p>Booléen permetant de désactiver la confirmation de l'exécution de l'action.</p>
</li>
</ul>
<ul>
<li>
<p><code>redirectToObjectList</code></p>
<p>Booléen permetant de rediriger ou non l'utilisateur vers la liste des objets (Vrai par défaut).
Si l'utilisateur n'est redirigé, le template par défaut (ou celui défini durant l'éxécution de la
fonction) sera affiché.</p>
</li>
</ul>
<ul>
<li>
<p><code>rights</code></p>
<p>Tableau contenant la liste des noms des <a href="#conf-global-ldap-lsprofile-profils-dutilisateurs">LSprofiles</a>
ayant le droit d'exécuter cette action.</p>
</li>
</ul>
<h3 id="conf-lsobject-lssearch-ecriture-dune-fonction-implementant-une-customaction">Écriture d'une fonction implémentant une customAction</h3>
<p>Une fonction implémentant une <em>customAction</em> se déclare de la manière suivante :</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lssearch-__codelineno-7-1" id="__codelineno-7-1" name="__codelineno-7-1"></a><span class="x">/*</span>
<a href="#conf-lsobject-lssearch-__codelineno-7-2" id="__codelineno-7-2" name="__codelineno-7-2"></a><span class="x"> * Ma fonction implémentant ma customAction</span>
<a href="#conf-lsobject-lssearch-__codelineno-7-3" id="__codelineno-7-3" name="__codelineno-7-3"></a><span class="x"> *</span>
<a href="#conf-lsobject-lssearch-__codelineno-7-4" id="__codelineno-7-4" name="__codelineno-7-4"></a><span class="x"> * Paramètre :</span>
<a href="#conf-lsobject-lssearch-__codelineno-7-5" id="__codelineno-7-5" name="__codelineno-7-5"></a><span class="x"> * - $search : L'objet LSsearch de la recherche sur lequel mon action doit être exécutée</span>
<a href="#conf-lsobject-lssearch-__codelineno-7-6" id="__codelineno-7-6" name="__codelineno-7-6"></a><span class="x"> *</span>
<a href="#conf-lsobject-lssearch-__codelineno-7-7" id="__codelineno-7-7" name="__codelineno-7-7"></a><span class="x"> * Valeurs retournées :</span>
<a href="#conf-lsobject-lssearch-__codelineno-7-8" id="__codelineno-7-8" name="__codelineno-7-8"></a><span class="x"> * - True : Tout s'est bien passé</span>
<a href="#conf-lsobject-lssearch-__codelineno-7-9" id="__codelineno-7-9" name="__codelineno-7-9"></a><span class="x"> * - False : Une erreur est survenue</span>
<a href="#conf-lsobject-lssearch-__codelineno-7-10" id="__codelineno-7-10" name="__codelineno-7-10"></a><span class="x"> */</span>
<a href="#conf-lsobject-lssearch-__codelineno-7-11" id="__codelineno-7-11" name="__codelineno-7-11"></a><span class="x">function maFonction ($search) {</span>
<a href="#conf-lsobject-lssearch-__codelineno-7-12" id="__codelineno-7-12" name="__codelineno-7-12"></a>
<a href="#conf-lsobject-lssearch-__codelineno-7-13" id="__codelineno-7-13" name="__codelineno-7-13"></a><span class="x"> // Actions</span>
<a href="#conf-lsobject-lssearch-__codelineno-7-14" id="__codelineno-7-14" name="__codelineno-7-14"></a>
<a href="#conf-lsobject-lssearch-__codelineno-7-15" id="__codelineno-7-15" name="__codelineno-7-15"></a><span class="x">}</span>
</code></pre></div>
<p>Cette fonction doit prendre pour seul paramètre, l'objet <a href="#conf-lsobject-lssearch-lssearch">LSsearch</a>. sur lequel l'action
personnalisée doit être exécutée et doit retourner soit <code>True</code> si tout s'est bien passé, soit
<code>False</code> en cas de problème.</p>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>La recherche passée en paramètre n'a pas encore été exécutée. En conséquence, si vous avez
besoin d'accéder au résultat de la recherche, il est nécessaire d'exécuter au préalable :
<code>$search -&gt; run();</code>. Cela permet en outre, de modifier les paramètres de la recherche avant de
l'exécuter. Cela peut par exemple être utile, si vous avez besoin d'accèder aux valeurs
d'attributs particuliers, d'ajouter des attributs au résultat de la recherche :</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lssearch-__codelineno-8-1" id="__codelineno-8-1" name="__codelineno-8-1"></a><span class="x">$search -&gt; setParam('attributes',array('attr1','attr2'));</span>
</code></pre></div>
</div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Ces fonctions sont le plus couramment définies au sein
d'<a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a>.</p>
</div></section><section class="print-page" id="conf-lsobject-ioformat"><h1 id="conf-lsobject-ioformat-les-formats-dimportexport-ioformat">Les formats d'import/export (ioFormat)</h1>
<p>Cette section décrit la manière de paramétrer les formats d'import/export pour un type d'
<a href="#conf-lsobject-configuration-lsobject">LSobject</a> donné.</p>
<p>La configuration des <em>ioFormats</em> se situe dans la configuration des
<a href="#conf-lsobject-configuration-lsobject">LSobjects</a>, dans la variable <code>ioFormat</code>
(<code>$GLOBALS['LSobjects']['[nom du type d'LSobject]']['ioFormat']</code>). Cette variable est un tableau
associatif dont la clé est l'identifiant du format et dont la valeur associée est la configuration
du format.</p>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>Le moteur d'importation simule la validation d'un formulaire de création du type
d'<a href="#conf-lsobject-configuration-lsobject">LSobject</a> (ou de modification en cas d'activation du mode
mise à jour uniquement, voir ci-dessous). En conséquence :</p>
<ul>
<li>seul les attributs présent dans le formulaire de création peuvent être importés.</li>
</ul>
<ul>
<li>tous les attributs obligatoires présents dans le formulaire de création doivent être fournis
par le fichier source ou générer à partir des autres attributs.</li>
</ul>
<ul>
<li>Les valeurs des attributs issus de l'importation seront vue comme des valeurs retournées par
le formulaire et non comme des valeurs des attribus LDAP eux-même. Ainsi et par exemple, un
attribut traité comme un booléen dans un formulaire pourra prendre comme valeur par
défaut <code>yes</code> ou <code>no</code>.</li>
</ul>
</div>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-ioformat-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>$GLOBALS['LSobjects']['[nom du type d'LSobject]']['ioFormat'] = array (
<a href="#conf-lsobject-ioformat-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> '[ioFormat ID]' =&gt; array (
<a href="#conf-lsobject-ioformat-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> 'label' =&gt; '[Label du type de fichier]',
<a href="#conf-lsobject-ioformat-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> 'driver' =&gt; '[Pilote d'ioFormat utilisé]',
<a href="#conf-lsobject-ioformat-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a> 'driver_options' =&gt; array([Options du pilote d'ioFormat utilisé]),
<a href="#conf-lsobject-ioformat-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a> 'update_only' =&gt; '[Booléen]',
<a href="#conf-lsobject-ioformat-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a> 'fields =&gt; array (
<a href="#conf-lsobject-ioformat-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a> '[champ 1]' =&gt; '[attribut 1]',
<a href="#conf-lsobject-ioformat-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a> '[champ 2]' =&gt; '[attribut 2]',
<a href="#conf-lsobject-ioformat-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a> [...]
<a href="#conf-lsobject-ioformat-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a> ),
<a href="#conf-lsobject-ioformat-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a> 'generated_fields' =&gt; array (
<a href="#conf-lsobject-ioformat-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a> '[attribute 3]' =&gt; '[LSformat]',
<a href="#conf-lsobject-ioformat-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a> '[attribute 4]' =&gt; array('[LSformat1]', '[LSformat2]', ...)
<a href="#conf-lsobject-ioformat-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a> '[attribute 5]' =&gt; function($attrs, $row) {
<a href="#conf-lsobject-ioformat-__codelineno-0-16" id="__codelineno-0-16" name="__codelineno-0-16"></a> return array([...]);
<a href="#conf-lsobject-ioformat-__codelineno-0-17" id="__codelineno-0-17" name="__codelineno-0-17"></a> },
<a href="#conf-lsobject-ioformat-__codelineno-0-18" id="__codelineno-0-18" name="__codelineno-0-18"></a> [...]
<a href="#conf-lsobject-ioformat-__codelineno-0-19" id="__codelineno-0-19" name="__codelineno-0-19"></a> ),
<a href="#conf-lsobject-ioformat-__codelineno-0-20" id="__codelineno-0-20" name="__codelineno-0-20"></a> 'before_import' =&gt; array('function1', 'function2'),
<a href="#conf-lsobject-ioformat-__codelineno-0-21" id="__codelineno-0-21" name="__codelineno-0-21"></a> 'after_import' =&gt; 'function3',
<a href="#conf-lsobject-ioformat-__codelineno-0-22" id="__codelineno-0-22" name="__codelineno-0-22"></a> ),
<a href="#conf-lsobject-ioformat-__codelineno-0-23" id="__codelineno-0-23" name="__codelineno-0-23"></a> [...]
<a href="#conf-lsobject-ioformat-__codelineno-0-24" id="__codelineno-0-24" name="__codelineno-0-24"></a>);
</code></pre></div>
<ul>
<li>
<p><code>label</code></p>
<p>Le label du format</p>
</li>
</ul>
<ul>
<li>
<p><code>driver</code></p>
<p>Le pilote a utilisé pour ce format. Le pilote permet de gérér la lecture et l'écriture dans un
type de fichier d'import/export. Pour plus d'information sur les pilotes disponibles,
<a href="#conf-lsobject-ioformat-pilote-dioformat">Voir la section concernée.</a></p>
</li>
</ul>
<ul>
<li>
<p><code>driver_options</code></p>
<p>Tableau associatif des options du pilote utilisé pour ce format. Pour plus d'informations,
consulter la documentation du pilote utilisé.</p>
</li>
</ul>
<ul>
<li>
<p><code>update_only</code></p>
<p>Booléen permettant d'activer le mode mise à jour uniquement pour ce format. Dans ce mode, les
données de l'objet LDAP correspondant seront chargées depuis l'annuaire avant toutes validations
des données fournies dans le fichier d'import, et ce, dans un formulaire de modifications et non
pas un formulaire de création autrement. Pour que cela soit possible, il est indispensable que le
DN de l'objet puisse être déduit depuis les données fournies dans le fichier d'import. Pour cela,
vous pouvez le fournir via un champ du fichier d'import associé à la clé <code>dn</code> ou à défaut il sera
généré à partir du RDN dont la valeur devra être fournie dans le fichier d'import. Vous pouvez
également le générer via le paramètre <code>generated_fields</code> (voir ci-dessous).</p>
</li>
</ul>
<ul>
<li>
<p><code>fields</code></p>
<p>Tableau associatif permettant d'associer un champ du fichier source (la clé) avec attribut de
l'objet LDAP (la valeur). Il est également possible d'associé un champ avec la valeur <code>dn</code> pour
fournir le DN de l'objet en mode mise à jour uniquement (voir ci-dessus).</p>
</li>
</ul>
<ul>
<li>
<p><code>generated_fields</code></p>
<p>Tableau associatif permettant de définir soit des
<a href="#conf-global-lsformat-format-parametrable">LSformats</a>, soit un <em>callable</em> (au sens PHP) pour
générer les valeurs d'attributs automatiquement. Ce tableau contient en clé, le nom de l'attribut
à générer (ou <code>dn</code> pour la génération du DN de l'objet en mode mise à jour uniquement), et en
valeur associée, un ou plusieurs <a href="#conf-global-lsformat-format-parametrable">LSformat</a> ou un
<em>callable</em> à utiliser pour générer ses valeurs.
En cas de <a href="#conf-global-lsformat-format-parametrable">LSformat</a>, ils seront composés à l'aide des
valeurs des autres attributs de l'objet. En cas d'un <em>callable</em>, il sera appeler avec en paramètre
le tableau des valeurs des autres attributs (<code>$attrs</code>), le tableau des données issues du fichier
source (<code>$row</code>) et devra retourner le tableau des valeurs générées de l'attribut ou <code>false</code> en cas
d'erreur.</p>
</li>
</ul>
<ul>
<li>
<p><code>before_import</code></p>
<p>Chaîne de caractères (ou tableau de chaîne de caractères) correspondant au nom d'une ou plusieurs
fonctions qui seront exécutées avant chaque import. <a href="#conf-lsobject-ioformat-declencheurs">Voir la section concernée</a></p>
</li>
</ul>
<ul>
<li>
<p><code>after_import</code></p>
<p>Chaîne de caractères (ou tableau de chaîne de caractères) correspondant au nom d'une ou plusieurs
fonctions qui seront exécutées après chaque import. <a href="#conf-lsobject-ioformat-declencheurs">Voir la section concernée</a></p>
</li>
</ul>
<h2 id="conf-lsobject-ioformat-pilote-dioformat">Pilote d'ioFormat</h2>
<p>Cette section décrit la manière de configurer les pilotes d'ioFormat utilisés lors des
imports/exports d'<a href="#conf-lsobject-configuration-lsobject">LSobjects</a>.</p>
<h3 id="conf-lsobject-ioformat-pilote-de-fichiers-csv">Pilote de fichiers CSV</h3>
<p>Ce pilote permet de gérer l'import/export de <a href="#conf-lsobject-configuration-lsobject">LSobject</a> à partir
d'un fichier <code>CSV</code>. Depuis la version 4 d'LdapSaisie, ce pilote utilise les fonctions standards
<code>fgetcsv()</code> et <code>fputcsv</code> fournis par PHP. Avant cela, la classe PEAR
<a href="http://pear.php.net/package/File_CSV_DataSource">File_CSV_DataSource</a> était utilisée. Par défaut,
les paramètres de lecture et d'écriture des fichiers sont : la virgule sert de délimiteur, le
caractère <code>"</code> peut être utilisé pour encadrer les valeurs des champs et la longueur maximale d'une
ligne est infini. Ces paramètres peuvent être modifiés en configurant les options du pilote.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-ioformat-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a>$GLOBALS['LSobjects']['[nom du type d'LSobject]']['ioFormat']['[ID ioFormat]']['driver_options'] = array (
<a href="#conf-lsobject-ioformat-__codelineno-1-2" id="__codelineno-1-2" name="__codelineno-1-2"></a> 'delimiter' =&gt; '[délimiteur]',
<a href="#conf-lsobject-ioformat-__codelineno-1-3" id="__codelineno-1-3" name="__codelineno-1-3"></a> 'enclosure' =&gt; '[caractère d'encadrement de texte]',
<a href="#conf-lsobject-ioformat-__codelineno-1-4" id="__codelineno-1-4" name="__codelineno-1-4"></a> 'length' =&gt; [longueur maximale d'une ligne],
<a href="#conf-lsobject-ioformat-__codelineno-1-5" id="__codelineno-1-5" name="__codelineno-1-5"></a> 'escape' =&gt; '[caractère d'échappement]',
<a href="#conf-lsobject-ioformat-__codelineno-1-6" id="__codelineno-1-6" name="__codelineno-1-6"></a> 'multiple_value_delimiter' =&gt; '[délimiteur]',
<a href="#conf-lsobject-ioformat-__codelineno-1-7" id="__codelineno-1-7" name="__codelineno-1-7"></a>);
</code></pre></div>
<ul>
<li>
<p><code>delimiter</code></p>
<p>Le caractère utilisé pour délimiter les champs (Par défaut, une virgule).</p>
</li>
</ul>
<ul>
<li>
<p><code>length</code></p>
<p>La longueur maximale d'une ligne du fichier. Si zéro est spécifié, la longueur d'une ligne ne sera
pas limité, mais la lecture du fichier sera ralentie. (Par défaut : <code>0</code>)</p>
</li>
</ul>
<ul>
<li>
<p><code>enclosure</code></p>
<p>Le caractère utilisé pour encadrer les valeurs des champs (Par défaut : <code>"</code>).</p>
</li>
</ul>
<ul>
<li>
<p><code>escape</code></p>
<p>Le caractère d'échappement utilisé si un des champs d'une ligne de fichier contient le caractère
utilisé pour encadrer les valeurs. (Par défaut : <code>\</code>).</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Selon la RFC4180, l'echappement du caractère utilisé pour encadrer les valeurs des champs doit
se faire en le doublant. Le caractère défini ici est une alternative à ce comportement par
défaut. Pour désactiver ce caractère d'échappement alternatif, il est possible depuis de la
version 7.4.0 de PHP de mettre ici une chaine vide.</p>
</div>
</li>
</ul>
<ul>
<li>
<p><code>multiple_value_delimiter</code></p>
<p>Le caractère utilisé pour délimiter au sein d'un champs, les valeurs valeurs multiples d'un
attribut (Par défaut : <code>|</code>).</p>
</li>
</ul>
<h2 id="conf-lsobject-ioformat-declencheurs">Déclencheurs</h2>
<p>Cette section décrit la manière de paramétrer des déclencheurs afin que LdapSaisie exécute durant
ses processus, et à des moments bien précis des traitements d'un <a href="#conf-lsobject-ioformat-ioformat">ioFormat</a>, des
fonctions que vous pourrez développer vous même. De plus, le résultat de l'exécution de vos
fonctions pourra influer sur le déroulement des processus.</p>
<p>Actuellement, les évenements suivant sont gérés :</p>
<table>
<thead>
<tr>
<th>Nom</th>
<th>Description</th>
<th>Bloquant</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>before_import</code></td>
<td>Avant l'import.</td>
<td>Oui</td>
</tr>
<tr>
<td><code>after_import</code></td>
<td>Après l'import'.</td>
<td>Non</td>
</tr>
</tbody>
</table>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Si un événement est dit <em>bloquant</em>, lors de l'exécution des actions liées, si une des fonctions
retourne <code>false</code>, le processus s'arrêtera.</p>
</div>
<h3 id="conf-lsobject-ioformat-configuration">Configuration</h3>
<p>La configuration des déclencheurs se fait dans la définition des types d'<a href="#conf-lsobject-ioformat-ioformat">ioFormat</a>. Par
exemple, pour définir les fonctions à exécuter après l'import des LSobjects de type <em>LSpeople</em> avec
son LSioFormat <em>mycsv</em>, c'est à dire lors de leur évènement <code>after_import</code>, il faut définir la
variable suivante :</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-ioformat-__codelineno-2-1" id="__codelineno-2-1" name="__codelineno-2-1"></a><span class="x">$GLOBALS['LSobjects']['LSpeople']['ioFormat']['mycsv']['after_import']</span>
</code></pre></div>
<p>Cette variable peut contenir soit une chaine de caractères correspondant au nom de la fonction à
exécuter, soit un tableau de chaînes de caractères correspondant aux noms des fonctions à exécuter.
Il est également possible de mettre ici directement des
<a href="https://www.php.net/manual/fr/functions.anonymous.php">fonctions anonymes</a>.</p>
<h3 id="conf-lsobject-ioformat-ecriture-dune-fonction">Ecriture d'une fonction</h3>
<p>Une fonction exécutée par un déclencheur d'un ioFormat se déclare de la manière suivante :</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-ioformat-__codelineno-3-1" id="__codelineno-3-1" name="__codelineno-3-1"></a><span class="x">/*</span>
<a href="#conf-lsobject-ioformat-__codelineno-3-2" id="__codelineno-3-2" name="__codelineno-3-2"></a><span class="x"> * Ma fonction à exécuter lors de l'evenement [event]</span>
<a href="#conf-lsobject-ioformat-__codelineno-3-3" id="__codelineno-3-3" name="__codelineno-3-3"></a><span class="x"> *</span>
<a href="#conf-lsobject-ioformat-__codelineno-3-4" id="__codelineno-3-4" name="__codelineno-3-4"></a><span class="x"> * Paramètres :</span>
<a href="#conf-lsobject-ioformat-__codelineno-3-5" id="__codelineno-3-5" name="__codelineno-3-5"></a><span class="x"> * - $ioFormat : Le LSioFormat sur lequel l'évènement survient</span>
<a href="#conf-lsobject-ioformat-__codelineno-3-6" id="__codelineno-3-6" name="__codelineno-3-6"></a><span class="x"> * - $data : Les données de contexte de l'évènement</span>
<a href="#conf-lsobject-ioformat-__codelineno-3-7" id="__codelineno-3-7" name="__codelineno-3-7"></a><span class="x"> *</span>
<a href="#conf-lsobject-ioformat-__codelineno-3-8" id="__codelineno-3-8" name="__codelineno-3-8"></a><span class="x"> * Valeurs retournées :</span>
<a href="#conf-lsobject-ioformat-__codelineno-3-9" id="__codelineno-3-9" name="__codelineno-3-9"></a><span class="x"> * - True : Tout s'est bien passé</span>
<a href="#conf-lsobject-ioformat-__codelineno-3-10" id="__codelineno-3-10" name="__codelineno-3-10"></a><span class="x"> * - False : Une erreur est survenue ou la fonction souhaite bloquer le</span>
<a href="#conf-lsobject-ioformat-__codelineno-3-11" id="__codelineno-3-11" name="__codelineno-3-11"></a><span class="x"> * processus lors d'un évènement bloquant.</span>
<a href="#conf-lsobject-ioformat-__codelineno-3-12" id="__codelineno-3-12" name="__codelineno-3-12"></a><span class="x"> */</span>
<a href="#conf-lsobject-ioformat-__codelineno-3-13" id="__codelineno-3-13" name="__codelineno-3-13"></a><span class="x">function maFonction (&amp;$ioFormat, &amp;$data) {</span>
<a href="#conf-lsobject-ioformat-__codelineno-3-14" id="__codelineno-3-14" name="__codelineno-3-14"></a>
<a href="#conf-lsobject-ioformat-__codelineno-3-15" id="__codelineno-3-15" name="__codelineno-3-15"></a><span class="x"> // Actions</span>
<a href="#conf-lsobject-ioformat-__codelineno-3-16" id="__codelineno-3-16" name="__codelineno-3-16"></a>
<a href="#conf-lsobject-ioformat-__codelineno-3-17" id="__codelineno-3-17" name="__codelineno-3-17"></a><span class="x">}</span>
</code></pre></div>
<p>Cette fonction doit accepter deux paramètres, le LSioFormat sur lequel l'évènement survient et un
tableau des données contextuelles de l'évènement. Elle doit par ailleurs retourner <code>True</code> si tout
s'est bien passé ou <code>False</code> en cas de problème. Dans le cas d'un événement bloquant, si la fonction
retourne <code>False</code>, le processus est arrêté.</p>
<p>Les données contextuelles de l'évènement, passées en paramètre, pourront dépendre du contexte et de
l'évènement déclencheur, mais pour les moments, il s'agit toujours d'un tableau telque décrit
ci-dessous :</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-ioformat-__codelineno-4-1" id="__codelineno-4-1" name="__codelineno-4-1"></a><span class="x">array(</span>
<a href="#conf-lsobject-ioformat-__codelineno-4-2" id="__codelineno-4-2" name="__codelineno-4-2"></a><span class="x"> 'input_file' =&gt; "[/path/of/import.file]",</span>
<a href="#conf-lsobject-ioformat-__codelineno-4-3" id="__codelineno-4-3" name="__codelineno-4-3"></a><span class="x"> 'updateIfExists' =&gt; [boolean],</span>
<a href="#conf-lsobject-ioformat-__codelineno-4-4" id="__codelineno-4-4" name="__codelineno-4-4"></a><span class="x"> 'justTry' =&gt; [boolean],</span>
<a href="#conf-lsobject-ioformat-__codelineno-4-5" id="__codelineno-4-5" name="__codelineno-4-5"></a><span class="x"> 'objectsData' =&gt; array(</span>
<a href="#conf-lsobject-ioformat-__codelineno-4-6" id="__codelineno-4-6" name="__codelineno-4-6"></a><span class="x"> [Données des objets chargés depuis le fichier d'import]</span>
<a href="#conf-lsobject-ioformat-__codelineno-4-7" id="__codelineno-4-7" name="__codelineno-4-7"></a><span class="x"> ),</span>
<a href="#conf-lsobject-ioformat-__codelineno-4-8" id="__codelineno-4-8" name="__codelineno-4-8"></a><span class="x"> 'return' =&gt; array(</span>
<a href="#conf-lsobject-ioformat-__codelineno-4-9" id="__codelineno-4-9" name="__codelineno-4-9"></a><span class="x"> 'success' =&gt; [boolean],</span>
<a href="#conf-lsobject-ioformat-__codelineno-4-10" id="__codelineno-4-10" name="__codelineno-4-10"></a><span class="x"> 'LSobject' =&gt; "[nom du type d'LSobject]",</span>
<a href="#conf-lsobject-ioformat-__codelineno-4-11" id="__codelineno-4-11" name="__codelineno-4-11"></a><span class="x"> 'ioFormat' =&gt; "[nom du type d'ioFormat]",</span>
<a href="#conf-lsobject-ioformat-__codelineno-4-12" id="__codelineno-4-12" name="__codelineno-4-12"></a><span class="x"> 'updateIfExists' =&gt; [boolean],</span>
<a href="#conf-lsobject-ioformat-__codelineno-4-13" id="__codelineno-4-13" name="__codelineno-4-13"></a><span class="x"> 'justTry' =&gt; [boolean],</span>
<a href="#conf-lsobject-ioformat-__codelineno-4-14" id="__codelineno-4-14" name="__codelineno-4-14"></a><span class="x"> 'imported' =&gt; array([objets importés]),</span>
<a href="#conf-lsobject-ioformat-__codelineno-4-15" id="__codelineno-4-15" name="__codelineno-4-15"></a><span class="x"> 'updated' =&gt; array([objets mis à jour]),</span>
<a href="#conf-lsobject-ioformat-__codelineno-4-16" id="__codelineno-4-16" name="__codelineno-4-16"></a><span class="x"> 'errors' =&gt; array(</span>
<a href="#conf-lsobject-ioformat-__codelineno-4-17" id="__codelineno-4-17" name="__codelineno-4-17"></a><span class="x"> array(</span>
<a href="#conf-lsobject-ioformat-__codelineno-4-18" id="__codelineno-4-18" name="__codelineno-4-18"></a><span class="x"> 'data' =&gt; [données de l'objet importé ayant déclenché l'erreur],</span>
<a href="#conf-lsobject-ioformat-__codelineno-4-19" id="__codelineno-4-19" name="__codelineno-4-19"></a><span class="x"> 'errors' =&gt; array (</span>
<a href="#conf-lsobject-ioformat-__codelineno-4-20" id="__codelineno-4-20" name="__codelineno-4-20"></a><span class="x"> 'globals' =&gt; array("Erreur 1", [...]),</span>
<a href="#conf-lsobject-ioformat-__codelineno-4-21" id="__codelineno-4-21" name="__codelineno-4-21"></a><span class="x"> 'attrs' =&gt; array(</span>
<a href="#conf-lsobject-ioformat-__codelineno-4-22" id="__codelineno-4-22" name="__codelineno-4-22"></a><span class="x"> 'attr1' =&gt; array("Erreur 1", [...]),</span>
<a href="#conf-lsobject-ioformat-__codelineno-4-23" id="__codelineno-4-23" name="__codelineno-4-23"></a><span class="x"> [...]</span>
<a href="#conf-lsobject-ioformat-__codelineno-4-24" id="__codelineno-4-24" name="__codelineno-4-24"></a><span class="x"> ),</span>
<a href="#conf-lsobject-ioformat-__codelineno-4-25" id="__codelineno-4-25" name="__codelineno-4-25"></a><span class="x"> ),</span>
<a href="#conf-lsobject-ioformat-__codelineno-4-26" id="__codelineno-4-26" name="__codelineno-4-26"></a><span class="x"> ),</span>
<a href="#conf-lsobject-ioformat-__codelineno-4-27" id="__codelineno-4-27" name="__codelineno-4-27"></a><span class="x"> [...]</span>
<a href="#conf-lsobject-ioformat-__codelineno-4-28" id="__codelineno-4-28" name="__codelineno-4-28"></a><span class="x"> ),</span>
<a href="#conf-lsobject-ioformat-__codelineno-4-29" id="__codelineno-4-29" name="__codelineno-4-29"></a><span class="x"> ),</span>
<a href="#conf-lsobject-ioformat-__codelineno-4-30" id="__codelineno-4-30" name="__codelineno-4-30"></a><span class="x">)</span>
</code></pre></div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Les clés <code>objectsData</code> et <code>return</code> sont des références. En cas de modification, cela influencera
respectivement sur les données utilisées pour l'import et sur le résultat de l'import tel
qu'affiché dans l'interface.</p>
</div></section><h1 class="nav-section-title-end">Ended: Objets de l'annuaire</h1><h2 class="nav-section-title">Configuration des addons (LSaddons)</h2><section class="print-page" id="conf-lsaddon"><h1 id="conf-lsaddon-configuration-des-lsaddons">Configuration des LSaddons</h1>
<p>Cette partie décrit la manière de configurer les différents LSaddons actuellement supportés par
LdapSaisie. Ces addons peuvent avoir un fichier de configuration et il sera alors stocké dans le
dossier <code>conf/LSaddons/</code> et potera le nom <code>config.LSaddons.[addon name].php</code>.</p></section><section class="print-page" id="conf-lsaddon-lsaddon_accesslog"><h1 id="conf-lsaddon-lsaddon_accesslog-lsaddon_accesslog">LSaddon_accesslog</h1>
<p>Cet <a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a> fournit la fonction <code>showObjectAccessLogs()</code>
pouvant être utilisée comme <a href="#conf-lsobject-customactions-customactions">customActions</a> et
permettant d'afficher les logs d'accès produits par
<a href="https://www.openldap.org/doc/admin24/overlays.html#Access%20Logging">l'overlay OpenLDAP accesslog</a>
sur un objet de l'annuaire.</p>
<p>La constante <code>LS_ACCESSLOG_BASEDN</code> du fichier de configuration de l'addon
(<code>conf/LSaddons/config.LSaddons.accesslog.php</code>) permet d'indiquer le base DN de la base stockant les
logs :</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsaddon-lsaddon_accesslog-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>// Accesslog base DN
<a href="#conf-lsaddon-lsaddon_accesslog-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a>define('LS_ACCESSLOG_BASEDN', 'cn=ldapsaisie-accesslog');
</code></pre></div>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>LdapSaisie se connectera à la base stockant les logs d'accès de l'annuaire avec les mêmes
paramètres de connexion que pour la base principale (excepté le base DN). Pensez à ajuster les
ACLs de la base stockant les logs d'accès pour autoriser l'utilisateur d'LdapSaisie à se
connecter et lire les informations qu'elle contient.</p>
<p><strong>Exemple d'ACL à mettre en place :</strong>
</p><div class="highlight"><pre><span></span><code><a href="#conf-lsaddon-lsaddon_accesslog-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a>to *
<a href="#conf-lsaddon-lsaddon_accesslog-__codelineno-1-2" id="__codelineno-1-2" name="__codelineno-1-2"></a> by dn.exact=uid=ldapsaisie,ou=sysaccounts,o=ls read
<a href="#conf-lsaddon-lsaddon_accesslog-__codelineno-1-3" id="__codelineno-1-3" name="__codelineno-1-3"></a> by * break
</code></pre></div><p></p>
</div>
<p>Ci-dessous, vous trouverez un exemple de configuration de la fonction <code>showObjectAccessLogs()</code> comme
<a href="#conf-lsobject-customactions-customactions">customActions</a> :</p>
<p><strong>Exemple d'utilisation :</strong></p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsaddon-lsaddon_accesslog-__codelineno-2-1" id="__codelineno-2-1" name="__codelineno-2-1"></a><span class="x">$GLOBALS['LSobjects']['LSpeople'] = array (</span>
<a href="#conf-lsaddon-lsaddon_accesslog-__codelineno-2-2" id="__codelineno-2-2" name="__codelineno-2-2"></a><span class="x"> [...]</span>
<a href="#conf-lsaddon-lsaddon_accesslog-__codelineno-2-3" id="__codelineno-2-3" name="__codelineno-2-3"></a><span class="x"> 'customActions' =&gt; array (</span>
<a href="#conf-lsaddon-lsaddon_accesslog-__codelineno-2-4" id="__codelineno-2-4" name="__codelineno-2-4"></a><span class="x"> 'showObjectAccessLogs' =&gt; array (</span>
<a href="#conf-lsaddon-lsaddon_accesslog-__codelineno-2-5" id="__codelineno-2-5" name="__codelineno-2-5"></a><span class="x"> 'function' =&gt; 'showObjectAccessLogs',</span>
<a href="#conf-lsaddon-lsaddon_accesslog-__codelineno-2-6" id="__codelineno-2-6" name="__codelineno-2-6"></a><span class="x"> 'label' =&gt; 'Show access logs',</span>
<a href="#conf-lsaddon-lsaddon_accesslog-__codelineno-2-7" id="__codelineno-2-7" name="__codelineno-2-7"></a><span class="x"> 'hideLabel' =&gt; true,</span>
<a href="#conf-lsaddon-lsaddon_accesslog-__codelineno-2-8" id="__codelineno-2-8" name="__codelineno-2-8"></a><span class="x"> 'noConfirmation' =&gt; true,</span>
<a href="#conf-lsaddon-lsaddon_accesslog-__codelineno-2-9" id="__codelineno-2-9" name="__codelineno-2-9"></a><span class="x"> 'disableOnSuccessMsg' =&gt; true,</span>
<a href="#conf-lsaddon-lsaddon_accesslog-__codelineno-2-10" id="__codelineno-2-10" name="__codelineno-2-10"></a><span class="x"> 'icon' =&gt; 'clock',</span>
<a href="#conf-lsaddon-lsaddon_accesslog-__codelineno-2-11" id="__codelineno-2-11" name="__codelineno-2-11"></a><span class="x"> 'rights' =&gt; array (</span>
<a href="#conf-lsaddon-lsaddon_accesslog-__codelineno-2-12" id="__codelineno-2-12" name="__codelineno-2-12"></a><span class="x"> 'admin'</span>
<a href="#conf-lsaddon-lsaddon_accesslog-__codelineno-2-13" id="__codelineno-2-13" name="__codelineno-2-13"></a><span class="x"> ),</span>
<a href="#conf-lsaddon-lsaddon_accesslog-__codelineno-2-14" id="__codelineno-2-14" name="__codelineno-2-14"></a><span class="x"> ),</span>
<a href="#conf-lsaddon-lsaddon_accesslog-__codelineno-2-15" id="__codelineno-2-15" name="__codelineno-2-15"></a><span class="x"> ),</span>
<a href="#conf-lsaddon-lsaddon_accesslog-__codelineno-2-16" id="__codelineno-2-16" name="__codelineno-2-16"></a><span class="x"> [...]</span>
<a href="#conf-lsaddon-lsaddon_accesslog-__codelineno-2-17" id="__codelineno-2-17" name="__codelineno-2-17"></a><span class="x">);</span>
</code></pre></div></section><section class="print-page" id="conf-lsaddon-lsaddon_asterisk"><h1 id="conf-lsaddon-lsaddon_asterisk-lsaddon_asterisk">LSaddon_asterisk</h1>
<p>Cet <a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a> est utilisé pour gérer les fonctionnalités
spécifiques au serveur de téléphonie Asterisk. Cet <a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a>
donne accès à une fonction permettant l'encodage d'un mot de passe au format spécifique attendu par
Asterisk. Ce format est un hash MD5 d'une chaine de caractère composée du nom d'utilisateur, d'une
chaine fixe spécifiée dans la configuration d'Asterisk et du mot de passe en clair.</p></section><section class="print-page" id="conf-lsaddon-lsaddon_exportsearchresultascsv"><h1 id="conf-lsaddon-lsaddon_exportsearchresultascsv-lsaddon_exportsearchresultascsv">LSaddon_exportSearchResultAsCSV</h1>
<p>Cet <a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a> fournie une fonction du même nom pouvant être
utilisée comme <a href="#conf-lsobject-lssearch-customactions_1">customActions</a> et permettant de télécharger
le résultat d'une recherche au format CSV. L'export généré reprend exactement le contenu des
colonnes du tableau du résultat de la recherche. Le DN de l'objet LDAP correspondant est également
fournis dans une colonne.</p>
<p>Des paramètres de configuration sont disponibles dans le fichier de configuration
<code>config.LSaddons.exportSearchResultAsCSV.php</code>. Ils permettent notamment de contrôller le format du
fichier CSV généré.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsaddon-lsaddon_exportsearchresultascsv-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="x">// CSV file delimiter</span>
<a href="#conf-lsaddon-lsaddon_exportsearchresultascsv-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a><span class="x">define('LS_EXPORTSEARCHRESULTASCSV_DELIMITER',',');</span>
<a href="#conf-lsaddon-lsaddon_exportsearchresultascsv-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a>
<a href="#conf-lsaddon-lsaddon_exportsearchresultascsv-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a><span class="x">// CSV file enclosure</span>
<a href="#conf-lsaddon-lsaddon_exportsearchresultascsv-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a><span class="x">define('LS_EXPORTSEARCHRESULTASCSV_ENCLOSURE','"');</span>
<a href="#conf-lsaddon-lsaddon_exportsearchresultascsv-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a>
<a href="#conf-lsaddon-lsaddon_exportsearchresultascsv-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a><span class="x">// CSV file escape character (available since PHP 5.5.4)</span>
<a href="#conf-lsaddon-lsaddon_exportsearchresultascsv-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a><span class="x">define('LS_EXPORTSEARCHRESULTASCSV_ESCAPE_CHAR','\\');</span>
</code></pre></div>
<p>Ci-dessous, vous trouverez un exemple de configuration de la fonction <code>exportSearchResultAsCSV()</code>
comme <a href="#conf-lsobject-lssearch-customactions_1">customActions</a> :</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsaddon-lsaddon_exportsearchresultascsv-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a><span class="x">$GLOBALS['LSobjects']['LSpeople']['LSsearch'] = array (</span>
<a href="#conf-lsaddon-lsaddon_exportsearchresultascsv-__codelineno-1-2" id="__codelineno-1-2" name="__codelineno-1-2"></a><span class="x"> [...]</span>
<a href="#conf-lsaddon-lsaddon_exportsearchresultascsv-__codelineno-1-3" id="__codelineno-1-3" name="__codelineno-1-3"></a><span class="x"> 'customActions' =&gt; array (</span>
<a href="#conf-lsaddon-lsaddon_exportsearchresultascsv-__codelineno-1-4" id="__codelineno-1-4" name="__codelineno-1-4"></a><span class="x"> 'exportSearchResultAsCSV' =&gt; array (</span>
<a href="#conf-lsaddon-lsaddon_exportsearchresultascsv-__codelineno-1-5" id="__codelineno-1-5" name="__codelineno-1-5"></a><span class="x"> 'label' =&gt; 'Export result as CSV',</span>
<a href="#conf-lsaddon-lsaddon_exportsearchresultascsv-__codelineno-1-6" id="__codelineno-1-6" name="__codelineno-1-6"></a><span class="x"> 'icon' =&gt; 'export_csv',</span>
<a href="#conf-lsaddon-lsaddon_exportsearchresultascsv-__codelineno-1-7" id="__codelineno-1-7" name="__codelineno-1-7"></a><span class="x"> 'function' =&gt; 'exportSearchResultAsCSV',</span>
<a href="#conf-lsaddon-lsaddon_exportsearchresultascsv-__codelineno-1-8" id="__codelineno-1-8" name="__codelineno-1-8"></a><span class="x"> 'noConfirmation' =&gt; true,</span>
<a href="#conf-lsaddon-lsaddon_exportsearchresultascsv-__codelineno-1-9" id="__codelineno-1-9" name="__codelineno-1-9"></a><span class="x"> 'disableOnSuccessMsg' =&gt; true,</span>
<a href="#conf-lsaddon-lsaddon_exportsearchresultascsv-__codelineno-1-10" id="__codelineno-1-10" name="__codelineno-1-10"></a><span class="x"> 'rights' =&gt; array (</span>
<a href="#conf-lsaddon-lsaddon_exportsearchresultascsv-__codelineno-1-11" id="__codelineno-1-11" name="__codelineno-1-11"></a><span class="x"> 'admin'</span>
<a href="#conf-lsaddon-lsaddon_exportsearchresultascsv-__codelineno-1-12" id="__codelineno-1-12" name="__codelineno-1-12"></a><span class="x"> )</span>
<a href="#conf-lsaddon-lsaddon_exportsearchresultascsv-__codelineno-1-13" id="__codelineno-1-13" name="__codelineno-1-13"></a><span class="x"> ),</span>
<a href="#conf-lsaddon-lsaddon_exportsearchresultascsv-__codelineno-1-14" id="__codelineno-1-14" name="__codelineno-1-14"></a><span class="x"> ),</span>
<a href="#conf-lsaddon-lsaddon_exportsearchresultascsv-__codelineno-1-15" id="__codelineno-1-15" name="__codelineno-1-15"></a><span class="x"> [...]</span>
<a href="#conf-lsaddon-lsaddon_exportsearchresultascsv-__codelineno-1-16" id="__codelineno-1-16" name="__codelineno-1-16"></a><span class="x">);</span>
</code></pre></div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Le label et l'icône fournis dans cet exemple sont traduits et délivrés avec LdapSaisie.</p>
</div></section><section class="print-page" id="conf-lsaddon-lsaddon_impersonate"><h1 id="conf-lsaddon-lsaddon_impersonate-lsaddon_impersonate">LSaddon_impersonate</h1>
<p>Cet <a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a> fournie une fonction du même nom pouvant être
utilisée comme <a href="#conf-lsobject-customactions-customactions">customActions</a> et permettant de se
reconnecter en tant qu'un autre utilisateur de l'annuaire.</p>
<p>Ci-dessous, vous trouverez un exemple de configuration de la fonction <code>impersonate()</code> comme
<a href="#conf-lsobject-customactions-customactions">customActions</a> :</p>
<p><strong>Exemple d'utilisation :</strong></p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsaddon-lsaddon_impersonate-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="x">$GLOBALS['LSobjects']['LSpeople'] = array (</span>
<a href="#conf-lsaddon-lsaddon_impersonate-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a><span class="x"> [...]</span>
<a href="#conf-lsaddon-lsaddon_impersonate-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a><span class="x"> 'customActions' =&gt; array (</span>
<a href="#conf-lsaddon-lsaddon_impersonate-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a><span class="x"> 'impersonate' =&gt; array (</span>
<a href="#conf-lsaddon-lsaddon_impersonate-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a><span class="x"> 'function' =&gt; 'impersonate',</span>
<a href="#conf-lsaddon-lsaddon_impersonate-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a><span class="x"> 'label' =&gt; 'Reconnect as this user',</span>
<a href="#conf-lsaddon-lsaddon_impersonate-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a><span class="x"> 'hideLabel' =&gt; True,</span>
<a href="#conf-lsaddon-lsaddon_impersonate-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a><span class="x"> 'noConfirmation' =&gt; true,</span>
<a href="#conf-lsaddon-lsaddon_impersonate-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a><span class="x"> 'disableOnSuccessMsg' =&gt; true,</span>
<a href="#conf-lsaddon-lsaddon_impersonate-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a><span class="x"> 'icon' =&gt; 'user_go',</span>
<a href="#conf-lsaddon-lsaddon_impersonate-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a><span class="x"> 'rights' =&gt; array (</span>
<a href="#conf-lsaddon-lsaddon_impersonate-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a><span class="x"> 'admin'</span>
<a href="#conf-lsaddon-lsaddon_impersonate-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a><span class="x"> ),</span>
<a href="#conf-lsaddon-lsaddon_impersonate-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a><span class="x"> ),</span>
<a href="#conf-lsaddon-lsaddon_impersonate-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a><span class="x"> ),</span>
<a href="#conf-lsaddon-lsaddon_impersonate-__codelineno-0-16" id="__codelineno-0-16" name="__codelineno-0-16"></a><span class="x"> [...]</span>
<a href="#conf-lsaddon-lsaddon_impersonate-__codelineno-0-17" id="__codelineno-0-17" name="__codelineno-0-17"></a><span class="x">);</span>
</code></pre></div></section><section class="print-page" id="conf-lsaddon-lsaddon_lsaccessrightsmatrixview"><h1 id="conf-lsaddon-lsaddon_lsaccessrightsmatrixview-lsaddon_lsaccessrightsmatrixview">LSaddon_LSaccessRightsMatrixView</h1>
<p>Cet <a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a> offre une interface de visualisation des droits
d'accès des différents <a href="#conf-global-ldap-lsprofile-profils-dutilisateurs">LSprofiles</a> configurés.
Pour chaque type d'objet, la matrice des droits d'accès par attribut et par profil est affiché sous
la forme d'un tableau.</p>
<p>Le fichier de configuration permet de définir au travers la variable
<code>$GLOBALS['LSaccessRightsMatrixView_allowed_LSprofiles']</code> la liste des
<a href="#conf-global-ldap-lsprofile-profils-dutilisateurs">LSprofiles</a> autorisés à accéder à cette interface.</p></section><section class="print-page" id="conf-lsaddon-lsaddon_mail"><h1 id="conf-lsaddon-lsaddon_mail-lsaddon_mail">LSaddon_mail</h1>
<p>Cet <a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a> est utilisé pour gérer l'envoi de courriels. Il
utilise pour cela les librairies <a href="http://pear.php.net/">PEAR</a> <em>Mail</em> et <em>Mail_Mime</em> qui doivent être
installés.</p>
<p>Cet <a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a> offre aussi la possibilité d'envoyer des
courriels dont le contenu est construit à partir de modèles. Ces modèles sont enregistrés dans des
fichiers textes stockés (voir <code>$GLOBALS['MAIL_TEMPLATES_DIRECTORIES']</code>). Pour chaque modèle, vous
devez fournir trois fichiers portant le même nom mais avec des extensions différentes :</p>
<ul>
<li><code>template.subject</code> : le sujet du courriel. Note : seule la première ligne du fichier est utilisé
(et passée dans la fonction <code>trim()</code>)</li>
<li><code>template.html</code> : le contenu HTML du courriel</li>
<li><code>template.txt</code>: le contenu texte du courriel</li>
</ul>
<p>Ces trois fichiers sont utilisés en tant que modèle <a href="http://www.smarty.net/">Smarty</a> et seront
construit en utilisant les variables fournies dans le contexte d'envoi des courriels. À noter que le
moteur Smarty utilisé pour la génération du contenu de ces courriels n'est pas le même que celui
utilisé par LdapSaisie pour l'affichage des pages.</p>
<p>Par ailleurs, cet <a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a> fourni une vue de gestion des
modèles de courriels existants (voir <code>$GLOBALS['MAIL_TEMPLATES_EDITOR_VIEW_ACCESS']</code> pour la
configuration des accès).</p>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>Cette vue n'est pas conçues pour être mise entre toutes les mains. La sécurisation de modèles de
courriels étant très complexe, il est fortement recommandé de n'ouvrir l'accès à cette vue
qu'aux utilisateurs avertis et de confiances.</p>
</div>
<p>Cet <a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a> doit être configuré en éditant son
fichier de configuration <code>config.LSaddons.mail.php</code>.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="x"> ***********************************************</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a><span class="x"> * Configuration du support de l'envoi de mail *</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a><span class="x"> ***********************************************</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a><span class="x"> */</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a><span class="x">// Pear :: Mail</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a><span class="x">define('PEAR_MAIL','/usr/share/php/Mail.php');</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a><span class="x">// Pear :: Mail_mime</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a><span class="x">define('PEAR_MAIL_MIME','/usr/share/php/Mail/mime.php');</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a><span class="x">/*</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a><span class="x"> * Méthode d'envoie :</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a><span class="x"> * - mail : envoie avec la méthode PHP mail()</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a><span class="x"> * - sendmail : envoie la commande sendmail du système</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-16" id="__codelineno-0-16" name="__codelineno-0-16"></a><span class="x"> * - smtp : envoie en utilisant un serveur SMTP</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-17" id="__codelineno-0-17" name="__codelineno-0-17"></a><span class="x"> */</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-18" id="__codelineno-0-18" name="__codelineno-0-18"></a><span class="x">define('MAIL_SEND_METHOD','smtp');</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-19" id="__codelineno-0-19" name="__codelineno-0-19"></a>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-20" id="__codelineno-0-20" name="__codelineno-0-20"></a><span class="x">/*</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-21" id="__codelineno-0-21" name="__codelineno-0-21"></a><span class="x"> * Paramètres d'envoie :</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-22" id="__codelineno-0-22" name="__codelineno-0-22"></a><span class="x"> * Ces paramètres dépende de la méthode utilisé. Repporté vous à la documentation</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-23" id="__codelineno-0-23" name="__codelineno-0-23"></a><span class="x"> * de PEAR :: Mail pour plus d'information.</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-24" id="__codelineno-0-24" name="__codelineno-0-24"></a><span class="x"> * Lien : http://pear.php.net/manual/en/package.mail.mail.factory.php</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-25" id="__codelineno-0-25" name="__codelineno-0-25"></a><span class="x"> * Infos :</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-26" id="__codelineno-0-26" name="__codelineno-0-26"></a><span class="x"> * List of parameter for the backends</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-27" id="__codelineno-0-27" name="__codelineno-0-27"></a><span class="x"> * mail</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-28" id="__codelineno-0-28" name="__codelineno-0-28"></a><span class="x"> * o If safe mode is disabled, $params will be passed as the fifth</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-29" id="__codelineno-0-29" name="__codelineno-0-29"></a><span class="x"> * argument to the PHP mail() function. If $params is an array,</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-30" id="__codelineno-0-30" name="__codelineno-0-30"></a><span class="x"> * its elements will be joined as a space-delimited string.</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-31" id="__codelineno-0-31" name="__codelineno-0-31"></a><span class="x"> * sendmail</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-32" id="__codelineno-0-32" name="__codelineno-0-32"></a><span class="x"> * o $params["sendmail_path"] - The location of the sendmail program</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-33" id="__codelineno-0-33" name="__codelineno-0-33"></a><span class="x"> * on the filesystem. Default is /usr/bin/sendmail.</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-34" id="__codelineno-0-34" name="__codelineno-0-34"></a><span class="x"> * o $params["sendmail_args"] - Additional parameters to pass to the</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-35" id="__codelineno-0-35" name="__codelineno-0-35"></a><span class="x"> * sendmail. Default is -i.</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-36" id="__codelineno-0-36" name="__codelineno-0-36"></a><span class="x"> * smtp</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-37" id="__codelineno-0-37" name="__codelineno-0-37"></a><span class="x"> * o $params["host"] - The server to connect. Default is localhost.</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-38" id="__codelineno-0-38" name="__codelineno-0-38"></a><span class="x"> * o $params["port"] - The port to connect. Default is 25.</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-39" id="__codelineno-0-39" name="__codelineno-0-39"></a><span class="x"> * o $params["auth"] - Whether or not to use SMTP authentication.</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-40" id="__codelineno-0-40" name="__codelineno-0-40"></a><span class="x"> * Default is FALSE.</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-41" id="__codelineno-0-41" name="__codelineno-0-41"></a><span class="x"> * o $params["username"] - The username to use for SMTP authentication.</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-42" id="__codelineno-0-42" name="__codelineno-0-42"></a><span class="x"> * o $params["password"] - The password to use for SMTP authentication.</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-43" id="__codelineno-0-43" name="__codelineno-0-43"></a><span class="x"> * o $params["localhost"] - The value to give when sending EHLO or HELO.</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-44" id="__codelineno-0-44" name="__codelineno-0-44"></a><span class="x"> * Default is localhost</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-45" id="__codelineno-0-45" name="__codelineno-0-45"></a><span class="x"> * o $params["timeout"] - The SMTP connection timeout.</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-46" id="__codelineno-0-46" name="__codelineno-0-46"></a><span class="x"> * Default is NULL (no timeout).</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-47" id="__codelineno-0-47" name="__codelineno-0-47"></a><span class="x"> * o $params["verp"] - Whether to use VERP or not. Default is FALSE.</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-48" id="__codelineno-0-48" name="__codelineno-0-48"></a><span class="x"> * o $params["debug"] - Whether to enable SMTP debug mode or not.</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-49" id="__codelineno-0-49" name="__codelineno-0-49"></a><span class="x"> * Default is FALSE.</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-50" id="__codelineno-0-50" name="__codelineno-0-50"></a><span class="x"> * o $params["persist"] - Indicates whether or not the SMTP connection</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-51" id="__codelineno-0-51" name="__codelineno-0-51"></a><span class="x"> * should persist over multiple calls to the send() method.</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-52" id="__codelineno-0-52" name="__codelineno-0-52"></a><span class="x"> */</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-53" id="__codelineno-0-53" name="__codelineno-0-53"></a><span class="x">$GLOBALS['MAIL_SEND_PARAMS'] = NULL;</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-54" id="__codelineno-0-54" name="__codelineno-0-54"></a>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-55" id="__codelineno-0-55" name="__codelineno-0-55"></a><span class="x">/*</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-56" id="__codelineno-0-56" name="__codelineno-0-56"></a><span class="x"> * Headers :</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-57" id="__codelineno-0-57" name="__codelineno-0-57"></a><span class="x"> */</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-58" id="__codelineno-0-58" name="__codelineno-0-58"></a><span class="x">$GLOBALS['MAIL_HEARDERS = array();</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-59" id="__codelineno-0-59" name="__codelineno-0-59"></a>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-60" id="__codelineno-0-60" name="__codelineno-0-60"></a><span class="x">// Catch all sent emails</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-61" id="__codelineno-0-61" name="__codelineno-0-61"></a><span class="x">$GLOBALS['MAIL_CATCH_ALL'] = array();</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-62" id="__codelineno-0-62" name="__codelineno-0-62"></a>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-63" id="__codelineno-0-63" name="__codelineno-0-63"></a><span class="x">/**</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-64" id="__codelineno-0-64" name="__codelineno-0-64"></a><span class="x"> * Email templates</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-65" id="__codelineno-0-65" name="__codelineno-0-65"></a><span class="x"> *</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-66" id="__codelineno-0-66" name="__codelineno-0-66"></a><span class="x"> * This addon offer ability to send email by using templates. Email templates are stored in</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-67" id="__codelineno-0-67" name="__codelineno-0-67"></a><span class="x"> * full-text files in configured directories (see $GLOBALS['MAIL_TEMPLATES_DIRECTORIES']). For each</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-68" id="__codelineno-0-68" name="__codelineno-0-68"></a><span class="x"> * template, you have to provide three files with the same name but with different extensions:</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-69" id="__codelineno-0-69" name="__codelineno-0-69"></a><span class="x"> * - template.subject: the email subject. Note: only the first line is used (and stripped)</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-70" id="__codelineno-0-70" name="__codelineno-0-70"></a><span class="x"> * - template.html: the HTML content of the email</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-71" id="__codelineno-0-71" name="__codelineno-0-71"></a><span class="x"> * - template.txt: the text content of the email</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-72" id="__codelineno-0-72" name="__codelineno-0-72"></a><span class="x"> * All these files will be used as Smarty templates and will be computed using variables provided</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-73" id="__codelineno-0-73" name="__codelineno-0-73"></a><span class="x"> * in the sending context. Note that the Smarty object used to compute the template is not the same</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-74" id="__codelineno-0-74" name="__codelineno-0-74"></a><span class="x"> * as the one used by LdapSaisie to display pages.</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-75" id="__codelineno-0-75" name="__codelineno-0-75"></a><span class="x"> *</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-76" id="__codelineno-0-76" name="__codelineno-0-76"></a><span class="x"> * Futhermore, this addon offer a view to list and edit existing template (see</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-77" id="__codelineno-0-77" name="__codelineno-0-77"></a><span class="x"> * $GLOBALS['MAIL_TEMPLATES_EDITOR_VIEW_ACCESS'] to configured access).</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-78" id="__codelineno-0-78" name="__codelineno-0-78"></a><span class="x"> */</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-79" id="__codelineno-0-79" name="__codelineno-0-79"></a>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-80" id="__codelineno-0-80" name="__codelineno-0-80"></a><span class="x">// List of directory paths where as stored mail templates</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-81" id="__codelineno-0-81" name="__codelineno-0-81"></a><span class="x">// Notes:</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-82" id="__codelineno-0-82" name="__codelineno-0-82"></a><span class="x">// - provided path could be absolute or relative. Relative path are relative to the root base</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-83" id="__codelineno-0-83" name="__codelineno-0-83"></a><span class="x">// sources LdapSaisie directory (commonly /usr/share/ldapsaisie or the src directory if you</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-84" id="__codelineno-0-84" name="__codelineno-0-84"></a><span class="x">// installed it from sources). On Debian installation, you can specify 'local/email_templates' to</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-85" id="__codelineno-0-85" name="__codelineno-0-85"></a><span class="x">// refer to /etc/ldapsaisie/local/email_templates directory/</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-86" id="__codelineno-0-86" name="__codelineno-0-86"></a><span class="x">// - Multiple directories could be specified, sorted so that the first ones take priority over</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-87" id="__codelineno-0-87" name="__codelineno-0-87"></a><span class="x">// the last one.</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-88" id="__codelineno-0-88" name="__codelineno-0-88"></a><span class="x">// - To allow users to edit them using the editor view, these directories must be</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-89" id="__codelineno-0-89" name="__codelineno-0-89"></a><span class="x">// writable by PHP process (commonly runed as www-data).</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-90" id="__codelineno-0-90" name="__codelineno-0-90"></a><span class="x">$GLOBALS['MAIL_TEMPLATES_DIRECTORIES'] = array('local/email_templates');</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-91" id="__codelineno-0-91" name="__codelineno-0-91"></a>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-92" id="__codelineno-0-92" name="__codelineno-0-92"></a><span class="x">// List of granted LSprofiles to access mail templates editor view</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-93" id="__codelineno-0-93" name="__codelineno-0-93"></a><span class="x">// WARNING: Sanitizing mail templates is hell... EXPOSE THIS VIEW ONLY TO TRUSTED USERS!</span>
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-94" id="__codelineno-0-94" name="__codelineno-0-94"></a><span class="x">$GLOBALS['MAIL_TEMPLATES_EDITOR_VIEW_ACCESS'] = array('admin');</span>
</code></pre></div>
<p>Cet <a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a> offre avant tout la possibilité d'envoyer des
courriels en utilisant la fonction PHP <code>sendMail()</code> :</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsaddon-lsaddon_mail-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a>bool sendMail(
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-1-2" id="__codelineno-1-2" name="__codelineno-1-2"></a> &lt;string&gt; $to,
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-1-3" id="__codelineno-1-3" name="__codelineno-1-3"></a> &lt;string&gt; $subject,
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-1-4" id="__codelineno-1-4" name="__codelineno-1-4"></a> &lt;string&gt; $msg,
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-1-5" id="__codelineno-1-5" name="__codelineno-1-5"></a> &lt;array(string)&gt; $headers,
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-1-6" id="__codelineno-1-6" name="__codelineno-1-6"></a> &lt;array&gt; $attachments,
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-1-7" id="__codelineno-1-7" name="__codelineno-1-7"></a> &lt;string&gt; $eol,
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-1-8" id="__codelineno-1-8" name="__codelineno-1-8"></a> &lt;string&gt; $encoding,
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-1-9" id="__codelineno-1-9" name="__codelineno-1-9"></a> &lt;boolean&gt; $html
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-1-10" id="__codelineno-1-10" name="__codelineno-1-10"></a>);
</code></pre></div>
<p>Pour l'envoi de courriels en utilisant un modèle, il faut utiliser la fonction PHP
<code>sendMailFromTemplate()</code> :</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsaddon-lsaddon_mail-__codelineno-2-1" id="__codelineno-2-1" name="__codelineno-2-1"></a>bool sendMailFromTemplate(
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-2-2" id="__codelineno-2-2" name="__codelineno-2-2"></a> &lt;string&gt; $tplname,
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-2-3" id="__codelineno-2-3" name="__codelineno-2-3"></a> &lt;string&gt; $to,
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-2-4" id="__codelineno-2-4" name="__codelineno-2-4"></a> &lt;array&gt; $variables,
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-2-5" id="__codelineno-2-5" name="__codelineno-2-5"></a> &lt;array(string)&gt; $headers,
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-2-6" id="__codelineno-2-6" name="__codelineno-2-6"></a> &lt;array&gt; $attachments
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-2-7" id="__codelineno-2-7" name="__codelineno-2-7"></a>);
</code></pre></div></section><section class="print-page" id="conf-lsaddon-lsaddon_maildir"><h1 id="conf-lsaddon-lsaddon_maildir-lsaddon_maildir">LSaddon_maildir</h1>
<p>Cet <a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a> est utilisé pour gérer la manipulation distante
de maildir.</p>
<p><strong>FIXME</strong></p></section><section class="print-page" id="conf-lsaddon-lsaddon_mailquota"><h1 id="conf-lsaddon-lsaddon_mailquota-lsaddon_mailquota">LSaddon_mailquota</h1>
<p>Cet <a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a> fournie une fonction <code>mailquota_get_usage</code>
pouvant être utilisée pour récupérer l'utilisation du quota d'une boîte mail IMAP. Pour cela,
LdapSaisie se connecte au serveur IMAP en utilisant un compte maître.</p>
<p>Cet <a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a> fournie une également une fonction
<code>mailquota_show_usage</code> pouvant être utilisée comme
<a href="#conf-lsobject-customactions-customactions">customActions</a> et permettant d'afficher l'utilisation
du quota de la boîte mail correspondante via une message dynamique (<code>LSinfo</code>).</p>
<p>Des paramètres de configuration sont disponibles dans le fichier de configuration
<code>config.LSaddons.mailquota.php</code>.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="x">// IMAP Mailbox connection string LSformat (composed with LSldapObject attributes)</span>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a><span class="x">// See : https://php.net/imap_open (parameter $mailbox)</span>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a><span class="x">define('MAILQUOTA_IMAP_MAILBOX','{localhost}');</span>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a><span class="x">// IMAP Master user</span>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a><span class="x">define('MAILQUOTA_IMAP_MASTER_USER', 'ldapsaisie');</span>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a><span class="x">// IMAP Master user's password</span>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a><span class="x">define('MAILQUOTA_IMAP_MASTER_USER_PWD', 'secret');</span>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a><span class="x">// IMAP Master user LSformat composed with :</span>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a><span class="x">// * masteruser = master username (MAILQUOTA_IMAP_MASTER_USER)</span>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a><span class="x">// * LSldapObject attributes</span>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a><span class="x">define('MAILQUOTA_IMAP_MASTER_USER_FORMAT', '%{mail}*%{masteruser}');</span>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-16" id="__codelineno-0-16" name="__codelineno-0-16"></a><span class="x">// IMAP quota root mailbox</span>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-17" id="__codelineno-0-17" name="__codelineno-0-17"></a><span class="x">define('MAILQUOTA_IMAP_QUOTA_ROOT_MAILBOX', 'INBOX');</span>
</code></pre></div>
<p>Ci-dessous, vous trouverez un exemple de configuration de la fonction <code>mailquota_show_usage()</code>
comme <a href="#conf-lsobject-customactions-customactions">customActions</a> :</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a><span class="x">$GLOBALS['LSobjects']['LSpeople'] = array (</span>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-1-2" id="__codelineno-1-2" name="__codelineno-1-2"></a><span class="x"> [...]</span>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-1-3" id="__codelineno-1-3" name="__codelineno-1-3"></a><span class="x"> 'customActions' =&gt; array (</span>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-1-4" id="__codelineno-1-4" name="__codelineno-1-4"></a><span class="x"> 'showmailquotausage' =&gt; array (</span>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-1-5" id="__codelineno-1-5" name="__codelineno-1-5"></a><span class="x"> 'function' =&gt; 'mailquota_show_usage',</span>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-1-6" id="__codelineno-1-6" name="__codelineno-1-6"></a><span class="x"> 'label' =&gt; 'Show mail quota usage',</span>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-1-7" id="__codelineno-1-7" name="__codelineno-1-7"></a><span class="x"> 'noConfirmation' =&gt; true,</span>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-1-8" id="__codelineno-1-8" name="__codelineno-1-8"></a><span class="x"> 'disableOnSuccessMsg' =&gt; true,</span>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-1-9" id="__codelineno-1-9" name="__codelineno-1-9"></a><span class="x"> 'icon' =&gt; 'mail',</span>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-1-10" id="__codelineno-1-10" name="__codelineno-1-10"></a><span class="x"> 'rights' =&gt; array (</span>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-1-11" id="__codelineno-1-11" name="__codelineno-1-11"></a><span class="x"> 'admin'</span>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-1-12" id="__codelineno-1-12" name="__codelineno-1-12"></a><span class="x"> )</span>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-1-13" id="__codelineno-1-13" name="__codelineno-1-13"></a><span class="x"> ),</span>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-1-14" id="__codelineno-1-14" name="__codelineno-1-14"></a><span class="x"> [...]</span>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-1-15" id="__codelineno-1-15" name="__codelineno-1-15"></a><span class="x"> ),</span>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-1-16" id="__codelineno-1-16" name="__codelineno-1-16"></a><span class="x"> [...]</span>
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-1-17" id="__codelineno-1-17" name="__codelineno-1-17"></a><span class="x">);</span>
</code></pre></div></section><section class="print-page" id="conf-lsaddon-lsaddon_phpldapadmin"><h1 id="conf-lsaddon-lsaddon_phpldapadmin-lsaddon_phpldapadmin">LSaddon_phpldapadmin</h1>
<p>Cet <a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a> est utilisé pour permettre un lien facile entre
le logiciel <a href="https://github.com/leenooks/phpLDAPadmin">PhpLdapAdmin</a> et LdapSaisie. Il sera possible
ainsi à partir d'un objet dans LdapSaisie de voir ce même objet dans
<a href="https://github.com/leenooks/phpLDAPadmin">PhpLdapAdmin</a>.</p>
<p>Il est necessaire de configurer l'URL de votre installation de
<a href="https://github.com/leenooks/phpLDAPadmin">PhpLdapAdmin</a> dans le fichier de configuration
<code>config.LSaddons.phpldapadmin.php</code>.</p>
<p><strong>Structure du fichier :</strong></p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsaddon-lsaddon_phpldapadmin-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="x">// PhpLdapAdmin View Object URL format</span>
<a href="#conf-lsaddon-lsaddon_phpldapadmin-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a><span class="x">define('LS_PHPLDAPADMIN_VIEW_OBJECT_URL_FORMAT','//'.$_SERVER['SERVER_NAME'].'/phpldapadmin/cmd.php?cmd=template_engine&amp;server_id=0&amp;dn=%{dn}');</span>
</code></pre></div>
<p>Cet <a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a> offre la possibilité d'utilisé la fonction PHP
<code>redirectToPhpLdapAdmin()</code> comme <a href="#conf-lsobject-customactions-customactions">customActions</a>.</p>
<p><strong>Exemple d'utilisation :</strong></p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsaddon-lsaddon_phpldapadmin-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a><span class="x">$GLOBALS['LSobjects']['LSpeople'] = array (</span>
<a href="#conf-lsaddon-lsaddon_phpldapadmin-__codelineno-1-2" id="__codelineno-1-2" name="__codelineno-1-2"></a><span class="x"> [...]</span>
<a href="#conf-lsaddon-lsaddon_phpldapadmin-__codelineno-1-3" id="__codelineno-1-3" name="__codelineno-1-3"></a><span class="x"> 'customActions' =&gt; array (</span>
<a href="#conf-lsaddon-lsaddon_phpldapadmin-__codelineno-1-4" id="__codelineno-1-4" name="__codelineno-1-4"></a><span class="x"> 'redirectPhpLdapAdmin' =&gt; array (</span>
<a href="#conf-lsaddon-lsaddon_phpldapadmin-__codelineno-1-5" id="__codelineno-1-5" name="__codelineno-1-5"></a><span class="x"> 'function' =&gt; 'redirectToPhpLdapAdmin',</span>
<a href="#conf-lsaddon-lsaddon_phpldapadmin-__codelineno-1-6" id="__codelineno-1-6" name="__codelineno-1-6"></a><span class="x"> 'label' =&gt; 'See in PhpLdapAdmin',</span>
<a href="#conf-lsaddon-lsaddon_phpldapadmin-__codelineno-1-7" id="__codelineno-1-7" name="__codelineno-1-7"></a><span class="x"> 'hideLabel' =&gt; True,</span>
<a href="#conf-lsaddon-lsaddon_phpldapadmin-__codelineno-1-8" id="__codelineno-1-8" name="__codelineno-1-8"></a><span class="x"> 'noConfirmation' =&gt; true,</span>
<a href="#conf-lsaddon-lsaddon_phpldapadmin-__codelineno-1-9" id="__codelineno-1-9" name="__codelineno-1-9"></a><span class="x"> 'disableOnSuccessMsg' =&gt; true,</span>
<a href="#conf-lsaddon-lsaddon_phpldapadmin-__codelineno-1-10" id="__codelineno-1-10" name="__codelineno-1-10"></a><span class="x"> 'icon' =&gt; 'phpldapadmin',</span>
<a href="#conf-lsaddon-lsaddon_phpldapadmin-__codelineno-1-11" id="__codelineno-1-11" name="__codelineno-1-11"></a><span class="x"> 'rights' =&gt; array (</span>
<a href="#conf-lsaddon-lsaddon_phpldapadmin-__codelineno-1-12" id="__codelineno-1-12" name="__codelineno-1-12"></a><span class="x"> 'admin'</span>
<a href="#conf-lsaddon-lsaddon_phpldapadmin-__codelineno-1-13" id="__codelineno-1-13" name="__codelineno-1-13"></a><span class="x"> )</span>
<a href="#conf-lsaddon-lsaddon_phpldapadmin-__codelineno-1-14" id="__codelineno-1-14" name="__codelineno-1-14"></a><span class="x"> ),</span>
<a href="#conf-lsaddon-lsaddon_phpldapadmin-__codelineno-1-15" id="__codelineno-1-15" name="__codelineno-1-15"></a><span class="x"> ),</span>
<a href="#conf-lsaddon-lsaddon_phpldapadmin-__codelineno-1-16" id="__codelineno-1-16" name="__codelineno-1-16"></a><span class="x"> [...]</span>
<a href="#conf-lsaddon-lsaddon_phpldapadmin-__codelineno-1-17" id="__codelineno-1-17" name="__codelineno-1-17"></a><span class="x">);</span>
</code></pre></div></section><section class="print-page" id="conf-lsaddon-lsaddon_ppolicy"><h1 id="conf-lsaddon-lsaddon_ppolicy-lsaddon_ppolicy">LSaddon_ppolicy</h1>
<p>Cet <a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a> fourni :</p>
<ul>
<li>
<p>une fonction <code>ppolicy_extraDisplayColumn_password_expiration</code> pouvant être utilisée pour la
génération d'une <em>extraDisplayedColumn</em> affichant l'état d'expiration du mot de passe des objets
d'une recherche.</p>
<p><strong>Exemple d'utilisation :</strong></p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>$GLOBALS['LSobjects']['LSpeople']['LSsearch'] = array (
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> [...]
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> 'extraDisplayedColumns' =&gt; array (
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> [...]
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a> 'password_expiration' =&gt; array (
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a> 'label' =&gt; 'Password expiration',
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a> 'generateFunction' =&gt; 'ppolicy_extraDisplayColumn_password_expiration',
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a> 'additionalAttrs' =&gt; array('pwdChangedTime', 'pwdPolicySubentry'),
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a> 'escape' =&gt; false,
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a> 'cssStyle' =&gt; 'width: 14em; text-align: center;'
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a> ),
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a> [...]
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a> ),
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a> [...]
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a>);
</code></pre></div>
</li>
</ul>
<ul>
<li>
<p>une fonction <code>ppolicy_export_search_info</code> pouvant être utilisée comme
<a href="#conf-lsobject-lssearch-customactions_1">actions personnalisées sur les recherches d'LSobjects</a>
pour exporter au format CSV les informations des politiques de mots de passe des objets retournés
par la recherche.</p>
<p><strong>Exemple d'utilisation :</strong></p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a><span class="x">$GLOBALS['LSobjects']['LSpeople']['LSsearch'] = array (</span>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-1-2" id="__codelineno-1-2" name="__codelineno-1-2"></a><span class="x"> [...]</span>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-1-3" id="__codelineno-1-3" name="__codelineno-1-3"></a><span class="x"> 'customActions' =&gt; array (</span>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-1-4" id="__codelineno-1-4" name="__codelineno-1-4"></a><span class="x"> 'exportPpolicyInfo' =&gt; array (</span>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-1-5" id="__codelineno-1-5" name="__codelineno-1-5"></a><span class="x"> 'label' =&gt; 'Export password policy info',</span>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-1-6" id="__codelineno-1-6" name="__codelineno-1-6"></a><span class="x"> 'icon' =&gt; 'export_csv',</span>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-1-7" id="__codelineno-1-7" name="__codelineno-1-7"></a><span class="x"> 'function' =&gt; 'ppolicy_export_search_info',</span>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-1-8" id="__codelineno-1-8" name="__codelineno-1-8"></a><span class="x"> 'noConfirmation' =&gt; true,</span>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-1-9" id="__codelineno-1-9" name="__codelineno-1-9"></a><span class="x"> 'disableOnSuccessMsg' =&gt; true,</span>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-1-10" id="__codelineno-1-10" name="__codelineno-1-10"></a><span class="x"> 'rights' =&gt; array (</span>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-1-11" id="__codelineno-1-11" name="__codelineno-1-11"></a><span class="x"> 'admin',</span>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-1-12" id="__codelineno-1-12" name="__codelineno-1-12"></a><span class="x"> ),</span>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-1-13" id="__codelineno-1-13" name="__codelineno-1-13"></a><span class="x"> ),</span>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-1-14" id="__codelineno-1-14" name="__codelineno-1-14"></a><span class="x"> ),</span>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-1-15" id="__codelineno-1-15" name="__codelineno-1-15"></a><span class="x"> [...]</span>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-1-16" id="__codelineno-1-16" name="__codelineno-1-16"></a><span class="x">);</span>
</code></pre></div>
</li>
</ul>
<ul>
<li>la méthode d'API <code>exportPpolicyInfo</code> permettant d'exporter les informations des politiques de mots
de passe de tous les objets d'un type donné. Cette méthode est accessible via l'URL au format
suivant : <code>/api/1.0/exportPpolicyInfo/[object type]</code></li>
</ul>
<ul>
<li>
<p>la commande CLI <code>export_ppolicy_info</code> permettant d'exporter les informations des politiques de
mots de passe de tous les objets d'un type donné.</p>
<p><strong>Utilisation :</strong></p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-2-1" id="__codelineno-2-1" name="__codelineno-2-1"></a>ldapsaisie<span class="w"> </span>export_ppolicy_info<span class="w"> </span><span class="o">[</span>object<span class="w"> </span>type<span class="o">]</span><span class="w"> </span><span class="o">[</span>-o<span class="p">|</span>--output<span class="w"> </span>filepath<span class="o">]</span><span class="w"> </span><span class="o">[</span>-j<span class="p">|</span>--json<span class="w"> </span><span class="o">[</span>-p<span class="p">|</span>--pretty<span class="o">]]</span>
</code></pre></div>
</li>
</ul>
<p>Des paramètres de configuration sont disponibles dans le fichier de configuration
<code>config.LSaddons.ppolicy.php</code>.</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-3-1" id="__codelineno-3-1" name="__codelineno-3-1"></a><span class="x">// Default password policy object DN (set to null if no default policy is configured)</span>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-3-2" id="__codelineno-3-2" name="__codelineno-3-2"></a><span class="x">define('LS_PPOLICY_DEFAULT_DN', null);</span>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-3-3" id="__codelineno-3-3" name="__codelineno-3-3"></a>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-3-4" id="__codelineno-3-4" name="__codelineno-3-4"></a><span class="x">// Ppolicy password warning expiration threshold (in seconds)</span>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-3-5" id="__codelineno-3-5" name="__codelineno-3-5"></a><span class="x">define('LS_PPOLICY_WARNING_EXPIRATION_THRESHOLD', 7 * 86400);</span>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-3-6" id="__codelineno-3-6" name="__codelineno-3-6"></a>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-3-7" id="__codelineno-3-7" name="__codelineno-3-7"></a><span class="x">// Ppolicy password critical expiration threshold (in seconds)</span>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-3-8" id="__codelineno-3-8" name="__codelineno-3-8"></a><span class="x">define('LS_PPOLICY_CRITICAL_EXPIRATION_THRESHOLD', 2 * 86400);</span>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-3-9" id="__codelineno-3-9" name="__codelineno-3-9"></a>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-3-10" id="__codelineno-3-10" name="__codelineno-3-10"></a><span class="x">// CSV file delimiter</span>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-3-11" id="__codelineno-3-11" name="__codelineno-3-11"></a><span class="x">define('LS_PPOLICY_CSV_DELIMITER',';');</span>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-3-12" id="__codelineno-3-12" name="__codelineno-3-12"></a>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-3-13" id="__codelineno-3-13" name="__codelineno-3-13"></a><span class="x">// CSV file enclosure</span>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-3-14" id="__codelineno-3-14" name="__codelineno-3-14"></a><span class="x">define('LS_PPOLICY_CSV_ENCLOSURE','"');</span>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-3-15" id="__codelineno-3-15" name="__codelineno-3-15"></a>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-3-16" id="__codelineno-3-16" name="__codelineno-3-16"></a><span class="x">// CSV file escape character (available since PHP 5.5.4)</span>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-3-17" id="__codelineno-3-17" name="__codelineno-3-17"></a><span class="x">define('LS_PPOLICY_CSV_ESCAPE_CHAR','\\');</span>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-3-18" id="__codelineno-3-18" name="__codelineno-3-18"></a>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-3-19" id="__codelineno-3-19" name="__codelineno-3-19"></a><span class="x">// List of LSprofiles who are granted to use the exportPpolicyInfo API method</span>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-3-20" id="__codelineno-3-20" name="__codelineno-3-20"></a><span class="x">$GLOBALS['LS_PPOLICY_API_GRANTED_PROFILES'] = array('admin');</span>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-3-21" id="__codelineno-3-21" name="__codelineno-3-21"></a>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-3-22" id="__codelineno-3-22" name="__codelineno-3-22"></a><span class="x">// List of extra attributes to include in Ppolicy info export</span>
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-3-23" id="__codelineno-3-23" name="__codelineno-3-23"></a><span class="x">$GLOBALS['LS_PPOLICY_INFO_EXPORT_EXTRA_ATTRS'] = array();</span>
</code></pre></div>
<ul>
<li>
<p><code>LS_PPOLICY_DEFAULT_DN</code></p>
<p>Constante définissant le DN de la politique par défaut. Si aucune politique par défaut n'est
définie, ce paramètre doit valoir <code>null</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>LS_PPOLICY_WARNING_EXPIRATION_THRESHOLD</code></p>
<p>Constante définissant le seuil d'alerte pour l'expiration des mots de passe (en seconde). Par
défaut : 7 jours.</p>
</li>
</ul>
<ul>
<li>
<p><code>LS_PPOLICY_CRITICAL_EXPIRATION_THRESHOLD</code></p>
<p>Constante définissant le seuil critique pour l'expiration des mots de passe (en seconde). Par
défaut : 2 jours.</p>
</li>
</ul>
<ul>
<li>
<p><code>LS_PPOLICY_CSV_DELIMITER</code></p>
<p>Constante définissant le caractère utilisé lors de la génération de l'export CSV comme séparateur
de champ. Par défaut : un point-virgule.</p>
</li>
</ul>
<ul>
<li>
<p><code>LS_PPOLICY_CSV_ENCLOSURE</code></p>
<p>Constante définissant le caractère utilisé lors de la génération de l'export CSV pour
l'encadrement des champs. Par défaut : un guillemet double.</p>
</li>
</ul>
<ul>
<li>
<p><code>LS_PPOLICY_CSV_ESCAPE_CHAR</code></p>
<p>Constante définissant le caractère utilisé lors de la génération de l'export CSV pour
l'échappement des champs. Par défaut : une barre oblique inverse.</p>
</li>
</ul>
<ul>
<li>
<p><code>$GLOBALS['LS_PPOLICY_API_GRANTED_PROFILES']</code></p>
<p>Tableau global listant les <a href="#conf-global-ldap-lsprofile-profils-dutilisateurs">LSprofiles</a>
autorisés à utiliser la méthode d'API <code>exportPpolicyInfo</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>$GLOBALS['LS_PPOLICY_INFO_EXPORT_EXTRA_ATTRS']</code></p>
<p>Tableau global listant les attributs supplémentaires à inclure lors de l'export des informations
de politique de mots de passe.</p>
</li>
</ul></section><section class="print-page" id="conf-lsaddon-lsaddon_showsupportinfo"><h1 id="conf-lsaddon-lsaddon_showsupportinfo-lsaddon_showsupportinfo">LSaddon_showSupportInfo</h1>
<p>Cet <a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a> fourni une page affichant les informations utiles
pour l'équipe assurant le support de l'application. Cette page est accessible à l'adresse
<code>addon/showSupportInfo/showMySupportInfo</code>. Elle compile (et permet de télécharger) l'ensemble des
informations utiles à l'appréciation du contexte d'accès à l'application par l'utilisateur.</p>
<p>Cette page est accessible par tous les utilisateurs connectés à l'application. Cependant, par
défaut, il n'y a aucun lien d'accès à celle-ci. Il est possible d'ajouter un lien d'accès dans le
menu et modifiant la valeur de la constante <code>SHOW_SUPPORT_INFO_IN_MENU</code> à <code>True</code>.</p>
<p>Une fonction <code>showMySupportInfo()</code> est également fournie et peut-être utilisée comme
<a href="#conf-lsobject-customactions-customactions">customActions</a>. Elle redirigera alors l'utilisateur
vers cette page. Ci-dessous, vous trouverez un exemple de configuration de la fonction
<code>showMySupportInfo()</code> comme <a href="#conf-lsobject-customactions-customactions">customActions</a> :</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsaddon-lsaddon_showsupportinfo-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="x">$GLOBALS['LSobjects']['LSpeople'] = array (</span>
<a href="#conf-lsaddon-lsaddon_showsupportinfo-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a><span class="x"> [...]</span>
<a href="#conf-lsaddon-lsaddon_showsupportinfo-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a><span class="x"> 'customActions' =&gt; array (</span>
<a href="#conf-lsaddon-lsaddon_showsupportinfo-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a><span class="x"> 'showMySupportInfo' =&gt; array (</span>
<a href="#conf-lsaddon-lsaddon_showsupportinfo-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a><span class="x"> 'function' =&gt; 'showMySupportInfo',</span>
<a href="#conf-lsaddon-lsaddon_showsupportinfo-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a><span class="x"> 'label' =&gt; 'Show my support information',</span>
<a href="#conf-lsaddon-lsaddon_showsupportinfo-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a><span class="x"> 'hideLabel' =&gt; True,</span>
<a href="#conf-lsaddon-lsaddon_showsupportinfo-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a><span class="x"> 'noConfirmation' =&gt; true,</span>
<a href="#conf-lsaddon-lsaddon_showsupportinfo-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a><span class="x"> 'disableOnSuccessMsg' =&gt; true,</span>
<a href="#conf-lsaddon-lsaddon_showsupportinfo-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a><span class="x"> 'icon' =&gt; 'terminal',</span>
<a href="#conf-lsaddon-lsaddon_showsupportinfo-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a><span class="x"> 'rights' =&gt; array (</span>
<a href="#conf-lsaddon-lsaddon_showsupportinfo-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a><span class="x"> 'self'</span>
<a href="#conf-lsaddon-lsaddon_showsupportinfo-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a><span class="x"> ),</span>
<a href="#conf-lsaddon-lsaddon_showsupportinfo-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a><span class="x"> ),</span>
<a href="#conf-lsaddon-lsaddon_showsupportinfo-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a><span class="x"> ),</span>
<a href="#conf-lsaddon-lsaddon_showsupportinfo-__codelineno-0-16" id="__codelineno-0-16" name="__codelineno-0-16"></a><span class="x"> [...]</span>
<a href="#conf-lsaddon-lsaddon_showsupportinfo-__codelineno-0-17" id="__codelineno-0-17" name="__codelineno-0-17"></a><span class="x">);</span>
</code></pre></div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Le label et l'icône fournis dans cet exemple sont traduits et délivrés avec LdapSaisie.</p>
</div></section><section class="print-page" id="conf-lsaddon-lsaddon_showtechinfo"><h1 id="conf-lsaddon-lsaddon_showtechinfo-lsaddon_showtechinfo">LSaddon_showTechInfo</h1>
<p>Cet <a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a> fournie une fonction du même nom pouvant être
utilisée comme <a href="#conf-lsobject-customactions-customactions">customActions</a> et permettant d'afficher
les informations techniques d'un objet de l'annuaire.</p>
<p>Ci-dessous, vous trouverez un exemple de configuration de la fonction <code>showTechInfo()</code> comme
<a href="#conf-lsobject-customactions-customactions">customActions</a> :</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsaddon-lsaddon_showtechinfo-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="x">$GLOBALS['LSobjects']['LSpeople'] = array (</span>
<a href="#conf-lsaddon-lsaddon_showtechinfo-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a><span class="x"> [...]</span>
<a href="#conf-lsaddon-lsaddon_showtechinfo-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a><span class="x"> 'customActions' =&gt; array (</span>
<a href="#conf-lsaddon-lsaddon_showtechinfo-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a><span class="x"> 'showTechInfo' =&gt; array (</span>
<a href="#conf-lsaddon-lsaddon_showtechinfo-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a><span class="x"> 'function' =&gt; 'showTechInfo',</span>
<a href="#conf-lsaddon-lsaddon_showtechinfo-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a><span class="x"> 'label' =&gt; 'Show technical information',</span>
<a href="#conf-lsaddon-lsaddon_showtechinfo-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a><span class="x"> 'hideLabel' =&gt; True,</span>
<a href="#conf-lsaddon-lsaddon_showtechinfo-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a><span class="x"> 'noConfirmation' =&gt; true,</span>
<a href="#conf-lsaddon-lsaddon_showtechinfo-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a><span class="x"> 'disableOnSuccessMsg' =&gt; true,</span>
<a href="#conf-lsaddon-lsaddon_showtechinfo-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a><span class="x"> 'icon' =&gt; 'tech_info',</span>
<a href="#conf-lsaddon-lsaddon_showtechinfo-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a><span class="x"> 'rights' =&gt; array (</span>
<a href="#conf-lsaddon-lsaddon_showtechinfo-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a><span class="x"> 'admin'</span>
<a href="#conf-lsaddon-lsaddon_showtechinfo-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a><span class="x"> ),</span>
<a href="#conf-lsaddon-lsaddon_showtechinfo-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a><span class="x"> ),</span>
<a href="#conf-lsaddon-lsaddon_showtechinfo-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a><span class="x"> ),</span>
<a href="#conf-lsaddon-lsaddon_showtechinfo-__codelineno-0-16" id="__codelineno-0-16" name="__codelineno-0-16"></a><span class="x"> [...]</span>
<a href="#conf-lsaddon-lsaddon_showtechinfo-__codelineno-0-17" id="__codelineno-0-17" name="__codelineno-0-17"></a><span class="x">);</span>
</code></pre></div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Le label et l'icône fournis dans cet exemple sont traduits et délivrés avec LdapSaisie.</p>
</div></section><h1 class="nav-section-title-end">Ended: Configuration des addons (LSaddons)</h1><h2 class="nav-section-title">Configuration des méthodes d'authentification (LSauthMethod)</h2><section class="print-page" id="conf-lsauthmethod"><h1 id="conf-lsauthmethod-configuration-des-methodes-dauthentification-lsauthmethod">Configuration des méthodes d'authentification (LSauthMethod)</h1>
<p>Cette partie décrit la manière de configurer les méthodes d'authentification d'LdapSaisie appelée
LSauthMethod). Ces librairies peuvent avoir un fichier de configuration et il sera alors stocké dans
le dossier <code>conf/LSauth/</code>.</p></section><section class="print-page" id="conf-lsauthmethod-lsauthmethod_anonymous"><h1 id="conf-lsauthmethod-lsauthmethod_anonymous-lsauthmethod_anonymous">LSauthMethod_anonymous</h1>
<p>Cette <a href="#conf-lsauthmethod-configuration-des-lsauthmethods">LSauthMethod</a> est utilisée pour gérer
l'authentification automatique des utilisateurs arrivant (équivalent à un mode anonyme). Cette
librairie doit être configurée en éditant le fichier de configuration
<code>conf/LSauth/config.LSauthMethod_anonymous.php</code> et notament en définissant la constante
<code>LSAUTHMETHOD_ANONYMOUS_USER</code> contenant le login d'un utilisateur dont les droits d'accès seront
endossés par tout les personnes utilisant LdapSaisie.</p></section><section class="print-page" id="conf-lsauthmethod-lsauthmethod_cas"><h1 id="conf-lsauthmethod-lsauthmethod_cas-lsauthmethod_cas">LSauthMethod_CAS</h1>
<p>Cette <a href="#conf-lsauthmethod-configuration-des-lsauthmethods">LSauthMethod</a> est utilisée pour gérer
l'authentification via un service SSO CAS. Cette librairie doit être configurée en éditant le
fichier de configuration <code>conf/LSauth/config.LSauthMethod_CAS.php</code>.</p>
<p><strong>Structure du fichier :</strong></p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="x">/*</span>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a><span class="x"> *****************************************************</span>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a><span class="x"> * Configuration of the CAS authentification support *</span>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a><span class="x"> *****************************************************</span>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a><span class="x"> */</span>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a><span class="x">// phpCAS Path (http://www.ja-sig.org/wiki/display/CASC/phpCAS)</span>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a><span class="x">define('PHP_CAS_PATH','/usr/share/php/CAS.php');</span>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a><span class="x">// phpCAS Debug File</span>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a><span class="x">// define('PHP_CAS_DEBUG_FILE','/tmp/phpCAS.log');</span>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a><span class="x">// Disable logout</span>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a><span class="x">define('LSAUTH_CAS_DISABLE_LOGOUT',false);</span>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-16" id="__codelineno-0-16" name="__codelineno-0-16"></a><span class="x">// CAS Server version (used constant name know by phpCAS : CAS_VERSION_1_0 or CAS_VERSION_2_0)</span>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-17" id="__codelineno-0-17" name="__codelineno-0-17"></a><span class="x">define('LSAUTH_CAS_VERSION','CAS_VERSION_2_0');</span>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-18" id="__codelineno-0-18" name="__codelineno-0-18"></a>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-19" id="__codelineno-0-19" name="__codelineno-0-19"></a><span class="x">// CAS Server hostname</span>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-20" id="__codelineno-0-20" name="__codelineno-0-20"></a><span class="x">define('LSAUTH_CAS_SERVER_HOSTNAME','cas.univ.fr');</span>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-21" id="__codelineno-0-21" name="__codelineno-0-21"></a>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-22" id="__codelineno-0-22" name="__codelineno-0-22"></a><span class="x">// CAS Server port</span>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-23" id="__codelineno-0-23" name="__codelineno-0-23"></a><span class="x">define('LSAUTH_CAS_SERVER_PORT',443);</span>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-24" id="__codelineno-0-24" name="__codelineno-0-24"></a>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-25" id="__codelineno-0-25" name="__codelineno-0-25"></a><span class="x">// CAS Server URI (empty by default)</span>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-26" id="__codelineno-0-26" name="__codelineno-0-26"></a><span class="x">// define('LSAUTH_CAS_SERVER_URI','cas/');</span>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-27" id="__codelineno-0-27" name="__codelineno-0-27"></a>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-28" id="__codelineno-0-28" name="__codelineno-0-28"></a><span class="x">// No SSL validation for the CAS server</span>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-29" id="__codelineno-0-29" name="__codelineno-0-29"></a><span class="x">define('LSAUTH_CAS_SERVER_NO_SSL_VALIDATION',false);</span>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-30" id="__codelineno-0-30" name="__codelineno-0-30"></a>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-31" id="__codelineno-0-31" name="__codelineno-0-31"></a><span class="x">// CAS server SSL CA Certificate path</span>
<a href="#conf-lsauthmethod-lsauthmethod_cas-__codelineno-0-32" id="__codelineno-0-32" name="__codelineno-0-32"></a><span class="x">//define('LSAUTH_CAS_SERVER_SSL_CACERT','');</span>
</code></pre></div>
<ul>
<li>
<p><code>PHP_CAS_PATH</code></p>
<p>Le chemin d'accès du fichier <code>CAS.php</code> de la librairie
<a href="http://www.ja-sig.org/wiki/display/CASC/phpCAS">phpCAS</a>. Le chemin d'exemple correspond au chemin
résultant d'une installation via <a href="http://pear.php.net/">PEAR</a> sur une Debian (Lenny).</p>
</li>
</ul>
<ul>
<li>
<p><code>PHP_CAS_DEBUG_FILE</code></p>
<p>Chemin du fichier de log de la librairie <a href="http://www.ja-sig.org/wiki/display/CASC/phpCAS">phpCAS</a>.
Commenter la ligne pour désactiver les logs.</p>
</li>
</ul>
<ul>
<li>
<p><code>LSAUTH_CAS_DISABLE_LOGOUT</code></p>
<p>Booléen définissant si l'utilisateur peut se déconnecter du serveur CAS depuis l'interface.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Remarque : l'appel de l'URL de déconnexion via une requête <code>GET</code> supprimera la session PHP et
donc la session LdapSaisie sans déconnecter pour autant l'utilisateur au niveau du serveur
CAS. Cela peut donc permettre de gérer la déconnexion automatique au niveau d'LdapSaisie suite
à une déconnexion au niveau du CAS à traver le concepte de <code>Global Logout</code>.</p>
</div>
</li>
</ul>
<ul>
<li>
<p><code>LSAUTH_CAS_VERSION</code></p>
<p>Nom de la constant <a href="http://www.ja-sig.org/wiki/display/CASC/phpCAS">phpCAS</a> permettant de définir
la version CAS du serveur. Actuellement, la librairie
<a href="http://www.ja-sig.org/wiki/display/CASC/phpCAS">phpCAS</a> ne reconnait que la constante
<code>CAS_VERSION_1_0</code> pour la version 1 de CAS ou la constante <code>CAS_VERSION_2_0</code> pour la version 2 de
CAS.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Remarque : Des tests on montrés que l'utilisation d'une compatibilité CAS version 2 peut
également fonctionner sur un version 3 du serveur CAS.</p>
</div>
</li>
</ul>
<ul>
<li>
<p><code>LSAUTH_CAS_SERVER_HOSTNAME</code></p>
<p>Le nom d'hôte du serveur CAS.</p>
</li>
</ul>
<ul>
<li>
<p><code>LSAUTH_CAS_SERVER_PORT</code></p>
<p>Le port d'écoute du serveur CAS.</p>
</li>
</ul>
<ul>
<li>
<p><code>LSAUTH_CAS_SERVER_URI</code></p>
<p>Le dossier HTTP dans lequel se trouve le service CAS. Exemple : Pour un service CAS accessible via
l'URL <code>https://cas.univ.fr/cas/</code>, la constante devra valoir <code>cas/</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>LSAUTH_CAS_SERVER_NO_SSL_VALIDATION</code></p>
<p>Booléen permettant de désactiver la validation du certificat SSL du serveur CAS lors des requêtes
de validation des tickets CAS.</p>
</li>
</ul>
<ul>
<li>
<p><code>LSAUTH_CAS_SERVER_SSL_CACERT</code></p>
<p>Chemin d'accès du fichier contenant le certificat SSL de la CA du serveur CAS au format PEM.
Commenter la ligne pour désactiver ce paramètre.</p>
</li>
</ul></section><section class="print-page" id="conf-lsauthmethod-lsauthmethod_http"><h1 id="conf-lsauthmethod-lsauthmethod_http-lsauthmethod_http">LSauthMethod_HTTP</h1>
<p>Cette <a href="#conf-lsauthmethod-configuration-des-lsauthmethods">LSauthMethod</a> est utilisée pour gérer
l'authentification via les variables d'environnements définies suite à une authentification,
potentiellement déléguée au serveur web.</p>
<p>Cette méthode récupère dans l'environment d'exécution PHP, le nom d'utilisateur et le mot de passe
de l'utilisateur connecté. À partir du nom d'utilisateur, une recherche dans l'annuaire sera
effectuée pour trouver l'utilisateur correspondant. L'authentification sera réussie uniquement si un
et un seul utilisateur est retourné par la recherche et si une authentification auprès de l'annuaire
LDAP réussie à l'aide du DN de l'objet LDAP trouvé et du mot de passe fourni.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>En cas d'authentification déléguée au serveur web, il est possible de désactiver la vérification
du mot de passe via le paramètre <code>LSAUTHMETHOD_HTTP_TRUST_WITHOUT_PASSWORD_CHALLENGE</code>
(voir ci-dessous).</p>
</div>
<p>Les variables d'environnements utilisées pour authentifier l'utilisateur connecté dépendent de la
méthode configurée via la constante <code>LSAUTHMETHOD_HTTP_METHOD</code> (voir ci-dessous). Si ces variables
ne sont pas disponibles, une erreur HTTP 403 sera générée pour réclamer une authentification à
l'utilisateur.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Cette <a href="#conf-lsauthmethod-configuration-des-lsauthmethods">LSauthMethod</a> supporte le mode API et il s'agit
de la méthode utilisée par défaut dans ce mode.</p>
</div>
<p>Cette librairie peut être configurée en éditant le fichier de configuration
<code>conf/LSauth/config.LSauthMethod_HTTP.php</code>.</p>
<p><strong>Structure du fichier :</strong></p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsauthmethod-lsauthmethod_http-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="x">/*</span>
<a href="#conf-lsauthmethod-lsauthmethod_http-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a><span class="x"> *****************************************************</span>
<a href="#conf-lsauthmethod-lsauthmethod_http-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a><span class="x"> * Configuration of the HTTP authentification support *</span>
<a href="#conf-lsauthmethod-lsauthmethod_http-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a><span class="x"> *****************************************************</span>
<a href="#conf-lsauthmethod-lsauthmethod_http-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a><span class="x"> */</span>
<a href="#conf-lsauthmethod-lsauthmethod_http-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a>
<a href="#conf-lsauthmethod-lsauthmethod_http-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a><span class="x">// Don't check HTTP server's login/password by LDAP authentication challenge</span>
<a href="#conf-lsauthmethod-lsauthmethod_http-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a><span class="x">//define('LSAUTHMETHOD_HTTP_TRUST_WITHOUT_PASSWORD_CHALLENGE',true);</span>
<a href="#conf-lsauthmethod-lsauthmethod_http-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a>
<a href="#conf-lsauthmethod-lsauthmethod_http-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a><span class="x">// Authentication realm (API mode only)</span>
<a href="#conf-lsauthmethod-lsauthmethod_http-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a><span class="x">//define('LSAUTHMETHOD_HTTP_API_REALM', ___('LdapSaisie API - Authentication required'));</span>
</code></pre></div>
<ul>
<li>
<p><code>LSAUTHMETHOD_HTTP_TRUST_WITHOUT_PASSWORD_CHALLENGE</code></p>
<p>Permet de désactiver le test d'authentification auprès de l'annuaire LDAP. Pour cela, cette
constante doit être définie et valoir <code>True</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>LSAUTHMETHOD_HTTP_METHOD</code></p>
<p>Permet de définir la méthode utilisée par le serveur web pour passer à <a href="http://www.php.net/">PHP</a>
l'identifiant de l'utilisateur connecté et son mot de passe.</p>
<p>Cette constance peut pendre les valeurs suivantes :</p>
<ul>
<li>
<p><code>PHP_PASS</code></p>
<p>Dans cette méthode, le serveur web défini les variables d'environnement <code>PHP_AUTH_USER</code> et
<code>PHP_AUTH_PW</code>. Cette méthode est la méthode par défaut et convient en cas d'utilisation de
<code>mod_php</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>REMOTE_USER</code></p>
<p>Dans cette méthode, le serveur web défini la variable d'environnement <code>REMOTE_USER</code>. Cette
variable ne contient que l'identifiant de l'utilisateur connecté. Cette méthode ne peut donc
être utilisée que conjointement avec l'activation du paramètre
<code>LSAUTHMETHOD_HTTP_TRUST_WITHOUT_PASSWORD_CHALLENGE</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>AUTHORIZATION</code></p>
<p>Dans cette méthode, le serveur web passe le contenu de l'entête HTTP <code>Authorization</code> dans la
variable d'environnement <code>HTTP_AUTHORIZATION</code>. Cette méthode convient en cas d'utilisation de
<a href="http://www.php.net/">PHP</a> en mode CGI ou encore via PHP-FPM.</p>
<p>Pour utiliser cette méthode, il faudra adapter la configuration du serveur web. Par exemple,
pour Apache HTTPd, vous pouvez utiliser le module <code>rewrite</code> et la règle de réécriture suivante :</p>
<div class="highlight"><pre><span></span><code><a href="#conf-lsauthmethod-lsauthmethod_http-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a>RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
</code></pre></div>
</li>
</ul>
</li>
</ul>
<ul>
<li>
<p><code>LSAUTHMETHOD_HTTP_LOGOUT_REMOTE_URL</code></p>
<p>URL de déconnexion externe, utile par exemple dans le contexte d'une connexion via un service SSO.
L'utilisateur sera automatiquement redirigé vers cette URL après sa déconnexion effective au
niveau d'LdapSaisie.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Si cette URL de déconnexion n'est pas défini, le bouton de déconnexion sera masqué.</p>
</div>
</li>
</ul>
<ul>
<li>
<p><code>LSAUTHMETHOD_HTTP_REALM</code></p>
<p>Domaine d'authentification (<code>reaml</code>) utilisé pour réclamer l'authentification de l'utilisateur
(facultatif).</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Pour que le message soit traduit, utilisez la fonction <code>___()</code> (voir exemple).</p>
</div>
</li>
</ul></section><h1 class="nav-section-title-end">Ended: Configuration des méthodes d'authentification (LSauthMethod)</h1><h1 class="nav-section-title-end">Ended: Configuration</h1><section class="print-page" id="api"><h1 id="api-api">API</h1>
<p>Depuis la version 4.0, LdapSaisie offre une API visant à permettre de faire les mêmes choses que ce
qu'il est possible d'accomplir via l'interface web. L'idée n'est bien entendue pas de se substituer
systématiquement à la possibilité de se connecter directement à l'annuaire, mais plutôt d'offrir une
API web pour l'intégration d'outil préférant ce mode d'interaction, ou encore, pour exposer des
méthodes accès aux données de l'annuaire tout en profitant des logiques métiers
implémentées/configurées dans LdapSaisie : validation syntaxique et d'unicité, règle de génération
et d'interdépendances des attributs, déclencheurs, ...</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Cette API est actuellement dans une phase de test et n'offre pas encore toutes les
fonctionnalités proposées dans l'interface web. Elle est vouée à évoluer pour intégrer petit à
petit un maximum de fonctionnalités. Des contributions à ce sujet seront plus qu'appréciée !</p>
</div>
<h2 id="api-authentification">Authentification</h2>
<p>L'authentification à l'API utilise le même composant <code>LSauth</code> que lors d'une authentification à
l'interface web, cependant, ce composant s'adapte pour prendre en compte de mode de connexion. Par
défaut, la méthode d'authentification utilisée sera
<a href="#conf-lsauthmethod-lsauthmethod_http-LSauthMethod_HTTP">LSauthMethod_HTTP</a> et permettra de se
connecter en spécifiant le nom d'utilisateur et le mot de l'utilisateur cherchant à se connecter via
une authentification basique HTTP.</p>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>Il est à noter que tous les types d'utilisateur ne peuvent pas forcément utiliser l'API : le
paramètre <code>api_access</code> doit être explicitement positionné à <code>True</code> dans
<a href="#conf-global-ldap-configuration-des-serveurs-ldap">la configuration du serveur LDAP</a>.</p>
</div>
<p>Une fois connecté, l'utilisateur endossera les droits associés à ses
<a href="#conf-global-ldap-lsprofile-profils-dutilisateurs">LSprofiles</a>, tout comme un utilisateur
connecté à l'interface web.</p>
<h2 id="api-methodes-exposees">Méthodes exposées</h2>
<p>Les URLs des méthodes de l'API ont été construites par mimétisme sur celle de l'interface web et
sous la racine web <code>api/</code>. Par ailleurs, un numéro de version d'API a été insérée dans chacune
d'elles afin d'anticiper toutes évolutions futures majeures nécéssitants de conserver une
rétrocompatibilité avec les anciennes versions de l'API.</p>
<p>Toutes les méthodes retournent des informations au format JSON et accepte le paramètre <code>pretty</code>
permettant d'obtenir un retour plus facilement lisible. Les chaines de caractères échangées doivent
par ailleurs être encodées en UTF-8. On trouvera par ailleurs dans le retour JSON :</p>
<ul>
<li>
<p><code>success</code></p>
<p>Booléen précisant si l'action demandée a correctement été exécutée.</p>
</li>
</ul>
<ul>
<li>
<p><code>messages</code></p>
<p>Ce tableau pourra être présent et lister les messages d'informations générées par l'action
demandée. Il s'agira des mêmes messages que ceux affichés dans l'interface web lorsque les
actions équivalentes y sont faites.</p>
</li>
</ul>
<ul>
<li><code>errors</code>
Ce tableau pourra être présent et lister les messages d'erreurs générées par l'action demandée.</li>
</ul>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Les messages d'informations et d'erreurs générées par l'application sont traduites dans la
langue courante qui peut être spécifiée via le paramètre <code>lang</code> accepté par toutes les méthodes
(exemple : <code>fr_FR</code> ou <code>en_US</code>).</p>
</div>
<p>Lorsqu'une méthode cible un type d'objets, voir un objet en particulier, ces informations seront
transmises dans l'URL appelée. Si le type d'objet ou l'objet demandé est introuvable, une erreur
HTTP 404 sera générée.</p>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>Sauf précision contraire, toutes les méthodes exposées sont accessibles uniquement via les
méthodes HTTP <code>GET</code> ou <code>POST</code>. L'accès via une autre méthode retournera une erreur 404.</p>
</div>
<ul>
<li>
<p><code>/api/1.0/object/[object type]</code></p>
<p>Cette méthode permet de rechercher/lister les informations d'un type d'objets de l'annuaire en
particulier. Le type de l'objet est précisé dans l'URL et doit être encodé en conséquence. Par
mimétisme du comportement de l'interface web, la recherche est paginée et accepte des paramètres
similaires en plus de paramètre plus appropriés à un fonctionnement programmatique :</p>
<ul>
<li>
<p><code>filter</code></p>
<p>Permet de spécifier un filtre de recherche LDAP personnalisé. Celui-ci sera combiné avec les
paramètres propres au type d'objets recherchés et aux autres paramètres spécifiés (<code>pattern</code>
par exemple).</p>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>Du fait d'une limitation de la classe <code>Net_LDAP2_Filter</code> utilisée pour analyser le
filtre passé en paramètre, seuls les filtres simples du type <code>(attribut=valeur)</code> sont
acceptés ici. Pour les mêmes raisons, il est important que le filtre spécifié soit
toujours entourné de paranthèses.</p>
</div>
</li>
</ul>
<ul>
<li>
<p><code>predefinedFilter</code></p>
<p>Permet de spécifier un des filtres de recherche LDAP prédéfinis dans la configuration du
type d'objet.</p>
</li>
</ul>
<ul>
<li>
<p><code>pattern</code></p>
<p>Permet de spécifier un mot clé de recherche, comme proposé dans l'interface web.</p>
</li>
</ul>
<ul>
<li>
<p><code>approx</code></p>
<p>Booléen permettant d'activer/désactiver la recherche approximative sur le mot clé. Les
valeurs acceptées sont <code>1</code> ou <code>0</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>basedn</code></p>
<p>Permet de spécifier une base de recherche personnalisé pour la recherche.</p>
</li>
</ul>
<ul>
<li>
<p><code>subDn</code></p>
<p>Dans le cas d'un serveur LDAP configuré avec des
<a href="#conf-global-ldap-subdn-sous-niveaux-de-connexion">sous-niveaux de connexion</a>, permet de
spécifier le sous-niveau pour la recherche.</p>
</li>
</ul>
<ul>
<li>
<p><code>scope</code></p>
<p>Permet de spécifier l'étendue de la recherche dans l'annuaire. Valeurs acceptées: <code>sub</code>,
<code>one</code> et <code>base</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>recursive</code></p>
<p>Booléen permettant d'activer/désactiver la recherche recursive, c'est à dire une recherche à
la racine de l'annuaire (ou du
<a href="#conf-global-ldap-subdn-sous-niveaux-de-connexion">sous-niveau de connexion</a>) avec une
étendue de recherche maximale. Les valeurs acceptées sont <code>1</code> ou <code>0</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>displayFormat</code></p>
<p>Permet de spécifier un <a href="#conf-global-lsformat-format-parametrable">LSformat</a> personnalisé
pour le nom des objets dans le résultat de recherche.</p>
</li>
</ul>
<ul>
<li>
<p><code>extraDisplayedColumns</code></p>
<p>Booléen permettant d'activer le retour des colonnes personnalisées dans le résultat de
recherche. Les valeurs acceptées sont <code>1</code> ou <code>0</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>attributes</code></p>
<p>Liste des attributs supplémentaires que devra retourner la recherche.</p>
</li>
</ul>
<ul>
<li>
<p><code>attributesDetails</code></p>
<p>Permet d'obtenir les détails sur les valeurs des attributs (au lieu des valeurs au format
attendu en cas de création/modification de l'objet). Seul la présence de ce paramètre suffit
à activer ce comportement, sa valeur n'a pas d'importance.</p>
</li>
</ul>
<ul>
<li>
<p><code>sortBy</code></p>
<p>Permet de préciser sur quelle information le résultat de recherche doit être trié. Valeurs
acceptées : <code>displayName</code>, <code>subDn</code> ou un des noms des colonnes personnalisées.</p>
</li>
</ul>
<ul>
<li>
<p><code>sortDirection</code></p>
<p>Permet de préciser l'ordre de tri du résultat de recherche. Valeurs acceptées : <code>ASC</code> (A-Z)
ou <code>DESC</code> (Z-A).</p>
</li>
</ul>
<ul>
<li>
<p><code>page</code></p>
<p>Permet de préciser la page du résultat de recherche.</p>
</li>
</ul>
<ul>
<li>
<p><code>nbObjectsByPage</code></p>
<p>Permet de préciser le nombre maximum d'objets retournés par page du résultat de recherche.</p>
</li>
</ul>
<ul>
<li>
<p><code>all</code></p>
<p>Permet de réclamer le résultat complet de la recherche (désactivation de la pagination).
Seul la présence de ce paramètre suffit à activer ce comportement, sa valeur n'a pas
d'importance.</p>
</li>
</ul>
<ul>
<li>
<p><code>as_list</code></p>
<p>Permet de réclamer un résultat de recherche dans lequel, la clé <code>objects</code> sera une liste et
non un dictionnaire. Dans ce cas, le DN de l'objet est fourni dans la clé <code>dn</code> des détails
des objets. Seul la présence de ce paramètre suffit à activer ce comportement, sa valeur n'a pas
d'importance.</p>
</li>
</ul>
<ul>
<li>
<p><code>withoutCache</code></p>
<p>Booléen permettant de désactiver l'utilisation du cache. Les valeurs acceptées sont <code>1</code> ou
<code>0</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>keepParamsBetweenSearches</code></p>
<p>Booléen permettant d'activer/désactiver le stockage en session des paramètres de recherche
(optionnel, par défaut : <code>False</code>). Les valeurs acceptées sont <code>1</code> ou <code>0</code>.</p>
</li>
</ul>
<p><strong>Exemple :</strong></p>
<div class="highlight"><pre><span></span><code><a href="#api-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a># curl -u username:secret 'https://ldapsaisie/api/1.0/object/LSpeople?extraDisplayedColumns=1&amp;pretty'
<a href="#api-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a>{
<a href="#api-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> "success": true,
<a href="#api-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> "objects": {
<a href="#api-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a> "uid=hmartin,ou=people,o=ls": {
<a href="#api-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a> "name": "Henri MARTIN",
<a href="#api-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a> "Mail": "henri.martin@ls.com"
<a href="#api-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a> },
<a href="#api-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a> "uid=s.ldapsaisie,ou=people,o=ls": {
<a href="#api-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a> "name": "Secretariat LdapSaisie",
<a href="#api-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a> "Mail": "secretariat@ldapsaisie.biz"
<a href="#api-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a> },
<a href="#api-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a> "uid=ls,ou=people,o=ls": {
<a href="#api-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a> "name": "LdapSaisie",
<a href="#api-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a> "Mail": "ldap.saisie@ls.com"
<a href="#api-__codelineno-0-16" id="__codelineno-0-16" name="__codelineno-0-16"></a> },
<a href="#api-__codelineno-0-17" id="__codelineno-0-17" name="__codelineno-0-17"></a> "uid=erwpa,ou=people,o=ls": {
<a href="#api-__codelineno-0-18" id="__codelineno-0-18" name="__codelineno-0-18"></a> "name": "Erwan PAGE",
<a href="#api-__codelineno-0-19" id="__codelineno-0-19" name="__codelineno-0-19"></a> "Mail": "erwan.page@ldapsaisie.biz"
<a href="#api-__codelineno-0-20" id="__codelineno-0-20" name="__codelineno-0-20"></a> },
<a href="#api-__codelineno-0-21" id="__codelineno-0-21" name="__codelineno-0-21"></a> "uid=user2,ou=people,ou=company1,ou=companies,o=ls": {
<a href="#api-__codelineno-0-22" id="__codelineno-0-22" name="__codelineno-0-22"></a> "name": "prenom2 nom2",
<a href="#api-__codelineno-0-23" id="__codelineno-0-23" name="__codelineno-0-23"></a> "Mail": "user2@ls.com"
<a href="#api-__codelineno-0-24" id="__codelineno-0-24" name="__codelineno-0-24"></a> }
<a href="#api-__codelineno-0-25" id="__codelineno-0-25" name="__codelineno-0-25"></a> },
<a href="#api-__codelineno-0-26" id="__codelineno-0-26" name="__codelineno-0-26"></a> "total": 14,
<a href="#api-__codelineno-0-27" id="__codelineno-0-27" name="__codelineno-0-27"></a> "params": {
<a href="#api-__codelineno-0-28" id="__codelineno-0-28" name="__codelineno-0-28"></a> "keepParamsBetweenSearches": false,
<a href="#api-__codelineno-0-29" id="__codelineno-0-29" name="__codelineno-0-29"></a> "filter": null,
<a href="#api-__codelineno-0-30" id="__codelineno-0-30" name="__codelineno-0-30"></a> "pattern": null,
<a href="#api-__codelineno-0-31" id="__codelineno-0-31" name="__codelineno-0-31"></a> "predefinedFilter": false,
<a href="#api-__codelineno-0-32" id="__codelineno-0-32" name="__codelineno-0-32"></a> "basedn": null,
<a href="#api-__codelineno-0-33" id="__codelineno-0-33" name="__codelineno-0-33"></a> "scope": null,
<a href="#api-__codelineno-0-34" id="__codelineno-0-34" name="__codelineno-0-34"></a> "sizelimit": 0,
<a href="#api-__codelineno-0-35" id="__codelineno-0-35" name="__codelineno-0-35"></a> "attronly": false,
<a href="#api-__codelineno-0-36" id="__codelineno-0-36" name="__codelineno-0-36"></a> "approx": false,
<a href="#api-__codelineno-0-37" id="__codelineno-0-37" name="__codelineno-0-37"></a> "recursive": true,
<a href="#api-__codelineno-0-38" id="__codelineno-0-38" name="__codelineno-0-38"></a> "attributes": [],
<a href="#api-__codelineno-0-39" id="__codelineno-0-39" name="__codelineno-0-39"></a> "onlyAccessible": true,
<a href="#api-__codelineno-0-40" id="__codelineno-0-40" name="__codelineno-0-40"></a> "sortDirection": null,
<a href="#api-__codelineno-0-41" id="__codelineno-0-41" name="__codelineno-0-41"></a> "sortBy": null,
<a href="#api-__codelineno-0-42" id="__codelineno-0-42" name="__codelineno-0-42"></a> "sortlimit": 0,
<a href="#api-__codelineno-0-43" id="__codelineno-0-43" name="__codelineno-0-43"></a> "displayFormat": "%{cn}",
<a href="#api-__codelineno-0-44" id="__codelineno-0-44" name="__codelineno-0-44"></a> "nbObjectsByPage": 25,
<a href="#api-__codelineno-0-45" id="__codelineno-0-45" name="__codelineno-0-45"></a> "withoutCache": false,
<a href="#api-__codelineno-0-46" id="__codelineno-0-46" name="__codelineno-0-46"></a> "extraDisplayedColumns": true
<a href="#api-__codelineno-0-47" id="__codelineno-0-47" name="__codelineno-0-47"></a> },
<a href="#api-__codelineno-0-48" id="__codelineno-0-48" name="__codelineno-0-48"></a> "page": 1,
<a href="#api-__codelineno-0-49" id="__codelineno-0-49" name="__codelineno-0-49"></a> "nbPages": 3
<a href="#api-__codelineno-0-50" id="__codelineno-0-50" name="__codelineno-0-50"></a>}
</code></pre></div>
</li>
</ul>
<ul>
<li>
<p><code>/api/1.0/object/[object type]/[dn]</code></p>
<p>Cette méthode permet de récupérer les informations d'un objet de l'annuaire au format JSON. Le
type de l'objet et son DN sont précisés dans l'URL et doivent être encodés en conséquence. Par
défaut, les valeurs des attributs retournées sont au format tel qu'attendu en cas de
création/modification de l'objet. Il est cependant possible d'ajouter le paramètre <code>details</code>
afin d'obtenir des informations complémentaires sur les valeurs des attributs.</p>
<p><strong>Exemple :</strong></p>
<div class="highlight"><pre><span></span><code><a href="#api-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a># curl -u username:secret 'https://ldapsaisie/api/1.0/object/LSpeople/uid=hmartin,ou=people,o=ls?pretty'
<a href="#api-__codelineno-1-2" id="__codelineno-1-2" name="__codelineno-1-2"></a>{
<a href="#api-__codelineno-1-3" id="__codelineno-1-3" name="__codelineno-1-3"></a> "success": true,
<a href="#api-__codelineno-1-4" id="__codelineno-1-4" name="__codelineno-1-4"></a> "dn": "uid=hmartin,ou=people,o=ls",
<a href="#api-__codelineno-1-5" id="__codelineno-1-5" name="__codelineno-1-5"></a> "type": "LSpeople",
<a href="#api-__codelineno-1-6" id="__codelineno-1-6" name="__codelineno-1-6"></a> "name": "Henri MARTIN",
<a href="#api-__codelineno-1-7" id="__codelineno-1-7" name="__codelineno-1-7"></a> "details": false,
<a href="#api-__codelineno-1-8" id="__codelineno-1-8" name="__codelineno-1-8"></a> "attributes": {
<a href="#api-__codelineno-1-9" id="__codelineno-1-9" name="__codelineno-1-9"></a> "uid": "hmartin",
<a href="#api-__codelineno-1-10" id="__codelineno-1-10" name="__codelineno-1-10"></a> "givenName": "Henri",
<a href="#api-__codelineno-1-11" id="__codelineno-1-11" name="__codelineno-1-11"></a> "sn": "MARTIN",
<a href="#api-__codelineno-1-12" id="__codelineno-1-12" name="__codelineno-1-12"></a> "cn": "Henri MARTIN",
<a href="#api-__codelineno-1-13" id="__codelineno-1-13" name="__codelineno-1-13"></a> "mail": "henri.martin@ls.com",
<a href="#api-__codelineno-1-14" id="__codelineno-1-14" name="__codelineno-1-14"></a> "personalTitle": "M.",
<a href="#api-__codelineno-1-15" id="__codelineno-1-15" name="__codelineno-1-15"></a> "description": [],
<a href="#api-__codelineno-1-16" id="__codelineno-1-16" name="__codelineno-1-16"></a> "jpegPhoto": null,
<a href="#api-__codelineno-1-17" id="__codelineno-1-17" name="__codelineno-1-17"></a> "lsGodfatherDn": [
<a href="#api-__codelineno-1-18" id="__codelineno-1-18" name="__codelineno-1-18"></a> "uid=eeggs,ou=people,o=ls"
<a href="#api-__codelineno-1-19" id="__codelineno-1-19" name="__codelineno-1-19"></a> ],
<a href="#api-__codelineno-1-20" id="__codelineno-1-20" name="__codelineno-1-20"></a> "uidNumber": "101022",
<a href="#api-__codelineno-1-21" id="__codelineno-1-21" name="__codelineno-1-21"></a> "gidNumber": "102001",
<a href="#api-__codelineno-1-22" id="__codelineno-1-22" name="__codelineno-1-22"></a> "loginShell": "no",
<a href="#api-__codelineno-1-23" id="__codelineno-1-23" name="__codelineno-1-23"></a> "homeDirectory": "\/home\/com",
<a href="#api-__codelineno-1-24" id="__codelineno-1-24" name="__codelineno-1-24"></a> "gecos": null,
<a href="#api-__codelineno-1-25" id="__codelineno-1-25" name="__codelineno-1-25"></a> "shadowExpire": null,
<a href="#api-__codelineno-1-26" id="__codelineno-1-26" name="__codelineno-1-26"></a> "shadowMax": null,
<a href="#api-__codelineno-1-27" id="__codelineno-1-27" name="__codelineno-1-27"></a> "shadowInactive": null,
<a href="#api-__codelineno-1-28" id="__codelineno-1-28" name="__codelineno-1-28"></a> "shadowLastChange": null,
<a href="#api-__codelineno-1-29" id="__codelineno-1-29" name="__codelineno-1-29"></a> "sambaSID": "S-1-5-21-2421470416-3566881284-3047381809-203044",
<a href="#api-__codelineno-1-30" id="__codelineno-1-30" name="__codelineno-1-30"></a> "sambaPrimaryGroupSID": "S-1-5-21-2421470416-3566881284-3047381809-205003",
<a href="#api-__codelineno-1-31" id="__codelineno-1-31" name="__codelineno-1-31"></a> "sambaAcctFlags": [
<a href="#api-__codelineno-1-32" id="__codelineno-1-32" name="__codelineno-1-32"></a> "U"
<a href="#api-__codelineno-1-33" id="__codelineno-1-33" name="__codelineno-1-33"></a> ],
<a href="#api-__codelineno-1-34" id="__codelineno-1-34" name="__codelineno-1-34"></a> "sambaHomeDrive": null,
<a href="#api-__codelineno-1-35" id="__codelineno-1-35" name="__codelineno-1-35"></a> "sambaHomePath": null,
<a href="#api-__codelineno-1-36" id="__codelineno-1-36" name="__codelineno-1-36"></a> "sambaProfilePath": null,
<a href="#api-__codelineno-1-37" id="__codelineno-1-37" name="__codelineno-1-37"></a> "sambaLogonScript": null,
<a href="#api-__codelineno-1-38" id="__codelineno-1-38" name="__codelineno-1-38"></a> "sambaLogonTime": null,
<a href="#api-__codelineno-1-39" id="__codelineno-1-39" name="__codelineno-1-39"></a> "sambaLogoffTime": null,
<a href="#api-__codelineno-1-40" id="__codelineno-1-40" name="__codelineno-1-40"></a> "sambaKickoffTime": null,
<a href="#api-__codelineno-1-41" id="__codelineno-1-41" name="__codelineno-1-41"></a> "sambaPwdLastSet": null,
<a href="#api-__codelineno-1-42" id="__codelineno-1-42" name="__codelineno-1-42"></a> "sambaPwdMustChange": null,
<a href="#api-__codelineno-1-43" id="__codelineno-1-43" name="__codelineno-1-43"></a> "sambaPwdCanChange": null
<a href="#api-__codelineno-1-44" id="__codelineno-1-44" name="__codelineno-1-44"></a> },
<a href="#api-__codelineno-1-45" id="__codelineno-1-45" name="__codelineno-1-45"></a> "relations": {
<a href="#api-__codelineno-1-46" id="__codelineno-1-46" name="__codelineno-1-46"></a> "groups": {
<a href="#api-__codelineno-1-47" id="__codelineno-1-47" name="__codelineno-1-47"></a> "cn=direction,ou=groups,o=ls": "direction",
<a href="#api-__codelineno-1-48" id="__codelineno-1-48" name="__codelineno-1-48"></a> "cn=secretariat,ou=groups,o=ls": "secretariat"
<a href="#api-__codelineno-1-49" id="__codelineno-1-49" name="__codelineno-1-49"></a> },
<a href="#api-__codelineno-1-50" id="__codelineno-1-50" name="__codelineno-1-50"></a> "godfather": []
<a href="#api-__codelineno-1-51" id="__codelineno-1-51" name="__codelineno-1-51"></a> }
<a href="#api-__codelineno-1-52" id="__codelineno-1-52" name="__codelineno-1-52"></a>}
</code></pre></div>
</li>
</ul>
<ul>
<li>
<p><code>/api/1.0/object/[object type]/create</code></p>
<p>Cette méthode permet de créer un objet dans l'annuaire. Le type de l'objet qui sera créé est
précisé dans l'URL et doit être encodé en conséquence. Les informations de l'objet doivent est
transmises au format <code>x-www-form-urlencoded</code>. Elles peuvent également être au format
<code>multipart/form-data</code>, en particulier si votre requête contient une image. Par mimétisme avec
l'interface web, seuls les attributs prévus dans le formulaire de création du type d'objet
peuvent être passées ici. De la même manière, les attributs non-spécifiés ici, pouront être
auto-générés en accord avec leur configuration et la requête sera acceptée uniquement si tous
les attributs obligatoires y sont spécifiés ou s'ils peuvent être auto-générés.</p>
<p>Le format et la syntaxe des valeurs des attributs dépends de leur type HTML. Ainsi, par exemple,
un attribut de type HTML <code>boolean</code> acceptera comme valeurs possibles <code>yes</code> ou <code>no</code>. Pour plus
de détails sur le type de valeur acceptée par un type d'attribut HTML en particulier, consultez
sa documentation. Vous pouvez également analyser le code de la méthode <code>getPostData()</code> de la
classe <a href="http://www.php.net/">PHP</a> correspondante.</p>
<p>Si l'application détecte un souci avec les informations transmises pour les attributs, un
tableau <code>fields_errors</code> sera présent dans la réponse JSON et contiendra pour chacun des
attributs problématique, un tableau des messages d'erreurs générées par l'application.</p>
<p>Si le type d'objet en prévoit, vous pouvez également utiliser un
<a href="#conf-lsobject-lsform-configuration-des-masques-de-saisie">masque de saisie</a> via le
paramètre <code>dataEntryForm</code>.</p>
<p><strong>Exemple :</strong></p>
<div class="highlight"><pre><span></span><code><a href="#api-__codelineno-2-1" id="__codelineno-2-1" name="__codelineno-2-1"></a># curl -u username:secret 'https://ldapsaisie/api/1.0/object/LSpeople/create?pretty' -d "uid=foo.bar&amp;personalTitle=M.&amp;givenName=foo&amp;sn=bar&amp;cn=Foo Bar&amp;mail=foo.bar@example.com&amp;userPassword=Y0urS3cr3t&amp;lsGodfatherDn[]=uid=admin,ou=people,o=ls&amp;gidNumber=70000"
<a href="#api-__codelineno-2-2" id="__codelineno-2-2" name="__codelineno-2-2"></a>{
<a href="#api-__codelineno-2-3" id="__codelineno-2-3" name="__codelineno-2-3"></a> "success": true,
<a href="#api-__codelineno-2-4" id="__codelineno-2-4" name="__codelineno-2-4"></a> "type": "LSpeople",
<a href="#api-__codelineno-2-5" id="__codelineno-2-5" name="__codelineno-2-5"></a> "dn": "uid=foo.bar,ou=people,o=ls",
<a href="#api-__codelineno-2-6" id="__codelineno-2-6" name="__codelineno-2-6"></a> "name": "Foo Bar",
<a href="#api-__codelineno-2-7" id="__codelineno-2-7" name="__codelineno-2-7"></a> "messages": [
<a href="#api-__codelineno-2-8" id="__codelineno-2-8" name="__codelineno-2-8"></a> "Le mail de notification a \u00e9t\u00e9 envoy\u00e9.",
<a href="#api-__codelineno-2-9" id="__codelineno-2-9" name="__codelineno-2-9"></a> "L'objet a \u00e9t\u00e9 ajout\u00e9."
<a href="#api-__codelineno-2-10" id="__codelineno-2-10" name="__codelineno-2-10"></a> ]
<a href="#api-__codelineno-2-11" id="__codelineno-2-11" name="__codelineno-2-11"></a>}
</code></pre></div>
</li>
</ul>
<ul>
<li>
<p><code>/api/1.0/object/[object type]/[dn]/modify</code></p>
<p>Cette méthode permet de modifier un objet dans l'annuaire. Le type de l'objet et son DN sont
précisés dans l'URL et doivent être encodés en conséquence. Les informations de l'objet à
modifier doivent être transmises au même format que pour la méthode <code>create</code> (voir ci-dessus).
Comme pour cette dernière, seuls les attributs prévus dans le formulaire de modification du type
d'objet peuvent être passées ici et la réponse JSON pourra contenir un tableau <code>fields_errors</code>
contenant les erreurs générées par l'application au sujet des valeurs transmises pour les
attributs.</p>
<p><strong>Exemple :</strong></p>
<div class="highlight"><pre><span></span><code><a href="#api-__codelineno-3-1" id="__codelineno-3-1" name="__codelineno-3-1"></a># curl -u username:secret 'https://ldapsaisie/api/1.0/object/LSpeople/uid=foo.bar,ou=people,o=ls/modify?pretty' -d "givenName=foo&amp;sn=bar&amp;cn=Foo Bar"
<a href="#api-__codelineno-3-2" id="__codelineno-3-2" name="__codelineno-3-2"></a>{
<a href="#api-__codelineno-3-3" id="__codelineno-3-3" name="__codelineno-3-3"></a> "dn": "uid=foo.bar,ou=people,o=ls",
<a href="#api-__codelineno-3-4" id="__codelineno-3-4" name="__codelineno-3-4"></a> "type": "LSpeople",
<a href="#api-__codelineno-3-5" id="__codelineno-3-5" name="__codelineno-3-5"></a> "name": "Foo Bar",
<a href="#api-__codelineno-3-6" id="__codelineno-3-6" name="__codelineno-3-6"></a> "success": true,
<a href="#api-__codelineno-3-7" id="__codelineno-3-7" name="__codelineno-3-7"></a> "messages": [
<a href="#api-__codelineno-3-8" id="__codelineno-3-8" name="__codelineno-3-8"></a> "L'objet a bien \u00e9t\u00e9 modifi\u00e9."
<a href="#api-__codelineno-3-9" id="__codelineno-3-9" name="__codelineno-3-9"></a> ]
<a href="#api-__codelineno-3-10" id="__codelineno-3-10" name="__codelineno-3-10"></a>}
</code></pre></div>
</li>
</ul>
<ul>
<li>
<p><code>/api/1.0/object/[object type]/[dn]/remove</code></p>
<p>Cette méthode permet de supprimer un objet dans l'annuaire. Le type de l'objet et son DN sont
précisés dans l'URL et doivent être encodés en conséquence.</p>
<p><strong>Exemple :</strong></p>
<div class="highlight"><pre><span></span><code><a href="#api-__codelineno-4-1" id="__codelineno-4-1" name="__codelineno-4-1"></a># curl -u username:secret 'https://ldapsaisie/api/1.0/object/LSpeople/uid=foo.bar,ou=people,o=ls/remove?pretty'
<a href="#api-__codelineno-4-2" id="__codelineno-4-2" name="__codelineno-4-2"></a>{
<a href="#api-__codelineno-4-3" id="__codelineno-4-3" name="__codelineno-4-3"></a> "dn": "uid=foo.bar,ou=people,o=ls",
<a href="#api-__codelineno-4-4" id="__codelineno-4-4" name="__codelineno-4-4"></a> "type": "LSpeople",
<a href="#api-__codelineno-4-5" id="__codelineno-4-5" name="__codelineno-4-5"></a> "name": "Foo Bar",
<a href="#api-__codelineno-4-6" id="__codelineno-4-6" name="__codelineno-4-6"></a> "success": true,
<a href="#api-__codelineno-4-7" id="__codelineno-4-7" name="__codelineno-4-7"></a> "messages": [
<a href="#api-__codelineno-4-8" id="__codelineno-4-8" name="__codelineno-4-8"></a> "Foo Bar a bien \u00e9t\u00e9 supprim\u00e9."
<a href="#api-__codelineno-4-9" id="__codelineno-4-9" name="__codelineno-4-9"></a> ]
<a href="#api-__codelineno-4-10" id="__codelineno-4-10" name="__codelineno-4-10"></a>}
</code></pre></div>
</li>
</ul>
<ul>
<li>
<p><code>/api/1.0/object/[object type]/[dn]/customAction/[customAction]</code></p>
<p>Cette méthode permet d'exécuter une <a href="#conf-lsobject-customactions">action personnalisée</a> sur
un objet dans l'annuaire. Le nom de l'action ainsi que le type de l'objet et son DN sont précisés
dans l'URL et doivent être encodés en conséquence.</p>
<p><strong>Exemple :</strong></p>
<div class="highlight"><pre><span></span><code><a href="#api-__codelineno-5-1" id="__codelineno-5-1" name="__codelineno-5-1"></a># curl -u username:secret 'https://ldapsaisie/api/1.0/object/LSpeople/uid=foo.bar,ou=people,o=ls/customAction/action?pretty'
<a href="#api-__codelineno-5-2" id="__codelineno-5-2" name="__codelineno-5-2"></a>{
<a href="#api-__codelineno-5-3" id="__codelineno-5-3" name="__codelineno-5-3"></a> "dn": "uid=foo.bar,ou=people,o=ls",
<a href="#api-__codelineno-5-4" id="__codelineno-5-4" name="__codelineno-5-4"></a> "type": "LSpeople",
<a href="#api-__codelineno-5-5" id="__codelineno-5-5" name="__codelineno-5-5"></a> "name": "Foo Bar",
<a href="#api-__codelineno-5-6" id="__codelineno-5-6" name="__codelineno-5-6"></a> "success": true,
<a href="#api-__codelineno-5-7" id="__codelineno-5-7" name="__codelineno-5-7"></a> "messages": [
<a href="#api-__codelineno-5-8" id="__codelineno-5-8" name="__codelineno-5-8"></a> "L'action personnalis\u00e9e action a \u00e9t\u00e9 correctement ex\u00e9cut\u00e9e sur Foo Bar.",
<a href="#api-__codelineno-5-9" id="__codelineno-5-9" name="__codelineno-5-9"></a> ]
<a href="#api-__codelineno-5-10" id="__codelineno-5-10" name="__codelineno-5-10"></a>}
</code></pre></div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Par défaut, une action personnalisée ne retourne qu'un booléen permettant de savoir si
l'action a correctement été exécutée ou non. En outre, dans un contexte d'appel via l'API, il
est possible de retourner des informations via un tableau associatif dont le contenu sera
fusionné avec les données retournées par la requête. Pour plus d'informations à ce sujet,
consultez la <a href="#conf-lsobject-customactions-ecriture-dune-fonction-implementant-une-customaction">documentation sur l'écriture d'une fonction implémentant une customAction</a>.</p>
</div>
</li>
</ul>
<ul>
<li>
<p><code>/api/1.0/object/[object type]/import</code></p>
<p>Cette méthode permet d'importer des objets d'un type en particulier à partir de données d'import
formatées selon un <a href="#conf-lsobject-ioformat-ioformat">ioFormat</a> configuré pour ce type
d'objets. Le type de l'objet est précisé dans l'URL et doit être encodé en conséquence. Par
mimétisme du comportement de l'interface web, cette méthode accepte des paramètres similaires et
s'attend à récupérer les données d'import dans le corps de la requête.</p>
<ul>
<li>
<p><code>ioFormat</code></p>
<p>Le nom de l'<a href="#conf-lsobject-ioformat-ioformat">ioFormat</a>des données d'import.</p>
</li>
</ul>
<ul>
<li>
<p><code>updateIfExists</code></p>
<p>Booléen permettant d'activer/désactiver la mise à jour des données des objets s'ils existent
déjà. Si ce mode est inactif et qu'un objet des données d'import existe déjà, une erreur
sera remontée. Les valeurs acceptées sont <code>1</code> ou <code>0</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>justTry</code></p>
<p>Booléen permettant d'activer/désactiver le mode de vérification des données d'import
uniquement. Si ce mode est actif, les données d'import seront analysées pour vérifier
qu'elles sont correctes, mais l'import en lui-même ne sera pas effectué. Les valeurs
acceptées sont <code>1</code> ou <code>0</code>.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Le retour de cette méthode en mode <code>justTry</code> est identique à une exécution en mode
normal. Ce mode permet donc d'anticiper le résultat d'un import à partir d'un jeu de
données sources.</p>
</div>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>En mode <code>justTry</code>, seul la vérification syntaxique des données est fiable, car les
informations doublonnées au sein des données d'import ne pourront être détectées.</p>
</div>
</li>
</ul>
<p>En cas d'erreurs détectées dans les informations des objets des données d'import, le tableau
<code>errors</code> du retour de la méthode contiendra une entrée pour chaque objet en erreur sous le
format d'un dictionnaire dont la clé <code>data</code> reprendra les informations de l'objet telle que
chargé (ou générée) depuis les données sources, ainsi qu'un dictionnaire sous la clé <code>errors</code>
qui contiendra les erreurs globales concernant l'objet sous la clé <code>globals</code> et les erreurs
propres à ses attributs dans un dictionnaire sous la clé <code>attrs</code>.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Les erreurs d'importation sur un objet sont non-bloquantes : l'importation des autres objets
ne sera pas interrompue.</p>
</div>
<p><strong>Exemple :</strong></p>
<div class="highlight"><pre><span></span><code><a href="#api-__codelineno-6-1" id="__codelineno-6-1" name="__codelineno-6-1"></a># curl -u username:secret --data-binary @/path/to/input.file 'https://ldapsaisie/api/1.0/object/LSpeople/import?ioFormat=mycsv&amp;pretty'
<a href="#api-__codelineno-6-2" id="__codelineno-6-2" name="__codelineno-6-2"></a>{
<a href="#api-__codelineno-6-3" id="__codelineno-6-3" name="__codelineno-6-3"></a> "success": false,
<a href="#api-__codelineno-6-4" id="__codelineno-6-4" name="__codelineno-6-4"></a> "LSobject": "LSpeople",
<a href="#api-__codelineno-6-5" id="__codelineno-6-5" name="__codelineno-6-5"></a> "ioFormat": "mycsv",
<a href="#api-__codelineno-6-6" id="__codelineno-6-6" name="__codelineno-6-6"></a> "updateIfExists": false,
<a href="#api-__codelineno-6-7" id="__codelineno-6-7" name="__codelineno-6-7"></a> "justTry": false,
<a href="#api-__codelineno-6-8" id="__codelineno-6-8" name="__codelineno-6-8"></a> "imported": {
<a href="#api-__codelineno-6-9" id="__codelineno-6-9" name="__codelineno-6-9"></a> "uid=rturin,ou=people,o=ls": "M. Roger TURIN"
<a href="#api-__codelineno-6-10" id="__codelineno-6-10" name="__codelineno-6-10"></a> },
<a href="#api-__codelineno-6-11" id="__codelineno-6-11" name="__codelineno-6-11"></a> "updated": [],
<a href="#api-__codelineno-6-12" id="__codelineno-6-12" name="__codelineno-6-12"></a> "errors": [
<a href="#api-__codelineno-6-13" id="__codelineno-6-13" name="__codelineno-6-13"></a> {
<a href="#api-__codelineno-6-14" id="__codelineno-6-14" name="__codelineno-6-14"></a> "data": {
<a href="#api-__codelineno-6-15" id="__codelineno-6-15" name="__codelineno-6-15"></a> "uid": [
<a href="#api-__codelineno-6-16" id="__codelineno-6-16" name="__codelineno-6-16"></a> "lmartin"
<a href="#api-__codelineno-6-17" id="__codelineno-6-17" name="__codelineno-6-17"></a> ],
<a href="#api-__codelineno-6-18" id="__codelineno-6-18" name="__codelineno-6-18"></a> "personalTitle": [
<a href="#api-__codelineno-6-19" id="__codelineno-6-19" name="__codelineno-6-19"></a> "Mme"
<a href="#api-__codelineno-6-20" id="__codelineno-6-20" name="__codelineno-6-20"></a> ],
<a href="#api-__codelineno-6-21" id="__codelineno-6-21" name="__codelineno-6-21"></a> "givenName": [
<a href="#api-__codelineno-6-22" id="__codelineno-6-22" name="__codelineno-6-22"></a> "Ludivine"
<a href="#api-__codelineno-6-23" id="__codelineno-6-23" name="__codelineno-6-23"></a> ],
<a href="#api-__codelineno-6-24" id="__codelineno-6-24" name="__codelineno-6-24"></a> "sn": [
<a href="#api-__codelineno-6-25" id="__codelineno-6-25" name="__codelineno-6-25"></a> "MARTIN"
<a href="#api-__codelineno-6-26" id="__codelineno-6-26" name="__codelineno-6-26"></a> ],
<a href="#api-__codelineno-6-27" id="__codelineno-6-27" name="__codelineno-6-27"></a> "mail": [
<a href="#api-__codelineno-6-28" id="__codelineno-6-28" name="__codelineno-6-28"></a> "lmartin@gmail.com"
<a href="#api-__codelineno-6-29" id="__codelineno-6-29" name="__codelineno-6-29"></a> ],
<a href="#api-__codelineno-6-30" id="__codelineno-6-30" name="__codelineno-6-30"></a> "userPassword": [
<a href="#api-__codelineno-6-31" id="__codelineno-6-31" name="__codelineno-6-31"></a> "123Yh%uT"
<a href="#api-__codelineno-6-32" id="__codelineno-6-32" name="__codelineno-6-32"></a> ],
<a href="#api-__codelineno-6-33" id="__codelineno-6-33" name="__codelineno-6-33"></a> "gidNumber": [
<a href="#api-__codelineno-6-34" id="__codelineno-6-34" name="__codelineno-6-34"></a> "102009"
<a href="#api-__codelineno-6-35" id="__codelineno-6-35" name="__codelineno-6-35"></a> ],
<a href="#api-__codelineno-6-36" id="__codelineno-6-36" name="__codelineno-6-36"></a> "loginShell": [
<a href="#api-__codelineno-6-37" id="__codelineno-6-37" name="__codelineno-6-37"></a> "no"
<a href="#api-__codelineno-6-38" id="__codelineno-6-38" name="__codelineno-6-38"></a> ],
<a href="#api-__codelineno-6-39" id="__codelineno-6-39" name="__codelineno-6-39"></a> "cn": [
<a href="#api-__codelineno-6-40" id="__codelineno-6-40" name="__codelineno-6-40"></a> "Mme Ludivine MARTIN"
<a href="#api-__codelineno-6-41" id="__codelineno-6-41" name="__codelineno-6-41"></a> ]
<a href="#api-__codelineno-6-42" id="__codelineno-6-42" name="__codelineno-6-42"></a> },
<a href="#api-__codelineno-6-43" id="__codelineno-6-43" name="__codelineno-6-43"></a> "errors": {
<a href="#api-__codelineno-6-44" id="__codelineno-6-44" name="__codelineno-6-44"></a> "globals": [
<a href="#api-__codelineno-6-45" id="__codelineno-6-45" name="__codelineno-6-45"></a> "Un objet existe d\u00e9j\u00e0 dans l'annuaire LDAP avec le DN uid=lmartin,ou=people,o=ls."
<a href="#api-__codelineno-6-46" id="__codelineno-6-46" name="__codelineno-6-46"></a> ],
<a href="#api-__codelineno-6-47" id="__codelineno-6-47" name="__codelineno-6-47"></a> "attrs": []
<a href="#api-__codelineno-6-48" id="__codelineno-6-48" name="__codelineno-6-48"></a> }
<a href="#api-__codelineno-6-49" id="__codelineno-6-49" name="__codelineno-6-49"></a> }
<a href="#api-__codelineno-6-50" id="__codelineno-6-50" name="__codelineno-6-50"></a> ],
<a href="#api-__codelineno-6-51" id="__codelineno-6-51" name="__codelineno-6-51"></a> "messages": [
<a href="#api-__codelineno-6-52" id="__codelineno-6-52" name="__codelineno-6-52"></a> "Le mail de notification a \u00e9t\u00e9 envoy\u00e9."
<a href="#api-__codelineno-6-53" id="__codelineno-6-53" name="__codelineno-6-53"></a> ]
<a href="#api-__codelineno-6-54" id="__codelineno-6-54" name="__codelineno-6-54"></a>}
</code></pre></div>
</li>
</ul>
<ul>
<li>
<p><code>/api/1.0/object/[object type]/export</code></p>
<p>Cette méthode permet d'exporter les objets d'un type en particulier dans un
<a href="#conf-lsobject-ioformat-ioformat">ioFormat</a> configuré pour ce type d'objets. Le type de
l'objet est précisé dans l'URL et doit être encodé en conséquence.</p>
<ul>
<li>
<p><code>ioFormat</code></p>
<p>Le nom de l'<a href="#conf-lsobject-ioformat-ioformat">ioFormat</a> .</p>
</li>
</ul>
<p>En tant normal, le retour de cette méthode sera directement le fichier d'export demandé.
Cependant, si une erreur survient, les paramètres d'export seront repris dans le retour <code>JSON</code>
de la méthode qui contiendra également les erreurs survenues.</p>
<p><strong>Exemple :</strong></p>
<div class="highlight"><pre><span></span><code><a href="#api-__codelineno-7-1" id="__codelineno-7-1" name="__codelineno-7-1"></a># curl -u username:secret --data-binary @/path/to/input.file 'https://ldapsaisie/api/1.0/object/LSpeople/export?ioFormat=mycsv&amp;pretty'
<a href="#api-__codelineno-7-2" id="__codelineno-7-2" name="__codelineno-7-2"></a>login;civility;firstname;name;mail;password;gid;shell
<a href="#api-__codelineno-7-3" id="__codelineno-7-3" name="__codelineno-7-3"></a>hmartin;M.;Henri;MARTIN;henri.martin@ls.com;********;102001;no
<a href="#api-__codelineno-7-4" id="__codelineno-7-4" name="__codelineno-7-4"></a>s.ldapsaisie;M.;Secretariat;LdapSaisie;secretariat@ldapsaisie.biz;********;70000;no
<a href="#api-__codelineno-7-5" id="__codelineno-7-5" name="__codelineno-7-5"></a>ls;M.;Ldap;Saisie;ldap.saisie@ls.com;********;102001;no
<a href="#api-__codelineno-7-6" id="__codelineno-7-6" name="__codelineno-7-6"></a>erwpa;M.;Erwan;PAGEARD;erwan.page@ldapsaisie.biz;********;102009;no
<a href="#api-__codelineno-7-7" id="__codelineno-7-7" name="__codelineno-7-7"></a>[...]
</code></pre></div>
</li>
</ul>
<ul>
<li>
<p><code>/api/1.0/object/[object type]/[dn]/relation/[relation]</code></p>
<p>Cette méthode permet de gérer les objets en relation avec un objet en particulier de l'annuaire.
Le type de l'objet, son DN et le nom de la relation sont précisés dans l'URL et doivent être
encodés en conséquence. Cette méthode accepte les paramètres <code>add</code> et <code>remove</code> permettant de
lister le ou les DN d'objet(s) à respectivement ajouter ou supprimer parmis les objets
actuellement en relation avec l'objet spécifié. Si aucun DN n'est spécifié comme devant être
ajouté ou supprimé, la méthode retournera simplement les DN des objets en relation. En cas de
modification demandée, la méthode retournera la nouvelle liste des DNs des objets en relation,
quel que soit le résultat de l'opération de mise à jour.</p>
<p><strong>Exemple :</strong></p>
<div class="highlight"><pre><span></span><code><a href="#api-__codelineno-8-1" id="__codelineno-8-1" name="__codelineno-8-1"></a># curl -u username:secret 'https://ldapsaisie/api/1.0/object/LSpeople/uid=foo.bar,ou=people,o=ls/relation/groups?pretty&amp;add[]=cn=ls,ou=groups,o=ls&amp;add[]=cn=invite,ou=groups,o=ls'
<a href="#api-__codelineno-8-2" id="__codelineno-8-2" name="__codelineno-8-2"></a>{
<a href="#api-__codelineno-8-3" id="__codelineno-8-3" name="__codelineno-8-3"></a> "dn": "uid=foo.bar,ou=people,o=ls",
<a href="#api-__codelineno-8-4" id="__codelineno-8-4" name="__codelineno-8-4"></a> "type": "LSpeople",
<a href="#api-__codelineno-8-5" id="__codelineno-8-5" name="__codelineno-8-5"></a> "name": "Foo Bar",
<a href="#api-__codelineno-8-6" id="__codelineno-8-6" name="__codelineno-8-6"></a> "relation": "groups",
<a href="#api-__codelineno-8-7" id="__codelineno-8-7" name="__codelineno-8-7"></a> "success": true,
<a href="#api-__codelineno-8-8" id="__codelineno-8-8" name="__codelineno-8-8"></a> "relatedObjects": [
<a href="#api-__codelineno-8-9" id="__codelineno-8-9" name="__codelineno-8-9"></a> "cn=ls,ou=groups,o=ls",
<a href="#api-__codelineno-8-10" id="__codelineno-8-10" name="__codelineno-8-10"></a> "cn=invite,ou=groups,o=ls"
<a href="#api-__codelineno-8-11" id="__codelineno-8-11" name="__codelineno-8-11"></a> ],
<a href="#api-__codelineno-8-12" id="__codelineno-8-12" name="__codelineno-8-12"></a> "messages": [
<a href="#api-__codelineno-8-13" id="__codelineno-8-13" name="__codelineno-8-13"></a> "Objects in relation updated."
<a href="#api-__codelineno-8-14" id="__codelineno-8-14" name="__codelineno-8-14"></a> ]
<a href="#api-__codelineno-8-15" id="__codelineno-8-15" name="__codelineno-8-15"></a>}
</code></pre></div>
</li>
</ul>
<ul>
<li>
<p><code>/api/1.0/search</code></p>
<p>Cette méthode permet d'effectuer une recherche sur plusieurs types d'objets de l'annuaire à la
fois. Par mimétisme du comportement de l'interface web, la recherche est paginée et accepte des
paramètres similaires en plus de paramètre plus appropriés à un fonctionnement programmatique.</p>
<p>Les paramètres acceptés par cette méthode sont sensiblement les mêmes que ceux acceptés par la
méthode de recherche d'un type d'objet de l'annuaire en particulier et ils ne seront donc pas
tous redocumentés ici :</p>
<ul>
<li><code>filter</code></li>
</ul>
<ul>
<li><code>predefinedFilter</code></li>
</ul>
<ul>
<li><code>pattern</code></li>
</ul>
<ul>
<li><code>approx</code></li>
</ul>
<ul>
<li><code>basedn</code></li>
</ul>
<ul>
<li><code>subDn</code></li>
</ul>
<ul>
<li><code>scope</code></li>
</ul>
<ul>
<li><code>recursive</code></li>
</ul>
<ul>
<li><code>displayFormat</code></li>
</ul>
<ul>
<li><code>extraDisplayedColumns</code></li>
</ul>
<ul>
<li><code>attributes</code></li>
</ul>
<ul>
<li><code>attributesDetails</code></li>
</ul>
<ul>
<li><code>page</code></li>
</ul>
<ul>
<li><code>all</code></li>
</ul>
<ul>
<li><code>as_list</code></li>
</ul>
<ul>
<li><code>withoutCache</code></li>
</ul>
<ul>
<li><code>keepParamsBetweenSearches</code></li>
</ul>
<ul>
<li>
<p><code>nbObjectsByPage</code></p>
<p>Permet de préciser le nombre maximum d'objets retournés par type d'objet ET par page du résultat
de recherche.</p>
</li>
</ul>
<ul>
<li>
<p><code>types</code></p>
<p>Permet de limiter les types d'objets à inclure dans le résultat de recherche. Par défaut, tous
les types d'objets auxquels l'utilisateur à accès et dont la recherche globale n'est pas
désactivée seront inclus.</p>
</li>
</ul>
<ul>
<li>
<p><code>splited_result</code></p>
<p>Permet de faire en sorte que les objets inclus dans le résultat de recherche soient séparés par
type dans des sous-clés de <code>objects</code>. Par défaut, tous les objets sont retournés dans la clé
<code>objects</code> et une sous-clé <code>type</code> est ajouté à chacun d'eux pour les distinguer. Seul la présence
de ce paramètre suffit à activer ce comportement, sa valeur n'a pas d'importance.</p>
</li>
</ul>
</li>
</ul>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p><strong>Pour chaque type d'objets inclus dans la recherche, un filtre et/ou un mot clé de recherche
doit être spécifié.</strong> Cette méthode n'a pas vocation à permettre de lister tous les objets de
l'annuaire.</p>
</div>
<p><strong>Exemple :</strong></p>
<div class="highlight"><pre><span></span><code><a href="#api-__codelineno-9-1" id="__codelineno-9-1" name="__codelineno-9-1"></a># curl -u username:secret 'https://ldapsaisie/api/1.0/search?pattern=LdapSaisie&amp;pretty'
<a href="#api-__codelineno-9-2" id="__codelineno-9-2" name="__codelineno-9-2"></a>{
<a href="#api-__codelineno-9-3" id="__codelineno-9-3" name="__codelineno-9-3"></a> "success": true,
<a href="#api-__codelineno-9-4" id="__codelineno-9-4" name="__codelineno-9-4"></a> "objects": {
<a href="#api-__codelineno-9-5" id="__codelineno-9-5" name="__codelineno-9-5"></a> "uid=s.ldapsaisie,ou=people,o=ls": {
<a href="#api-__codelineno-9-6" id="__codelineno-9-6" name="__codelineno-9-6"></a> "name": "Secretariat LdapSaisie",
<a href="#api-__codelineno-9-7" id="__codelineno-9-7" name="__codelineno-9-7"></a> "type": "LSpeople",
<a href="#api-__codelineno-9-8" id="__codelineno-9-8" name="__codelineno-9-8"></a> "Mail": "secretariat@ldapsaisie.biz"
<a href="#api-__codelineno-9-9" id="__codelineno-9-9" name="__codelineno-9-9"></a> },
<a href="#api-__codelineno-9-10" id="__codelineno-9-10" name="__codelineno-9-10"></a> "uid=ls,ou=people,o=ls": {
<a href="#api-__codelineno-9-11" id="__codelineno-9-11" name="__codelineno-9-11"></a> "name": "LdapSaisie",
<a href="#api-__codelineno-9-12" id="__codelineno-9-12" name="__codelineno-9-12"></a> "type": "LSpeople",
<a href="#api-__codelineno-9-13" id="__codelineno-9-13" name="__codelineno-9-13"></a> "Mail": "ldap.saisie@ls.com"
<a href="#api-__codelineno-9-14" id="__codelineno-9-14" name="__codelineno-9-14"></a> },
<a href="#api-__codelineno-9-15" id="__codelineno-9-15" name="__codelineno-9-15"></a> "uid=erwpa,ou=people,o=ls": {
<a href="#api-__codelineno-9-16" id="__codelineno-9-16" name="__codelineno-9-16"></a> "name": "Erwan PAGE",
<a href="#api-__codelineno-9-17" id="__codelineno-9-17" name="__codelineno-9-17"></a> "type": "LSpeople",
<a href="#api-__codelineno-9-18" id="__codelineno-9-18" name="__codelineno-9-18"></a> "Mail": "erwan.page@ldapsaisie.biz"
<a href="#api-__codelineno-9-19" id="__codelineno-9-19" name="__codelineno-9-19"></a> },
<a href="#api-__codelineno-9-20" id="__codelineno-9-20" name="__codelineno-9-20"></a> "uid=invite,ou=people,o=ls": {
<a href="#api-__codelineno-9-21" id="__codelineno-9-21" name="__codelineno-9-21"></a> "name": "Utilisateur de passage",
<a href="#api-__codelineno-9-22" id="__codelineno-9-22" name="__codelineno-9-22"></a> "type": "LSpeople",
<a href="#api-__codelineno-9-23" id="__codelineno-9-23" name="__codelineno-9-23"></a> "Mail": "invite@ldapsaisie.biz"
<a href="#api-__codelineno-9-24" id="__codelineno-9-24" name="__codelineno-9-24"></a> },
<a href="#api-__codelineno-9-25" id="__codelineno-9-25" name="__codelineno-9-25"></a> "uid=demo,ou=people,o=ls": {
<a href="#api-__codelineno-9-26" id="__codelineno-9-26" name="__codelineno-9-26"></a> "name": "Demonstration LdapSaisie",
<a href="#api-__codelineno-9-27" id="__codelineno-9-27" name="__codelineno-9-27"></a> "type": "LSpeople",
<a href="#api-__codelineno-9-28" id="__codelineno-9-28" name="__codelineno-9-28"></a> "Mail": "demo@ls.com"
<a href="#api-__codelineno-9-29" id="__codelineno-9-29" name="__codelineno-9-29"></a> },
<a href="#api-__codelineno-9-30" id="__codelineno-9-30" name="__codelineno-9-30"></a> "uid=admin,ou=people,o=ls": {
<a href="#api-__codelineno-9-31" id="__codelineno-9-31" name="__codelineno-9-31"></a> "name": "Administration LdapSaisie",
<a href="#api-__codelineno-9-32" id="__codelineno-9-32" name="__codelineno-9-32"></a> "type": "LSpeople",
<a href="#api-__codelineno-9-33" id="__codelineno-9-33" name="__codelineno-9-33"></a> "Mail": "admin@ls.com"
<a href="#api-__codelineno-9-34" id="__codelineno-9-34" name="__codelineno-9-34"></a> },
<a href="#api-__codelineno-9-35" id="__codelineno-9-35" name="__codelineno-9-35"></a> "uid=admin3,ou=people,o=ls": {
<a href="#api-__codelineno-9-36" id="__codelineno-9-36" name="__codelineno-9-36"></a> "name": "ZAdministration LdapSaisie",
<a href="#api-__codelineno-9-37" id="__codelineno-9-37" name="__codelineno-9-37"></a> "type": "LSpeople",
<a href="#api-__codelineno-9-38" id="__codelineno-9-38" name="__codelineno-9-38"></a> "Mail": "admin@ls.com"
<a href="#api-__codelineno-9-39" id="__codelineno-9-39" name="__codelineno-9-39"></a> },
<a href="#api-__codelineno-9-40" id="__codelineno-9-40" name="__codelineno-9-40"></a> "uid=ldapsaisie,ou=sysaccounts,o=ls": {
<a href="#api-__codelineno-9-41" id="__codelineno-9-41" name="__codelineno-9-41"></a> "name": "ldapsaisie",
<a href="#api-__codelineno-9-42" id="__codelineno-9-42" name="__codelineno-9-42"></a> "type": "LSsysaccount"
<a href="#api-__codelineno-9-43" id="__codelineno-9-43" name="__codelineno-9-43"></a> }
<a href="#api-__codelineno-9-44" id="__codelineno-9-44" name="__codelineno-9-44"></a> },
<a href="#api-__codelineno-9-45" id="__codelineno-9-45" name="__codelineno-9-45"></a> "total": null,
<a href="#api-__codelineno-9-46" id="__codelineno-9-46" name="__codelineno-9-46"></a> "params": {
<a href="#api-__codelineno-9-47" id="__codelineno-9-47" name="__codelineno-9-47"></a> "keepParamsBetweenSearches": false,
<a href="#api-__codelineno-9-48" id="__codelineno-9-48" name="__codelineno-9-48"></a> "LSpeople": {
<a href="#api-__codelineno-9-49" id="__codelineno-9-49" name="__codelineno-9-49"></a> "filter": null,
<a href="#api-__codelineno-9-50" id="__codelineno-9-50" name="__codelineno-9-50"></a> "pattern": "LdapSaisie",
<a href="#api-__codelineno-9-51" id="__codelineno-9-51" name="__codelineno-9-51"></a> "predefinedFilter": false,
<a href="#api-__codelineno-9-52" id="__codelineno-9-52" name="__codelineno-9-52"></a> "basedn": null,
<a href="#api-__codelineno-9-53" id="__codelineno-9-53" name="__codelineno-9-53"></a> "scope": null,
<a href="#api-__codelineno-9-54" id="__codelineno-9-54" name="__codelineno-9-54"></a> "sizelimit": 0,
<a href="#api-__codelineno-9-55" id="__codelineno-9-55" name="__codelineno-9-55"></a> "attronly": false,
<a href="#api-__codelineno-9-56" id="__codelineno-9-56" name="__codelineno-9-56"></a> "approx": false,
<a href="#api-__codelineno-9-57" id="__codelineno-9-57" name="__codelineno-9-57"></a> "recursive": true,
<a href="#api-__codelineno-9-58" id="__codelineno-9-58" name="__codelineno-9-58"></a> "attributes": [],
<a href="#api-__codelineno-9-59" id="__codelineno-9-59" name="__codelineno-9-59"></a> "onlyAccessible": true,
<a href="#api-__codelineno-9-60" id="__codelineno-9-60" name="__codelineno-9-60"></a> "sortDirection": null,
<a href="#api-__codelineno-9-61" id="__codelineno-9-61" name="__codelineno-9-61"></a> "sortBy": null,
<a href="#api-__codelineno-9-62" id="__codelineno-9-62" name="__codelineno-9-62"></a> "sortlimit": 0,
<a href="#api-__codelineno-9-63" id="__codelineno-9-63" name="__codelineno-9-63"></a> "displayFormat": "%{cn}",
<a href="#api-__codelineno-9-64" id="__codelineno-9-64" name="__codelineno-9-64"></a> "nbObjectsByPage": 25,
<a href="#api-__codelineno-9-65" id="__codelineno-9-65" name="__codelineno-9-65"></a> "withoutCache": false,
<a href="#api-__codelineno-9-66" id="__codelineno-9-66" name="__codelineno-9-66"></a> "extraDisplayedColumns": true
<a href="#api-__codelineno-9-67" id="__codelineno-9-67" name="__codelineno-9-67"></a> },
<a href="#api-__codelineno-9-68" id="__codelineno-9-68" name="__codelineno-9-68"></a> "LSsysaccount": {
<a href="#api-__codelineno-9-69" id="__codelineno-9-69" name="__codelineno-9-69"></a> "filter": null,
<a href="#api-__codelineno-9-70" id="__codelineno-9-70" name="__codelineno-9-70"></a> "pattern": "LdapSaisie",
<a href="#api-__codelineno-9-71" id="__codelineno-9-71" name="__codelineno-9-71"></a> "predefinedFilter": false,
<a href="#api-__codelineno-9-72" id="__codelineno-9-72" name="__codelineno-9-72"></a> "basedn": null,
<a href="#api-__codelineno-9-73" id="__codelineno-9-73" name="__codelineno-9-73"></a> "scope": null,
<a href="#api-__codelineno-9-74" id="__codelineno-9-74" name="__codelineno-9-74"></a> "sizelimit": 0,
<a href="#api-__codelineno-9-75" id="__codelineno-9-75" name="__codelineno-9-75"></a> "attronly": false,
<a href="#api-__codelineno-9-76" id="__codelineno-9-76" name="__codelineno-9-76"></a> "approx": false,
<a href="#api-__codelineno-9-77" id="__codelineno-9-77" name="__codelineno-9-77"></a> "recursive": false,
<a href="#api-__codelineno-9-78" id="__codelineno-9-78" name="__codelineno-9-78"></a> "attributes": [],
<a href="#api-__codelineno-9-79" id="__codelineno-9-79" name="__codelineno-9-79"></a> "onlyAccessible": true,
<a href="#api-__codelineno-9-80" id="__codelineno-9-80" name="__codelineno-9-80"></a> "sortDirection": null,
<a href="#api-__codelineno-9-81" id="__codelineno-9-81" name="__codelineno-9-81"></a> "sortBy": null,
<a href="#api-__codelineno-9-82" id="__codelineno-9-82" name="__codelineno-9-82"></a> "sortlimit": 0,
<a href="#api-__codelineno-9-83" id="__codelineno-9-83" name="__codelineno-9-83"></a> "displayFormat": "%{uid}",
<a href="#api-__codelineno-9-84" id="__codelineno-9-84" name="__codelineno-9-84"></a> "nbObjectsByPage": 30,
<a href="#api-__codelineno-9-85" id="__codelineno-9-85" name="__codelineno-9-85"></a> "withoutCache": false,
<a href="#api-__codelineno-9-86" id="__codelineno-9-86" name="__codelineno-9-86"></a> "extraDisplayedColumns": true
<a href="#api-__codelineno-9-87" id="__codelineno-9-87" name="__codelineno-9-87"></a> }
<a href="#api-__codelineno-9-88" id="__codelineno-9-88" name="__codelineno-9-88"></a> },
<a href="#api-__codelineno-9-89" id="__codelineno-9-89" name="__codelineno-9-89"></a> "page": 1,
<a href="#api-__codelineno-9-90" id="__codelineno-9-90" name="__codelineno-9-90"></a> "nbPages": 1
<a href="#api-__codelineno-9-91" id="__codelineno-9-91" name="__codelineno-9-91"></a>}
</code></pre></div></section><h1 class="nav-section-title">Contribution</h1><section class="print-page" id="contrib"><h1 id="contrib-contribution">Contribution</h1>
<p>Comme tout projet libre qui se respecte, les contributions à LdapSaisie sont les bienvenues. Ce
chapitre explique les possibilités de contribution.</p></section><h2 class="nav-section-title">Les addons (LSaddon)</h2><section class="print-page" id="contrib-addons"><h1 id="contrib-addons-les-addons-lsaddon">Les addons (LSaddon)</h1>
<p>Les <a href="#conf-configuration-des-lsaddons">LSaddons</a> sont utilisés pour implémenter dans LdapSaisie
des fonctionnalités spécifiques tel que :</p>
<ul>
<li>le support d'une famille d'attributs spécifiques (POSIX, Samba, SUPANN…) par le biais de méthodes
de génération de la valeur de ces attributs par exemple (paramètre <code>generate_function</code>) ;</li>
</ul>
<ul>
<li>des tâches communes et génériques (envoi de mails, connexion FTP/SSH…) ;</li>
</ul>
<ul>
<li>l'implémentation de <a href="#conf-declencheurs_1">déclencheurs</a> spécifiques à votre environnement :
création automatique du dossier client sur le serveur de fichiers de l'entreprise, création de la
boite mail de l'utilisateur… ;</li>
</ul>
<ul>
<li>l'implémentation de <a href="#contrib-addons-les-vues-personnalisees">vues personnalisées</a> proposées dans l'interface</li>
</ul>
<ul>
<li>l'implémentation d'action personnalisée sur les <a href="#conf-customactions">objets</a> (synchronisation,
archivage…) ou sur les <a href="#conf-lsobject-lssearch-customactions">résultats de recherches</a>
(export, rapport personnalisé…) ;</li>
</ul>
<h2 id="contrib-addons-structure-decriture">Structure d'écriture</h2>
<p>L'écriture d'un <a href="#conf-configuration-des-lsaddons">LSaddon</a> doit respecter une structure
suffisamment souple afin de ne pas être un frein à vos contributions, tout en permettant d'assurer
la bonne intégration de votre contribution au projet. Le code que vous écrirez sera réparti dans
deux fichiers :</p>
<ul>
<li>
<p><code>conf/LSaddons/config.LSaddons.[addon name].php</code></p>
<p>Ce fichier contiendra la configuration de votre <a href="#conf-configuration-des-lsaddons">LSaddon</a>.
On y retrouvera la déclaration de constances et/ou variables de configuration permettant d'adapter
votre <a href="#conf-configuration-des-lsaddons">LSaddon</a> à une installation et à un environnement.</p>
</li>
</ul>
<ul>
<li>
<p><code>includes/addons/LSaddons.[addon name].php</code></p>
<p>Ce fichier contiendra le code à proprement dit de votre <a href="#conf-configuration-des-lsaddons">LSaddon</a>.</p>
<p><strong>Structure du fichier includes/addons/LSaddons.[addon name].php :</strong></p>
<div class="highlight"><pre><span></span><code><a href="#contrib-addons-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="cp">&lt;?php</span>
<a href="#contrib-addons-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a>
<a href="#contrib-addons-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a><span class="cm">/*</span>
<a href="#contrib-addons-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a><span class="cm"> * Error messages</span>
<a href="#contrib-addons-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a><span class="cm"> */</span>
<a href="#contrib-addons-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a>
<a href="#contrib-addons-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a><span class="c1">// Support error messages</span>
<a href="#contrib-addons-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a><span class="nx">LSerror</span> <span class="o">::</span> <span class="na">defineError</span><span class="p">(</span><span class="s1">'MYADDON_SUPPORT_01'</span><span class="p">,</span>
<a href="#contrib-addons-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a> <span class="nx">___</span><span class="p">(</span><span class="s2">"MYADDON Support : Unable to load %{dep}."</span><span class="p">)</span>
<a href="#contrib-addons-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a><span class="p">);</span>
<a href="#contrib-addons-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a>
<a href="#contrib-addons-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a><span class="nx">LSerror</span> <span class="o">::</span> <span class="na">defineError</span><span class="p">(</span><span class="s1">'MYADDON_SUPPORT_02'</span><span class="p">,</span>
<a href="#contrib-addons-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a> <span class="nx">___</span><span class="p">(</span><span class="s2">"MYADDON Support : The constant %{const} is not defined."</span><span class="p">)</span>
<a href="#contrib-addons-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a><span class="p">);</span>
<a href="#contrib-addons-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a>
<a href="#contrib-addons-__codelineno-0-16" id="__codelineno-0-16" name="__codelineno-0-16"></a><span class="c1">// Other orror messages</span>
<a href="#contrib-addons-__codelineno-0-17" id="__codelineno-0-17" name="__codelineno-0-17"></a><span class="nx">LSerror</span> <span class="o">::</span> <span class="na">defineError</span><span class="p">(</span><span class="s1">'MYADDON_01'</span><span class="p">,</span>
<a href="#contrib-addons-__codelineno-0-18" id="__codelineno-0-18" name="__codelineno-0-18"></a> <span class="nx">___</span><span class="p">(</span><span class="s2">"An error : %{msg}."</span><span class="p">)</span>
<a href="#contrib-addons-__codelineno-0-19" id="__codelineno-0-19" name="__codelineno-0-19"></a><span class="p">);</span>
<a href="#contrib-addons-__codelineno-0-20" id="__codelineno-0-20" name="__codelineno-0-20"></a>
<a href="#contrib-addons-__codelineno-0-21" id="__codelineno-0-21" name="__codelineno-0-21"></a><span class="nx">LSerror</span> <span class="o">::</span> <span class="na">defineError</span><span class="p">(</span><span class="s1">'MYADDON_02'</span><span class="p">,</span>
<a href="#contrib-addons-__codelineno-0-22" id="__codelineno-0-22" name="__codelineno-0-22"></a> <span class="nx">___</span><span class="p">(</span><span class="s2">"An other error about %{about} : %{msg}"</span><span class="p">)</span>
<a href="#contrib-addons-__codelineno-0-23" id="__codelineno-0-23" name="__codelineno-0-23"></a><span class="p">);</span>
<a href="#contrib-addons-__codelineno-0-24" id="__codelineno-0-24" name="__codelineno-0-24"></a>
<a href="#contrib-addons-__codelineno-0-25" id="__codelineno-0-25" name="__codelineno-0-25"></a><span class="nx">LSerror</span> <span class="o">::</span> <span class="na">defineError</span><span class="p">(</span><span class="s1">'MYADDON_03'</span><span class="p">,</span>
<a href="#contrib-addons-__codelineno-0-26" id="__codelineno-0-26" name="__codelineno-0-26"></a> <span class="nx">___</span><span class="p">(</span><span class="s2">"Unknown error."</span><span class="p">)</span>
<a href="#contrib-addons-__codelineno-0-27" id="__codelineno-0-27" name="__codelineno-0-27"></a><span class="p">);</span>
<a href="#contrib-addons-__codelineno-0-28" id="__codelineno-0-28" name="__codelineno-0-28"></a>
<a href="#contrib-addons-__codelineno-0-29" id="__codelineno-0-29" name="__codelineno-0-29"></a><span class="sd">/**</span>
<a href="#contrib-addons-__codelineno-0-30" id="__codelineno-0-30" name="__codelineno-0-30"></a><span class="sd"> * Verify support of my addon by LdapSaisie</span>
<a href="#contrib-addons-__codelineno-0-31" id="__codelineno-0-31" name="__codelineno-0-31"></a><span class="sd"> *</span>
<a href="#contrib-addons-__codelineno-0-32" id="__codelineno-0-32" name="__codelineno-0-32"></a><span class="sd"> * @author My Name &lt;my.email@example.com&gt;</span>
<a href="#contrib-addons-__codelineno-0-33" id="__codelineno-0-33" name="__codelineno-0-33"></a><span class="sd"> *</span>
<a href="#contrib-addons-__codelineno-0-34" id="__codelineno-0-34" name="__codelineno-0-34"></a><span class="sd"> * @return boolean true if my addon is totaly supported, false in other cases</span>
<a href="#contrib-addons-__codelineno-0-35" id="__codelineno-0-35" name="__codelineno-0-35"></a><span class="sd"> **/</span>
<a href="#contrib-addons-__codelineno-0-36" id="__codelineno-0-36" name="__codelineno-0-36"></a><span class="k">function</span> <span class="nf">LSaddon_myaddon_support</span><span class="p">()</span> <span class="p">{</span>
<a href="#contrib-addons-__codelineno-0-37" id="__codelineno-0-37" name="__codelineno-0-37"></a>
<a href="#contrib-addons-__codelineno-0-38" id="__codelineno-0-38" name="__codelineno-0-38"></a> <span class="nv">$retval</span><span class="o">=</span><span class="k">true</span><span class="p">;</span>
<a href="#contrib-addons-__codelineno-0-39" id="__codelineno-0-39" name="__codelineno-0-39"></a>
<a href="#contrib-addons-__codelineno-0-40" id="__codelineno-0-40" name="__codelineno-0-40"></a> <span class="c1">// Check/load dependencies</span>
<a href="#contrib-addons-__codelineno-0-41" id="__codelineno-0-41" name="__codelineno-0-41"></a> <span class="k">if</span> <span class="p">(</span> <span class="o">!</span><span class="nb">class_exists</span><span class="p">(</span><span class="s1">'mylib'</span><span class="p">)</span> <span class="p">)</span> <span class="p">{</span>
<a href="#contrib-addons-__codelineno-0-42" id="__codelineno-0-42" name="__codelineno-0-42"></a> <span class="k">if</span> <span class="p">(</span> <span class="o">!</span><span class="nx">LSsession</span><span class="o">::</span><span class="na">includeFile</span><span class="p">(</span><span class="nx">LS_LIB_DIR</span> <span class="o">.</span> <span class="s1">'class.mylib.php'</span><span class="p">)</span> <span class="p">)</span> <span class="p">{</span>
<a href="#contrib-addons-__codelineno-0-43" id="__codelineno-0-43" name="__codelineno-0-43"></a> <span class="nx">LSerror</span> <span class="o">::</span> <span class="na">addErrorCode</span><span class="p">(</span><span class="s1">'MYADDON_SUPPORT_01'</span><span class="p">,</span> <span class="s1">'mylib'</span><span class="p">);</span>
<a href="#contrib-addons-__codelineno-0-44" id="__codelineno-0-44" name="__codelineno-0-44"></a> <span class="nv">$retval</span><span class="o">=</span><span class="k">false</span><span class="p">;</span>
<a href="#contrib-addons-__codelineno-0-45" id="__codelineno-0-45" name="__codelineno-0-45"></a> <span class="p">}</span>
<a href="#contrib-addons-__codelineno-0-46" id="__codelineno-0-46" name="__codelineno-0-46"></a> <span class="p">}</span>
<a href="#contrib-addons-__codelineno-0-47" id="__codelineno-0-47" name="__codelineno-0-47"></a>
<a href="#contrib-addons-__codelineno-0-48" id="__codelineno-0-48" name="__codelineno-0-48"></a>
<a href="#contrib-addons-__codelineno-0-49" id="__codelineno-0-49" name="__codelineno-0-49"></a> <span class="nv">$MUST_DEFINE_CONST</span><span class="o">=</span> <span class="k">array</span><span class="p">(</span>
<a href="#contrib-addons-__codelineno-0-50" id="__codelineno-0-50" name="__codelineno-0-50"></a> <span class="s1">'LS_MYADDON_CONF_O1'</span><span class="p">,</span>
<a href="#contrib-addons-__codelineno-0-51" id="__codelineno-0-51" name="__codelineno-0-51"></a> <span class="s1">'LS_MYADDON_CONF_O2'</span><span class="p">,</span>
<a href="#contrib-addons-__codelineno-0-52" id="__codelineno-0-52" name="__codelineno-0-52"></a> <span class="o">...</span>
<a href="#contrib-addons-__codelineno-0-53" id="__codelineno-0-53" name="__codelineno-0-53"></a> <span class="p">);</span>
<a href="#contrib-addons-__codelineno-0-54" id="__codelineno-0-54" name="__codelineno-0-54"></a>
<a href="#contrib-addons-__codelineno-0-55" id="__codelineno-0-55" name="__codelineno-0-55"></a> <span class="k">foreach</span><span class="p">(</span><span class="nv">$MUST_DEFINE_CONST</span> <span class="k">as</span> <span class="nv">$const</span><span class="p">)</span> <span class="p">{</span>
<a href="#contrib-addons-__codelineno-0-56" id="__codelineno-0-56" name="__codelineno-0-56"></a> <span class="k">if</span> <span class="p">(</span> <span class="p">(</span><span class="o">!</span><span class="nb">defined</span><span class="p">(</span><span class="nv">$const</span><span class="p">))</span> <span class="o">||</span> <span class="p">(</span><span class="nb">constant</span><span class="p">(</span><span class="nv">$const</span><span class="p">)</span> <span class="o">==</span> <span class="s2">""</span><span class="p">))</span> <span class="p">{</span>
<a href="#contrib-addons-__codelineno-0-57" id="__codelineno-0-57" name="__codelineno-0-57"></a> <span class="nx">LSerror</span> <span class="o">::</span> <span class="na">addErrorCode</span><span class="p">(</span><span class="s1">'MYADDON_SUPPORT_02'</span><span class="p">,</span><span class="nv">$const</span><span class="p">);</span>
<a href="#contrib-addons-__codelineno-0-58" id="__codelineno-0-58" name="__codelineno-0-58"></a> <span class="nv">$retval</span><span class="o">=</span><span class="k">false</span><span class="p">;</span>
<a href="#contrib-addons-__codelineno-0-59" id="__codelineno-0-59" name="__codelineno-0-59"></a> <span class="p">}</span>
<a href="#contrib-addons-__codelineno-0-60" id="__codelineno-0-60" name="__codelineno-0-60"></a> <span class="p">}</span>
<a href="#contrib-addons-__codelineno-0-61" id="__codelineno-0-61" name="__codelineno-0-61"></a>
<a href="#contrib-addons-__codelineno-0-62" id="__codelineno-0-62" name="__codelineno-0-62"></a> <span class="k">if</span> <span class="p">(</span><span class="nv">$retval</span><span class="p">)</span> <span class="p">{</span>
<a href="#contrib-addons-__codelineno-0-63" id="__codelineno-0-63" name="__codelineno-0-63"></a> <span class="c1">// Register LSaddon view using LSsession :: registerLSaddonView()</span>
<a href="#contrib-addons-__codelineno-0-64" id="__codelineno-0-64" name="__codelineno-0-64"></a>
<a href="#contrib-addons-__codelineno-0-65" id="__codelineno-0-65" name="__codelineno-0-65"></a> <span class="k">if</span> <span class="p">(</span><span class="nb">php_sapi_name</span><span class="p">()</span> <span class="o">==</span> <span class="s1">'cli'</span><span class="p">)</span> <span class="p">{</span>
<a href="#contrib-addons-__codelineno-0-66" id="__codelineno-0-66" name="__codelineno-0-66"></a> <span class="c1">// Register LSaddon CLI command using LScli :: add_command()</span>
<a href="#contrib-addons-__codelineno-0-67" id="__codelineno-0-67" name="__codelineno-0-67"></a> <span class="p">}</span>
<a href="#contrib-addons-__codelineno-0-68" id="__codelineno-0-68" name="__codelineno-0-68"></a> <span class="p">}</span>
<a href="#contrib-addons-__codelineno-0-69" id="__codelineno-0-69" name="__codelineno-0-69"></a>
<a href="#contrib-addons-__codelineno-0-70" id="__codelineno-0-70" name="__codelineno-0-70"></a> <span class="k">return</span> <span class="nv">$retval</span><span class="p">;</span>
<a href="#contrib-addons-__codelineno-0-71" id="__codelineno-0-71" name="__codelineno-0-71"></a><span class="p">}</span>
<a href="#contrib-addons-__codelineno-0-72" id="__codelineno-0-72" name="__codelineno-0-72"></a>
<a href="#contrib-addons-__codelineno-0-73" id="__codelineno-0-73" name="__codelineno-0-73"></a><span class="sd">/**</span>
<a href="#contrib-addons-__codelineno-0-74" id="__codelineno-0-74" name="__codelineno-0-74"></a><span class="sd"> * My first function</span>
<a href="#contrib-addons-__codelineno-0-75" id="__codelineno-0-75" name="__codelineno-0-75"></a><span class="sd"> *</span>
<a href="#contrib-addons-__codelineno-0-76" id="__codelineno-0-76" name="__codelineno-0-76"></a><span class="sd"> * Description of this wonderfull function</span>
<a href="#contrib-addons-__codelineno-0-77" id="__codelineno-0-77" name="__codelineno-0-77"></a><span class="sd"> *</span>
<a href="#contrib-addons-__codelineno-0-78" id="__codelineno-0-78" name="__codelineno-0-78"></a><span class="sd"> * @author My Name &lt;my.email@example.com&gt;</span>
<a href="#contrib-addons-__codelineno-0-79" id="__codelineno-0-79" name="__codelineno-0-79"></a><span class="sd"> *</span>
<a href="#contrib-addons-__codelineno-0-80" id="__codelineno-0-80" name="__codelineno-0-80"></a><span class="sd"> * @return [type(s) of returned values (pipe separator)] Description of the return of this function</span>
<a href="#contrib-addons-__codelineno-0-81" id="__codelineno-0-81" name="__codelineno-0-81"></a><span class="sd"> **/</span>
<a href="#contrib-addons-__codelineno-0-82" id="__codelineno-0-82" name="__codelineno-0-82"></a><span class="k">function</span> <span class="nf">myaddon_first_function</span><span class="p">(</span><span class="nv">$arg1</span><span class="p">,</span> <span class="nv">$arg2</span><span class="p">)</span> <span class="p">{</span>
<a href="#contrib-addons-__codelineno-0-83" id="__codelineno-0-83" name="__codelineno-0-83"></a> <span class="c1">// Do some stuff</span>
<a href="#contrib-addons-__codelineno-0-84" id="__codelineno-0-84" name="__codelineno-0-84"></a> <span class="k">if</span> <span class="p">(</span><span class="nx">something</span><span class="p">)</span> <span class="p">{</span>
<a href="#contrib-addons-__codelineno-0-85" id="__codelineno-0-85" name="__codelineno-0-85"></a> <span class="nx">LSerror</span> <span class="o">::</span> <span class="na">addErrorCode</span><span class="p">(</span>
<a href="#contrib-addons-__codelineno-0-86" id="__codelineno-0-86" name="__codelineno-0-86"></a> <span class="s1">'MYADDON_01'</span><span class="p">,</span>
<a href="#contrib-addons-__codelineno-0-87" id="__codelineno-0-87" name="__codelineno-0-87"></a> <span class="s1">'something went wrong'</span> <span class="c1">// Error LSformat unique argument</span>
<a href="#contrib-addons-__codelineno-0-88" id="__codelineno-0-88" name="__codelineno-0-88"></a> <span class="p">);</span>
<a href="#contrib-addons-__codelineno-0-89" id="__codelineno-0-89" name="__codelineno-0-89"></a> <span class="k">return</span> <span class="k">false</span><span class="p">;</span>
<a href="#contrib-addons-__codelineno-0-90" id="__codelineno-0-90" name="__codelineno-0-90"></a> <span class="p">}</span>
<a href="#contrib-addons-__codelineno-0-91" id="__codelineno-0-91" name="__codelineno-0-91"></a>
<a href="#contrib-addons-__codelineno-0-92" id="__codelineno-0-92" name="__codelineno-0-92"></a> <span class="k">if</span> <span class="p">(</span><span class="nx">something</span> <span class="k">else</span><span class="p">)</span> <span class="p">{</span>
<a href="#contrib-addons-__codelineno-0-93" id="__codelineno-0-93" name="__codelineno-0-93"></a> <span class="nx">LSerror</span> <span class="o">::</span> <span class="na">addErrorCode</span><span class="p">(</span>
<a href="#contrib-addons-__codelineno-0-94" id="__codelineno-0-94" name="__codelineno-0-94"></a> <span class="s1">'MYADDON_02'</span><span class="p">,</span>
<a href="#contrib-addons-__codelineno-0-95" id="__codelineno-0-95" name="__codelineno-0-95"></a> <span class="k">array</span><span class="p">(</span> <span class="c1">// Error LSformat arguments</span>
<a href="#contrib-addons-__codelineno-0-96" id="__codelineno-0-96" name="__codelineno-0-96"></a> <span class="s1">'about'</span> <span class="o">=&gt;</span> <span class="s1">'second step'</span><span class="p">,</span>
<a href="#contrib-addons-__codelineno-0-97" id="__codelineno-0-97" name="__codelineno-0-97"></a> <span class="s1">'msg'</span> <span class="o">=&gt;</span> <span class="s1">'something went wrong'</span>
<a href="#contrib-addons-__codelineno-0-98" id="__codelineno-0-98" name="__codelineno-0-98"></a> <span class="p">)</span>
<a href="#contrib-addons-__codelineno-0-99" id="__codelineno-0-99" name="__codelineno-0-99"></a> <span class="p">);</span>
<a href="#contrib-addons-__codelineno-0-100" id="__codelineno-0-100" name="__codelineno-0-100"></a> <span class="k">return</span> <span class="k">false</span><span class="p">;</span>
<a href="#contrib-addons-__codelineno-0-101" id="__codelineno-0-101" name="__codelineno-0-101"></a> <span class="p">}</span>
<a href="#contrib-addons-__codelineno-0-102" id="__codelineno-0-102" name="__codelineno-0-102"></a>
<a href="#contrib-addons-__codelineno-0-103" id="__codelineno-0-103" name="__codelineno-0-103"></a> <span class="k">if</span> <span class="p">(</span><span class="nx">still</span> <span class="nx">something</span> <span class="k">else</span><span class="p">)</span> <span class="p">{</span>
<a href="#contrib-addons-__codelineno-0-104" id="__codelineno-0-104" name="__codelineno-0-104"></a> <span class="nx">LSerror</span> <span class="o">::</span> <span class="na">addErrorCode</span><span class="p">(</span><span class="s1">'MYADDON_03'</span><span class="p">);</span> <span class="c1">// Error without argument</span>
<a href="#contrib-addons-__codelineno-0-105" id="__codelineno-0-105" name="__codelineno-0-105"></a> <span class="k">return</span> <span class="k">false</span><span class="p">;</span>
<a href="#contrib-addons-__codelineno-0-106" id="__codelineno-0-106" name="__codelineno-0-106"></a> <span class="p">}</span>
<a href="#contrib-addons-__codelineno-0-107" id="__codelineno-0-107" name="__codelineno-0-107"></a> <span class="k">return</span> <span class="k">true</span><span class="p">;</span>
<a href="#contrib-addons-__codelineno-0-108" id="__codelineno-0-108" name="__codelineno-0-108"></a><span class="p">}</span>
<a href="#contrib-addons-__codelineno-0-109" id="__codelineno-0-109" name="__codelineno-0-109"></a>
<a href="#contrib-addons-__codelineno-0-110" id="__codelineno-0-110" name="__codelineno-0-110"></a><span class="p">[</span><span class="o">...</span><span class="p">]</span>
<a href="#contrib-addons-__codelineno-0-111" id="__codelineno-0-111" name="__codelineno-0-111"></a>
<a href="#contrib-addons-__codelineno-0-112" id="__codelineno-0-112" name="__codelineno-0-112"></a><span class="c1">// Defined custom CLI commands functions only on CLI context</span>
<a href="#contrib-addons-__codelineno-0-113" id="__codelineno-0-113" name="__codelineno-0-113"></a><span class="k">if</span> <span class="p">(</span><span class="nb">php_sapi_name</span><span class="p">()</span> <span class="o">!=</span> <span class="s1">'cli'</span><span class="p">)</span>
<a href="#contrib-addons-__codelineno-0-114" id="__codelineno-0-114" name="__codelineno-0-114"></a> <span class="k">return</span> <span class="k">true</span><span class="p">;</span> <span class="c1">// Always return true to avoid some warning in log</span>
<a href="#contrib-addons-__codelineno-0-115" id="__codelineno-0-115" name="__codelineno-0-115"></a>
<a href="#contrib-addons-__codelineno-0-116" id="__codelineno-0-116" name="__codelineno-0-116"></a><span class="c1">// Defined functions handling custom CLI commands and optionnaly</span>
<a href="#contrib-addons-__codelineno-0-117" id="__codelineno-0-117" name="__codelineno-0-117"></a><span class="c1">// their arguments autocompleter functions.</span>
</code></pre></div>
</li>
</ul>
<p>Par convention, la structure de ce fichier est toujours à peu près la même:</p>
<ul>
<li>On déclare tout d'abord les messages d'erreurs qui seront potentiellement émis par notre
<a href="#conf-configuration-des-lsaddons">LSaddon</a> en commençant par les messages d'erreurs liés au
support de cet <a href="#conf-configuration-des-lsaddons">LSaddon</a>. On utilise pour cela la méthode
<code>LSerror :: defineError()</code> qui attends en premier argument, l'identifiant du message
d'erreur et en tant que second argument, le
<a href="#conf-global-lsformat-format-parametrable">LSformat</a> du message d'erreur. Par convention,
les identifiants des messages d'erreurs seront en majuscule et préfixés du nom du
<a href="#conf-configuration-des-lsaddons">LSaddon</a>.</li>
</ul>
<ul>
<li>
<p>On déclare ensuite une fonction <code>LSaddon_[myaddon]_support</code> qui sera exécutée lors du chargement
de l'addon et qui permettra de s'assurer du support de celui-ci. Cette fonction devra retourner
<code>True</code> si c'est le cas ou <code>False</code> dans le cas contraire.</p>
<p>Cette fonction s'assura notamment :</p>
<ul>
<li>que les librairies dont l'addon dépends sont bien chargées et fonctionnelles ;</li>
<li>que ses variables et constantes de configuration sont bien définies ;</li>
<li>de déclarer <a href="#contrib-addons-les-vues-personnalisees">les vues personnalisées</a> fournies par cet
<a href="#conf-configuration-des-lsaddons">LSaddon</a> ;</li>
<li>de déclarer <a href="#contrib-addons-les-commandes-cli-personnalisees">les commandes <em>CLI</em> personnalisées</a> fournies par
cet <a href="#conf-configuration-des-lsaddons">LSaddon</a> ;</li>
</ul>
</li>
</ul>
<ul>
<li>On déclare ensuite les fonctions, classes et éléments fournis et manipulés par l'addon.</li>
<li>
<p>Si notre addon offre des <a href="#contrib-addons-les-commandes-cli-personnalisees">commandes <em>CLI</em> personnalisées</a>, les
fonctions les implémentant ne seront définies, dans un souci de performance, que dans un contexte
ou elles seraient potentiellement appelables, c'est à dire dans un contexte d'exécution <code>CLI</code>.
Pour cela, nous utilisons communément la fonction <code>php_sapi_name</code> pour déterminer le contexte
d'exécution et si celui-ci vaut <code>cli</code>, nous stoppons l'exécution du reste du code du fichier via
un <code>return true</code>.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Il est important dans ce contexte de ne jamais retourner autre chose que <code>True</code> pour éviter
tout message d'erreur inutile dans les logs.</p>
</div>
</li>
</ul>
<ul>
<li>On déclare, pour finir, les fonctions implémentant les
<a href="#contrib-addons-les-commandes-cli-personnalisees">commandes <em>CLI</em> personnalisées</a> et leur éventuelle fonction
gérant l'autocomplétion des arguments qu'elles acceptent.</li>
</ul></section><section class="print-page" id="contrib-addons-custom-views"><h1 id="contrib-addons-custom-views-les-vues-personnalisees">Les vues personnalisées</h1>
<p>Les <a href="#conf-configuration-des-lsaddons">LSaddons</a> peuvent fournir des vues personnalisées qui
seront accessibles à tout ou parties des utilisateurs de l'application. Ce filtrage d'accès sera
fait en utilisant les <a href="#conf-global-ldap-lsprofile-profils-dutilisateurs">LSprofiles</a> de
l'utilisateur connecté sur la
<a href="#conf-global-ldap-subdn-sous-niveaux-de-connexion">racine courante de l'annuaire LDAP</a>.</p>
<p>Pour mettre en place une telle vue personnalisée, il est nécessaire de :</p>
<ul>
<li>Déclarer cette vue dans la fonction <code>LSaddon_[addon]_support</code> de l'addon à l'aide de la méthode
<code>LSsession :: registerLSaddonView()</code> ;</li>
</ul>
<ul>
<li>Déclarer la fonction implémentant cette vue. Cette fonction n'acceptera aucun paramètre et ne
retournera rien. Elle devra en outre s'occuper de définir son fichier template et charger les
dépendances de ce dernier (fichiers <em>CSS &amp; JS</em>, variables...).</li>
</ul>
<p>Pour implémenter une telle vue personnalisée, vous pouvez vous inspirer de l'exemple fourni
ci-dessous ou encore des vues fournies par les autres
<a href="#conf-configuration-des-lsaddons">LSaddons</a> (par exemple, l'addon
<a href="#conf-lsaddon-lsaddon_exportsearchresultascsv-lsaddon_exportsearchresultascsv">exportSearchResultAsCSV</a>).</p>
<p><strong>Structure du fichier includes/addons/LSaddons.[addon name].php :</strong></p>
<div class="highlight"><pre><span></span><code><a href="#contrib-addons-custom-views-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="cp">&lt;?php</span>
<a href="#contrib-addons-custom-views-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a><span class="k">function</span> <span class="nf">LSaddon_myaddon_support</span><span class="p">()</span> <span class="p">{</span>
<a href="#contrib-addons-custom-views-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a>
<a href="#contrib-addons-custom-views-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> <span class="nv">$retval</span><span class="o">=</span><span class="k">true</span><span class="p">;</span>
<a href="#contrib-addons-custom-views-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a>
<a href="#contrib-addons-custom-views-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a> <span class="c1">// Some check</span>
<a href="#contrib-addons-custom-views-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a>
<a href="#contrib-addons-custom-views-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a> <span class="k">if</span> <span class="p">(</span><span class="nv">$retval</span><span class="p">)</span> <span class="p">{</span>
<a href="#contrib-addons-custom-views-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a> <span class="nv">$retval</span> <span class="o">=</span> <span class="nx">LSsession</span> <span class="o">::</span> <span class="na">registerLSaddonView</span><span class="p">(</span>
<a href="#contrib-addons-custom-views-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a> <span class="s1">'myaddon'</span><span class="p">,</span> <span class="c1">// addon name</span>
<a href="#contrib-addons-custom-views-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a> <span class="s1">'myaddon_view'</span><span class="p">,</span> <span class="c1">// addon view ID</span>
<a href="#contrib-addons-custom-views-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a> <span class="nx">__</span><span class="p">(</span><span class="s1">'MyAddon view'</span><span class="p">),</span> <span class="c1">// addon view label</span>
<a href="#contrib-addons-custom-views-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a> <span class="s1">'myaddon_view'</span><span class="p">,</span> <span class="c1">// callable (ex: function name) that implement addon view</span>
<a href="#contrib-addons-custom-views-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a> <span class="k">array</span><span class="p">(</span><span class="s1">'user'</span><span class="p">),</span> <span class="c1">// array listing allowed LSprofiles</span>
<a href="#contrib-addons-custom-views-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a> <span class="k">true</span> <span class="c1">// Show/hide this addon view in user menu</span>
<a href="#contrib-addons-custom-views-__codelineno-0-16" id="__codelineno-0-16" name="__codelineno-0-16"></a> <span class="p">);</span>
<a href="#contrib-addons-custom-views-__codelineno-0-17" id="__codelineno-0-17" name="__codelineno-0-17"></a> <span class="p">}</span>
<a href="#contrib-addons-custom-views-__codelineno-0-18" id="__codelineno-0-18" name="__codelineno-0-18"></a>
<a href="#contrib-addons-custom-views-__codelineno-0-19" id="__codelineno-0-19" name="__codelineno-0-19"></a> <span class="k">return</span> <span class="nv">$retval</span><span class="p">;</span>
<a href="#contrib-addons-custom-views-__codelineno-0-20" id="__codelineno-0-20" name="__codelineno-0-20"></a><span class="p">}</span>
<a href="#contrib-addons-custom-views-__codelineno-0-21" id="__codelineno-0-21" name="__codelineno-0-21"></a>
<a href="#contrib-addons-custom-views-__codelineno-0-22" id="__codelineno-0-22" name="__codelineno-0-22"></a><span class="p">[</span><span class="o">...</span><span class="p">]</span>
<a href="#contrib-addons-custom-views-__codelineno-0-23" id="__codelineno-0-23" name="__codelineno-0-23"></a>
<a href="#contrib-addons-custom-views-__codelineno-0-24" id="__codelineno-0-24" name="__codelineno-0-24"></a><span class="sd">/**</span>
<a href="#contrib-addons-custom-views-__codelineno-0-25" id="__codelineno-0-25" name="__codelineno-0-25"></a><span class="sd"> * My addon view handler function</span>
<a href="#contrib-addons-custom-views-__codelineno-0-26" id="__codelineno-0-26" name="__codelineno-0-26"></a><span class="sd"> *</span>
<a href="#contrib-addons-custom-views-__codelineno-0-27" id="__codelineno-0-27" name="__codelineno-0-27"></a><span class="sd"> * Description of this view</span>
<a href="#contrib-addons-custom-views-__codelineno-0-28" id="__codelineno-0-28" name="__codelineno-0-28"></a><span class="sd"> *</span>
<a href="#contrib-addons-custom-views-__codelineno-0-29" id="__codelineno-0-29" name="__codelineno-0-29"></a><span class="sd"> * @author My Name &lt;my.email@example.com&gt;</span>
<a href="#contrib-addons-custom-views-__codelineno-0-30" id="__codelineno-0-30" name="__codelineno-0-30"></a><span class="sd"> *</span>
<a href="#contrib-addons-custom-views-__codelineno-0-31" id="__codelineno-0-31" name="__codelineno-0-31"></a><span class="sd"> * @return void</span>
<a href="#contrib-addons-custom-views-__codelineno-0-32" id="__codelineno-0-32" name="__codelineno-0-32"></a><span class="sd"> **/</span>
<a href="#contrib-addons-custom-views-__codelineno-0-33" id="__codelineno-0-33" name="__codelineno-0-33"></a><span class="k">function</span> <span class="nf">myaddon_view</span><span class="p">()</span> <span class="p">{</span>
<a href="#contrib-addons-custom-views-__codelineno-0-34" id="__codelineno-0-34" name="__codelineno-0-34"></a> <span class="c1">// Do some stuff and set some template variables</span>
<a href="#contrib-addons-custom-views-__codelineno-0-35" id="__codelineno-0-35" name="__codelineno-0-35"></a> <span class="nv">$list</span> <span class="o">=</span> <span class="k">array</span> <span class="p">([</span><span class="o">...</span><span class="p">]);</span>
<a href="#contrib-addons-custom-views-__codelineno-0-36" id="__codelineno-0-36" name="__codelineno-0-36"></a> <span class="nx">LStemplate</span> <span class="o">::</span> <span class="na">assign</span><span class="p">(</span><span class="s1">'list'</span><span class="p">,</span> <span class="nv">$list</span><span class="p">);</span>
<a href="#contrib-addons-custom-views-__codelineno-0-37" id="__codelineno-0-37" name="__codelineno-0-37"></a>
<a href="#contrib-addons-custom-views-__codelineno-0-38" id="__codelineno-0-38" name="__codelineno-0-38"></a> <span class="c1">// Load some CSS &amp; JS files need on this view</span>
<a href="#contrib-addons-custom-views-__codelineno-0-39" id="__codelineno-0-39" name="__codelineno-0-39"></a> <span class="nx">LStemplate</span> <span class="o">::</span> <span class="na">addCssFile</span><span class="p">(</span><span class="s1">'LSaddon_myadon.css'</span><span class="p">);</span>
<a href="#contrib-addons-custom-views-__codelineno-0-40" id="__codelineno-0-40" name="__codelineno-0-40"></a> <span class="nx">LStemplate</span> <span class="o">::</span> <span class="na">addJSscript</span><span class="p">(</span><span class="s1">'LSaddon_myadon.js'</span><span class="p">);</span>
<a href="#contrib-addons-custom-views-__codelineno-0-41" id="__codelineno-0-41" name="__codelineno-0-41"></a>
<a href="#contrib-addons-custom-views-__codelineno-0-42" id="__codelineno-0-42" name="__codelineno-0-42"></a> <span class="c1">// Set template file of the view</span>
<a href="#contrib-addons-custom-views-__codelineno-0-43" id="__codelineno-0-43" name="__codelineno-0-43"></a> <span class="nx">LSsession</span> <span class="o">::</span> <span class="na">setTemplate</span><span class="p">(</span><span class="s1">'LSaddon_myadon_view.tpl'</span><span class="p">);</span>
<a href="#contrib-addons-custom-views-__codelineno-0-44" id="__codelineno-0-44" name="__codelineno-0-44"></a><span class="p">}</span>
</code></pre></div></section><section class="print-page" id="contrib-addons-cli-commands"><h1 id="contrib-addons-cli-commands-les-commandes-cli-personnalisees">Les commandes <em>CLI</em> personnalisées</h1>
<h2 id="contrib-addons-cli-commands-introduction">Introduction</h2>
<p>Les <a href="#conf-configuration-des-lsaddons">LSaddons</a> peuvent fournir des commandes <em>CLI</em>
personnalisées qui seront accessibles via la commande <code>ldapsaisie</code> fournie avec l'application. Cela
peut, par exemple, vous permettre de rendre accessible en ligne de commandes une procédure
implémentée dans le code d'LdapSaisie et vous permettre de mettre en place une tâche planifiée
exécutant cette procédure régulièrement.</p>
<p>Pour mettre en place une telle commande <em>CLI</em> personnalisée, il est nécessaire de :</p>
<ul>
<li>Déclarer cette commande <em>CLI</em> personnalisée dans la fonction <code>LSaddon_[addon]_support</code> de l'addon
à l'aide de la méthode <code>LScli::add_command()</code> ;</li>
</ul>
<ul>
<li>Déclarer la fonction implémentant cette commande <em>CLI</em> personnalisée. Cette fonction acceptera,
en tant qu'unique paramètre, un tableau des arguments reçus lors de l'exécution de la commande et
retournera <code>True</code> ou <code>False</code> en cas de succès/d'erreur d'exécution de la commande. Cette valeur
de retour influencera le code retourné par la commande : <code>0</code> en cas de succès, <code>1</code> en cas
d'erreur.</li>
</ul>
<ul>
<li>Bien que cela ne soit pas obligatoire, il sera également possible de déclarer une fonction
permettant l'autocomplétion des arguments acceptés par la commande. Pour plus d'informations à ce
propos, reportez-vous à la <a href="#contrib-addons-cli-commands-auto-completion">section dédiée</a>.</li>
</ul>
<h2 id="contrib-addons-cli-commands-outils-a-votre-disposition">Outils à votre disposition</h2>
<p>Pour vous aider dans l'écriture de vos méthodes <em>CLI</em>, la classe <code>LScli</code> offre des méthodes
pour les tâches les plus courantes :</p>
<ul>
<li>
<p><code>LScli::usage($error, ...$extra_args)</code></p>
<p>Affichage du message d'aide de votre commande avant arrêt. Un message d'erreur peut également
être spécifié avec d'éventuels arguments supplémentaires pour le composer (via <code>sprintf()</code>). Si un
message d'erreur est fourni, le code de retour de la commande sera <code>1</code> et à défaut, <code>0</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>LScli::need_ldap_con()</code></p>
<p>Permet d'établir la connexion à l'annuaire LDAP (si ce n'est pas déjà fait).</p>
</li>
</ul>
<ul>
<li>
<p><code>LScli::run_external_command($command, $data_stdin=null, $escape_command_args=true, $cwd=null)</code> :</p>
<p>Permet d'exécuter une commande externe et de récupérer un tableau contenant le code de
retour de la commande exécutée, le contenu affiché sur la sortie standard et le contenu
affiché sur la sortie d'erreur.</p>
<p>La commande à exécuter peut être passée sous la forme d'une chaîne de caractères ou d'un
tableau de chaînes de caractères correspondant à la commande et ses arguments. Par défaut,
les caractères spéciaux contenus dans les paramètres passés à la commande seront
"échappés", mais il est possible de désactiver cela via le paramètre <code>$escape_command_args</code>.</p>
<p>Il est possible de fournir des données à passer à la commande via son entrée standard via
le paramètre <code>$data_stdin</code>.</p>
<p>Enfin, il est possible de spécifier l'emplacement du dossier courant d'exécution de la
commande via le paramètre <code>$cwd</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>LScli::confirm($question=null)</code></p>
<p>Permet de demander à l'utilisateur de confirmer quelque chose. La question à poser peut être
passée en paramètre et cette méthode retournera <code>true</code> ou <code>false</code> en fonction du choix de
l'utilisateur.</p>
</li>
</ul>
<ul>
<li>
<p><code>LScli::parse_arg_value($value, $custom_values=null)</code></p>
<p>Permet d'interpréter la valeur d'un argument fourni par l'utilisateur. Celui-ci pourra spécifier
le type de l'argument en préfixant l'argument de son type entre crochets (exemple : <code>[bool]1</code>,
types supportés : <code>string</code>, <code>str</code>, <code>bool</code>, <code>boolean</code>, <code>int</code>, <code>integer</code>, <code>float</code>, <code>array</code>) et à
défaut, la valeur sera analysée comme une valeur JSON permettant de passer des paramètres
complexes à vos méthodes (un tableau associatif arborescent par exemple).</p>
<p>Des valeurs particulières seront également analysées de manières prédéfinies si elles ne
sont pas préfixées d'un type particulier. C'est le cas par défaut des chaînes de
caractères <code>true</code> et <code>false</code> qui seront comprises comme des booléens et <code>null</code> qui sera
compris comme la valeur <code>NULL</code> au sens PHP.</p>
<p>Vous pouvez également spécifier vos propres valeurs particulières via l'argument
<code>$custom_values</code> sous la forme d'un tableau associatif dont les clés sont les valeurs
particulières fournies par l'utilisateur et la valeur correspondante, la valeur au sens
<em>PHP</em>.</p>
<p><strong>Important :</strong> l'analyse des valeurs particulières sera faite en mettant
<strong>en minuscule</strong> la valeur fournie par l'utilisateur. Il est donc important que vos
valeurs particulières spécifiées via l'argument <code>$custom_values</code> soient toutes en
minuscule.</p>
</li>
</ul>
<h2 id="contrib-addons-cli-commands-auto-completion">Auto-complétion</h2>
<p>Lors de la déclaration de votre commande CLI personnalisée à l'aide de la méthode
<code>LScli::add_command()</code>, vous avez la possibilité de spécifier une fonction permettant
l'autocomplétion des arguments acceptés par celle-ci.</p>
<p>Cette fonction recevra en paramètre :</p>
<ul>
<li>
<p><code>$command_args</code></p>
<p>Un tableau des arguments déjà reçus par la commande.</p>
</li>
</ul>
<ul>
<li>
<p><code>$comp_word_num</code></p>
<p>Un entier indiquant le rang de l'argument que l'autocomplétion tente de compléter. Il peut
s'agir du rang d'un paramètre déjà fourni et présent dans le tableau <code>$command_args</code> ou bien
d'un rang supérieur aux nombres d'arguments déjà fournis à la commande et dans ce cas il s'agira
d'autocompléter tous potentiels autres arguments que pourrait accepter cette commande.</p>
</li>
</ul>
<ul>
<li>
<p><code>$comp_word</code></p>
<p>Une chaîne de caractères correspondant à ce qu'a déjà saisi l'utilisateur de l'argument que l'on
tente d'autocompléter. Cette chaîne de caractères peut être vide ou non, en fonction de s'il
s'agit d'un nouvel argument à autocompléter ou non.</p>
</li>
</ul>
<ul>
<li>
<p><code>$opts</code></p>
<p>Un tableau des potentiels arguments globaux acceptés par <em>LScli</em> dans le contexte actuel (par
exemple, <code>-d</code> ou <code>--debug</code> pour l'activation du mode debug). La réponse de cette fonction devra
inclure ces potentiels arguments si le contexte d'autocomplétion s'y prête (nouvel argument par
exemple).</p>
</li>
</ul>
<p>Pour finir, cette fonction devra retourner un tableau des potentielles valeurs que pourrait
prendre l'argument autocomplété. Si une unique proposition est faite à l'utilisateur, celle-ci
sera automatiquement proposée à l'utilisateur et à défaut, la liste des valeurs possibles lui
seront affichées.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Pour vous aider dans l'écriture d'une telle méthode d'autocomplétion, des méthodes statiques
sont fournies par la classe <code>LScli</code> pour les autocomplétions les plus courantes :</p>
<ul>
<li><code>LScli::autocomplete_class_name()</code> : Autocomplétion du nom d'une classe PHP.</li>
</ul>
<ul>
<li><code>LScli::autocomplete_addon_name()</code> : Autocomplétion du nom d'un
<a href="#conf-configuration-des-lsaddons">LSaddon</a>.</li>
</ul>
<ul>
<li><code>LScli::autocomplete_int()</code> : Autocomplétion d'un nombre entier.</li>
</ul>
<ul>
<li><code>LScli::autocomplete_LSobject_types()</code> : Autocomplétion du nom d'un type
d'<a href="#conf-configuration-lsobject">LSobject</a>.</li>
</ul>
<ul>
<li><code>LScli::autocomplete_LSobject_dn()</code> : Autocomplétion du DN d'un type précis
d'<a href="#conf-configuration-lsobject">LSobject</a> de l'annuaire.</li>
</ul>
<ul>
<li><code>LScli::autocomplete_LSobject_attr_name()</code> : Autocomplétion du nom d'un attribut précis
pour un type d'<a href="#conf-configuration-lsobject">LSobject</a> de l'annuaire.</li>
</ul>
<ul>
<li><code>LScli::autocomplete_LSobject_ioFormat()</code> : Autocomplétion du nom d'un
<a href="#conf-lsobject-ioformat-ioformat">ioFormat</a> pour un type
d'<a href="#conf-configuration-lsobject">LSobject</a> de l'annuaire.</li>
</ul>
<ul>
<li><code>LScli::autocomplete_LSform_name()</code> : Autocomplétion du nom d'un formulaire de
l'application.</li>
</ul>
<p>Par ailleurs, la méthode <code>LScli::autocomplete_opts()</code> vous facilitera la construction de la
liste des valeurs d'autocomplétion de l'argument courant en fonction de ce qui a déjà été
saisi par l'utilisateur (paramètre <code>$comp_word</code>). Cette méthode s'occupera en l'occurrence de
filtrer parmi toutes les valeurs contextuelles possibles, celles qui correspondent au préfixe
fourni par l'utilisateur.</p>
</div>
<h2 id="contrib-addons-cli-commands-exemple-dimplementation">Exemple d'implémentation</h2>
<p>Pour implémenter une telle commande <em>CLI</em> personnalisée, vous pouvez vous inspirer de l'exemple
fourni ci-dessous ou encore des commandes <em>CLI</em> fournies par les autres
<a href="#conf-configuration-des-lsaddons">LSaddons</a> ou classes PHP de l'application.</p>
<p><strong>Structure du fichier includes/addons/LSaddons.[addon name].php :</strong></p>
<div class="highlight"><pre><span></span><code><a href="#contrib-addons-cli-commands-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="cp">&lt;?php</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a><span class="k">function</span> <span class="nf">LSaddon_myaddon_support</span><span class="p">()</span> <span class="p">{</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a>
<a href="#contrib-addons-cli-commands-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> <span class="nv">$retval</span><span class="o">=</span><span class="k">true</span><span class="p">;</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a>
<a href="#contrib-addons-cli-commands-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a> <span class="c1"># Some other checks need to verify your addon support</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a>
<a href="#contrib-addons-cli-commands-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a> <span class="k">if</span> <span class="p">(</span><span class="nv">$retval</span><span class="p">)</span> <span class="p">{</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a> <span class="k">if</span> <span class="p">(</span><span class="nb">php_sapi_name</span><span class="p">()</span> <span class="o">==</span> <span class="s1">'cli'</span><span class="p">)</span> <span class="p">{</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a> <span class="nx">LScli</span><span class="o">::</span><span class="na">add_command</span><span class="p">(</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a> <span class="c1"># The CLI command name (required)</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a> <span class="s1">'my_custom_cli_cmd'</span><span class="p">,</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a> <span class="c1"># The CLI command handler (must be callable, required)</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a> <span class="s1">'cli_my_custom_cli_cmd'</span><span class="p">,</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a> <span class="c1"># A short description of what this command does (required)</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-16" id="__codelineno-0-16" name="__codelineno-0-16"></a> <span class="s1">'My custom CLI command'</span><span class="p">,</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-17" id="__codelineno-0-17" name="__codelineno-0-17"></a> <span class="c1"># A short list of commands available arguments show in usage message</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-18" id="__codelineno-0-18" name="__codelineno-0-18"></a> <span class="c1"># (optional, default: false)</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-19" id="__codelineno-0-19" name="__codelineno-0-19"></a> <span class="s1">'[arg1] [arg2] [...]'</span><span class="p">,</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-20" id="__codelineno-0-20" name="__codelineno-0-20"></a> <span class="c1"># A long description of what this command does</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-21" id="__codelineno-0-21" name="__codelineno-0-21"></a> <span class="c1"># (optional, default: false)</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-22" id="__codelineno-0-22" name="__codelineno-0-22"></a> <span class="s1">'This command permit to ...'</span><span class="p">,</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-23" id="__codelineno-0-23" name="__codelineno-0-23"></a> <span class="c1"># Permit to define if this command need connection to LDAP server</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-24" id="__codelineno-0-24" name="__codelineno-0-24"></a> <span class="c1"># (optional, default: true)</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-25" id="__codelineno-0-25" name="__codelineno-0-25"></a> <span class="k">true</span><span class="p">,</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-26" id="__codelineno-0-26" name="__codelineno-0-26"></a> <span class="c1"># Callable of the CLI command arguments autocompleter</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-27" id="__codelineno-0-27" name="__codelineno-0-27"></a> <span class="c1"># (optional, default: null)</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-28" id="__codelineno-0-28" name="__codelineno-0-28"></a> <span class="s1">'cli_my_custom_cli_cmd_autocompleter'</span><span class="p">,</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-29" id="__codelineno-0-29" name="__codelineno-0-29"></a> <span class="c1"># Allow override if a command already exists with the same name</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-30" id="__codelineno-0-30" name="__codelineno-0-30"></a> <span class="c1"># (optional, default: null)</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-31" id="__codelineno-0-31" name="__codelineno-0-31"></a> <span class="k">true</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-32" id="__codelineno-0-32" name="__codelineno-0-32"></a> <span class="p">);</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-33" id="__codelineno-0-33" name="__codelineno-0-33"></a> <span class="p">}</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-34" id="__codelineno-0-34" name="__codelineno-0-34"></a> <span class="p">}</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-35" id="__codelineno-0-35" name="__codelineno-0-35"></a>
<a href="#contrib-addons-cli-commands-__codelineno-0-36" id="__codelineno-0-36" name="__codelineno-0-36"></a> <span class="k">return</span> <span class="nv">$retval</span><span class="p">;</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-37" id="__codelineno-0-37" name="__codelineno-0-37"></a><span class="p">}</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-38" id="__codelineno-0-38" name="__codelineno-0-38"></a>
<a href="#contrib-addons-cli-commands-__codelineno-0-39" id="__codelineno-0-39" name="__codelineno-0-39"></a><span class="p">[</span><span class="o">...</span><span class="p">]</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-40" id="__codelineno-0-40" name="__codelineno-0-40"></a>
<a href="#contrib-addons-cli-commands-__codelineno-0-41" id="__codelineno-0-41" name="__codelineno-0-41"></a><span class="c1">// Defined CLI commands functions only on CLI context</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-42" id="__codelineno-0-42" name="__codelineno-0-42"></a><span class="k">if</span> <span class="p">(</span><span class="nb">php_sapi_name</span><span class="p">()</span> <span class="o">!=</span> <span class="s1">'cli'</span><span class="p">)</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-43" id="__codelineno-0-43" name="__codelineno-0-43"></a> <span class="k">return</span> <span class="k">true</span><span class="p">;</span> <span class="c1">// Always return true to avoid some warning in log</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-44" id="__codelineno-0-44" name="__codelineno-0-44"></a>
<a href="#contrib-addons-cli-commands-__codelineno-0-45" id="__codelineno-0-45" name="__codelineno-0-45"></a><span class="sd">/**</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-46" id="__codelineno-0-46" name="__codelineno-0-46"></a><span class="sd"> * My addon CLI command my_custom_cli_cmd handler function</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-47" id="__codelineno-0-47" name="__codelineno-0-47"></a><span class="sd"> *</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-48" id="__codelineno-0-48" name="__codelineno-0-48"></a><span class="sd"> * Description of this CLI command.</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-49" id="__codelineno-0-49" name="__codelineno-0-49"></a><span class="sd"> *</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-50" id="__codelineno-0-50" name="__codelineno-0-50"></a><span class="sd"> * @param array $command_args Command arguments</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-51" id="__codelineno-0-51" name="__codelineno-0-51"></a><span class="sd"> * - Positional arguments :</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-52" id="__codelineno-0-52" name="__codelineno-0-52"></a><span class="sd"> * - LSobject</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-53" id="__codelineno-0-53" name="__codelineno-0-53"></a><span class="sd"> * - dn</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-54" id="__codelineno-0-54" name="__codelineno-0-54"></a><span class="sd"> * - Optional arguments :</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-55" id="__codelineno-0-55" name="__codelineno-0-55"></a><span class="sd"> * - -f|--force : Force mode</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-56" id="__codelineno-0-56" name="__codelineno-0-56"></a><span class="sd"> *</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-57" id="__codelineno-0-57" name="__codelineno-0-57"></a><span class="sd"> * @author My Name &lt;my.email@example.com&gt;</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-58" id="__codelineno-0-58" name="__codelineno-0-58"></a><span class="sd"> *</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-59" id="__codelineno-0-59" name="__codelineno-0-59"></a><span class="sd"> * @return boolean True on success, false otherwise</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-60" id="__codelineno-0-60" name="__codelineno-0-60"></a><span class="sd"> **/</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-61" id="__codelineno-0-61" name="__codelineno-0-61"></a><span class="k">function</span> <span class="nf">cli_my_custom_cli_cmd</span><span class="p">(</span><span class="nv">$command_args</span><span class="p">)</span> <span class="p">{</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-62" id="__codelineno-0-62" name="__codelineno-0-62"></a> <span class="nv">$objType</span> <span class="o">=</span> <span class="k">null</span><span class="p">;</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-63" id="__codelineno-0-63" name="__codelineno-0-63"></a> <span class="nv">$dn</span> <span class="o">=</span> <span class="k">null</span><span class="p">;</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-64" id="__codelineno-0-64" name="__codelineno-0-64"></a> <span class="nv">$force_mode</span> <span class="o">=</span> <span class="k">false</span><span class="p">;</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-65" id="__codelineno-0-65" name="__codelineno-0-65"></a> <span class="k">foreach</span> <span class="p">(</span><span class="nv">$command_args</span> <span class="k">as</span> <span class="nv">$arg</span><span class="p">)</span> <span class="p">{</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-66" id="__codelineno-0-66" name="__codelineno-0-66"></a> <span class="k">if</span> <span class="p">(</span><span class="nv">$arg</span> <span class="o">==</span> <span class="s1">'-f'</span> <span class="o">||</span> <span class="nv">$arg</span> <span class="o">==</span> <span class="s1">'--force'</span><span class="p">)</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-67" id="__codelineno-0-67" name="__codelineno-0-67"></a> <span class="nv">$force_mode</span> <span class="o">=</span> <span class="k">true</span><span class="p">;</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-68" id="__codelineno-0-68" name="__codelineno-0-68"></a> <span class="k">elseif</span> <span class="p">(</span><span class="nb">is_null</span><span class="p">(</span><span class="nv">$objType</span><span class="p">))</span> <span class="p">{</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-69" id="__codelineno-0-69" name="__codelineno-0-69"></a> <span class="nv">$objType</span> <span class="o">=</span> <span class="nv">$arg</span><span class="p">;</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-70" id="__codelineno-0-70" name="__codelineno-0-70"></a> <span class="p">}</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-71" id="__codelineno-0-71" name="__codelineno-0-71"></a> <span class="k">elseif</span> <span class="p">(</span><span class="nb">is_null</span><span class="p">(</span><span class="nv">$dn</span><span class="p">))</span> <span class="p">{</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-72" id="__codelineno-0-72" name="__codelineno-0-72"></a> <span class="nv">$dn</span> <span class="o">=</span> <span class="nv">$arg</span><span class="p">;</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-73" id="__codelineno-0-73" name="__codelineno-0-73"></a> <span class="p">}</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-74" id="__codelineno-0-74" name="__codelineno-0-74"></a> <span class="k">else</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-75" id="__codelineno-0-75" name="__codelineno-0-75"></a> <span class="nx">LScli</span><span class="o">::</span><span class="na">usage</span><span class="p">(</span><span class="s2">"Invalid </span><span class="si">$arg</span><span class="s2"> parameter."</span><span class="p">);</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-76" id="__codelineno-0-76" name="__codelineno-0-76"></a> <span class="p">}</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-77" id="__codelineno-0-77" name="__codelineno-0-77"></a>
<a href="#contrib-addons-cli-commands-__codelineno-0-78" id="__codelineno-0-78" name="__codelineno-0-78"></a> <span class="k">if</span> <span class="p">(</span><span class="nb">is_null</span><span class="p">(</span><span class="nv">$objType</span><span class="p">)</span> <span class="o">||</span> <span class="nb">is_null</span><span class="p">(</span><span class="nv">$dn</span><span class="p">))</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-79" id="__codelineno-0-79" name="__codelineno-0-79"></a> <span class="nx">LScli</span><span class="o">::</span><span class="na">usage</span><span class="p">(</span><span class="s1">'You must provide LSobject type and DN.'</span><span class="p">);</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-80" id="__codelineno-0-80" name="__codelineno-0-80"></a>
<a href="#contrib-addons-cli-commands-__codelineno-0-81" id="__codelineno-0-81" name="__codelineno-0-81"></a> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">LSsession</span><span class="o">::</span><span class="na">loadLSobject</span><span class="p">(</span><span class="nv">$objType</span><span class="p">))</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-82" id="__codelineno-0-82" name="__codelineno-0-82"></a> <span class="k">return</span> <span class="k">false</span><span class="p">;</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-83" id="__codelineno-0-83" name="__codelineno-0-83"></a>
<a href="#contrib-addons-cli-commands-__codelineno-0-84" id="__codelineno-0-84" name="__codelineno-0-84"></a> <span class="nv">$obj</span> <span class="o">=</span> <span class="k">new</span> <span class="nv">$objType</span><span class="p">();</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-85" id="__codelineno-0-85" name="__codelineno-0-85"></a> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nv">$obj</span><span class="o">-&gt;</span><span class="na">loadData</span><span class="p">(</span><span class="nv">$dn</span><span class="p">))</span> <span class="p">{</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-86" id="__codelineno-0-86" name="__codelineno-0-86"></a> <span class="nx">self</span><span class="o">::</span><span class="na">log_fatal</span><span class="p">(</span><span class="s2">"Fail to load object </span><span class="si">$dn</span><span class="s2"> data from LDAP"</span><span class="p">);</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-87" id="__codelineno-0-87" name="__codelineno-0-87"></a> <span class="k">return</span> <span class="k">false</span><span class="p">;</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-88" id="__codelineno-0-88" name="__codelineno-0-88"></a> <span class="p">}</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-89" id="__codelineno-0-89" name="__codelineno-0-89"></a>
<a href="#contrib-addons-cli-commands-__codelineno-0-90" id="__codelineno-0-90" name="__codelineno-0-90"></a> <span class="c1">// Do some stuff on loaded object</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-91" id="__codelineno-0-91" name="__codelineno-0-91"></a> <span class="p">[</span><span class="o">...</span><span class="p">]</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-92" id="__codelineno-0-92" name="__codelineno-0-92"></a>
<a href="#contrib-addons-cli-commands-__codelineno-0-93" id="__codelineno-0-93" name="__codelineno-0-93"></a> <span class="k">return</span> <span class="k">true</span><span class="p">;</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-94" id="__codelineno-0-94" name="__codelineno-0-94"></a><span class="p">}</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-95" id="__codelineno-0-95" name="__codelineno-0-95"></a>
<a href="#contrib-addons-cli-commands-__codelineno-0-96" id="__codelineno-0-96" name="__codelineno-0-96"></a><span class="sd">/**</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-97" id="__codelineno-0-97" name="__codelineno-0-97"></a><span class="sd"> * Args autocompleter for CLI my_custom_cli_cmd command</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-98" id="__codelineno-0-98" name="__codelineno-0-98"></a><span class="sd"> *</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-99" id="__codelineno-0-99" name="__codelineno-0-99"></a><span class="sd"> * @param array&lt;string&gt; $command_args List of already typed words of the command</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-100" id="__codelineno-0-100" name="__codelineno-0-100"></a><span class="sd"> * @param int $comp_word_num The command word number to autocomplete</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-101" id="__codelineno-0-101" name="__codelineno-0-101"></a><span class="sd"> * @param string $comp_word The command word to autocomplete</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-102" id="__codelineno-0-102" name="__codelineno-0-102"></a><span class="sd"> * @param array&lt;string&gt; $opts List of global available options</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-103" id="__codelineno-0-103" name="__codelineno-0-103"></a><span class="sd"> *</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-104" id="__codelineno-0-104" name="__codelineno-0-104"></a><span class="sd"> * @return array&lt;string&gt; List of available options for the word to autocomplete</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-105" id="__codelineno-0-105" name="__codelineno-0-105"></a><span class="sd"> **/</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-106" id="__codelineno-0-106" name="__codelineno-0-106"></a><span class="k">public</span> <span class="k">static</span> <span class="k">function</span> <span class="nf">cli_my_custom_cli_cmd_autocompleter</span><span class="p">(</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-107" id="__codelineno-0-107" name="__codelineno-0-107"></a> <span class="nv">$command_args</span><span class="p">,</span> <span class="nv">$comp_word_num</span><span class="p">,</span> <span class="nv">$comp_word</span><span class="p">,</span> <span class="nv">$opts</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-108" id="__codelineno-0-108" name="__codelineno-0-108"></a><span class="p">)</span> <span class="p">{</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-109" id="__codelineno-0-109" name="__codelineno-0-109"></a> <span class="nv">$opts</span> <span class="o">=</span> <span class="nb">array_merge</span><span class="p">(</span><span class="nv">$opts</span><span class="p">,</span> <span class="k">array</span> <span class="p">(</span><span class="s1">'-f'</span><span class="p">,</span> <span class="s1">'--force'</span><span class="p">));</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-110" id="__codelineno-0-110" name="__codelineno-0-110"></a>
<a href="#contrib-addons-cli-commands-__codelineno-0-111" id="__codelineno-0-111" name="__codelineno-0-111"></a> <span class="c1">// Handle positional args</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-112" id="__codelineno-0-112" name="__codelineno-0-112"></a> <span class="nv">$objType</span> <span class="o">=</span> <span class="k">null</span><span class="p">;</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-113" id="__codelineno-0-113" name="__codelineno-0-113"></a> <span class="nv">$objType_arg_num</span> <span class="o">=</span> <span class="k">null</span><span class="p">;</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-114" id="__codelineno-0-114" name="__codelineno-0-114"></a> <span class="nv">$dn</span> <span class="o">=</span> <span class="k">null</span><span class="p">;</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-115" id="__codelineno-0-115" name="__codelineno-0-115"></a> <span class="nv">$dn_arg_num</span> <span class="o">=</span> <span class="k">null</span><span class="p">;</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-116" id="__codelineno-0-116" name="__codelineno-0-116"></a> <span class="k">for</span> <span class="p">(</span><span class="nv">$i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="nv">$i</span> <span class="o">&lt;</span> <span class="nb">count</span><span class="p">(</span><span class="nv">$command_args</span><span class="p">);</span> <span class="nv">$i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-117" id="__codelineno-0-117" name="__codelineno-0-117"></a> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nb">in_array</span><span class="p">(</span><span class="nv">$command_args</span><span class="p">[</span><span class="nv">$i</span><span class="p">],</span> <span class="nv">$opts</span><span class="p">))</span> <span class="p">{</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-118" id="__codelineno-0-118" name="__codelineno-0-118"></a> <span class="c1">// If object type not defined</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-119" id="__codelineno-0-119" name="__codelineno-0-119"></a> <span class="k">if</span> <span class="p">(</span><span class="nb">is_null</span><span class="p">(</span><span class="nv">$objType</span><span class="p">))</span> <span class="p">{</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-120" id="__codelineno-0-120" name="__codelineno-0-120"></a> <span class="c1">// Defined it</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-121" id="__codelineno-0-121" name="__codelineno-0-121"></a> <span class="nv">$objType</span> <span class="o">=</span> <span class="nv">$command_args</span><span class="p">[</span><span class="nv">$i</span><span class="p">];</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-122" id="__codelineno-0-122" name="__codelineno-0-122"></a> <span class="nx">LScli</span><span class="o">::</span><span class="na">unquote_word</span><span class="p">(</span><span class="nv">$objType</span><span class="p">);</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-123" id="__codelineno-0-123" name="__codelineno-0-123"></a> <span class="nv">$objType_arg_num</span> <span class="o">=</span> <span class="nv">$i</span><span class="p">;</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-124" id="__codelineno-0-124" name="__codelineno-0-124"></a>
<a href="#contrib-addons-cli-commands-__codelineno-0-125" id="__codelineno-0-125" name="__codelineno-0-125"></a> <span class="c1">// Check object type exists</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-126" id="__codelineno-0-126" name="__codelineno-0-126"></a> <span class="nv">$objTypes</span> <span class="o">=</span> <span class="nx">LScli</span><span class="o">::</span><span class="na">autocomplete_LSobject_types</span><span class="p">(</span><span class="nv">$objType</span><span class="p">);</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-127" id="__codelineno-0-127" name="__codelineno-0-127"></a>
<a href="#contrib-addons-cli-commands-__codelineno-0-128" id="__codelineno-0-128" name="__codelineno-0-128"></a> <span class="c1">// Load it if exist and not trying to complete it</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-129" id="__codelineno-0-129" name="__codelineno-0-129"></a> <span class="k">if</span> <span class="p">(</span><span class="nb">in_array</span><span class="p">(</span><span class="nv">$objType</span><span class="p">,</span> <span class="nv">$objTypes</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="nv">$i</span> <span class="o">!=</span> <span class="nv">$comp_word_num</span><span class="p">)</span> <span class="p">{</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-130" id="__codelineno-0-130" name="__codelineno-0-130"></a> <span class="nx">LSsession</span><span class="o">::</span><span class="na">loadLSobject</span><span class="p">(</span><span class="nv">$objType</span><span class="p">,</span> <span class="k">false</span><span class="p">);</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-131" id="__codelineno-0-131" name="__codelineno-0-131"></a> <span class="p">}</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-132" id="__codelineno-0-132" name="__codelineno-0-132"></a> <span class="p">}</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-133" id="__codelineno-0-133" name="__codelineno-0-133"></a> <span class="k">elseif</span> <span class="p">(</span><span class="nb">is_null</span><span class="p">(</span><span class="nv">$dn</span><span class="p">))</span> <span class="p">{</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-134" id="__codelineno-0-134" name="__codelineno-0-134"></a> <span class="nv">$dn</span> <span class="o">=</span> <span class="nv">$command_args</span><span class="p">[</span><span class="nv">$i</span><span class="p">];</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-135" id="__codelineno-0-135" name="__codelineno-0-135"></a> <span class="nx">LScli</span><span class="o">::</span><span class="na">unquote_word</span><span class="p">(</span><span class="nv">$dn</span><span class="p">);</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-136" id="__codelineno-0-136" name="__codelineno-0-136"></a> <span class="nv">$dn_arg_num</span> <span class="o">=</span> <span class="nv">$i</span><span class="p">;</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-137" id="__codelineno-0-137" name="__codelineno-0-137"></a> <span class="p">}</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-138" id="__codelineno-0-138" name="__codelineno-0-138"></a> <span class="p">}</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-139" id="__codelineno-0-139" name="__codelineno-0-139"></a> <span class="p">}</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-140" id="__codelineno-0-140" name="__codelineno-0-140"></a>
<a href="#contrib-addons-cli-commands-__codelineno-0-141" id="__codelineno-0-141" name="__codelineno-0-141"></a> <span class="c1">// If objType not already chosen (or currently autocomplete),</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-142" id="__codelineno-0-142" name="__codelineno-0-142"></a> <span class="c1">// add LSobject types to available options</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-143" id="__codelineno-0-143" name="__codelineno-0-143"></a> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nv">$objType</span> <span class="o">||</span> <span class="nv">$objType_arg_num</span> <span class="o">==</span> <span class="nv">$comp_word_num</span><span class="p">)</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-144" id="__codelineno-0-144" name="__codelineno-0-144"></a> <span class="nv">$opts</span> <span class="o">=</span> <span class="nb">array_merge</span><span class="p">(</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-145" id="__codelineno-0-145" name="__codelineno-0-145"></a> <span class="nv">$opts</span><span class="p">,</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-146" id="__codelineno-0-146" name="__codelineno-0-146"></a> <span class="nx">LScli</span><span class="o">::</span><span class="na">autocomplete_LSobject_types</span><span class="p">(</span><span class="nv">$comp_word</span><span class="p">)</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-147" id="__codelineno-0-147" name="__codelineno-0-147"></a> <span class="p">);</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-148" id="__codelineno-0-148" name="__codelineno-0-148"></a>
<a href="#contrib-addons-cli-commands-__codelineno-0-149" id="__codelineno-0-149" name="__codelineno-0-149"></a> <span class="c1">// If dn not already chosen (or currently autocomplete), try autocomplete it</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-150" id="__codelineno-0-150" name="__codelineno-0-150"></a> <span class="k">elseif</span> <span class="p">(</span><span class="o">!</span><span class="nv">$dn</span> <span class="o">||</span> <span class="nv">$dn_arg_num</span> <span class="o">==</span> <span class="nv">$comp_word_num</span><span class="p">)</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-151" id="__codelineno-0-151" name="__codelineno-0-151"></a> <span class="nv">$opts</span> <span class="o">=</span> <span class="nb">array_merge</span><span class="p">(</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-152" id="__codelineno-0-152" name="__codelineno-0-152"></a> <span class="nv">$opts</span><span class="p">,</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-153" id="__codelineno-0-153" name="__codelineno-0-153"></a> <span class="nx">LScli</span><span class="o">::</span><span class="na">autocomplete_LSobject_dn</span><span class="p">(</span><span class="nv">$objType</span><span class="p">,</span> <span class="nv">$comp_word</span><span class="p">)</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-154" id="__codelineno-0-154" name="__codelineno-0-154"></a> <span class="p">);</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-155" id="__codelineno-0-155" name="__codelineno-0-155"></a>
<a href="#contrib-addons-cli-commands-__codelineno-0-156" id="__codelineno-0-156" name="__codelineno-0-156"></a> <span class="k">return</span> <span class="nx">LScli</span><span class="o">::</span><span class="na">autocomplete_opts</span><span class="p">(</span><span class="nv">$opts</span><span class="p">,</span> <span class="nv">$comp_word</span><span class="p">);</span>
<a href="#contrib-addons-cli-commands-__codelineno-0-157" id="__codelineno-0-157" name="__codelineno-0-157"></a><span class="p">}</span>
</code></pre></div></section><h1 class="nav-section-title-end">Ended: Les addons (LSaddon)</h1><section class="print-page" id="contrib-form-elements"><h1 id="contrib-form-elements-les-elements-des-formulaires-lsformelement">Les éléments des formulaires (LSformElement)</h1>
<p>Les <a href="#contrib-form-elements-lsformelements">LSformElements</a> sont les types de champs de formulaire supportés par
l'application.</p>
<p>Pour chaque type implémenté, on devra trouver :</p>
<ul>
<li>Une classe PHP dérivée de la classe <code>LSattr_html</code> et devant s'appeler
<code>LSattr_html_[nom du type d'attribut HTML]</code>. Dans celle-ci, il devra être défini à minima la
variable de classe <code>LSformElement_type</code> permettant de référencer le type
d'<a href="#contrib-form-elements-lsformelements">LSformElement</a> à utiliser ;</li>
</ul>
<ul>
<li>
<p>Une classe PHP dérivée de la classe <code>LSformElement</code> et devant s'appeler
<code>LSformElement_[nom du type d'LSformElement]</code>. Cette classe implémentera tout ce qui concerne
l'affichage du champ dans le formulaire et le traitement d'une valeur retournée par ce dernier.
Cela concerne notamment les méthodes suivantes :</p>
<ul>
<li>
<p><code>getDisplay()</code></p>
<p>Retourne les informations d'affichage du champ dans un formulaire sous la forme d'un tableau
<em>(implémentation obligatoire, pas de méthode par défaut)</em>. Il sera possible de s'appuyer sur la
méthode <code>getLabelInfos()</code> permettant de générer et récupérer tout ce qui concerne le label du
champ du formulaire. Il faudra cependant à minima fournir également la clé <code>html</code> dans le
tableau retourné qui devra contenir le bout de code HTML correspondant au champ du formulaire.
Communément, ce code HTML est généré en appelant la méthode <code>fetchTemplate()</code>.</p>
</li>
</ul>
<ul>
<li>
<p><code>fetchTemplate()</code></p>
<p>Retourne le code HTML du champ dans le formulaire. L'implémentation de cette méthode est
facultative et par défaut, cette méthode utilisera la variable de classe <code>$template</code> pour
connaître le fichier de template à utiliser. Ce fichier de template permettra la génération de
la liste de tous les champs associés à chacune des valeurs de l'attribut. Individuellement, le
champ d'une des valeurs de l'attribut est généré à l'aide du fichier de template référencé dans
la variable de class <code>$fieldTemplate</code>.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>La variable de classe <code>$fieldTemplate</code> est également utilisée par la méthode
<code>LSformElement :: getEmptyField()</code> qui sert à générer le code HTML d'un champ du formulaire
pour une nouvelle valeur de l'attribut. Cette méthode est notamment utilisée lorsque l'on
clique sur le bouton permettant d'ajouter une valeur à un champ du formulaire.</p>
</div>
</li>
</ul>
<ul>
<li>
<p><code>getPostData()</code></p>
<p>Récupère dans les données postées par le formulaire, celle concernant ce champ. Cette méthode
devra potentiellement traiter l'ensemble des valeurs de l'attribut envoyées par le formulaire
et les définir dans le tableau passé en référence en tant que premier argument, les valeurs de
l'attribut. L'implémentation de cette méthode est facultative et par défaut, un tableau de
valeurs portant le nom de l'attribut LDAP correspondant sera récupérée comme valeur de
l'attribut.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Pour plus d'informations sur le rôle et fonctionnement de cette méthode, référer à la
méthode par défaut, définie dans la classe PHP parente <code>LSformElement</code>.</p>
</div>
</li>
</ul>
<ul>
<li>
<p><code>setValueFromPostData()</code></p>
<p>Définit les valeurs de l'attribut à partir des données reçues du formulaire (et récupérées par
la méthode <code>getPostData</code>). L'implémentation de cette méthode est facultative et par défaut,
aucune transformation ne sera faites à cette étape sur les données récupérées depuis le
formulaire. Implémenter cette méthode pourra cependant se révéler utile en cas de champs de
formulaire complexe (attribut composite par exemple).</p>
</li>
</ul>
<ul>
<li>
<p><code>autocomplete_attr_values()</code></p>
<p>Génère de la liste des valeurs possibles de l'attribut dans un contexte <em>CLI</em>.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Pour plus d'informations sur le rôle et fonctionnement de cette méthode, référer aux
commentaires de la méthode par défaut, définie dans la classe PHP parente <code>LSformElement</code>.
Vous pouvez également vous inspirer des exemples d'implémentations fournies avec les autres
type d'<a href="#contrib-form-elements-lsformelements">LSformElement</a>.</p>
</div>
</li>
</ul>
</li>
</ul>
<ul>
<li>Un (ou plusieurs) fichier template pour la génération du code HTML du champ du formulaire.
Communément, le fichier <code>LSformElement.tpl</code> est utilisé pour générer la structure de la liste des
champs correspondant aux différentes valeurs de l'attribut. Ce template utilise une variable
<code>$fieldTemplate</code> pour définir quel fichier template devra être utilisé pour générer le code HTML
de chaque champ associés à une valeur. C'est ce second fichier de template qui est en général à
fournir à minima avec votre <a href="#contrib-form-elements-lsformelements">LSformElement</a>.</li>
</ul>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Il peut être utile d'étendre un type d'<a href="#contrib-form-elements-lsformelements">LSformElement</a> existant pour faciliter
l'implémentation d'un nouveau type. Pour cela, vous devez utiliser l'héritage de classe PHP en
faisant dériver vos nouvelles classes des classes du <a href="#contrib-form-elements-lsformelements">LSformElement</a> dont vous
vous inspirer, plutôt que les classes génériques. Vous pouvez prendre exemple sur le type
d'<a href="#contrib-form-elements-lsformelements">LSformElement</a> <code>pre</code> qui s'inspire du type <code>textarea</code>, ou encore du type
<code>url</code> dérivé du type <code>text</code>.</p>
</div></section><section class="print-page" id="contrib-form-rules"><h1 id="contrib-form-rules-les-regles-de-validation-syntaxiques-lsformrule">Les règles de validation syntaxiques (LSformRule)</h1>
<p>Les <a href="#contrib-form-rules-lsformrules">LSformRules</a> sont les règles syntaxiques applicables aux champs des formulaires.
Ces règles serviront à s'assurer que les valeurs des champs récupérées des formulaires sont
syntaxiquement correctes. Elles seront configurables via le paramètre <code>check_data</code> des attributs des
<a href="#conf-configuration-lsobject">LSobjects</a>.</p>
<p>Pour chaque type implémenté, on trouvera une classe PHP dérivée de la classe <code>LSformRule</code> et devant
s'appeler <code>LSattr_rule_[nom du type]</code>. Dans celle-ci, il devra être défini la méthode statique
<code>validate()</code> qui implémentera le contrôle syntaxique. Cette méthode prendra en paramètres :</p>
<ul>
<li>
<p><code>$value</code></p>
<p>La valeur à tester.</p>
</li>
</ul>
<ul>
<li>
<p><code>$options</code></p>
<p>Un tableau des options définies dans la configuration pour ce contrôle syntaxique.</p>
</li>
</ul>
<ul>
<li>
<p><code>$formElement</code></p>
<p>Une référence au champ du formulaire (objet <a href="#contrib-form-rules-lsformelements">LSformElement</a>).</p>
</li>
</ul>
<p>Cette méthode devra retourner <code>True</code> ou <code>False</code> si la valeur testée est respectivement valide ou
invalide. Elle pourra également déclencher une exception <code>LSformRuleException</code> qui lui permettra de
donner des messages d'erreurs elle-même sur le(s) problème(s) detecté(s) durant l'analyse de la
valeur passée. Le constructeur de ce type d'exception prend en tant que premier paramètre un tableau
de messages d'erreurs (ou un simple message d'erreur) qui seront retournés à l'utilisateur.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Par défaut, les valeurs de l'attribut sont testées une à une via la méthode <code>validate()</code>.
Cependant, il est possible d'implémenter une méthode de validation pour toutes les valeurs de
l'attribut en une seule fois en affectant la valeur <code>false</code> à la constante de classe
<code>validate_one_by_one</code>. Dans ce cas, l'ensemble des valeurs de l'attribut seront passées via le
paramètre <code>$value</code> à la méthode <code>validate()</code> (sous la forme d'un tableau). Cela pourra par
exemple être utile pour implémenter une validation de la cohérence des valeurs les unes vis à
vis des autres (unicité, nombre maximum de valeurs, …).</p>
</div></section><h1 class="nav-section-title-end">Ended: Contribution</h1></div>
</article>
</div>
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
</div>
</main>
<footer class="md-footer">
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
<div class="md-copyright__highlight">
Easter-eggs
</div>
Made with
<a href="https://squidfunk.github.io/mkdocs-material/" rel="noopener" target="_blank">
Material for MkDocs
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"base": "../..", "features": [], "search": "../assets/javascripts/workers/search.6ce7567c.min.js", "translations": {"clipboard.copied": "Copi\u00e9 dans le presse-papier", "clipboard.copy": "Copier dans le presse-papier", "search.result.more.one": "1 de plus sur cette page", "search.result.more.other": "# de plus sur cette page", "search.result.none": "Aucun document trouv\u00e9", "search.result.one": "1 document trouv\u00e9", "search.result.other": "# documents trouv\u00e9s", "search.result.placeholder": "Taper pour d\u00e9marrer la recherche", "search.result.term.missing": "Non trouv\u00e9", "select.version": "S\u00e9lectionner la version"}, "version": {"provider": "mike"}}</script>
<script src="data:text/javascript;base64,InVzZSBzdHJpY3QiOygoKT0+e3ZhciBXaT1PYmplY3QuY3JlYXRlO3ZhciBncj1PYmplY3QuZGVmaW5lUHJvcGVydHk7dmFyIERpPU9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3I7dmFyIFZpPU9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzLFZ0PU9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMsTmk9T2JqZWN0LmdldFByb3RvdHlwZU9mLHlyPU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHksYW89T2JqZWN0LnByb3RvdHlwZS5wcm9wZXJ0eUlzRW51bWVyYWJsZTt2YXIgaW89KGUsdCxyKT0+dCBpbiBlP2dyKGUsdCx7ZW51bWVyYWJsZTohMCxjb25maWd1cmFibGU6ITAsd3JpdGFibGU6ITAsdmFsdWU6cn0pOmVbdF09ciwkPShlLHQpPT57Zm9yKHZhciByIGluIHR8fCh0PXt9KSl5ci5jYWxsKHQscikmJmlvKGUscix0W3JdKTtpZihWdClmb3IodmFyIHIgb2YgVnQodCkpYW8uY2FsbCh0LHIpJiZpbyhlLHIsdFtyXSk7cmV0dXJuIGV9O3ZhciBzbz0oZSx0KT0+e3ZhciByPXt9O2Zvcih2YXIgbyBpbiBlKXlyLmNhbGwoZSxvKSYmdC5pbmRleE9mKG8pPDAmJihyW29dPWVbb10pO2lmKGUhPW51bGwmJlZ0KWZvcih2YXIgbyBvZiBWdChlKSl0LmluZGV4T2Yobyk8MCYmYW8uY2FsbChlLG8pJiYocltvXT1lW29dKTtyZXR1cm4gcn07dmFyIHhyPShlLHQpPT4oKT0+KHR8fGUoKHQ9e2V4cG9ydHM6e319KS5leHBvcnRzLHQpLHQuZXhwb3J0cyk7dmFyIHppPShlLHQscixvKT0+e2lmKHQmJnR5cGVvZiB0PT0ib2JqZWN0Inx8dHlwZW9mIHQ9PSJmdW5jdGlvbiIpZm9yKGxldCBuIG9mIFZpKHQpKSF5ci5jYWxsKGUsbikmJm4hPT1yJiZncihlLG4se2dldDooKT0+dFtuXSxlbnVtZXJhYmxlOiEobz1EaSh0LG4pKXx8by5lbnVtZXJhYmxlfSk7cmV0dXJuIGV9O3ZhciBNdD0oZSx0LHIpPT4ocj1lIT1udWxsP1dpKE5pKGUpKTp7fSx6aSh0fHwhZXx8IWUuX19lc01vZHVsZT9ncihyLCJkZWZhdWx0Iix7dmFsdWU6ZSxlbnVtZXJhYmxlOiEwfSk6cixlKSk7dmFyIGNvPShlLHQscik9Pm5ldyBQcm9taXNlKChvLG4pPT57dmFyIGk9cD0+e3RyeXtzKHIubmV4dChwKSl9Y2F0Y2goYyl7bihjKX19LGE9cD0+e3RyeXtzKHIudGhyb3cocCkpfWNhdGNoKGMpe24oYyl9fSxzPXA9PnAuZG9uZT9vKHAudmFsdWUpOlByb21pc2UucmVzb2x2ZShwLnZhbHVlKS50aGVuKGksYSk7cygocj1yLmFwcGx5KGUsdCkpLm5leHQoKSl9KTt2YXIgbG89eHIoKEVyLHBvKT0+eyhmdW5jdGlvbihlLHQpe3R5cGVvZiBFcj09Im9iamVjdCImJnR5cGVvZiBwbyE9InVuZGVmaW5lZCI/dCgpOnR5cGVvZiBkZWZpbmU9PSJmdW5jdGlvbiImJmRlZmluZS5hbWQ/ZGVmaW5lKHQpOnQoKX0pKEVyLGZ1bmN0aW9uKCl7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIGUocil7dmFyIG89ITAsbj0hMSxpPW51bGwsYT17dGV4dDohMCxzZWFyY2g6ITAsdXJsOiEwLHRlbDohMCxlbWFpbDohMCxwYXNzd29yZDohMCxudW1iZXI6ITAsZGF0ZTohMCxtb250aDohMCx3ZWVrOiEwLHRpbWU6ITAsZGF0ZXRpbWU6ITAsImRhdGV0aW1lLWxvY2FsIjohMH07ZnVuY3Rpb24gcyhrKXtyZXR1cm4hIShrJiZrIT09ZG9jdW1lbnQmJmsubm9kZU5hbWUhPT0iSFRNTCImJmsubm9kZU5hbWUhPT0iQk9EWSImJiJjbGFzc0xpc3QiaW4gayYmImNvbnRhaW5zImluIGsuY2xhc3NMaXN0KX1mdW5jdGlvbiBwKGspe3ZhciBmdD1rLnR5cGUscWU9ay50YWdOYW1lO3JldHVybiEhKHFlPT09IklOUFVUIiYmYVtmdF0mJiFrLnJlYWRPbmx5fHxxZT09PSJURVhUQVJFQSImJiFrLnJlYWRPbmx5fHxrLmlzQ29udGVudEVkaXRhYmxlKX1mdW5jdGlvbiBjKGspe2suY2xhc3NMaXN0LmNvbnRhaW5zKCJmb2N1cy12aXNpYmxlIil8fChrLmNsYXNzTGlzdC5hZGQoImZvY3VzLXZpc2libGUiKSxrLnNldEF0dHJpYnV0ZSgiZGF0YS1mb2N1cy12aXNpYmxlLWFkZGVkIiwiIikpfWZ1bmN0aW9uIGwoayl7ay5oYXNBdHRyaWJ1dGUoImRhdGEtZm9jdXMtdmlzaWJsZS1hZGRlZCIpJiYoay5jbGFzc0xpc3QucmVtb3ZlKCJmb2N1cy12aXNpYmxlIiksay5yZW1vdmVBdHRyaWJ1dGUoImRhdGEtZm9jdXMtdmlzaWJsZS1hZGRlZCIpKX1mdW5jdGlvbiBmKGspe2subWV0YUtleXx8ay5hbHRLZXl8fGsuY3RybEtleXx8KHMoci5hY3RpdmVFbGVtZW50KSYmYyhyLmFjdGl2ZUVsZW1lbnQpLG89ITApfWZ1bmN0aW9uIHUoayl7bz0hMX1mdW5jdGlvbiBkKGspe3Moay50YXJnZXQpJiYob3x8cChrLnRhcmdldCkpJiZjKGsudGFyZ2V0KX1mdW5jdGlvbiB5KGspe3Moay50YXJnZXQpJiYoay50YXJnZXQuY2xhc3NMaXN0LmNvbnRhaW5zKCJmb2N1cy12aXNpYmxlIil8fGsudGFyZ2V0Lmhhc0F0dHJpYnV0ZSgiZGF0YS1mb2N1cy12aXNpYmxlLWFkZGVkIikpJiYobj0hMCx3aW5kb3cuY2xlYXJUaW1lb3V0KGkpLGk9d2luZG93LnNldFRpbWVvdXQoZnVuY3Rpb24oKXtuPSExfSwxMDApLGwoay50YXJnZXQpKX1mdW5jdGlvbiBMKGspe2RvY3VtZW50LnZpc2liaWxpdHlTdGF0ZT09PSJoaWRkZW4iJiYobiYmKG89ITApLFgoKSl9ZnVuY3Rpb24gWCgpe2RvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoIm1vdXNlbW92ZSIsSiksZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigibW91c2Vkb3duIixKKSxkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCJtb3VzZXVwIixKKSxkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCJwb2ludGVybW92ZSIsSiksZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigicG9pbnRlcmRvd24iLEopLGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoInBvaW50ZXJ1cCIsSiksZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigidG91Y2htb3ZlIixKKSxkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCJ0b3VjaHN0YXJ0IixKKSxkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCJ0b3VjaGVuZCIsSil9ZnVuY3Rpb24gdGUoKXtkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCJtb3VzZW1vdmUiLEopLGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoIm1vdXNlZG93biIsSiksZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigibW91c2V1cCIsSiksZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigicG9pbnRlcm1vdmUiLEopLGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoInBvaW50ZXJkb3duIixKKSxkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCJwb2ludGVydXAiLEopLGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoInRvdWNobW92ZSIsSiksZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigidG91Y2hzdGFydCIsSiksZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigidG91Y2hlbmQiLEopfWZ1bmN0aW9uIEooayl7ay50YXJnZXQubm9kZU5hbWUmJmsudGFyZ2V0Lm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk9PT0iaHRtbCJ8fChvPSExLHRlKCkpfWRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoImtleWRvd24iLGYsITApLGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoIm1vdXNlZG93biIsdSwhMCksZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigicG9pbnRlcmRvd24iLHUsITApLGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoInRvdWNoc3RhcnQiLHUsITApLGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoInZpc2liaWxpdHljaGFuZ2UiLEwsITApLFgoKSxyLmFkZEV2ZW50TGlzdGVuZXIoImZvY3VzIixkLCEwKSxyLmFkZEV2ZW50TGlzdGVuZXIoImJsdXIiLHksITApLHIubm9kZVR5cGU9PT1Ob2RlLkRPQ1VNRU5UX0ZSQUdNRU5UX05PREUmJnIuaG9zdD9yLmhvc3Quc2V0QXR0cmlidXRlKCJkYXRhLWpzLWZvY3VzLXZpc2libGUiLCIiKTpyLm5vZGVUeXBlPT09Tm9kZS5ET0NVTUVOVF9OT0RFJiYoZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsYXNzTGlzdC5hZGQoImpzLWZvY3VzLXZpc2libGUiKSxkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuc2V0QXR0cmlidXRlKCJkYXRhLWpzLWZvY3VzLXZpc2libGUiLCIiKSl9aWYodHlwZW9mIHdpbmRvdyE9InVuZGVmaW5lZCImJnR5cGVvZiBkb2N1bWVudCE9InVuZGVmaW5lZCIpe3dpbmRvdy5hcHBseUZvY3VzVmlzaWJsZVBvbHlmaWxsPWU7dmFyIHQ7dHJ5e3Q9bmV3IEN1c3RvbUV2ZW50KCJmb2N1cy12aXNpYmxlLXBvbHlmaWxsLXJlYWR5Iil9Y2F0Y2gocil7dD1kb2N1bWVudC5jcmVhdGVFdmVudCgiQ3VzdG9tRXZlbnQiKSx0LmluaXRDdXN0b21FdmVudCgiZm9jdXMtdmlzaWJsZS1wb2x5ZmlsbC1yZWFkeSIsITEsITEse30pfXdpbmRvdy5kaXNwYXRjaEV2ZW50KHQpfXR5cGVvZiBkb2N1bWVudCE9InVuZGVmaW5lZCImJmUoZG9jdW1lbnQpfSl9KTt2YXIgcXI9eHIoKGh5LE9uKT0+eyJ1c2Ugc3RyaWN0IjsvKiEKICogZXNjYXBlLWh0bWwKICogQ29weXJpZ2h0KGMpIDIwMTItMjAxMyBUSiBIb2xvd2F5Y2h1awogKiBDb3B5cmlnaHQoYykgMjAxNSBBbmRyZWFzIEx1YmJlCiAqIENvcHlyaWdodChjKSAyMDE1IFRpYW5jaGVuZyAiVGltb3RoeSIgR3UKICogTUlUIExpY2Vuc2VkCiAqL3ZhciAkYT0vWyInJjw+XS87T24uZXhwb3J0cz1QYTtmdW5jdGlvbiBQYShlKXt2YXIgdD0iIitlLHI9JGEuZXhlYyh0KTtpZighcilyZXR1cm4gdDt2YXIgbyxuPSIiLGk9MCxhPTA7Zm9yKGk9ci5pbmRleDtpPHQubGVuZ3RoO2krKyl7c3dpdGNoKHQuY2hhckNvZGVBdChpKSl7Y2FzZSAzNDpvPSImcXVvdDsiO2JyZWFrO2Nhc2UgMzg6bz0iJmFtcDsiO2JyZWFrO2Nhc2UgMzk6bz0iJiMzOTsiO2JyZWFrO2Nhc2UgNjA6bz0iJmx0OyI7YnJlYWs7Y2FzZSA2MjpvPSImZ3Q7IjticmVhaztkZWZhdWx0OmNvbnRpbnVlfWEhPT1pJiYobis9dC5zdWJzdHJpbmcoYSxpKSksYT1pKzEsbis9b31yZXR1cm4gYSE9PWk/bit0LnN1YnN0cmluZyhhLGkpOm59fSk7dmFyIEJyPXhyKChJdCxZcik9PnsvKiEKICogY2xpcGJvYXJkLmpzIHYyLjAuMTEKICogaHR0cHM6Ly9jbGlwYm9hcmRqcy5jb20vCiAqCiAqIExpY2Vuc2VkIE1JVCDCqSBaZW5vIFJvY2hhCiAqLyhmdW5jdGlvbih0LHIpe3R5cGVvZiBJdD09Im9iamVjdCImJnR5cGVvZiBZcj09Im9iamVjdCI/WXIuZXhwb3J0cz1yKCk6dHlwZW9mIGRlZmluZT09ImZ1bmN0aW9uIiYmZGVmaW5lLmFtZD9kZWZpbmUoW10scik6dHlwZW9mIEl0PT0ib2JqZWN0Ij9JdC5DbGlwYm9hcmRKUz1yKCk6dC5DbGlwYm9hcmRKUz1yKCl9KShJdCxmdW5jdGlvbigpe3JldHVybiBmdW5jdGlvbigpe3ZhciBlPXs2ODY6ZnVuY3Rpb24obyxuLGkpeyJ1c2Ugc3RyaWN0IjtpLmQobix7ZGVmYXVsdDpmdW5jdGlvbigpe3JldHVybiBVaX19KTt2YXIgYT1pKDI3OSkscz1pLm4oYSkscD1pKDM3MCksYz1pLm4ocCksbD1pKDgxNyksZj1pLm4obCk7ZnVuY3Rpb24gdShWKXt0cnl7cmV0dXJuIGRvY3VtZW50LmV4ZWNDb21tYW5kKFYpfWNhdGNoKEEpe3JldHVybiExfX12YXIgZD1mdW5jdGlvbihBKXt2YXIgTT1mKCkoQSk7cmV0dXJuIHUoImN1dCIpLE19LHk9ZDtmdW5jdGlvbiBMKFYpe3ZhciBBPWRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5nZXRBdHRyaWJ1dGUoImRpciIpPT09InJ0bCIsTT1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJ0ZXh0YXJlYSIpO00uc3R5bGUuZm9udFNpemU9IjEycHQiLE0uc3R5bGUuYm9yZGVyPSIwIixNLnN0eWxlLnBhZGRpbmc9IjAiLE0uc3R5bGUubWFyZ2luPSIwIixNLnN0eWxlLnBvc2l0aW9uPSJhYnNvbHV0ZSIsTS5zdHlsZVtBPyJyaWdodCI6ImxlZnQiXT0iLTk5OTlweCI7dmFyIEY9d2luZG93LnBhZ2VZT2Zmc2V0fHxkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuc2Nyb2xsVG9wO3JldHVybiBNLnN0eWxlLnRvcD0iIi5jb25jYXQoRiwicHgiKSxNLnNldEF0dHJpYnV0ZSgicmVhZG9ubHkiLCIiKSxNLnZhbHVlPVYsTX12YXIgWD1mdW5jdGlvbihBLE0pe3ZhciBGPUwoQSk7TS5jb250YWluZXIuYXBwZW5kQ2hpbGQoRik7dmFyIEQ9ZigpKEYpO3JldHVybiB1KCJjb3B5IiksRi5yZW1vdmUoKSxEfSx0ZT1mdW5jdGlvbihBKXt2YXIgTT1hcmd1bWVudHMubGVuZ3RoPjEmJmFyZ3VtZW50c1sxXSE9PXZvaWQgMD9hcmd1bWVudHNbMV06e2NvbnRhaW5lcjpkb2N1bWVudC5ib2R5fSxGPSIiO3JldHVybiB0eXBlb2YgQT09InN0cmluZyI/Rj1YKEEsTSk6QSBpbnN0YW5jZW9mIEhUTUxJbnB1dEVsZW1lbnQmJiFbInRleHQiLCJzZWFyY2giLCJ1cmwiLCJ0ZWwiLCJwYXNzd29yZCJdLmluY2x1ZGVzKEE9PW51bGw/dm9pZCAwOkEudHlwZSk/Rj1YKEEudmFsdWUsTSk6KEY9ZigpKEEpLHUoImNvcHkiKSksRn0sSj10ZTtmdW5jdGlvbiBrKFYpeyJAYmFiZWwvaGVscGVycyAtIHR5cGVvZiI7cmV0dXJuIHR5cGVvZiBTeW1ib2w9PSJmdW5jdGlvbiImJnR5cGVvZiBTeW1ib2wuaXRlcmF0b3I9PSJzeW1ib2wiP2s9ZnVuY3Rpb24oTSl7cmV0dXJuIHR5cGVvZiBNfTprPWZ1bmN0aW9uKE0pe3JldHVybiBNJiZ0eXBlb2YgU3ltYm9sPT0iZnVuY3Rpb24iJiZNLmNvbnN0cnVjdG9yPT09U3ltYm9sJiZNIT09U3ltYm9sLnByb3RvdHlwZT8ic3ltYm9sIjp0eXBlb2YgTX0sayhWKX12YXIgZnQ9ZnVuY3Rpb24oKXt2YXIgQT1hcmd1bWVudHMubGVuZ3RoPjAmJmFyZ3VtZW50c1swXSE9PXZvaWQgMD9hcmd1bWVudHNbMF06e30sTT1BLmFjdGlvbixGPU09PT12b2lkIDA/ImNvcHkiOk0sRD1BLmNvbnRhaW5lcixZPUEudGFyZ2V0LCRlPUEudGV4dDtpZihGIT09ImNvcHkiJiZGIT09ImN1dCIpdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkICJhY3Rpb24iIHZhbHVlLCB1c2UgZWl0aGVyICJjb3B5IiBvciAiY3V0IicpO2lmKFkhPT12b2lkIDApaWYoWSYmayhZKT09PSJvYmplY3QiJiZZLm5vZGVUeXBlPT09MSl7aWYoRj09PSJjb3B5IiYmWS5oYXNBdHRyaWJ1dGUoImRpc2FibGVkIikpdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkICJ0YXJnZXQiIGF0dHJpYnV0ZS4gUGxlYXNlIHVzZSAicmVhZG9ubHkiIGluc3RlYWQgb2YgImRpc2FibGVkIiBhdHRyaWJ1dGUnKTtpZihGPT09ImN1dCImJihZLmhhc0F0dHJpYnV0ZSgicmVhZG9ubHkiKXx8WS5oYXNBdHRyaWJ1dGUoImRpc2FibGVkIikpKXRocm93IG5ldyBFcnJvcihgSW52YWxpZCAidGFyZ2V0IiBhdHRyaWJ1dGUuIFlvdSBjYW4ndCBjdXQgdGV4dCBmcm9tIGVsZW1lbnRzIHdpdGggInJlYWRvbmx5IiBvciAiZGlzYWJsZWQiIGF0dHJpYnV0ZXNgKX1lbHNlIHRocm93IG5ldyBFcnJvcignSW52YWxpZCAidGFyZ2V0IiB2YWx1ZSwgdXNlIGEgdmFsaWQgRWxlbWVudCcpO2lmKCRlKXJldHVybiBKKCRlLHtjb250YWluZXI6RH0pO2lmKFkpcmV0dXJuIEY9PT0iY3V0Ij95KFkpOkooWSx7Y29udGFpbmVyOkR9KX0scWU9ZnQ7ZnVuY3Rpb24gRmUoVil7IkBiYWJlbC9oZWxwZXJzIC0gdHlwZW9mIjtyZXR1cm4gdHlwZW9mIFN5bWJvbD09ImZ1bmN0aW9uIiYmdHlwZW9mIFN5bWJvbC5pdGVyYXRvcj09InN5bWJvbCI/RmU9ZnVuY3Rpb24oTSl7cmV0dXJuIHR5cGVvZiBNfTpGZT1mdW5jdGlvbihNKXtyZXR1cm4gTSYmdHlwZW9mIFN5bWJvbD09ImZ1bmN0aW9uIiYmTS5jb25zdHJ1Y3Rvcj09PVN5bWJvbCYmTSE9PVN5bWJvbC5wcm90b3R5cGU/InN5bWJvbCI6dHlwZW9mIE19LEZlKFYpfWZ1bmN0aW9uIGtpKFYsQSl7aWYoIShWIGluc3RhbmNlb2YgQSkpdGhyb3cgbmV3IFR5cGVFcnJvcigiQ2Fubm90IGNhbGwgYSBjbGFzcyBhcyBhIGZ1bmN0aW9uIil9ZnVuY3Rpb24gbm8oVixBKXtmb3IodmFyIE09MDtNPEEubGVuZ3RoO00rKyl7dmFyIEY9QVtNXTtGLmVudW1lcmFibGU9Ri5lbnVtZXJhYmxlfHwhMSxGLmNvbmZpZ3VyYWJsZT0hMCwidmFsdWUiaW4gRiYmKEYud3JpdGFibGU9ITApLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShWLEYua2V5LEYpfX1mdW5jdGlvbiBIaShWLEEsTSl7cmV0dXJuIEEmJm5vKFYucHJvdG90eXBlLEEpLE0mJm5vKFYsTSksVn1mdW5jdGlvbiAkaShWLEEpe2lmKHR5cGVvZiBBIT0iZnVuY3Rpb24iJiZBIT09bnVsbCl0aHJvdyBuZXcgVHlwZUVycm9yKCJTdXBlciBleHByZXNzaW9uIG11c3QgZWl0aGVyIGJlIG51bGwgb3IgYSBmdW5jdGlvbiIpO1YucHJvdG90eXBlPU9iamVjdC5jcmVhdGUoQSYmQS5wcm90b3R5cGUse2NvbnN0cnVjdG9yOnt2YWx1ZTpWLHdyaXRhYmxlOiEwLGNvbmZpZ3VyYWJsZTohMH19KSxBJiZicihWLEEpfWZ1bmN0aW9uIGJyKFYsQSl7cmV0dXJuIGJyPU9iamVjdC5zZXRQcm90b3R5cGVPZnx8ZnVuY3Rpb24oRixEKXtyZXR1cm4gRi5fX3Byb3RvX189RCxGfSxicihWLEEpfWZ1bmN0aW9uIFBpKFYpe3ZhciBBPWppKCk7cmV0dXJuIGZ1bmN0aW9uKCl7dmFyIEY9V3QoViksRDtpZihBKXt2YXIgWT1XdCh0aGlzKS5jb25zdHJ1Y3RvcjtEPVJlZmxlY3QuY29uc3RydWN0KEYsYXJndW1lbnRzLFkpfWVsc2UgRD1GLmFwcGx5KHRoaXMsYXJndW1lbnRzKTtyZXR1cm4gUmkodGhpcyxEKX19ZnVuY3Rpb24gUmkoVixBKXtyZXR1cm4gQSYmKEZlKEEpPT09Im9iamVjdCJ8fHR5cGVvZiBBPT0iZnVuY3Rpb24iKT9BOklpKFYpfWZ1bmN0aW9uIElpKFYpe2lmKFY9PT12b2lkIDApdGhyb3cgbmV3IFJlZmVyZW5jZUVycm9yKCJ0aGlzIGhhc24ndCBiZWVuIGluaXRpYWxpc2VkIC0gc3VwZXIoKSBoYXNuJ3QgYmVlbiBjYWxsZWQiKTtyZXR1cm4gVn1mdW5jdGlvbiBqaSgpe2lmKHR5cGVvZiBSZWZsZWN0PT0idW5kZWZpbmVkInx8IVJlZmxlY3QuY29uc3RydWN0fHxSZWZsZWN0LmNvbnN0cnVjdC5zaGFtKXJldHVybiExO2lmKHR5cGVvZiBQcm94eT09ImZ1bmN0aW9uIilyZXR1cm4hMDt0cnl7cmV0dXJuIERhdGUucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoUmVmbGVjdC5jb25zdHJ1Y3QoRGF0ZSxbXSxmdW5jdGlvbigpe30pKSwhMH1jYXRjaChWKXtyZXR1cm4hMX19ZnVuY3Rpb24gV3QoVil7cmV0dXJuIFd0PU9iamVjdC5zZXRQcm90b3R5cGVPZj9PYmplY3QuZ2V0UHJvdG90eXBlT2Y6ZnVuY3Rpb24oTSl7cmV0dXJuIE0uX19wcm90b19ffHxPYmplY3QuZ2V0UHJvdG90eXBlT2YoTSl9LFd0KFYpfWZ1bmN0aW9uIHZyKFYsQSl7dmFyIE09ImRhdGEtY2xpcGJvYXJkLSIuY29uY2F0KFYpO2lmKEEuaGFzQXR0cmlidXRlKE0pKXJldHVybiBBLmdldEF0dHJpYnV0ZShNKX12YXIgRmk9ZnVuY3Rpb24oVil7JGkoTSxWKTt2YXIgQT1QaShNKTtmdW5jdGlvbiBNKEYsRCl7dmFyIFk7cmV0dXJuIGtpKHRoaXMsTSksWT1BLmNhbGwodGhpcyksWS5yZXNvbHZlT3B0aW9ucyhEKSxZLmxpc3RlbkNsaWNrKEYpLFl9cmV0dXJuIEhpKE0sW3trZXk6InJlc29sdmVPcHRpb25zIix2YWx1ZTpmdW5jdGlvbigpe3ZhciBEPWFyZ3VtZW50cy5sZW5ndGg+MCYmYXJndW1lbnRzWzBdIT09dm9pZCAwP2FyZ3VtZW50c1swXTp7fTt0aGlzLmFjdGlvbj10eXBlb2YgRC5hY3Rpb249PSJmdW5jdGlvbiI/RC5hY3Rpb246dGhpcy5kZWZhdWx0QWN0aW9uLHRoaXMudGFyZ2V0PXR5cGVvZiBELnRhcmdldD09ImZ1bmN0aW9uIj9ELnRhcmdldDp0aGlzLmRlZmF1bHRUYXJnZXQsdGhpcy50ZXh0PXR5cGVvZiBELnRleHQ9PSJmdW5jdGlvbiI/RC50ZXh0OnRoaXMuZGVmYXVsdFRleHQsdGhpcy5jb250YWluZXI9RmUoRC5jb250YWluZXIpPT09Im9iamVjdCI/RC5jb250YWluZXI6ZG9jdW1lbnQuYm9keX19LHtrZXk6Imxpc3RlbkNsaWNrIix2YWx1ZTpmdW5jdGlvbihEKXt2YXIgWT10aGlzO3RoaXMubGlzdGVuZXI9YygpKEQsImNsaWNrIixmdW5jdGlvbigkZSl7cmV0dXJuIFkub25DbGljaygkZSl9KX19LHtrZXk6Im9uQ2xpY2siLHZhbHVlOmZ1bmN0aW9uKEQpe3ZhciBZPUQuZGVsZWdhdGVUYXJnZXR8fEQuY3VycmVudFRhcmdldCwkZT10aGlzLmFjdGlvbihZKXx8ImNvcHkiLER0PXFlKHthY3Rpb246JGUsY29udGFpbmVyOnRoaXMuY29udGFpbmVyLHRhcmdldDp0aGlzLnRhcmdldChZKSx0ZXh0OnRoaXMudGV4dChZKX0pO3RoaXMuZW1pdChEdD8ic3VjY2VzcyI6ImVycm9yIix7YWN0aW9uOiRlLHRleHQ6RHQsdHJpZ2dlcjpZLGNsZWFyU2VsZWN0aW9uOmZ1bmN0aW9uKCl7WSYmWS5mb2N1cygpLHdpbmRvdy5nZXRTZWxlY3Rpb24oKS5yZW1vdmVBbGxSYW5nZXMoKX19KX19LHtrZXk6ImRlZmF1bHRBY3Rpb24iLHZhbHVlOmZ1bmN0aW9uKEQpe3JldHVybiB2cigiYWN0aW9uIixEKX19LHtrZXk6ImRlZmF1bHRUYXJnZXQiLHZhbHVlOmZ1bmN0aW9uKEQpe3ZhciBZPXZyKCJ0YXJnZXQiLEQpO2lmKFkpcmV0dXJuIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoWSl9fSx7a2V5OiJkZWZhdWx0VGV4dCIsdmFsdWU6ZnVuY3Rpb24oRCl7cmV0dXJuIHZyKCJ0ZXh0IixEKX19LHtrZXk6ImRlc3Ryb3kiLHZhbHVlOmZ1bmN0aW9uKCl7dGhpcy5saXN0ZW5lci5kZXN0cm95KCl9fV0sW3trZXk6ImNvcHkiLHZhbHVlOmZ1bmN0aW9uKEQpe3ZhciBZPWFyZ3VtZW50cy5sZW5ndGg+MSYmYXJndW1lbnRzWzFdIT09dm9pZCAwP2FyZ3VtZW50c1sxXTp7Y29udGFpbmVyOmRvY3VtZW50LmJvZHl9O3JldHVybiBKKEQsWSl9fSx7a2V5OiJjdXQiLHZhbHVlOmZ1bmN0aW9uKEQpe3JldHVybiB5KEQpfX0se2tleToiaXNTdXBwb3J0ZWQiLHZhbHVlOmZ1bmN0aW9uKCl7dmFyIEQ9YXJndW1lbnRzLmxlbmd0aD4wJiZhcmd1bWVudHNbMF0hPT12b2lkIDA/YXJndW1lbnRzWzBdOlsiY29weSIsImN1dCJdLFk9dHlwZW9mIEQ9PSJzdHJpbmciP1tEXTpELCRlPSEhZG9jdW1lbnQucXVlcnlDb21tYW5kU3VwcG9ydGVkO3JldHVybiBZLmZvckVhY2goZnVuY3Rpb24oRHQpeyRlPSRlJiYhIWRvY3VtZW50LnF1ZXJ5Q29tbWFuZFN1cHBvcnRlZChEdCl9KSwkZX19XSksTX0ocygpKSxVaT1GaX0sODI4OmZ1bmN0aW9uKG8pe3ZhciBuPTk7aWYodHlwZW9mIEVsZW1lbnQhPSJ1bmRlZmluZWQiJiYhRWxlbWVudC5wcm90b3R5cGUubWF0Y2hlcyl7dmFyIGk9RWxlbWVudC5wcm90b3R5cGU7aS5tYXRjaGVzPWkubWF0Y2hlc1NlbGVjdG9yfHxpLm1vek1hdGNoZXNTZWxlY3Rvcnx8aS5tc01hdGNoZXNTZWxlY3Rvcnx8aS5vTWF0Y2hlc1NlbGVjdG9yfHxpLndlYmtpdE1hdGNoZXNTZWxlY3Rvcn1mdW5jdGlvbiBhKHMscCl7Zm9yKDtzJiZzLm5vZGVUeXBlIT09bjspe2lmKHR5cGVvZiBzLm1hdGNoZXM9PSJmdW5jdGlvbiImJnMubWF0Y2hlcyhwKSlyZXR1cm4gcztzPXMucGFyZW50Tm9kZX19by5leHBvcnRzPWF9LDQzODpmdW5jdGlvbihvLG4saSl7dmFyIGE9aSg4MjgpO2Z1bmN0aW9uIHMobCxmLHUsZCx5KXt2YXIgTD1jLmFwcGx5KHRoaXMsYXJndW1lbnRzKTtyZXR1cm4gbC5hZGRFdmVudExpc3RlbmVyKHUsTCx5KSx7ZGVzdHJveTpmdW5jdGlvbigpe2wucmVtb3ZlRXZlbnRMaXN0ZW5lcih1LEwseSl9fX1mdW5jdGlvbiBwKGwsZix1LGQseSl7cmV0dXJuIHR5cGVvZiBsLmFkZEV2ZW50TGlzdGVuZXI9PSJmdW5jdGlvbiI/cy5hcHBseShudWxsLGFyZ3VtZW50cyk6dHlwZW9mIHU9PSJmdW5jdGlvbiI/cy5iaW5kKG51bGwsZG9jdW1lbnQpLmFwcGx5KG51bGwsYXJndW1lbnRzKToodHlwZW9mIGw9PSJzdHJpbmciJiYobD1kb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKGwpKSxBcnJheS5wcm90b3R5cGUubWFwLmNhbGwobCxmdW5jdGlvbihMKXtyZXR1cm4gcyhMLGYsdSxkLHkpfSkpfWZ1bmN0aW9uIGMobCxmLHUsZCl7cmV0dXJuIGZ1bmN0aW9uKHkpe3kuZGVsZWdhdGVUYXJnZXQ9YSh5LnRhcmdldCxmKSx5LmRlbGVnYXRlVGFyZ2V0JiZkLmNhbGwobCx5KX19by5leHBvcnRzPXB9LDg3OTpmdW5jdGlvbihvLG4pe24ubm9kZT1mdW5jdGlvbihpKXtyZXR1cm4gaSE9PXZvaWQgMCYmaSBpbnN0YW5jZW9mIEhUTUxFbGVtZW50JiZpLm5vZGVUeXBlPT09MX0sbi5ub2RlTGlzdD1mdW5jdGlvbihpKXt2YXIgYT1PYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoaSk7cmV0dXJuIGkhPT12b2lkIDAmJihhPT09IltvYmplY3QgTm9kZUxpc3RdInx8YT09PSJbb2JqZWN0IEhUTUxDb2xsZWN0aW9uXSIpJiYibGVuZ3RoImluIGkmJihpLmxlbmd0aD09PTB8fG4ubm9kZShpWzBdKSl9LG4uc3RyaW5nPWZ1bmN0aW9uKGkpe3JldHVybiB0eXBlb2YgaT09InN0cmluZyJ8fGkgaW5zdGFuY2VvZiBTdHJpbmd9LG4uZm49ZnVuY3Rpb24oaSl7dmFyIGE9T2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKGkpO3JldHVybiBhPT09IltvYmplY3QgRnVuY3Rpb25dIn19LDM3MDpmdW5jdGlvbihvLG4saSl7dmFyIGE9aSg4NzkpLHM9aSg0MzgpO2Z1bmN0aW9uIHAodSxkLHkpe2lmKCF1JiYhZCYmIXkpdGhyb3cgbmV3IEVycm9yKCJNaXNzaW5nIHJlcXVpcmVkIGFyZ3VtZW50cyIpO2lmKCFhLnN0cmluZyhkKSl0aHJvdyBuZXcgVHlwZUVycm9yKCJTZWNvbmQgYXJndW1lbnQgbXVzdCBiZSBhIFN0cmluZyIpO2lmKCFhLmZuKHkpKXRocm93IG5ldyBUeXBlRXJyb3IoIlRoaXJkIGFyZ3VtZW50IG11c3QgYmUgYSBGdW5jdGlvbiIpO2lmKGEubm9kZSh1KSlyZXR1cm4gYyh1LGQseSk7aWYoYS5ub2RlTGlzdCh1KSlyZXR1cm4gbCh1LGQseSk7aWYoYS5zdHJpbmcodSkpcmV0dXJuIGYodSxkLHkpO3Rocm93IG5ldyBUeXBlRXJyb3IoIkZpcnN0IGFyZ3VtZW50IG11c3QgYmUgYSBTdHJpbmcsIEhUTUxFbGVtZW50LCBIVE1MQ29sbGVjdGlvbiwgb3IgTm9kZUxpc3QiKX1mdW5jdGlvbiBjKHUsZCx5KXtyZXR1cm4gdS5hZGRFdmVudExpc3RlbmVyKGQseSkse2Rlc3Ryb3k6ZnVuY3Rpb24oKXt1LnJlbW92ZUV2ZW50TGlzdGVuZXIoZCx5KX19fWZ1bmN0aW9uIGwodSxkLHkpe3JldHVybiBBcnJheS5wcm90b3R5cGUuZm9yRWFjaC5jYWxsKHUsZnVuY3Rpb24oTCl7TC5hZGRFdmVudExpc3RlbmVyKGQseSl9KSx7ZGVzdHJveTpmdW5jdGlvbigpe0FycmF5LnByb3RvdHlwZS5mb3JFYWNoLmNhbGwodSxmdW5jdGlvbihMKXtMLnJlbW92ZUV2ZW50TGlzdGVuZXIoZCx5KX0pfX19ZnVuY3Rpb24gZih1LGQseSl7cmV0dXJuIHMoZG9jdW1lbnQuYm9keSx1LGQseSl9by5leHBvcnRzPXB9LDgxNzpmdW5jdGlvbihvKXtmdW5jdGlvbiBuKGkpe3ZhciBhO2lmKGkubm9kZU5hbWU9PT0iU0VMRUNUIilpLmZvY3VzKCksYT1pLnZhbHVlO2Vsc2UgaWYoaS5ub2RlTmFtZT09PSJJTlBVVCJ8fGkubm9kZU5hbWU9PT0iVEVYVEFSRUEiKXt2YXIgcz1pLmhhc0F0dHJpYnV0ZSgicmVhZG9ubHkiKTtzfHxpLnNldEF0dHJpYnV0ZSgicmVhZG9ubHkiLCIiKSxpLnNlbGVjdCgpLGkuc2V0U2VsZWN0aW9uUmFuZ2UoMCxpLnZhbHVlLmxlbmd0aCksc3x8aS5yZW1vdmVBdHRyaWJ1dGUoInJlYWRvbmx5IiksYT1pLnZhbHVlfWVsc2V7aS5oYXNBdHRyaWJ1dGUoImNvbnRlbnRlZGl0YWJsZSIpJiZpLmZvY3VzKCk7dmFyIHA9d2luZG93LmdldFNlbGVjdGlvbigpLGM9ZG9jdW1lbnQuY3JlYXRlUmFuZ2UoKTtjLnNlbGVjdE5vZGVDb250ZW50cyhpKSxwLnJlbW92ZUFsbFJhbmdlcygpLHAuYWRkUmFuZ2UoYyksYT1wLnRvU3RyaW5nKCl9cmV0dXJuIGF9by5leHBvcnRzPW59LDI3OTpmdW5jdGlvbihvKXtmdW5jdGlvbiBuKCl7fW4ucHJvdG90eXBlPXtvbjpmdW5jdGlvbihpLGEscyl7dmFyIHA9dGhpcy5lfHwodGhpcy5lPXt9KTtyZXR1cm4ocFtpXXx8KHBbaV09W10pKS5wdXNoKHtmbjphLGN0eDpzfSksdGhpc30sb25jZTpmdW5jdGlvbihpLGEscyl7dmFyIHA9dGhpcztmdW5jdGlvbiBjKCl7cC5vZmYoaSxjKSxhLmFwcGx5KHMsYXJndW1lbnRzKX1yZXR1cm4gYy5fPWEsdGhpcy5vbihpLGMscyl9LGVtaXQ6ZnVuY3Rpb24oaSl7dmFyIGE9W10uc2xpY2UuY2FsbChhcmd1bWVudHMsMSkscz0oKHRoaXMuZXx8KHRoaXMuZT17fSkpW2ldfHxbXSkuc2xpY2UoKSxwPTAsYz1zLmxlbmd0aDtmb3IocDtwPGM7cCsrKXNbcF0uZm4uYXBwbHkoc1twXS5jdHgsYSk7cmV0dXJuIHRoaXN9LG9mZjpmdW5jdGlvbihpLGEpe3ZhciBzPXRoaXMuZXx8KHRoaXMuZT17fSkscD1zW2ldLGM9W107aWYocCYmYSlmb3IodmFyIGw9MCxmPXAubGVuZ3RoO2w8ZjtsKyspcFtsXS5mbiE9PWEmJnBbbF0uZm4uXyE9PWEmJmMucHVzaChwW2xdKTtyZXR1cm4gYy5sZW5ndGg/c1tpXT1jOmRlbGV0ZSBzW2ldLHRoaXN9fSxvLmV4cG9ydHM9bixvLmV4cG9ydHMuVGlueUVtaXR0ZXI9bn19LHQ9e307ZnVuY3Rpb24gcihvKXtpZih0W29dKXJldHVybiB0W29dLmV4cG9ydHM7dmFyIG49dFtvXT17ZXhwb3J0czp7fX07cmV0dXJuIGVbb10obixuLmV4cG9ydHMsciksbi5leHBvcnRzfXJldHVybiBmdW5jdGlvbigpe3Iubj1mdW5jdGlvbihvKXt2YXIgbj1vJiZvLl9fZXNNb2R1bGU/ZnVuY3Rpb24oKXtyZXR1cm4gby5kZWZhdWx0fTpmdW5jdGlvbigpe3JldHVybiBvfTtyZXR1cm4gci5kKG4se2E6bn0pLG59fSgpLGZ1bmN0aW9uKCl7ci5kPWZ1bmN0aW9uKG8sbil7Zm9yKHZhciBpIGluIG4pci5vKG4saSkmJiFyLm8obyxpKSYmT2JqZWN0LmRlZmluZVByb3BlcnR5KG8saSx7ZW51bWVyYWJsZTohMCxnZXQ6bltpXX0pfX0oKSxmdW5jdGlvbigpe3Iubz1mdW5jdGlvbihvLG4pe3JldHVybiBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwobyxuKX19KCkscig2ODYpfSgpLmRlZmF1bHR9KX0pO3ZhciBsTD1NdChsbygpKTt2YXIgd3I9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gd3I9T2JqZWN0LnNldFByb3RvdHlwZU9mfHx7X19wcm90b19fOltdfWluc3RhbmNlb2YgQXJyYXkmJmZ1bmN0aW9uKHIsbyl7ci5fX3Byb3RvX189b318fGZ1bmN0aW9uKHIsbyl7Zm9yKHZhciBuIGluIG8pT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG8sbikmJihyW25dPW9bbl0pfSx3cihlLHQpfTtmdW5jdGlvbiBvZShlLHQpe2lmKHR5cGVvZiB0IT0iZnVuY3Rpb24iJiZ0IT09bnVsbCl0aHJvdyBuZXcgVHlwZUVycm9yKCJDbGFzcyBleHRlbmRzIHZhbHVlICIrU3RyaW5nKHQpKyIgaXMgbm90IGEgY29uc3RydWN0b3Igb3IgbnVsbCIpO3dyKGUsdCk7ZnVuY3Rpb24gcigpe3RoaXMuY29uc3RydWN0b3I9ZX1lLnByb3RvdHlwZT10PT09bnVsbD9PYmplY3QuY3JlYXRlKHQpOihyLnByb3RvdHlwZT10LnByb3RvdHlwZSxuZXcgcil9ZnVuY3Rpb24gbW8oZSx0LHIsbyl7ZnVuY3Rpb24gbihpKXtyZXR1cm4gaSBpbnN0YW5jZW9mIHI/aTpuZXcgcihmdW5jdGlvbihhKXthKGkpfSl9cmV0dXJuIG5ldyhyfHwocj1Qcm9taXNlKSkoZnVuY3Rpb24oaSxhKXtmdW5jdGlvbiBzKGwpe3RyeXtjKG8ubmV4dChsKSl9Y2F0Y2goZil7YShmKX19ZnVuY3Rpb24gcChsKXt0cnl7YyhvLnRocm93KGwpKX1jYXRjaChmKXthKGYpfX1mdW5jdGlvbiBjKGwpe2wuZG9uZT9pKGwudmFsdWUpOm4obC52YWx1ZSkudGhlbihzLHApfWMoKG89by5hcHBseShlLHR8fFtdKSkubmV4dCgpKX0pfWZ1bmN0aW9uIE50KGUsdCl7dmFyIHI9e2xhYmVsOjAsc2VudDpmdW5jdGlvbigpe2lmKGlbMF0mMSl0aHJvdyBpWzFdO3JldHVybiBpWzFdfSx0cnlzOltdLG9wczpbXX0sbyxuLGksYT1PYmplY3QuY3JlYXRlKCh0eXBlb2YgSXRlcmF0b3I9PSJmdW5jdGlvbiI/SXRlcmF0b3I6T2JqZWN0KS5wcm90b3R5cGUpO3JldHVybiBhLm5leHQ9cygwKSxhLnRocm93PXMoMSksYS5yZXR1cm49cygyKSx0eXBlb2YgU3ltYm9sPT0iZnVuY3Rpb24iJiYoYVtTeW1ib2wuaXRlcmF0b3JdPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXN9KSxhO2Z1bmN0aW9uIHMoYyl7cmV0dXJuIGZ1bmN0aW9uKGwpe3JldHVybiBwKFtjLGxdKX19ZnVuY3Rpb24gcChjKXtpZihvKXRocm93IG5ldyBUeXBlRXJyb3IoIkdlbmVyYXRvciBpcyBhbHJlYWR5IGV4ZWN1dGluZy4iKTtmb3IoO2EmJihhPTAsY1swXSYmKHI9MCkpLHI7KXRyeXtpZihvPTEsbiYmKGk9Y1swXSYyP24ucmV0dXJuOmNbMF0/bi50aHJvd3x8KChpPW4ucmV0dXJuKSYmaS5jYWxsKG4pLDApOm4ubmV4dCkmJiEoaT1pLmNhbGwobixjWzFdKSkuZG9uZSlyZXR1cm4gaTtzd2l0Y2gobj0wLGkmJihjPVtjWzBdJjIsaS52YWx1ZV0pLGNbMF0pe2Nhc2UgMDpjYXNlIDE6aT1jO2JyZWFrO2Nhc2UgNDpyZXR1cm4gci5sYWJlbCsrLHt2YWx1ZTpjWzFdLGRvbmU6ITF9O2Nhc2UgNTpyLmxhYmVsKyssbj1jWzFdLGM9WzBdO2NvbnRpbnVlO2Nhc2UgNzpjPXIub3BzLnBvcCgpLHIudHJ5cy5wb3AoKTtjb250aW51ZTtkZWZhdWx0OmlmKGk9ci50cnlzLCEoaT1pLmxlbmd0aD4wJiZpW2kubGVuZ3RoLTFdKSYmKGNbMF09PT02fHxjWzBdPT09Mikpe3I9MDtjb250aW51ZX1pZihjWzBdPT09MyYmKCFpfHxjWzFdPmlbMF0mJmNbMV08aVszXSkpe3IubGFiZWw9Y1sxXTticmVha31pZihjWzBdPT09NiYmci5sYWJlbDxpWzFdKXtyLmxhYmVsPWlbMV0saT1jO2JyZWFrfWlmKGkmJnIubGFiZWw8aVsyXSl7ci5sYWJlbD1pWzJdLHIub3BzLnB1c2goYyk7YnJlYWt9aVsyXSYmci5vcHMucG9wKCksci50cnlzLnBvcCgpO2NvbnRpbnVlfWM9dC5jYWxsKGUscil9Y2F0Y2gobCl7Yz1bNixsXSxuPTB9ZmluYWxseXtvPWk9MH1pZihjWzBdJjUpdGhyb3cgY1sxXTtyZXR1cm57dmFsdWU6Y1swXT9jWzFdOnZvaWQgMCxkb25lOiEwfX19ZnVuY3Rpb24gaGUoZSl7dmFyIHQ9dHlwZW9mIFN5bWJvbD09ImZ1bmN0aW9uIiYmU3ltYm9sLml0ZXJhdG9yLHI9dCYmZVt0XSxvPTA7aWYocilyZXR1cm4gci5jYWxsKGUpO2lmKGUmJnR5cGVvZiBlLmxlbmd0aD09Im51bWJlciIpcmV0dXJue25leHQ6ZnVuY3Rpb24oKXtyZXR1cm4gZSYmbz49ZS5sZW5ndGgmJihlPXZvaWQgMCkse3ZhbHVlOmUmJmVbbysrXSxkb25lOiFlfX19O3Rocm93IG5ldyBUeXBlRXJyb3IodD8iT2JqZWN0IGlzIG5vdCBpdGVyYWJsZS4iOiJTeW1ib2wuaXRlcmF0b3IgaXMgbm90IGRlZmluZWQuIil9ZnVuY3Rpb24gTihlLHQpe3ZhciByPXR5cGVvZiBTeW1ib2w9PSJmdW5jdGlvbiImJmVbU3ltYm9sLml0ZXJhdG9yXTtpZighcilyZXR1cm4gZTt2YXIgbz1yLmNhbGwoZSksbixpPVtdLGE7dHJ5e2Zvcig7KHQ9PT12b2lkIDB8fHQtLSA+MCkmJiEobj1vLm5leHQoKSkuZG9uZTspaS5wdXNoKG4udmFsdWUpfWNhdGNoKHMpe2E9e2Vycm9yOnN9fWZpbmFsbHl7dHJ5e24mJiFuLmRvbmUmJihyPW8ucmV0dXJuKSYmci5jYWxsKG8pfWZpbmFsbHl7aWYoYSl0aHJvdyBhLmVycm9yfX1yZXR1cm4gaX1mdW5jdGlvbiBxKGUsdCxyKXtpZihyfHxhcmd1bWVudHMubGVuZ3RoPT09Milmb3IodmFyIG89MCxuPXQubGVuZ3RoLGk7bzxuO28rKykoaXx8IShvIGluIHQpKSYmKGl8fChpPUFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKHQsMCxvKSksaVtvXT10W29dKTtyZXR1cm4gZS5jb25jYXQoaXx8QXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwodCkpfWZ1bmN0aW9uIG50KGUpe3JldHVybiB0aGlzIGluc3RhbmNlb2YgbnQ/KHRoaXMudj1lLHRoaXMpOm5ldyBudChlKX1mdW5jdGlvbiBmbyhlLHQscil7aWYoIVN5bWJvbC5hc3luY0l0ZXJhdG9yKXRocm93IG5ldyBUeXBlRXJyb3IoIlN5bWJvbC5hc3luY0l0ZXJhdG9yIGlzIG5vdCBkZWZpbmVkLiIpO3ZhciBvPXIuYXBwbHkoZSx0fHxbXSksbixpPVtdO3JldHVybiBuPU9iamVjdC5jcmVhdGUoKHR5cGVvZiBBc3luY0l0ZXJhdG9yPT0iZnVuY3Rpb24iP0FzeW5jSXRlcmF0b3I6T2JqZWN0KS5wcm90b3R5cGUpLHMoIm5leHQiKSxzKCJ0aHJvdyIpLHMoInJldHVybiIsYSksbltTeW1ib2wuYXN5bmNJdGVyYXRvcl09ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc30sbjtmdW5jdGlvbiBhKGQpe3JldHVybiBmdW5jdGlvbih5KXtyZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHkpLnRoZW4oZCxmKX19ZnVuY3Rpb24gcyhkLHkpe29bZF0mJihuW2RdPWZ1bmN0aW9uKEwpe3JldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihYLHRlKXtpLnB1c2goW2QsTCxYLHRlXSk+MXx8cChkLEwpfSl9LHkmJihuW2RdPXkobltkXSkpKX1mdW5jdGlvbiBwKGQseSl7dHJ5e2Mob1tkXSh5KSl9Y2F0Y2goTCl7dShpWzBdWzNdLEwpfX1mdW5jdGlvbiBjKGQpe2QudmFsdWUgaW5zdGFuY2VvZiBudD9Qcm9taXNlLnJlc29sdmUoZC52YWx1ZS52KS50aGVuKGwsZik6dShpWzBdWzJdLGQpfWZ1bmN0aW9uIGwoZCl7cCgibmV4dCIsZCl9ZnVuY3Rpb24gZihkKXtwKCJ0aHJvdyIsZCl9ZnVuY3Rpb24gdShkLHkpe2QoeSksaS5zaGlmdCgpLGkubGVuZ3RoJiZwKGlbMF1bMF0saVswXVsxXSl9fWZ1bmN0aW9uIHVvKGUpe2lmKCFTeW1ib2wuYXN5bmNJdGVyYXRvcil0aHJvdyBuZXcgVHlwZUVycm9yKCJTeW1ib2wuYXN5bmNJdGVyYXRvciBpcyBub3QgZGVmaW5lZC4iKTt2YXIgdD1lW1N5bWJvbC5hc3luY0l0ZXJhdG9yXSxyO3JldHVybiB0P3QuY2FsbChlKTooZT10eXBlb2YgaGU9PSJmdW5jdGlvbiI/aGUoZSk6ZVtTeW1ib2wuaXRlcmF0b3JdKCkscj17fSxvKCJuZXh0IiksbygidGhyb3ciKSxvKCJyZXR1cm4iKSxyW1N5bWJvbC5hc3luY0l0ZXJhdG9yXT1mdW5jdGlvbigpe3JldHVybiB0aGlzfSxyKTtmdW5jdGlvbiBvKGkpe3JbaV09ZVtpXSYmZnVuY3Rpb24oYSl7cmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHMscCl7YT1lW2ldKGEpLG4ocyxwLGEuZG9uZSxhLnZhbHVlKX0pfX1mdW5jdGlvbiBuKGksYSxzLHApe1Byb21pc2UucmVzb2x2ZShwKS50aGVuKGZ1bmN0aW9uKGMpe2koe3ZhbHVlOmMsZG9uZTpzfSl9LGEpfX1mdW5jdGlvbiBIKGUpe3JldHVybiB0eXBlb2YgZT09ImZ1bmN0aW9uIn1mdW5jdGlvbiB1dChlKXt2YXIgdD1mdW5jdGlvbihvKXtFcnJvci5jYWxsKG8pLG8uc3RhY2s9bmV3IEVycm9yKCkuc3RhY2t9LHI9ZSh0KTtyZXR1cm4gci5wcm90b3R5cGU9T2JqZWN0LmNyZWF0ZShFcnJvci5wcm90b3R5cGUpLHIucHJvdG90eXBlLmNvbnN0cnVjdG9yPXIscn12YXIgenQ9dXQoZnVuY3Rpb24oZSl7cmV0dXJuIGZ1bmN0aW9uKHIpe2UodGhpcyksdGhpcy5tZXNzYWdlPXI/ci5sZW5ndGgrYCBlcnJvcnMgb2NjdXJyZWQgZHVyaW5nIHVuc3Vic2NyaXB0aW9uOgpgK3IubWFwKGZ1bmN0aW9uKG8sbil7cmV0dXJuIG4rMSsiKSAiK28udG9TdHJpbmcoKX0pLmpvaW4oYAogIGApOiIiLHRoaXMubmFtZT0iVW5zdWJzY3JpcHRpb25FcnJvciIsdGhpcy5lcnJvcnM9cn19KTtmdW5jdGlvbiBRZShlLHQpe2lmKGUpe3ZhciByPWUuaW5kZXhPZih0KTswPD1yJiZlLnNwbGljZShyLDEpfX12YXIgVWU9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKHQpe3RoaXMuaW5pdGlhbFRlYXJkb3duPXQsdGhpcy5jbG9zZWQ9ITEsdGhpcy5fcGFyZW50YWdlPW51bGwsdGhpcy5fZmluYWxpemVycz1udWxsfXJldHVybiBlLnByb3RvdHlwZS51bnN1YnNjcmliZT1mdW5jdGlvbigpe3ZhciB0LHIsbyxuLGk7aWYoIXRoaXMuY2xvc2VkKXt0aGlzLmNsb3NlZD0hMDt2YXIgYT10aGlzLl9wYXJlbnRhZ2U7aWYoYSlpZih0aGlzLl9wYXJlbnRhZ2U9bnVsbCxBcnJheS5pc0FycmF5KGEpKXRyeXtmb3IodmFyIHM9aGUoYSkscD1zLm5leHQoKTshcC5kb25lO3A9cy5uZXh0KCkpe3ZhciBjPXAudmFsdWU7Yy5yZW1vdmUodGhpcyl9fWNhdGNoKEwpe3Q9e2Vycm9yOkx9fWZpbmFsbHl7dHJ5e3AmJiFwLmRvbmUmJihyPXMucmV0dXJuKSYmci5jYWxsKHMpfWZpbmFsbHl7aWYodCl0aHJvdyB0LmVycm9yfX1lbHNlIGEucmVtb3ZlKHRoaXMpO3ZhciBsPXRoaXMuaW5pdGlhbFRlYXJkb3duO2lmKEgobCkpdHJ5e2woKX1jYXRjaChMKXtpPUwgaW5zdGFuY2VvZiB6dD9MLmVycm9yczpbTF19dmFyIGY9dGhpcy5fZmluYWxpemVycztpZihmKXt0aGlzLl9maW5hbGl6ZXJzPW51bGw7dHJ5e2Zvcih2YXIgdT1oZShmKSxkPXUubmV4dCgpOyFkLmRvbmU7ZD11Lm5leHQoKSl7dmFyIHk9ZC52YWx1ZTt0cnl7aG8oeSl9Y2F0Y2goTCl7aT1pIT1udWxsP2k6W10sTCBpbnN0YW5jZW9mIHp0P2k9cShxKFtdLE4oaSkpLE4oTC5lcnJvcnMpKTppLnB1c2goTCl9fX1jYXRjaChMKXtvPXtlcnJvcjpMfX1maW5hbGx5e3RyeXtkJiYhZC5kb25lJiYobj11LnJldHVybikmJm4uY2FsbCh1KX1maW5hbGx5e2lmKG8pdGhyb3cgby5lcnJvcn19fWlmKGkpdGhyb3cgbmV3IHp0KGkpfX0sZS5wcm90b3R5cGUuYWRkPWZ1bmN0aW9uKHQpe3ZhciByO2lmKHQmJnQhPT10aGlzKWlmKHRoaXMuY2xvc2VkKWhvKHQpO2Vsc2V7aWYodCBpbnN0YW5jZW9mIGUpe2lmKHQuY2xvc2VkfHx0Ll9oYXNQYXJlbnQodGhpcykpcmV0dXJuO3QuX2FkZFBhcmVudCh0aGlzKX0odGhpcy5fZmluYWxpemVycz0ocj10aGlzLl9maW5hbGl6ZXJzKSE9PW51bGwmJnIhPT12b2lkIDA/cjpbXSkucHVzaCh0KX19LGUucHJvdG90eXBlLl9oYXNQYXJlbnQ9ZnVuY3Rpb24odCl7dmFyIHI9dGhpcy5fcGFyZW50YWdlO3JldHVybiByPT09dHx8QXJyYXkuaXNBcnJheShyKSYmci5pbmNsdWRlcyh0KX0sZS5wcm90b3R5cGUuX2FkZFBhcmVudD1mdW5jdGlvbih0KXt2YXIgcj10aGlzLl9wYXJlbnRhZ2U7dGhpcy5fcGFyZW50YWdlPUFycmF5LmlzQXJyYXkocik/KHIucHVzaCh0KSxyKTpyP1tyLHRdOnR9LGUucHJvdG90eXBlLl9yZW1vdmVQYXJlbnQ9ZnVuY3Rpb24odCl7dmFyIHI9dGhpcy5fcGFyZW50YWdlO3I9PT10P3RoaXMuX3BhcmVudGFnZT1udWxsOkFycmF5LmlzQXJyYXkocikmJlFlKHIsdCl9LGUucHJvdG90eXBlLnJlbW92ZT1mdW5jdGlvbih0KXt2YXIgcj10aGlzLl9maW5hbGl6ZXJzO3ImJlFlKHIsdCksdCBpbnN0YW5jZW9mIGUmJnQuX3JlbW92ZVBhcmVudCh0aGlzKX0sZS5FTVBUWT1mdW5jdGlvbigpe3ZhciB0PW5ldyBlO3JldHVybiB0LmNsb3NlZD0hMCx0fSgpLGV9KCk7dmFyIFRyPVVlLkVNUFRZO2Z1bmN0aW9uIHF0KGUpe3JldHVybiBlIGluc3RhbmNlb2YgVWV8fGUmJiJjbG9zZWQiaW4gZSYmSChlLnJlbW92ZSkmJkgoZS5hZGQpJiZIKGUudW5zdWJzY3JpYmUpfWZ1bmN0aW9uIGhvKGUpe0goZSk/ZSgpOmUudW5zdWJzY3JpYmUoKX12YXIgUGU9e29uVW5oYW5kbGVkRXJyb3I6bnVsbCxvblN0b3BwZWROb3RpZmljYXRpb246bnVsbCxQcm9taXNlOnZvaWQgMCx1c2VEZXByZWNhdGVkU3luY2hyb25vdXNFcnJvckhhbmRsaW5nOiExLHVzZURlcHJlY2F0ZWROZXh0Q29udGV4dDohMX07dmFyIGR0PXtzZXRUaW1lb3V0OmZ1bmN0aW9uKGUsdCl7Zm9yKHZhciByPVtdLG89MjtvPGFyZ3VtZW50cy5sZW5ndGg7bysrKXJbby0yXT1hcmd1bWVudHNbb107dmFyIG49ZHQuZGVsZWdhdGU7cmV0dXJuIG4hPW51bGwmJm4uc2V0VGltZW91dD9uLnNldFRpbWVvdXQuYXBwbHkobixxKFtlLHRdLE4ocikpKTpzZXRUaW1lb3V0LmFwcGx5KHZvaWQgMCxxKFtlLHRdLE4ocikpKX0sY2xlYXJUaW1lb3V0OmZ1bmN0aW9uKGUpe3ZhciB0PWR0LmRlbGVnYXRlO3JldHVybigodD09bnVsbD92b2lkIDA6dC5jbGVhclRpbWVvdXQpfHxjbGVhclRpbWVvdXQpKGUpfSxkZWxlZ2F0ZTp2b2lkIDB9O2Z1bmN0aW9uIFF0KGUpe2R0LnNldFRpbWVvdXQoZnVuY3Rpb24oKXt2YXIgdD1QZS5vblVuaGFuZGxlZEVycm9yO2lmKHQpdChlKTtlbHNlIHRocm93IGV9KX1mdW5jdGlvbiBiZSgpe312YXIgYm89ZnVuY3Rpb24oKXtyZXR1cm4gU3IoIkMiLHZvaWQgMCx2b2lkIDApfSgpO2Z1bmN0aW9uIHZvKGUpe3JldHVybiBTcigiRSIsdm9pZCAwLGUpfWZ1bmN0aW9uIGdvKGUpe3JldHVybiBTcigiTiIsZSx2b2lkIDApfWZ1bmN0aW9uIFNyKGUsdCxyKXtyZXR1cm57a2luZDplLHZhbHVlOnQsZXJyb3I6cn19dmFyIGl0PW51bGw7ZnVuY3Rpb24gaHQoZSl7aWYoUGUudXNlRGVwcmVjYXRlZFN5bmNocm9ub3VzRXJyb3JIYW5kbGluZyl7dmFyIHQ9IWl0O2lmKHQmJihpdD17ZXJyb3JUaHJvd246ITEsZXJyb3I6bnVsbH0pLGUoKSx0KXt2YXIgcj1pdCxvPXIuZXJyb3JUaHJvd24sbj1yLmVycm9yO2lmKGl0PW51bGwsbyl0aHJvdyBufX1lbHNlIGUoKX1mdW5jdGlvbiB5byhlKXtQZS51c2VEZXByZWNhdGVkU3luY2hyb25vdXNFcnJvckhhbmRsaW5nJiZpdCYmKGl0LmVycm9yVGhyb3duPSEwLGl0LmVycm9yPWUpfXZhciBfdD1mdW5jdGlvbihlKXtvZSh0LGUpO2Z1bmN0aW9uIHQocil7dmFyIG89ZS5jYWxsKHRoaXMpfHx0aGlzO3JldHVybiBvLmlzU3RvcHBlZD0hMSxyPyhvLmRlc3RpbmF0aW9uPXIscXQocikmJnIuYWRkKG8pKTpvLmRlc3RpbmF0aW9uPVlpLG99cmV0dXJuIHQuY3JlYXRlPWZ1bmN0aW9uKHIsbyxuKXtyZXR1cm4gbmV3IGF0KHIsbyxuKX0sdC5wcm90b3R5cGUubmV4dD1mdW5jdGlvbihyKXt0aGlzLmlzU3RvcHBlZD9McihnbyhyKSx0aGlzKTp0aGlzLl9uZXh0KHIpfSx0LnByb3RvdHlwZS5lcnJvcj1mdW5jdGlvbihyKXt0aGlzLmlzU3RvcHBlZD9Mcih2byhyKSx0aGlzKToodGhpcy5pc1N0b3BwZWQ9ITAsdGhpcy5fZXJyb3IocikpfSx0LnByb3RvdHlwZS5jb21wbGV0ZT1mdW5jdGlvbigpe3RoaXMuaXNTdG9wcGVkP0xyKGJvLHRoaXMpOih0aGlzLmlzU3RvcHBlZD0hMCx0aGlzLl9jb21wbGV0ZSgpKX0sdC5wcm90b3R5cGUudW5zdWJzY3JpYmU9ZnVuY3Rpb24oKXt0aGlzLmNsb3NlZHx8KHRoaXMuaXNTdG9wcGVkPSEwLGUucHJvdG90eXBlLnVuc3Vic2NyaWJlLmNhbGwodGhpcyksdGhpcy5kZXN0aW5hdGlvbj1udWxsKX0sdC5wcm90b3R5cGUuX25leHQ9ZnVuY3Rpb24ocil7dGhpcy5kZXN0aW5hdGlvbi5uZXh0KHIpfSx0LnByb3RvdHlwZS5fZXJyb3I9ZnVuY3Rpb24ocil7dHJ5e3RoaXMuZGVzdGluYXRpb24uZXJyb3Iocil9ZmluYWxseXt0aGlzLnVuc3Vic2NyaWJlKCl9fSx0LnByb3RvdHlwZS5fY29tcGxldGU9ZnVuY3Rpb24oKXt0cnl7dGhpcy5kZXN0aW5hdGlvbi5jb21wbGV0ZSgpfWZpbmFsbHl7dGhpcy51bnN1YnNjcmliZSgpfX0sdH0oVWUpO3ZhciBxaT1GdW5jdGlvbi5wcm90b3R5cGUuYmluZDtmdW5jdGlvbiBPcihlLHQpe3JldHVybiBxaS5jYWxsKGUsdCl9dmFyIFFpPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZSh0KXt0aGlzLnBhcnRpYWxPYnNlcnZlcj10fXJldHVybiBlLnByb3RvdHlwZS5uZXh0PWZ1bmN0aW9uKHQpe3ZhciByPXRoaXMucGFydGlhbE9ic2VydmVyO2lmKHIubmV4dCl0cnl7ci5uZXh0KHQpfWNhdGNoKG8pe0t0KG8pfX0sZS5wcm90b3R5cGUuZXJyb3I9ZnVuY3Rpb24odCl7dmFyIHI9dGhpcy5wYXJ0aWFsT2JzZXJ2ZXI7aWYoci5lcnJvcil0cnl7ci5lcnJvcih0KX1jYXRjaChvKXtLdChvKX1lbHNlIEt0KHQpfSxlLnByb3RvdHlwZS5jb21wbGV0ZT1mdW5jdGlvbigpe3ZhciB0PXRoaXMucGFydGlhbE9ic2VydmVyO2lmKHQuY29tcGxldGUpdHJ5e3QuY29tcGxldGUoKX1jYXRjaChyKXtLdChyKX19LGV9KCksYXQ9ZnVuY3Rpb24oZSl7b2UodCxlKTtmdW5jdGlvbiB0KHIsbyxuKXt2YXIgaT1lLmNhbGwodGhpcyl8fHRoaXMsYTtpZihIKHIpfHwhcilhPXtuZXh0OnIhPW51bGw/cjp2b2lkIDAsZXJyb3I6byE9bnVsbD9vOnZvaWQgMCxjb21wbGV0ZTpuIT1udWxsP246dm9pZCAwfTtlbHNle3ZhciBzO2kmJlBlLnVzZURlcHJlY2F0ZWROZXh0Q29udGV4dD8ocz1PYmplY3QuY3JlYXRlKHIpLHMudW5zdWJzY3JpYmU9ZnVuY3Rpb24oKXtyZXR1cm4gaS51bnN1YnNjcmliZSgpfSxhPXtuZXh0OnIubmV4dCYmT3Ioci5uZXh0LHMpLGVycm9yOnIuZXJyb3ImJk9yKHIuZXJyb3IscyksY29tcGxldGU6ci5jb21wbGV0ZSYmT3Ioci5jb21wbGV0ZSxzKX0pOmE9cn1yZXR1cm4gaS5kZXN0aW5hdGlvbj1uZXcgUWkoYSksaX1yZXR1cm4gdH0oX3QpO2Z1bmN0aW9uIEt0KGUpe1BlLnVzZURlcHJlY2F0ZWRTeW5jaHJvbm91c0Vycm9ySGFuZGxpbmc/eW8oZSk6UXQoZSl9ZnVuY3Rpb24gS2koZSl7dGhyb3cgZX1mdW5jdGlvbiBMcihlLHQpe3ZhciByPVBlLm9uU3RvcHBlZE5vdGlmaWNhdGlvbjtyJiZkdC5zZXRUaW1lb3V0KGZ1bmN0aW9uKCl7cmV0dXJuIHIoZSx0KX0pfXZhciBZaT17Y2xvc2VkOiEwLG5leHQ6YmUsZXJyb3I6S2ksY29tcGxldGU6YmV9O3ZhciBidD1mdW5jdGlvbigpe3JldHVybiB0eXBlb2YgU3ltYm9sPT0iZnVuY3Rpb24iJiZTeW1ib2wub2JzZXJ2YWJsZXx8IkBAb2JzZXJ2YWJsZSJ9KCk7ZnVuY3Rpb24gbGUoZSl7cmV0dXJuIGV9ZnVuY3Rpb24geG8oKXtmb3IodmFyIGU9W10sdD0wO3Q8YXJndW1lbnRzLmxlbmd0aDt0KyspZVt0XT1hcmd1bWVudHNbdF07cmV0dXJuIE1yKGUpfWZ1bmN0aW9uIE1yKGUpe3JldHVybiBlLmxlbmd0aD09PTA/bGU6ZS5sZW5ndGg9PT0xP2VbMF06ZnVuY3Rpb24ocil7cmV0dXJuIGUucmVkdWNlKGZ1bmN0aW9uKG8sbil7cmV0dXJuIG4obyl9LHIpfX12YXIgaj1mdW5jdGlvbigpe2Z1bmN0aW9uIGUodCl7dCYmKHRoaXMuX3N1YnNjcmliZT10KX1yZXR1cm4gZS5wcm90b3R5cGUubGlmdD1mdW5jdGlvbih0KXt2YXIgcj1uZXcgZTtyZXR1cm4gci5zb3VyY2U9dGhpcyxyLm9wZXJhdG9yPXQscn0sZS5wcm90b3R5cGUuc3Vic2NyaWJlPWZ1bmN0aW9uKHQscixvKXt2YXIgbj10aGlzLGk9R2kodCk/dDpuZXcgYXQodCxyLG8pO3JldHVybiBodChmdW5jdGlvbigpe3ZhciBhPW4scz1hLm9wZXJhdG9yLHA9YS5zb3VyY2U7aS5hZGQocz9zLmNhbGwoaSxwKTpwP24uX3N1YnNjcmliZShpKTpuLl90cnlTdWJzY3JpYmUoaSkpfSksaX0sZS5wcm90b3R5cGUuX3RyeVN1YnNjcmliZT1mdW5jdGlvbih0KXt0cnl7cmV0dXJuIHRoaXMuX3N1YnNjcmliZSh0KX1jYXRjaChyKXt0LmVycm9yKHIpfX0sZS5wcm90b3R5cGUuZm9yRWFjaD1mdW5jdGlvbih0LHIpe3ZhciBvPXRoaXM7cmV0dXJuIHI9RW8ociksbmV3IHIoZnVuY3Rpb24obixpKXt2YXIgYT1uZXcgYXQoe25leHQ6ZnVuY3Rpb24ocyl7dHJ5e3Qocyl9Y2F0Y2gocCl7aShwKSxhLnVuc3Vic2NyaWJlKCl9fSxlcnJvcjppLGNvbXBsZXRlOm59KTtvLnN1YnNjcmliZShhKX0pfSxlLnByb3RvdHlwZS5fc3Vic2NyaWJlPWZ1bmN0aW9uKHQpe3ZhciByO3JldHVybihyPXRoaXMuc291cmNlKT09PW51bGx8fHI9PT12b2lkIDA/dm9pZCAwOnIuc3Vic2NyaWJlKHQpfSxlLnByb3RvdHlwZVtidF09ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc30sZS5wcm90b3R5cGUucGlwZT1mdW5jdGlvbigpe2Zvcih2YXIgdD1bXSxyPTA7cjxhcmd1bWVudHMubGVuZ3RoO3IrKyl0W3JdPWFyZ3VtZW50c1tyXTtyZXR1cm4gTXIodCkodGhpcyl9LGUucHJvdG90eXBlLnRvUHJvbWlzZT1mdW5jdGlvbih0KXt2YXIgcj10aGlzO3JldHVybiB0PUVvKHQpLG5ldyB0KGZ1bmN0aW9uKG8sbil7dmFyIGk7ci5zdWJzY3JpYmUoZnVuY3Rpb24oYSl7cmV0dXJuIGk9YX0sZnVuY3Rpb24oYSl7cmV0dXJuIG4oYSl9LGZ1bmN0aW9uKCl7cmV0dXJuIG8oaSl9KX0pfSxlLmNyZWF0ZT1mdW5jdGlvbih0KXtyZXR1cm4gbmV3IGUodCl9LGV9KCk7ZnVuY3Rpb24gRW8oZSl7dmFyIHQ7cmV0dXJuKHQ9ZSE9bnVsbD9lOlBlLlByb21pc2UpIT09bnVsbCYmdCE9PXZvaWQgMD90OlByb21pc2V9ZnVuY3Rpb24gQmkoZSl7cmV0dXJuIGUmJkgoZS5uZXh0KSYmSChlLmVycm9yKSYmSChlLmNvbXBsZXRlKX1mdW5jdGlvbiBHaShlKXtyZXR1cm4gZSYmZSBpbnN0YW5jZW9mIF90fHxCaShlKSYmcXQoZSl9ZnVuY3Rpb24gSmkoZSl7cmV0dXJuIEgoZT09bnVsbD92b2lkIDA6ZS5saWZ0KX1mdW5jdGlvbiBFKGUpe3JldHVybiBmdW5jdGlvbih0KXtpZihKaSh0KSlyZXR1cm4gdC5saWZ0KGZ1bmN0aW9uKHIpe3RyeXtyZXR1cm4gZShyLHRoaXMpfWNhdGNoKG8pe3RoaXMuZXJyb3Iobyl9fSk7dGhyb3cgbmV3IFR5cGVFcnJvcigiVW5hYmxlIHRvIGxpZnQgdW5rbm93biBPYnNlcnZhYmxlIHR5cGUiKX19ZnVuY3Rpb24gVChlLHQscixvLG4pe3JldHVybiBuZXcgWGkoZSx0LHIsbyxuKX12YXIgWGk9ZnVuY3Rpb24oZSl7b2UodCxlKTtmdW5jdGlvbiB0KHIsbyxuLGksYSxzKXt2YXIgcD1lLmNhbGwodGhpcyxyKXx8dGhpcztyZXR1cm4gcC5vbkZpbmFsaXplPWEscC5zaG91bGRVbnN1YnNjcmliZT1zLHAuX25leHQ9bz9mdW5jdGlvbihjKXt0cnl7byhjKX1jYXRjaChsKXtyLmVycm9yKGwpfX06ZS5wcm90b3R5cGUuX25leHQscC5fZXJyb3I9aT9mdW5jdGlvbihjKXt0cnl7aShjKX1jYXRjaChsKXtyLmVycm9yKGwpfWZpbmFsbHl7dGhpcy51bnN1YnNjcmliZSgpfX06ZS5wcm90b3R5cGUuX2Vycm9yLHAuX2NvbXBsZXRlPW4/ZnVuY3Rpb24oKXt0cnl7bigpfWNhdGNoKGMpe3IuZXJyb3IoYyl9ZmluYWxseXt0aGlzLnVuc3Vic2NyaWJlKCl9fTplLnByb3RvdHlwZS5fY29tcGxldGUscH1yZXR1cm4gdC5wcm90b3R5cGUudW5zdWJzY3JpYmU9ZnVuY3Rpb24oKXt2YXIgcjtpZighdGhpcy5zaG91bGRVbnN1YnNjcmliZXx8dGhpcy5zaG91bGRVbnN1YnNjcmliZSgpKXt2YXIgbz10aGlzLmNsb3NlZDtlLnByb3RvdHlwZS51bnN1YnNjcmliZS5jYWxsKHRoaXMpLCFvJiYoKHI9dGhpcy5vbkZpbmFsaXplKT09PW51bGx8fHI9PT12b2lkIDB8fHIuY2FsbCh0aGlzKSl9fSx0fShfdCk7dmFyIHZ0PXtzY2hlZHVsZTpmdW5jdGlvbihlKXt2YXIgdD1yZXF1ZXN0QW5pbWF0aW9uRnJhbWUscj1jYW5jZWxBbmltYXRpb25GcmFtZSxvPXZ0LmRlbGVnYXRlO28mJih0PW8ucmVxdWVzdEFuaW1hdGlvbkZyYW1lLHI9by5jYW5jZWxBbmltYXRpb25GcmFtZSk7dmFyIG49dChmdW5jdGlvbihpKXtyPXZvaWQgMCxlKGkpfSk7cmV0dXJuIG5ldyBVZShmdW5jdGlvbigpe3JldHVybiByPT1udWxsP3ZvaWQgMDpyKG4pfSl9LHJlcXVlc3RBbmltYXRpb25GcmFtZTpmdW5jdGlvbigpe2Zvcih2YXIgZT1bXSx0PTA7dDxhcmd1bWVudHMubGVuZ3RoO3QrKyllW3RdPWFyZ3VtZW50c1t0XTt2YXIgcj12dC5kZWxlZ2F0ZTtyZXR1cm4oKHI9PW51bGw/dm9pZCAwOnIucmVxdWVzdEFuaW1hdGlvbkZyYW1lKXx8cmVxdWVzdEFuaW1hdGlvbkZyYW1lKS5hcHBseSh2b2lkIDAscShbXSxOKGUpKSl9LGNhbmNlbEFuaW1hdGlvbkZyYW1lOmZ1bmN0aW9uKCl7Zm9yKHZhciBlPVtdLHQ9MDt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKWVbdF09YXJndW1lbnRzW3RdO3ZhciByPXZ0LmRlbGVnYXRlO3JldHVybigocj09bnVsbD92b2lkIDA6ci5jYW5jZWxBbmltYXRpb25GcmFtZSl8fGNhbmNlbEFuaW1hdGlvbkZyYW1lKS5hcHBseSh2b2lkIDAscShbXSxOKGUpKSl9LGRlbGVnYXRlOnZvaWQgMH07dmFyIHdvPXV0KGZ1bmN0aW9uKGUpe3JldHVybiBmdW5jdGlvbigpe2UodGhpcyksdGhpcy5uYW1lPSJPYmplY3RVbnN1YnNjcmliZWRFcnJvciIsdGhpcy5tZXNzYWdlPSJvYmplY3QgdW5zdWJzY3JpYmVkIn19KTt2YXIgZz1mdW5jdGlvbihlKXtvZSh0LGUpO2Z1bmN0aW9uIHQoKXt2YXIgcj1lLmNhbGwodGhpcyl8fHRoaXM7cmV0dXJuIHIuY2xvc2VkPSExLHIuY3VycmVudE9ic2VydmVycz1udWxsLHIub2JzZXJ2ZXJzPVtdLHIuaXNTdG9wcGVkPSExLHIuaGFzRXJyb3I9ITEsci50aHJvd25FcnJvcj1udWxsLHJ9cmV0dXJuIHQucHJvdG90eXBlLmxpZnQ9ZnVuY3Rpb24ocil7dmFyIG89bmV3IFRvKHRoaXMsdGhpcyk7cmV0dXJuIG8ub3BlcmF0b3I9cixvfSx0LnByb3RvdHlwZS5fdGhyb3dJZkNsb3NlZD1mdW5jdGlvbigpe2lmKHRoaXMuY2xvc2VkKXRocm93IG5ldyB3b30sdC5wcm90b3R5cGUubmV4dD1mdW5jdGlvbihyKXt2YXIgbz10aGlzO2h0KGZ1bmN0aW9uKCl7dmFyIG4saTtpZihvLl90aHJvd0lmQ2xvc2VkKCksIW8uaXNTdG9wcGVkKXtvLmN1cnJlbnRPYnNlcnZlcnN8fChvLmN1cnJlbnRPYnNlcnZlcnM9QXJyYXkuZnJvbShvLm9ic2VydmVycykpO3RyeXtmb3IodmFyIGE9aGUoby5jdXJyZW50T2JzZXJ2ZXJzKSxzPWEubmV4dCgpOyFzLmRvbmU7cz1hLm5leHQoKSl7dmFyIHA9cy52YWx1ZTtwLm5leHQocil9fWNhdGNoKGMpe249e2Vycm9yOmN9fWZpbmFsbHl7dHJ5e3MmJiFzLmRvbmUmJihpPWEucmV0dXJuKSYmaS5jYWxsKGEpfWZpbmFsbHl7aWYobil0aHJvdyBuLmVycm9yfX19fSl9LHQucHJvdG90eXBlLmVycm9yPWZ1bmN0aW9uKHIpe3ZhciBvPXRoaXM7aHQoZnVuY3Rpb24oKXtpZihvLl90aHJvd0lmQ2xvc2VkKCksIW8uaXNTdG9wcGVkKXtvLmhhc0Vycm9yPW8uaXNTdG9wcGVkPSEwLG8udGhyb3duRXJyb3I9cjtmb3IodmFyIG49by5vYnNlcnZlcnM7bi5sZW5ndGg7KW4uc2hpZnQoKS5lcnJvcihyKX19KX0sdC5wcm90b3R5cGUuY29tcGxldGU9ZnVuY3Rpb24oKXt2YXIgcj10aGlzO2h0KGZ1bmN0aW9uKCl7aWYoci5fdGhyb3dJZkNsb3NlZCgpLCFyLmlzU3RvcHBlZCl7ci5pc1N0b3BwZWQ9ITA7Zm9yKHZhciBvPXIub2JzZXJ2ZXJzO28ubGVuZ3RoOylvLnNoaWZ0KCkuY29tcGxldGUoKX19KX0sdC5wcm90b3R5cGUudW5zdWJzY3JpYmU9ZnVuY3Rpb24oKXt0aGlzLmlzU3RvcHBlZD10aGlzLmNsb3NlZD0hMCx0aGlzLm9ic2VydmVycz10aGlzLmN1cnJlbnRPYnNlcnZlcnM9bnVsbH0sT2JqZWN0LmRlZmluZVByb3BlcnR5KHQucHJvdG90eXBlLCJvYnNlcnZlZCIse2dldDpmdW5jdGlvbigpe3ZhciByO3JldHVybigocj10aGlzLm9ic2VydmVycyk9PT1udWxsfHxyPT09dm9pZCAwP3ZvaWQgMDpyLmxlbmd0aCk+MH0sZW51bWVyYWJsZTohMSxjb25maWd1cmFibGU6ITB9KSx0LnByb3RvdHlwZS5fdHJ5U3Vic2NyaWJlPWZ1bmN0aW9uKHIpe3JldHVybiB0aGlzLl90aHJvd0lmQ2xvc2VkKCksZS5wcm90b3R5cGUuX3RyeVN1YnNjcmliZS5jYWxsKHRoaXMscil9LHQucHJvdG90eXBlLl9zdWJzY3JpYmU9ZnVuY3Rpb24ocil7cmV0dXJuIHRoaXMuX3Rocm93SWZDbG9zZWQoKSx0aGlzLl9jaGVja0ZpbmFsaXplZFN0YXR1c2VzKHIpLHRoaXMuX2lubmVyU3Vic2NyaWJlKHIpfSx0LnByb3RvdHlwZS5faW5uZXJTdWJzY3JpYmU9ZnVuY3Rpb24ocil7dmFyIG89dGhpcyxuPXRoaXMsaT1uLmhhc0Vycm9yLGE9bi5pc1N0b3BwZWQscz1uLm9ic2VydmVycztyZXR1cm4gaXx8YT9UcjoodGhpcy5jdXJyZW50T2JzZXJ2ZXJzPW51bGwscy5wdXNoKHIpLG5ldyBVZShmdW5jdGlvbigpe28uY3VycmVudE9ic2VydmVycz1udWxsLFFlKHMscil9KSl9LHQucHJvdG90eXBlLl9jaGVja0ZpbmFsaXplZFN0YXR1c2VzPWZ1bmN0aW9uKHIpe3ZhciBvPXRoaXMsbj1vLmhhc0Vycm9yLGk9by50aHJvd25FcnJvcixhPW8uaXNTdG9wcGVkO24/ci5lcnJvcihpKTphJiZyLmNvbXBsZXRlKCl9LHQucHJvdG90eXBlLmFzT2JzZXJ2YWJsZT1mdW5jdGlvbigpe3ZhciByPW5ldyBqO3JldHVybiByLnNvdXJjZT10aGlzLHJ9LHQuY3JlYXRlPWZ1bmN0aW9uKHIsbyl7cmV0dXJuIG5ldyBUbyhyLG8pfSx0fShqKTt2YXIgVG89ZnVuY3Rpb24oZSl7b2UodCxlKTtmdW5jdGlvbiB0KHIsbyl7dmFyIG49ZS5jYWxsKHRoaXMpfHx0aGlzO3JldHVybiBuLmRlc3RpbmF0aW9uPXIsbi5zb3VyY2U9byxufXJldHVybiB0LnByb3RvdHlwZS5uZXh0PWZ1bmN0aW9uKHIpe3ZhciBvLG47KG49KG89dGhpcy5kZXN0aW5hdGlvbik9PT1udWxsfHxvPT09dm9pZCAwP3ZvaWQgMDpvLm5leHQpPT09bnVsbHx8bj09PXZvaWQgMHx8bi5jYWxsKG8scil9LHQucHJvdG90eXBlLmVycm9yPWZ1bmN0aW9uKHIpe3ZhciBvLG47KG49KG89dGhpcy5kZXN0aW5hdGlvbik9PT1udWxsfHxvPT09dm9pZCAwP3ZvaWQgMDpvLmVycm9yKT09PW51bGx8fG49PT12b2lkIDB8fG4uY2FsbChvLHIpfSx0LnByb3RvdHlwZS5jb21wbGV0ZT1mdW5jdGlvbigpe3ZhciByLG87KG89KHI9dGhpcy5kZXN0aW5hdGlvbik9PT1udWxsfHxyPT09dm9pZCAwP3ZvaWQgMDpyLmNvbXBsZXRlKT09PW51bGx8fG89PT12b2lkIDB8fG8uY2FsbChyKX0sdC5wcm90b3R5cGUuX3N1YnNjcmliZT1mdW5jdGlvbihyKXt2YXIgbyxuO3JldHVybihuPShvPXRoaXMuc291cmNlKT09PW51bGx8fG89PT12b2lkIDA/dm9pZCAwOm8uc3Vic2NyaWJlKHIpKSE9PW51bGwmJm4hPT12b2lkIDA/bjpUcn0sdH0oZyk7dmFyIF9yPWZ1bmN0aW9uKGUpe29lKHQsZSk7ZnVuY3Rpb24gdChyKXt2YXIgbz1lLmNhbGwodGhpcyl8fHRoaXM7cmV0dXJuIG8uX3ZhbHVlPXIsb31yZXR1cm4gT2JqZWN0LmRlZmluZVByb3BlcnR5KHQucHJvdG90eXBlLCJ2YWx1ZSIse2dldDpmdW5jdGlvbigpe3JldHVybiB0aGlzLmdldFZhbHVlKCl9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksdC5wcm90b3R5cGUuX3N1YnNjcmliZT1mdW5jdGlvbihyKXt2YXIgbz1lLnByb3RvdHlwZS5fc3Vic2NyaWJlLmNhbGwodGhpcyxyKTtyZXR1cm4hby5jbG9zZWQmJnIubmV4dCh0aGlzLl92YWx1ZSksb30sdC5wcm90b3R5cGUuZ2V0VmFsdWU9ZnVuY3Rpb24oKXt2YXIgcj10aGlzLG89ci5oYXNFcnJvcixuPXIudGhyb3duRXJyb3IsaT1yLl92YWx1ZTtpZihvKXRocm93IG47cmV0dXJuIHRoaXMuX3Rocm93SWZDbG9zZWQoKSxpfSx0LnByb3RvdHlwZS5uZXh0PWZ1bmN0aW9uKHIpe2UucHJvdG90eXBlLm5leHQuY2FsbCh0aGlzLHRoaXMuX3ZhbHVlPXIpfSx0fShnKTt2YXIgQXQ9e25vdzpmdW5jdGlvbigpe3JldHVybihBdC5kZWxlZ2F0ZXx8RGF0ZSkubm93KCl9LGRlbGVnYXRlOnZvaWQgMH07dmFyIEN0PWZ1bmN0aW9uKGUpe29lKHQsZSk7ZnVuY3Rpb24gdChyLG8sbil7cj09PXZvaWQgMCYmKHI9MS8wKSxvPT09dm9pZCAwJiYobz0xLzApLG49PT12b2lkIDAmJihuPUF0KTt2YXIgaT1lLmNhbGwodGhpcyl8fHRoaXM7cmV0dXJuIGkuX2J1ZmZlclNpemU9cixpLl93aW5kb3dUaW1lPW8saS5fdGltZXN0YW1wUHJvdmlkZXI9bixpLl9idWZmZXI9W10saS5faW5maW5pdGVUaW1lV2luZG93PSEwLGkuX2luZmluaXRlVGltZVdpbmRvdz1vPT09MS8wLGkuX2J1ZmZlclNpemU9TWF0aC5tYXgoMSxyKSxpLl93aW5kb3dUaW1lPU1hdGgubWF4KDEsbyksaX1yZXR1cm4gdC5wcm90b3R5cGUubmV4dD1mdW5jdGlvbihyKXt2YXIgbz10aGlzLG49by5pc1N0b3BwZWQsaT1vLl9idWZmZXIsYT1vLl9pbmZpbml0ZVRpbWVXaW5kb3cscz1vLl90aW1lc3RhbXBQcm92aWRlcixwPW8uX3dpbmRvd1RpbWU7bnx8KGkucHVzaChyKSwhYSYmaS5wdXNoKHMubm93KCkrcCkpLHRoaXMuX3RyaW1CdWZmZXIoKSxlLnByb3RvdHlwZS5uZXh0LmNhbGwodGhpcyxyKX0sdC5wcm90b3R5cGUuX3N1YnNjcmliZT1mdW5jdGlvbihyKXt0aGlzLl90aHJvd0lmQ2xvc2VkKCksdGhpcy5fdHJpbUJ1ZmZlcigpO2Zvcih2YXIgbz10aGlzLl9pbm5lclN1YnNjcmliZShyKSxuPXRoaXMsaT1uLl9pbmZpbml0ZVRpbWVXaW5kb3csYT1uLl9idWZmZXIscz1hLnNsaWNlKCkscD0wO3A8cy5sZW5ndGgmJiFyLmNsb3NlZDtwKz1pPzE6MilyLm5leHQoc1twXSk7cmV0dXJuIHRoaXMuX2NoZWNrRmluYWxpemVkU3RhdHVzZXMociksb30sdC5wcm90b3R5cGUuX3RyaW1CdWZmZXI9ZnVuY3Rpb24oKXt2YXIgcj10aGlzLG89ci5fYnVmZmVyU2l6ZSxuPXIuX3RpbWVzdGFtcFByb3ZpZGVyLGk9ci5fYnVmZmVyLGE9ci5faW5maW5pdGVUaW1lV2luZG93LHM9KGE/MToyKSpvO2lmKG88MS8wJiZzPGkubGVuZ3RoJiZpLnNwbGljZSgwLGkubGVuZ3RoLXMpLCFhKXtmb3IodmFyIHA9bi5ub3coKSxjPTAsbD0xO2w8aS5sZW5ndGgmJmlbbF08PXA7bCs9MiljPWw7YyYmaS5zcGxpY2UoMCxjKzEpfX0sdH0oZyk7dmFyIFNvPWZ1bmN0aW9uKGUpe29lKHQsZSk7ZnVuY3Rpb24gdChyLG8pe3JldHVybiBlLmNhbGwodGhpcyl8fHRoaXN9cmV0dXJuIHQucHJvdG90eXBlLnNjaGVkdWxlPWZ1bmN0aW9uKHIsbyl7cmV0dXJuIG89PT12b2lkIDAmJihvPTApLHRoaXN9LHR9KFVlKTt2YXIga3Q9e3NldEludGVydmFsOmZ1bmN0aW9uKGUsdCl7Zm9yKHZhciByPVtdLG89MjtvPGFyZ3VtZW50cy5sZW5ndGg7bysrKXJbby0yXT1hcmd1bWVudHNbb107dmFyIG49a3QuZGVsZWdhdGU7cmV0dXJuIG4hPW51bGwmJm4uc2V0SW50ZXJ2YWw/bi5zZXRJbnRlcnZhbC5hcHBseShuLHEoW2UsdF0sTihyKSkpOnNldEludGVydmFsLmFwcGx5KHZvaWQgMCxxKFtlLHRdLE4ocikpKX0sY2xlYXJJbnRlcnZhbDpmdW5jdGlvbihlKXt2YXIgdD1rdC5kZWxlZ2F0ZTtyZXR1cm4oKHQ9PW51bGw/dm9pZCAwOnQuY2xlYXJJbnRlcnZhbCl8fGNsZWFySW50ZXJ2YWwpKGUpfSxkZWxlZ2F0ZTp2b2lkIDB9O3ZhciBndD1mdW5jdGlvbihlKXtvZSh0LGUpO2Z1bmN0aW9uIHQocixvKXt2YXIgbj1lLmNhbGwodGhpcyxyLG8pfHx0aGlzO3JldHVybiBuLnNjaGVkdWxlcj1yLG4ud29yaz1vLG4ucGVuZGluZz0hMSxufXJldHVybiB0LnByb3RvdHlwZS5zY2hlZHVsZT1mdW5jdGlvbihyLG8pe3ZhciBuO2lmKG89PT12b2lkIDAmJihvPTApLHRoaXMuY2xvc2VkKXJldHVybiB0aGlzO3RoaXMuc3RhdGU9cjt2YXIgaT10aGlzLmlkLGE9dGhpcy5zY2hlZHVsZXI7cmV0dXJuIGkhPW51bGwmJih0aGlzLmlkPXRoaXMucmVjeWNsZUFzeW5jSWQoYSxpLG8pKSx0aGlzLnBlbmRpbmc9ITAsdGhpcy5kZWxheT1vLHRoaXMuaWQ9KG49dGhpcy5pZCkhPT1udWxsJiZuIT09dm9pZCAwP246dGhpcy5yZXF1ZXN0QXN5bmNJZChhLHRoaXMuaWQsbyksdGhpc30sdC5wcm90b3R5cGUucmVxdWVzdEFzeW5jSWQ9ZnVuY3Rpb24ocixvLG4pe3JldHVybiBuPT09dm9pZCAwJiYobj0wKSxrdC5zZXRJbnRlcnZhbChyLmZsdXNoLmJpbmQocix0aGlzKSxuKX0sdC5wcm90b3R5cGUucmVjeWNsZUFzeW5jSWQ9ZnVuY3Rpb24ocixvLG4pe2lmKG49PT12b2lkIDAmJihuPTApLG4hPW51bGwmJnRoaXMuZGVsYXk9PT1uJiZ0aGlzLnBlbmRpbmc9PT0hMSlyZXR1cm4gbztvIT1udWxsJiZrdC5jbGVhckludGVydmFsKG8pfSx0LnByb3RvdHlwZS5leGVjdXRlPWZ1bmN0aW9uKHIsbyl7aWYodGhpcy5jbG9zZWQpcmV0dXJuIG5ldyBFcnJvcigiZXhlY3V0aW5nIGEgY2FuY2VsbGVkIGFjdGlvbiIpO3RoaXMucGVuZGluZz0hMTt2YXIgbj10aGlzLl9leGVjdXRlKHIsbyk7aWYobilyZXR1cm4gbjt0aGlzLnBlbmRpbmc9PT0hMSYmdGhpcy5pZCE9bnVsbCYmKHRoaXMuaWQ9dGhpcy5yZWN5Y2xlQXN5bmNJZCh0aGlzLnNjaGVkdWxlcix0aGlzLmlkLG51bGwpKX0sdC5wcm90b3R5cGUuX2V4ZWN1dGU9ZnVuY3Rpb24ocixvKXt2YXIgbj0hMSxpO3RyeXt0aGlzLndvcmsocil9Y2F0Y2goYSl7bj0hMCxpPWF8fG5ldyBFcnJvcigiU2NoZWR1bGVkIGFjdGlvbiB0aHJldyBmYWxzeSBlcnJvciIpfWlmKG4pcmV0dXJuIHRoaXMudW5zdWJzY3JpYmUoKSxpfSx0LnByb3RvdHlwZS51bnN1YnNjcmliZT1mdW5jdGlvbigpe2lmKCF0aGlzLmNsb3NlZCl7dmFyIHI9dGhpcyxvPXIuaWQsbj1yLnNjaGVkdWxlcixpPW4uYWN0aW9uczt0aGlzLndvcms9dGhpcy5zdGF0ZT10aGlzLnNjaGVkdWxlcj1udWxsLHRoaXMucGVuZGluZz0hMSxRZShpLHRoaXMpLG8hPW51bGwmJih0aGlzLmlkPXRoaXMucmVjeWNsZUFzeW5jSWQobixvLG51bGwpKSx0aGlzLmRlbGF5PW51bGwsZS5wcm90b3R5cGUudW5zdWJzY3JpYmUuY2FsbCh0aGlzKX19LHR9KFNvKTt2YXIgQXI9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKHQscil7cj09PXZvaWQgMCYmKHI9ZS5ub3cpLHRoaXMuc2NoZWR1bGVyQWN0aW9uQ3Rvcj10LHRoaXMubm93PXJ9cmV0dXJuIGUucHJvdG90eXBlLnNjaGVkdWxlPWZ1bmN0aW9uKHQscixvKXtyZXR1cm4gcj09PXZvaWQgMCYmKHI9MCksbmV3IHRoaXMuc2NoZWR1bGVyQWN0aW9uQ3Rvcih0aGlzLHQpLnNjaGVkdWxlKG8scil9LGUubm93PUF0Lm5vdyxlfSgpO3ZhciB5dD1mdW5jdGlvbihlKXtvZSh0LGUpO2Z1bmN0aW9uIHQocixvKXtvPT09dm9pZCAwJiYobz1Bci5ub3cpO3ZhciBuPWUuY2FsbCh0aGlzLHIsbyl8fHRoaXM7cmV0dXJuIG4uYWN0aW9ucz1bXSxuLl9hY3RpdmU9ITEsbn1yZXR1cm4gdC5wcm90b3R5cGUuZmx1c2g9ZnVuY3Rpb24ocil7dmFyIG89dGhpcy5hY3Rpb25zO2lmKHRoaXMuX2FjdGl2ZSl7by5wdXNoKHIpO3JldHVybn12YXIgbjt0aGlzLl9hY3RpdmU9ITA7ZG8gaWYobj1yLmV4ZWN1dGUoci5zdGF0ZSxyLmRlbGF5KSlicmVhazt3aGlsZShyPW8uc2hpZnQoKSk7aWYodGhpcy5fYWN0aXZlPSExLG4pe2Zvcig7cj1vLnNoaWZ0KCk7KXIudW5zdWJzY3JpYmUoKTt0aHJvdyBufX0sdH0oQXIpO3ZhciBzZT1uZXcgeXQoZ3QpLENyPXNlO3ZhciBPbz1mdW5jdGlvbihlKXtvZSh0LGUpO2Z1bmN0aW9uIHQocixvKXt2YXIgbj1lLmNhbGwodGhpcyxyLG8pfHx0aGlzO3JldHVybiBuLnNjaGVkdWxlcj1yLG4ud29yaz1vLG59cmV0dXJuIHQucHJvdG90eXBlLnNjaGVkdWxlPWZ1bmN0aW9uKHIsbyl7cmV0dXJuIG89PT12b2lkIDAmJihvPTApLG8+MD9lLnByb3RvdHlwZS5zY2hlZHVsZS5jYWxsKHRoaXMscixvKToodGhpcy5kZWxheT1vLHRoaXMuc3RhdGU9cix0aGlzLnNjaGVkdWxlci5mbHVzaCh0aGlzKSx0aGlzKX0sdC5wcm90b3R5cGUuZXhlY3V0ZT1mdW5jdGlvbihyLG8pe3JldHVybiBvPjB8fHRoaXMuY2xvc2VkP2UucHJvdG90eXBlLmV4ZWN1dGUuY2FsbCh0aGlzLHIsbyk6dGhpcy5fZXhlY3V0ZShyLG8pfSx0LnByb3RvdHlwZS5yZXF1ZXN0QXN5bmNJZD1mdW5jdGlvbihyLG8sbil7cmV0dXJuIG49PT12b2lkIDAmJihuPTApLG4hPW51bGwmJm4+MHx8bj09bnVsbCYmdGhpcy5kZWxheT4wP2UucHJvdG90eXBlLnJlcXVlc3RBc3luY0lkLmNhbGwodGhpcyxyLG8sbik6KHIuZmx1c2godGhpcyksMCl9LHR9KGd0KTt2YXIgTG89ZnVuY3Rpb24oZSl7b2UodCxlKTtmdW5jdGlvbiB0KCl7cmV0dXJuIGUhPT1udWxsJiZlLmFwcGx5KHRoaXMsYXJndW1lbnRzKXx8dGhpc31yZXR1cm4gdH0oeXQpO3ZhciBrcj1uZXcgTG8oT28pO3ZhciBNbz1mdW5jdGlvbihlKXtvZSh0LGUpO2Z1bmN0aW9uIHQocixvKXt2YXIgbj1lLmNhbGwodGhpcyxyLG8pfHx0aGlzO3JldHVybiBuLnNjaGVkdWxlcj1yLG4ud29yaz1vLG59cmV0dXJuIHQucHJvdG90eXBlLnJlcXVlc3RBc3luY0lkPWZ1bmN0aW9uKHIsbyxuKXtyZXR1cm4gbj09PXZvaWQgMCYmKG49MCksbiE9PW51bGwmJm4+MD9lLnByb3RvdHlwZS5yZXF1ZXN0QXN5bmNJZC5jYWxsKHRoaXMscixvLG4pOihyLmFjdGlvbnMucHVzaCh0aGlzKSxyLl9zY2hlZHVsZWR8fChyLl9zY2hlZHVsZWQ9dnQucmVxdWVzdEFuaW1hdGlvbkZyYW1lKGZ1bmN0aW9uKCl7cmV0dXJuIHIuZmx1c2godm9pZCAwKX0pKSl9LHQucHJvdG90eXBlLnJlY3ljbGVBc3luY0lkPWZ1bmN0aW9uKHIsbyxuKXt2YXIgaTtpZihuPT09dm9pZCAwJiYobj0wKSxuIT1udWxsP24+MDp0aGlzLmRlbGF5PjApcmV0dXJuIGUucHJvdG90eXBlLnJlY3ljbGVBc3luY0lkLmNhbGwodGhpcyxyLG8sbik7dmFyIGE9ci5hY3Rpb25zO28hPW51bGwmJigoaT1hW2EubGVuZ3RoLTFdKT09PW51bGx8fGk9PT12b2lkIDA/dm9pZCAwOmkuaWQpIT09byYmKHZ0LmNhbmNlbEFuaW1hdGlvbkZyYW1lKG8pLHIuX3NjaGVkdWxlZD12b2lkIDApfSx0fShndCk7dmFyIF9vPWZ1bmN0aW9uKGUpe29lKHQsZSk7ZnVuY3Rpb24gdCgpe3JldHVybiBlIT09bnVsbCYmZS5hcHBseSh0aGlzLGFyZ3VtZW50cyl8fHRoaXN9cmV0dXJuIHQucHJvdG90eXBlLmZsdXNoPWZ1bmN0aW9uKHIpe3RoaXMuX2FjdGl2ZT0hMDt2YXIgbz10aGlzLl9zY2hlZHVsZWQ7dGhpcy5fc2NoZWR1bGVkPXZvaWQgMDt2YXIgbj10aGlzLmFjdGlvbnMsaTtyPXJ8fG4uc2hpZnQoKTtkbyBpZihpPXIuZXhlY3V0ZShyLnN0YXRlLHIuZGVsYXkpKWJyZWFrO3doaWxlKChyPW5bMF0pJiZyLmlkPT09byYmbi5zaGlmdCgpKTtpZih0aGlzLl9hY3RpdmU9ITEsaSl7Zm9yKDsocj1uWzBdKSYmci5pZD09PW8mJm4uc2hpZnQoKTspci51bnN1YnNjcmliZSgpO3Rocm93IGl9fSx0fSh5dCk7dmFyIG1lPW5ldyBfbyhNbyk7dmFyIFM9bmV3IGooZnVuY3Rpb24oZSl7cmV0dXJuIGUuY29tcGxldGUoKX0pO2Z1bmN0aW9uIFl0KGUpe3JldHVybiBlJiZIKGUuc2NoZWR1bGUpfWZ1bmN0aW9uIEhyKGUpe3JldHVybiBlW2UubGVuZ3RoLTFdfWZ1bmN0aW9uIFhlKGUpe3JldHVybiBIKEhyKGUpKT9lLnBvcCgpOnZvaWQgMH1mdW5jdGlvbiBrZShlKXtyZXR1cm4gWXQoSHIoZSkpP2UucG9wKCk6dm9pZCAwfWZ1bmN0aW9uIEJ0KGUsdCl7cmV0dXJuIHR5cGVvZiBIcihlKT09Im51bWJlciI/ZS5wb3AoKTp0fXZhciB4dD1mdW5jdGlvbihlKXtyZXR1cm4gZSYmdHlwZW9mIGUubGVuZ3RoPT0ibnVtYmVyIiYmdHlwZW9mIGUhPSJmdW5jdGlvbiJ9O2Z1bmN0aW9uIEd0KGUpe3JldHVybiBIKGU9PW51bGw/dm9pZCAwOmUudGhlbil9ZnVuY3Rpb24gSnQoZSl7cmV0dXJuIEgoZVtidF0pfWZ1bmN0aW9uIFh0KGUpe3JldHVybiBTeW1ib2wuYXN5bmNJdGVyYXRvciYmSChlPT1udWxsP3ZvaWQgMDplW1N5bWJvbC5hc3luY0l0ZXJhdG9yXSl9ZnVuY3Rpb24gWnQoZSl7cmV0dXJuIG5ldyBUeXBlRXJyb3IoIllvdSBwcm92aWRlZCAiKyhlIT09bnVsbCYmdHlwZW9mIGU9PSJvYmplY3QiPyJhbiBpbnZhbGlkIG9iamVjdCI6IiciK2UrIiciKSsiIHdoZXJlIGEgc3RyZWFtIHdhcyBleHBlY3RlZC4gWW91IGNhbiBwcm92aWRlIGFuIE9ic2VydmFibGUsIFByb21pc2UsIFJlYWRhYmxlU3RyZWFtLCBBcnJheSwgQXN5bmNJdGVyYWJsZSwgb3IgSXRlcmFibGUuIil9ZnVuY3Rpb24gWmkoKXtyZXR1cm4gdHlwZW9mIFN5bWJvbCE9ImZ1bmN0aW9uInx8IVN5bWJvbC5pdGVyYXRvcj8iQEBpdGVyYXRvciI6U3ltYm9sLml0ZXJhdG9yfXZhciBlcj1aaSgpO2Z1bmN0aW9uIHRyKGUpe3JldHVybiBIKGU9PW51bGw/dm9pZCAwOmVbZXJdKX1mdW5jdGlvbiBycihlKXtyZXR1cm4gZm8odGhpcyxhcmd1bWVudHMsZnVuY3Rpb24oKXt2YXIgcixvLG4saTtyZXR1cm4gTnQodGhpcyxmdW5jdGlvbihhKXtzd2l0Y2goYS5sYWJlbCl7Y2FzZSAwOnI9ZS5nZXRSZWFkZXIoKSxhLmxhYmVsPTE7Y2FzZSAxOmEudHJ5cy5wdXNoKFsxLCw5LDEwXSksYS5sYWJlbD0yO2Nhc2UgMjpyZXR1cm5bNCxudChyLnJlYWQoKSldO2Nhc2UgMzpyZXR1cm4gbz1hLnNlbnQoKSxuPW8udmFsdWUsaT1vLmRvbmUsaT9bNCxudCh2b2lkIDApXTpbMyw1XTtjYXNlIDQ6cmV0dXJuWzIsYS5zZW50KCldO2Nhc2UgNTpyZXR1cm5bNCxudChuKV07Y2FzZSA2OnJldHVybls0LGEuc2VudCgpXTtjYXNlIDc6cmV0dXJuIGEuc2VudCgpLFszLDJdO2Nhc2UgODpyZXR1cm5bMywxMF07Y2FzZSA5OnJldHVybiByLnJlbGVhc2VMb2NrKCksWzddO2Nhc2UgMTA6cmV0dXJuWzJdfX0pfSl9ZnVuY3Rpb24gb3IoZSl7cmV0dXJuIEgoZT09bnVsbD92b2lkIDA6ZS5nZXRSZWFkZXIpfWZ1bmN0aW9uIFUoZSl7aWYoZSBpbnN0YW5jZW9mIGopcmV0dXJuIGU7aWYoZSE9bnVsbCl7aWYoSnQoZSkpcmV0dXJuIGVhKGUpO2lmKHh0KGUpKXJldHVybiB0YShlKTtpZihHdChlKSlyZXR1cm4gcmEoZSk7aWYoWHQoZSkpcmV0dXJuIEFvKGUpO2lmKHRyKGUpKXJldHVybiBvYShlKTtpZihvcihlKSlyZXR1cm4gbmEoZSl9dGhyb3cgWnQoZSl9ZnVuY3Rpb24gZWEoZSl7cmV0dXJuIG5ldyBqKGZ1bmN0aW9uKHQpe3ZhciByPWVbYnRdKCk7aWYoSChyLnN1YnNjcmliZSkpcmV0dXJuIHIuc3Vic2NyaWJlKHQpO3Rocm93IG5ldyBUeXBlRXJyb3IoIlByb3ZpZGVkIG9iamVjdCBkb2VzIG5vdCBjb3JyZWN0bHkgaW1wbGVtZW50IFN5bWJvbC5vYnNlcnZhYmxlIil9KX1mdW5jdGlvbiB0YShlKXtyZXR1cm4gbmV3IGooZnVuY3Rpb24odCl7Zm9yKHZhciByPTA7cjxlLmxlbmd0aCYmIXQuY2xvc2VkO3IrKyl0Lm5leHQoZVtyXSk7dC5jb21wbGV0ZSgpfSl9ZnVuY3Rpb24gcmEoZSl7cmV0dXJuIG5ldyBqKGZ1bmN0aW9uKHQpe2UudGhlbihmdW5jdGlvbihyKXt0LmNsb3NlZHx8KHQubmV4dChyKSx0LmNvbXBsZXRlKCkpfSxmdW5jdGlvbihyKXtyZXR1cm4gdC5lcnJvcihyKX0pLnRoZW4obnVsbCxRdCl9KX1mdW5jdGlvbiBvYShlKXtyZXR1cm4gbmV3IGooZnVuY3Rpb24odCl7dmFyIHIsbzt0cnl7Zm9yKHZhciBuPWhlKGUpLGk9bi5uZXh0KCk7IWkuZG9uZTtpPW4ubmV4dCgpKXt2YXIgYT1pLnZhbHVlO2lmKHQubmV4dChhKSx0LmNsb3NlZClyZXR1cm59fWNhdGNoKHMpe3I9e2Vycm9yOnN9fWZpbmFsbHl7dHJ5e2kmJiFpLmRvbmUmJihvPW4ucmV0dXJuKSYmby5jYWxsKG4pfWZpbmFsbHl7aWYocil0aHJvdyByLmVycm9yfX10LmNvbXBsZXRlKCl9KX1mdW5jdGlvbiBBbyhlKXtyZXR1cm4gbmV3IGooZnVuY3Rpb24odCl7aWEoZSx0KS5jYXRjaChmdW5jdGlvbihyKXtyZXR1cm4gdC5lcnJvcihyKX0pfSl9ZnVuY3Rpb24gbmEoZSl7cmV0dXJuIEFvKHJyKGUpKX1mdW5jdGlvbiBpYShlLHQpe3ZhciByLG8sbixpO3JldHVybiBtbyh0aGlzLHZvaWQgMCx2b2lkIDAsZnVuY3Rpb24oKXt2YXIgYSxzO3JldHVybiBOdCh0aGlzLGZ1bmN0aW9uKHApe3N3aXRjaChwLmxhYmVsKXtjYXNlIDA6cC50cnlzLnB1c2goWzAsNSw2LDExXSkscj11byhlKSxwLmxhYmVsPTE7Y2FzZSAxOnJldHVybls0LHIubmV4dCgpXTtjYXNlIDI6aWYobz1wLnNlbnQoKSwhIW8uZG9uZSlyZXR1cm5bMyw0XTtpZihhPW8udmFsdWUsdC5uZXh0KGEpLHQuY2xvc2VkKXJldHVyblsyXTtwLmxhYmVsPTM7Y2FzZSAzOnJldHVyblszLDFdO2Nhc2UgNDpyZXR1cm5bMywxMV07Y2FzZSA1OnJldHVybiBzPXAuc2VudCgpLG49e2Vycm9yOnN9LFszLDExXTtjYXNlIDY6cmV0dXJuIHAudHJ5cy5wdXNoKFs2LCw5LDEwXSksbyYmIW8uZG9uZSYmKGk9ci5yZXR1cm4pP1s0LGkuY2FsbChyKV06WzMsOF07Y2FzZSA3OnAuc2VudCgpLHAubGFiZWw9ODtjYXNlIDg6cmV0dXJuWzMsMTBdO2Nhc2UgOTppZihuKXRocm93IG4uZXJyb3I7cmV0dXJuWzddO2Nhc2UgMTA6cmV0dXJuWzddO2Nhc2UgMTE6cmV0dXJuIHQuY29tcGxldGUoKSxbMl19fSl9KX1mdW5jdGlvbiB3ZShlLHQscixvLG4pe289PT12b2lkIDAmJihvPTApLG49PT12b2lkIDAmJihuPSExKTt2YXIgaT10LnNjaGVkdWxlKGZ1bmN0aW9uKCl7cigpLG4/ZS5hZGQodGhpcy5zY2hlZHVsZShudWxsLG8pKTp0aGlzLnVuc3Vic2NyaWJlKCl9LG8pO2lmKGUuYWRkKGkpLCFuKXJldHVybiBpfWZ1bmN0aW9uIHZlKGUsdCl7cmV0dXJuIHQ9PT12b2lkIDAmJih0PTApLEUoZnVuY3Rpb24ocixvKXtyLnN1YnNjcmliZShUKG8sZnVuY3Rpb24obil7cmV0dXJuIHdlKG8sZSxmdW5jdGlvbigpe3JldHVybiBvLm5leHQobil9LHQpfSxmdW5jdGlvbigpe3JldHVybiB3ZShvLGUsZnVuY3Rpb24oKXtyZXR1cm4gby5jb21wbGV0ZSgpfSx0KX0sZnVuY3Rpb24obil7cmV0dXJuIHdlKG8sZSxmdW5jdGlvbigpe3JldHVybiBvLmVycm9yKG4pfSx0KX0pKX0pfWZ1bmN0aW9uIEtlKGUsdCl7cmV0dXJuIHQ9PT12b2lkIDAmJih0PTApLEUoZnVuY3Rpb24ocixvKXtvLmFkZChlLnNjaGVkdWxlKGZ1bmN0aW9uKCl7cmV0dXJuIHIuc3Vic2NyaWJlKG8pfSx0KSl9KX1mdW5jdGlvbiBDbyhlLHQpe3JldHVybiBVKGUpLnBpcGUoS2UodCksdmUodCkpfWZ1bmN0aW9uIGtvKGUsdCl7cmV0dXJuIFUoZSkucGlwZShLZSh0KSx2ZSh0KSl9ZnVuY3Rpb24gSG8oZSx0KXtyZXR1cm4gbmV3IGooZnVuY3Rpb24ocil7dmFyIG89MDtyZXR1cm4gdC5zY2hlZHVsZShmdW5jdGlvbigpe289PT1lLmxlbmd0aD9yLmNvbXBsZXRlKCk6KHIubmV4dChlW28rK10pLHIuY2xvc2VkfHx0aGlzLnNjaGVkdWxlKCkpfSl9KX1mdW5jdGlvbiAkbyhlLHQpe3JldHVybiBuZXcgaihmdW5jdGlvbihyKXt2YXIgbztyZXR1cm4gd2Uocix0LGZ1bmN0aW9uKCl7bz1lW2VyXSgpLHdlKHIsdCxmdW5jdGlvbigpe3ZhciBuLGksYTt0cnl7bj1vLm5leHQoKSxpPW4udmFsdWUsYT1uLmRvbmV9Y2F0Y2gocyl7ci5lcnJvcihzKTtyZXR1cm59YT9yLmNvbXBsZXRlKCk6ci5uZXh0KGkpfSwwLCEwKX0pLGZ1bmN0aW9uKCl7cmV0dXJuIEgobz09bnVsbD92b2lkIDA6by5yZXR1cm4pJiZvLnJldHVybigpfX0pfWZ1bmN0aW9uIG5yKGUsdCl7aWYoIWUpdGhyb3cgbmV3IEVycm9yKCJJdGVyYWJsZSBjYW5ub3QgYmUgbnVsbCIpO3JldHVybiBuZXcgaihmdW5jdGlvbihyKXt3ZShyLHQsZnVuY3Rpb24oKXt2YXIgbz1lW1N5bWJvbC5hc3luY0l0ZXJhdG9yXSgpO3dlKHIsdCxmdW5jdGlvbigpe28ubmV4dCgpLnRoZW4oZnVuY3Rpb24obil7bi5kb25lP3IuY29tcGxldGUoKTpyLm5leHQobi52YWx1ZSl9KX0sMCwhMCl9KX0pfWZ1bmN0aW9uIFBvKGUsdCl7cmV0dXJuIG5yKHJyKGUpLHQpfWZ1bmN0aW9uIFJvKGUsdCl7aWYoZSE9bnVsbCl7aWYoSnQoZSkpcmV0dXJuIENvKGUsdCk7aWYoeHQoZSkpcmV0dXJuIEhvKGUsdCk7aWYoR3QoZSkpcmV0dXJuIGtvKGUsdCk7aWYoWHQoZSkpcmV0dXJuIG5yKGUsdCk7aWYodHIoZSkpcmV0dXJuICRvKGUsdCk7aWYob3IoZSkpcmV0dXJuIFBvKGUsdCl9dGhyb3cgWnQoZSl9ZnVuY3Rpb24gdWUoZSx0KXtyZXR1cm4gdD9SbyhlLHQpOlUoZSl9ZnVuY3Rpb24gSSgpe2Zvcih2YXIgZT1bXSx0PTA7dDxhcmd1bWVudHMubGVuZ3RoO3QrKyllW3RdPWFyZ3VtZW50c1t0XTt2YXIgcj1rZShlKTtyZXR1cm4gdWUoZSxyKX1mdW5jdGlvbiAkcihlLHQpe3ZhciByPUgoZSk/ZTpmdW5jdGlvbigpe3JldHVybiBlfSxvPWZ1bmN0aW9uKG4pe3JldHVybiBuLmVycm9yKHIoKSl9O3JldHVybiBuZXcgaih0P2Z1bmN0aW9uKG4pe3JldHVybiB0LnNjaGVkdWxlKG8sMCxuKX06byl9dmFyIGlyPXV0KGZ1bmN0aW9uKGUpe3JldHVybiBmdW5jdGlvbigpe2UodGhpcyksdGhpcy5uYW1lPSJFbXB0eUVycm9yIix0aGlzLm1lc3NhZ2U9Im5vIGVsZW1lbnRzIGluIHNlcXVlbmNlIn19KTtmdW5jdGlvbiBJbyhlKXtyZXR1cm4gZSBpbnN0YW5jZW9mIERhdGUmJiFpc05hTihlKX1mdW5jdGlvbiBtKGUsdCl7cmV0dXJuIEUoZnVuY3Rpb24ocixvKXt2YXIgbj0wO3Iuc3Vic2NyaWJlKFQobyxmdW5jdGlvbihpKXtvLm5leHQoZS5jYWxsKHQsaSxuKyspKX0pKX0pfXZhciBhYT1BcnJheS5pc0FycmF5O2Z1bmN0aW9uIHNhKGUsdCl7cmV0dXJuIGFhKHQpP2UuYXBwbHkodm9pZCAwLHEoW10sTih0KSkpOmUodCl9ZnVuY3Rpb24gWmUoZSl7cmV0dXJuIG0oZnVuY3Rpb24odCl7cmV0dXJuIHNhKGUsdCl9KX12YXIgY2E9QXJyYXkuaXNBcnJheSxwYT1PYmplY3QuZ2V0UHJvdG90eXBlT2YsbGE9T2JqZWN0LnByb3RvdHlwZSxtYT1PYmplY3Qua2V5cztmdW5jdGlvbiBqbyhlKXtpZihlLmxlbmd0aD09PTEpe3ZhciB0PWVbMF07aWYoY2EodCkpcmV0dXJue2FyZ3M6dCxrZXlzOm51bGx9O2lmKGZhKHQpKXt2YXIgcj1tYSh0KTtyZXR1cm57YXJnczpyLm1hcChmdW5jdGlvbihvKXtyZXR1cm4gdFtvXX0pLGtleXM6cn19fXJldHVybnthcmdzOmUsa2V5czpudWxsfX1mdW5jdGlvbiBmYShlKXtyZXR1cm4gZSYmdHlwZW9mIGU9PSJvYmplY3QiJiZwYShlKT09PWxhfWZ1bmN0aW9uIEZvKGUsdCl7cmV0dXJuIGUucmVkdWNlKGZ1bmN0aW9uKHIsbyxuKXtyZXR1cm4gcltvXT10W25dLHJ9LHt9KX1mdW5jdGlvbiB6KCl7Zm9yKHZhciBlPVtdLHQ9MDt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKWVbdF09YXJndW1lbnRzW3RdO3ZhciByPWtlKGUpLG89WGUoZSksbj1qbyhlKSxpPW4uYXJncyxhPW4ua2V5cztpZihpLmxlbmd0aD09PTApcmV0dXJuIHVlKFtdLHIpO3ZhciBzPW5ldyBqKFByKGkscixhP2Z1bmN0aW9uKHApe3JldHVybiBGbyhhLHApfTpsZSkpO3JldHVybiBvP3MucGlwZShaZShvKSk6c31mdW5jdGlvbiBQcihlLHQscil7cmV0dXJuIHI9PT12b2lkIDAmJihyPWxlKSxmdW5jdGlvbihvKXtVbyh0LGZ1bmN0aW9uKCl7Zm9yKHZhciBuPWUubGVuZ3RoLGk9bmV3IEFycmF5KG4pLGE9bixzPW4scD1mdW5jdGlvbihsKXtVbyh0LGZ1bmN0aW9uKCl7dmFyIGY9dWUoZVtsXSx0KSx1PSExO2Yuc3Vic2NyaWJlKFQobyxmdW5jdGlvbihkKXtpW2xdPWQsdXx8KHU9ITAscy0tKSxzfHxvLm5leHQocihpLnNsaWNlKCkpKX0sZnVuY3Rpb24oKXstLWF8fG8uY29tcGxldGUoKX0pKX0sbyl9LGM9MDtjPG47YysrKXAoYyl9LG8pfX1mdW5jdGlvbiBVbyhlLHQscil7ZT93ZShyLGUsdCk6dCgpfWZ1bmN0aW9uIFdvKGUsdCxyLG8sbixpLGEscyl7dmFyIHA9W10sYz0wLGw9MCxmPSExLHU9ZnVuY3Rpb24oKXtmJiYhcC5sZW5ndGgmJiFjJiZ0LmNvbXBsZXRlKCl9LGQ9ZnVuY3Rpb24oTCl7cmV0dXJuIGM8bz95KEwpOnAucHVzaChMKX0seT1mdW5jdGlvbihMKXtpJiZ0Lm5leHQoTCksYysrO3ZhciBYPSExO1UocihMLGwrKykpLnN1YnNjcmliZShUKHQsZnVuY3Rpb24odGUpe249PW51bGx8fG4odGUpLGk/ZCh0ZSk6dC5uZXh0KHRlKX0sZnVuY3Rpb24oKXtYPSEwfSx2b2lkIDAsZnVuY3Rpb24oKXtpZihYKXRyeXtjLS07Zm9yKHZhciB0ZT1mdW5jdGlvbigpe3ZhciBKPXAuc2hpZnQoKTthP3dlKHQsYSxmdW5jdGlvbigpe3JldHVybiB5KEopfSk6eShKKX07cC5sZW5ndGgmJmM8bzspdGUoKTt1KCl9Y2F0Y2goSil7dC5lcnJvcihKKX19KSl9O3JldHVybiBlLnN1YnNjcmliZShUKHQsZCxmdW5jdGlvbigpe2Y9ITAsdSgpfSkpLGZ1bmN0aW9uKCl7cz09bnVsbHx8cygpfX1mdW5jdGlvbiBuZShlLHQscil7cmV0dXJuIHI9PT12b2lkIDAmJihyPTEvMCksSCh0KT9uZShmdW5jdGlvbihvLG4pe3JldHVybiBtKGZ1bmN0aW9uKGksYSl7cmV0dXJuIHQobyxpLG4sYSl9KShVKGUobyxuKSkpfSxyKToodHlwZW9mIHQ9PSJudW1iZXIiJiYocj10KSxFKGZ1bmN0aW9uKG8sbil7cmV0dXJuIFdvKG8sbixlLHIpfSkpfWZ1bmN0aW9uIEV0KGUpe3JldHVybiBlPT09dm9pZCAwJiYoZT0xLzApLG5lKGxlLGUpfWZ1bmN0aW9uIERvKCl7cmV0dXJuIEV0KDEpfWZ1bmN0aW9uIFdlKCl7Zm9yKHZhciBlPVtdLHQ9MDt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKWVbdF09YXJndW1lbnRzW3RdO3JldHVybiBEbygpKHVlKGUsa2UoZSkpKX1mdW5jdGlvbiBDKGUpe3JldHVybiBuZXcgaihmdW5jdGlvbih0KXtVKGUoKSkuc3Vic2NyaWJlKHQpfSl9dmFyIHVhPVsiYWRkTGlzdGVuZXIiLCJyZW1vdmVMaXN0ZW5lciJdLGRhPVsiYWRkRXZlbnRMaXN0ZW5lciIsInJlbW92ZUV2ZW50TGlzdGVuZXIiXSxoYT1bIm9uIiwib2ZmIl07ZnVuY3Rpb24gaChlLHQscixvKXtpZihIKHIpJiYobz1yLHI9dm9pZCAwKSxvKXJldHVybiBoKGUsdCxyKS5waXBlKFplKG8pKTt2YXIgbj1OKGdhKGUpP2RhLm1hcChmdW5jdGlvbihzKXtyZXR1cm4gZnVuY3Rpb24ocCl7cmV0dXJuIGVbc10odCxwLHIpfX0pOmJhKGUpP3VhLm1hcChWbyhlLHQpKTp2YShlKT9oYS5tYXAoVm8oZSx0KSk6W10sMiksaT1uWzBdLGE9blsxXTtpZighaSYmeHQoZSkpcmV0dXJuIG5lKGZ1bmN0aW9uKHMpe3JldHVybiBoKHMsdCxyKX0pKFUoZSkpO2lmKCFpKXRocm93IG5ldyBUeXBlRXJyb3IoIkludmFsaWQgZXZlbnQgdGFyZ2V0Iik7cmV0dXJuIG5ldyBqKGZ1bmN0aW9uKHMpe3ZhciBwPWZ1bmN0aW9uKCl7Zm9yKHZhciBjPVtdLGw9MDtsPGFyZ3VtZW50cy5sZW5ndGg7bCsrKWNbbF09YXJndW1lbnRzW2xdO3JldHVybiBzLm5leHQoMTxjLmxlbmd0aD9jOmNbMF0pfTtyZXR1cm4gaShwKSxmdW5jdGlvbigpe3JldHVybiBhKHApfX0pfWZ1bmN0aW9uIFZvKGUsdCl7cmV0dXJuIGZ1bmN0aW9uKHIpe3JldHVybiBmdW5jdGlvbihvKXtyZXR1cm4gZVtyXSh0LG8pfX19ZnVuY3Rpb24gYmEoZSl7cmV0dXJuIEgoZS5hZGRMaXN0ZW5lcikmJkgoZS5yZW1vdmVMaXN0ZW5lcil9ZnVuY3Rpb24gdmEoZSl7cmV0dXJuIEgoZS5vbikmJkgoZS5vZmYpfWZ1bmN0aW9uIGdhKGUpe3JldHVybiBIKGUuYWRkRXZlbnRMaXN0ZW5lcikmJkgoZS5yZW1vdmVFdmVudExpc3RlbmVyKX1mdW5jdGlvbiBhcihlLHQscil7cmV0dXJuIHI/YXIoZSx0KS5waXBlKFplKHIpKTpuZXcgaihmdW5jdGlvbihvKXt2YXIgbj1mdW5jdGlvbigpe2Zvcih2YXIgYT1bXSxzPTA7czxhcmd1bWVudHMubGVuZ3RoO3MrKylhW3NdPWFyZ3VtZW50c1tzXTtyZXR1cm4gby5uZXh0KGEubGVuZ3RoPT09MT9hWzBdOmEpfSxpPWUobik7cmV0dXJuIEgodCk/ZnVuY3Rpb24oKXtyZXR1cm4gdChuLGkpfTp2b2lkIDB9KX1mdW5jdGlvbiBMZShlLHQscil7ZT09PXZvaWQgMCYmKGU9MCkscj09PXZvaWQgMCYmKHI9Q3IpO3ZhciBvPS0xO3JldHVybiB0IT1udWxsJiYoWXQodCk/cj10Om89dCksbmV3IGooZnVuY3Rpb24obil7dmFyIGk9SW8oZSk/K2Utci5ub3coKTplO2k8MCYmKGk9MCk7dmFyIGE9MDtyZXR1cm4gci5zY2hlZHVsZShmdW5jdGlvbigpe24uY2xvc2VkfHwobi5uZXh0KGErKyksMDw9bz90aGlzLnNjaGVkdWxlKHZvaWQgMCxvKTpuLmNvbXBsZXRlKCkpfSxpKX0pfWZ1bmN0aW9uIE8oKXtmb3IodmFyIGU9W10sdD0wO3Q8YXJndW1lbnRzLmxlbmd0aDt0KyspZVt0XT1hcmd1bWVudHNbdF07dmFyIHI9a2UoZSksbz1CdChlLDEvMCksbj1lO3JldHVybiBuLmxlbmd0aD9uLmxlbmd0aD09PTE/VShuWzBdKTpFdChvKSh1ZShuLHIpKTpTfXZhciBZZT1uZXcgaihiZSk7dmFyIHlhPUFycmF5LmlzQXJyYXk7ZnVuY3Rpb24gd3QoZSl7cmV0dXJuIGUubGVuZ3RoPT09MSYmeWEoZVswXSk/ZVswXTplfWZ1bmN0aW9uIGIoZSx0KXtyZXR1cm4gRShmdW5jdGlvbihyLG8pe3ZhciBuPTA7ci5zdWJzY3JpYmUoVChvLGZ1bmN0aW9uKGkpe3JldHVybiBlLmNhbGwodCxpLG4rKykmJm8ubmV4dChpKX0pKX0pfWZ1bmN0aW9uIHN0KCl7Zm9yKHZhciBlPVtdLHQ9MDt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKWVbdF09YXJndW1lbnRzW3RdO3ZhciByPVhlKGUpLG89d3QoZSk7cmV0dXJuIG8ubGVuZ3RoP25ldyBqKGZ1bmN0aW9uKG4pe3ZhciBpPW8ubWFwKGZ1bmN0aW9uKCl7cmV0dXJuW119KSxhPW8ubWFwKGZ1bmN0aW9uKCl7cmV0dXJuITF9KTtuLmFkZChmdW5jdGlvbigpe2k9YT1udWxsfSk7Zm9yKHZhciBzPWZ1bmN0aW9uKGMpe1Uob1tjXSkuc3Vic2NyaWJlKFQobixmdW5jdGlvbihsKXtpZihpW2NdLnB1c2gobCksaS5ldmVyeShmdW5jdGlvbih1KXtyZXR1cm4gdS5sZW5ndGh9KSl7dmFyIGY9aS5tYXAoZnVuY3Rpb24odSl7cmV0dXJuIHUuc2hpZnQoKX0pO24ubmV4dChyP3IuYXBwbHkodm9pZCAwLHEoW10sTihmKSkpOmYpLGkuc29tZShmdW5jdGlvbih1LGQpe3JldHVybiF1Lmxlbmd0aCYmYVtkXX0pJiZuLmNvbXBsZXRlKCl9fSxmdW5jdGlvbigpe2FbY109ITAsIWlbY10ubGVuZ3RoJiZuLmNvbXBsZXRlKCl9KSl9LHA9MDshbi5jbG9zZWQmJnA8by5sZW5ndGg7cCsrKXMocCk7cmV0dXJuIGZ1bmN0aW9uKCl7aT1hPW51bGx9fSk6U31mdW5jdGlvbiBObyhlKXtyZXR1cm4gRShmdW5jdGlvbih0LHIpe3ZhciBvPSExLG49bnVsbCxpPW51bGwsYT0hMSxzPWZ1bmN0aW9uKCl7aWYoaT09bnVsbHx8aS51bnN1YnNjcmliZSgpLGk9bnVsbCxvKXtvPSExO3ZhciBjPW47bj1udWxsLHIubmV4dChjKX1hJiZyLmNvbXBsZXRlKCl9LHA9ZnVuY3Rpb24oKXtpPW51bGwsYSYmci5jb21wbGV0ZSgpfTt0LnN1YnNjcmliZShUKHIsZnVuY3Rpb24oYyl7bz0hMCxuPWMsaXx8VShlKGMpKS5zdWJzY3JpYmUoaT1UKHIscyxwKSl9LGZ1bmN0aW9uKCl7YT0hMCwoIW98fCFpfHxpLmNsb3NlZCkmJnIuY29tcGxldGUoKX0pKX0pfWZ1bmN0aW9uIE1lKGUsdCl7cmV0dXJuIHQ9PT12b2lkIDAmJih0PXNlKSxObyhmdW5jdGlvbigpe3JldHVybiBMZShlLHQpfSl9ZnVuY3Rpb24gQmUoZSx0KXtyZXR1cm4gdD09PXZvaWQgMCYmKHQ9bnVsbCksdD10IT1udWxsP3Q6ZSxFKGZ1bmN0aW9uKHIsbyl7dmFyIG49W10saT0wO3Iuc3Vic2NyaWJlKFQobyxmdW5jdGlvbihhKXt2YXIgcyxwLGMsbCxmPW51bGw7aSsrJXQ9PT0wJiZuLnB1c2goW10pO3RyeXtmb3IodmFyIHU9aGUobiksZD11Lm5leHQoKTshZC5kb25lO2Q9dS5uZXh0KCkpe3ZhciB5PWQudmFsdWU7eS5wdXNoKGEpLGU8PXkubGVuZ3RoJiYoZj1mIT1udWxsP2Y6W10sZi5wdXNoKHkpKX19Y2F0Y2godGUpe3M9e2Vycm9yOnRlfX1maW5hbGx5e3RyeXtkJiYhZC5kb25lJiYocD11LnJldHVybikmJnAuY2FsbCh1KX1maW5hbGx5e2lmKHMpdGhyb3cgcy5lcnJvcn19aWYoZil0cnl7Zm9yKHZhciBMPWhlKGYpLFg9TC5uZXh0KCk7IVguZG9uZTtYPUwubmV4dCgpKXt2YXIgeT1YLnZhbHVlO1FlKG4seSksby5uZXh0KHkpfX1jYXRjaCh0ZSl7Yz17ZXJyb3I6dGV9fWZpbmFsbHl7dHJ5e1gmJiFYLmRvbmUmJihsPUwucmV0dXJuKSYmbC5jYWxsKEwpfWZpbmFsbHl7aWYoYyl0aHJvdyBjLmVycm9yfX19LGZ1bmN0aW9uKCl7dmFyIGEsczt0cnl7Zm9yKHZhciBwPWhlKG4pLGM9cC5uZXh0KCk7IWMuZG9uZTtjPXAubmV4dCgpKXt2YXIgbD1jLnZhbHVlO28ubmV4dChsKX19Y2F0Y2goZil7YT17ZXJyb3I6Zn19ZmluYWxseXt0cnl7YyYmIWMuZG9uZSYmKHM9cC5yZXR1cm4pJiZzLmNhbGwocCl9ZmluYWxseXtpZihhKXRocm93IGEuZXJyb3J9fW8uY29tcGxldGUoKX0sdm9pZCAwLGZ1bmN0aW9uKCl7bj1udWxsfSkpfSl9ZnVuY3Rpb24gZGUoZSl7cmV0dXJuIEUoZnVuY3Rpb24odCxyKXt2YXIgbz1udWxsLG49ITEsaTtvPXQuc3Vic2NyaWJlKFQocix2b2lkIDAsdm9pZCAwLGZ1bmN0aW9uKGEpe2k9VShlKGEsZGUoZSkodCkpKSxvPyhvLnVuc3Vic2NyaWJlKCksbz1udWxsLGkuc3Vic2NyaWJlKHIpKTpuPSEwfSkpLG4mJihvLnVuc3Vic2NyaWJlKCksbz1udWxsLGkuc3Vic2NyaWJlKHIpKX0pfWZ1bmN0aW9uIHpvKGUsdCxyLG8sbil7cmV0dXJuIGZ1bmN0aW9uKGksYSl7dmFyIHM9cixwPXQsYz0wO2kuc3Vic2NyaWJlKFQoYSxmdW5jdGlvbihsKXt2YXIgZj1jKys7cD1zP2UocCxsLGYpOihzPSEwLGwpLG8mJmEubmV4dChwKX0sbiYmZnVuY3Rpb24oKXtzJiZhLm5leHQocCksYS5jb21wbGV0ZSgpfSkpfX1mdW5jdGlvbiBScigpe2Zvcih2YXIgZT1bXSx0PTA7dDxhcmd1bWVudHMubGVuZ3RoO3QrKyllW3RdPWFyZ3VtZW50c1t0XTt2YXIgcj1YZShlKTtyZXR1cm4gcj94byhSci5hcHBseSh2b2lkIDAscShbXSxOKGUpKSksWmUocikpOkUoZnVuY3Rpb24obyxuKXtQcihxKFtvXSxOKHd0KGUpKSkpKG4pfSl9ZnVuY3Rpb24gSGUoKXtmb3IodmFyIGU9W10sdD0wO3Q8YXJndW1lbnRzLmxlbmd0aDt0KyspZVt0XT1hcmd1bWVudHNbdF07cmV0dXJuIFJyLmFwcGx5KHZvaWQgMCxxKFtdLE4oZSkpKX1mdW5jdGlvbiBIdChlKXtyZXR1cm4gRShmdW5jdGlvbih0LHIpe3ZhciBvPSExLG49bnVsbCxpPW51bGwsYT1mdW5jdGlvbigpe2lmKGk9PW51bGx8fGkudW5zdWJzY3JpYmUoKSxpPW51bGwsbyl7bz0hMTt2YXIgcz1uO249bnVsbCxyLm5leHQocyl9fTt0LnN1YnNjcmliZShUKHIsZnVuY3Rpb24ocyl7aT09bnVsbHx8aS51bnN1YnNjcmliZSgpLG89ITAsbj1zLGk9VChyLGEsYmUpLFUoZShzKSkuc3Vic2NyaWJlKGkpfSxmdW5jdGlvbigpe2EoKSxyLmNvbXBsZXRlKCl9LHZvaWQgMCxmdW5jdGlvbigpe249aT1udWxsfSkpfSl9ZnVuY3Rpb24gX2UoZSx0KXtyZXR1cm4gdD09PXZvaWQgMCYmKHQ9c2UpLEUoZnVuY3Rpb24ocixvKXt2YXIgbj1udWxsLGk9bnVsbCxhPW51bGwscz1mdW5jdGlvbigpe2lmKG4pe24udW5zdWJzY3JpYmUoKSxuPW51bGw7dmFyIGM9aTtpPW51bGwsby5uZXh0KGMpfX07ZnVuY3Rpb24gcCgpe3ZhciBjPWErZSxsPXQubm93KCk7aWYobDxjKXtuPXRoaXMuc2NoZWR1bGUodm9pZCAwLGMtbCksby5hZGQobik7cmV0dXJufXMoKX1yLnN1YnNjcmliZShUKG8sZnVuY3Rpb24oYyl7aT1jLGE9dC5ub3coKSxufHwobj10LnNjaGVkdWxlKHAsZSksby5hZGQobikpfSxmdW5jdGlvbigpe3MoKSxvLmNvbXBsZXRlKCl9LHZvaWQgMCxmdW5jdGlvbigpe2k9bj1udWxsfSkpfSl9ZnVuY3Rpb24gRGUoZSl7cmV0dXJuIEUoZnVuY3Rpb24odCxyKXt2YXIgbz0hMTt0LnN1YnNjcmliZShUKHIsZnVuY3Rpb24obil7bz0hMCxyLm5leHQobil9LGZ1bmN0aW9uKCl7b3x8ci5uZXh0KGUpLHIuY29tcGxldGUoKX0pKX0pfWZ1bmN0aW9uIFRlKGUpe3JldHVybiBlPD0wP2Z1bmN0aW9uKCl7cmV0dXJuIFN9OkUoZnVuY3Rpb24odCxyKXt2YXIgbz0wO3Quc3Vic2NyaWJlKFQocixmdW5jdGlvbihuKXsrK288PWUmJihyLm5leHQobiksZTw9byYmci5jb21wbGV0ZSgpKX0pKX0pfWZ1bmN0aW9uIFooKXtyZXR1cm4gRShmdW5jdGlvbihlLHQpe2Uuc3Vic2NyaWJlKFQodCxiZSkpfSl9ZnVuY3Rpb24gcW8oZSl7cmV0dXJuIG0oZnVuY3Rpb24oKXtyZXR1cm4gZX0pfWZ1bmN0aW9uIElyKGUsdCl7cmV0dXJuIHQ/ZnVuY3Rpb24ocil7cmV0dXJuIFdlKHQucGlwZShUZSgxKSxaKCkpLHIucGlwZShJcihlKSkpfTpuZShmdW5jdGlvbihyLG8pe3JldHVybiBVKGUocixvKSkucGlwZShUZSgxKSxxbyhyKSl9KX1mdW5jdGlvbiBHZShlLHQpe3Q9PT12b2lkIDAmJih0PXNlKTt2YXIgcj1MZShlLHQpO3JldHVybiBJcihmdW5jdGlvbigpe3JldHVybiByfSl9ZnVuY3Rpb24gSyhlLHQpe3JldHVybiB0PT09dm9pZCAwJiYodD1sZSksZT1lIT1udWxsP2U6eGEsRShmdW5jdGlvbihyLG8pe3ZhciBuLGk9ITA7ci5zdWJzY3JpYmUoVChvLGZ1bmN0aW9uKGEpe3ZhciBzPXQoYSk7KGl8fCFlKG4scykpJiYoaT0hMSxuPXMsby5uZXh0KGEpKX0pKX0pfWZ1bmN0aW9uIHhhKGUsdCl7cmV0dXJuIGU9PT10fWZ1bmN0aW9uIGVlKGUsdCl7cmV0dXJuIEsoZnVuY3Rpb24ocixvKXtyZXR1cm4gdD90KHJbZV0sb1tlXSk6cltlXT09PW9bZV19KX1mdW5jdGlvbiBRbyhlKXtyZXR1cm4gZT09PXZvaWQgMCYmKGU9RWEpLEUoZnVuY3Rpb24odCxyKXt2YXIgbz0hMTt0LnN1YnNjcmliZShUKHIsZnVuY3Rpb24obil7bz0hMCxyLm5leHQobil9LGZ1bmN0aW9uKCl7cmV0dXJuIG8/ci5jb21wbGV0ZSgpOnIuZXJyb3IoZSgpKX0pKX0pfWZ1bmN0aW9uIEVhKCl7cmV0dXJuIG5ldyBpcn1mdW5jdGlvbiBpZSgpe2Zvcih2YXIgZT1bXSx0PTA7dDxhcmd1bWVudHMubGVuZ3RoO3QrKyllW3RdPWFyZ3VtZW50c1t0XTtyZXR1cm4gZnVuY3Rpb24ocil7cmV0dXJuIFdlKHIsSS5hcHBseSh2b2lkIDAscShbXSxOKGUpKSkpfX1mdW5jdGlvbiBfKGUpe3JldHVybiBFKGZ1bmN0aW9uKHQscil7dHJ5e3Quc3Vic2NyaWJlKHIpfWZpbmFsbHl7ci5hZGQoZSl9fSl9ZnVuY3Rpb24gQWUoZSx0KXt2YXIgcj1hcmd1bWVudHMubGVuZ3RoPj0yO3JldHVybiBmdW5jdGlvbihvKXtyZXR1cm4gby5waXBlKGU/YihmdW5jdGlvbihuLGkpe3JldHVybiBlKG4saSxvKX0pOmxlLFRlKDEpLHI/RGUodCk6UW8oZnVuY3Rpb24oKXtyZXR1cm4gbmV3IGlyfSkpfX1mdW5jdGlvbiBqcihlKXtyZXR1cm4gZTw9MD9mdW5jdGlvbigpe3JldHVybiBTfTpFKGZ1bmN0aW9uKHQscil7dmFyIG89W107dC5zdWJzY3JpYmUoVChyLGZ1bmN0aW9uKG4pe28ucHVzaChuKSxlPG8ubGVuZ3RoJiZvLnNoaWZ0KCl9LGZ1bmN0aW9uKCl7dmFyIG4saTt0cnl7Zm9yKHZhciBhPWhlKG8pLHM9YS5uZXh0KCk7IXMuZG9uZTtzPWEubmV4dCgpKXt2YXIgcD1zLnZhbHVlO3IubmV4dChwKX19Y2F0Y2goYyl7bj17ZXJyb3I6Y319ZmluYWxseXt0cnl7cyYmIXMuZG9uZSYmKGk9YS5yZXR1cm4pJiZpLmNhbGwoYSl9ZmluYWxseXtpZihuKXRocm93IG4uZXJyb3J9fXIuY29tcGxldGUoKX0sdm9pZCAwLGZ1bmN0aW9uKCl7bz1udWxsfSkpfSl9ZnVuY3Rpb24gS28oKXtmb3IodmFyIGU9W10sdD0wO3Q8YXJndW1lbnRzLmxlbmd0aDt0KyspZVt0XT1hcmd1bWVudHNbdF07dmFyIHI9a2UoZSksbz1CdChlLDEvMCk7cmV0dXJuIGU9d3QoZSksRShmdW5jdGlvbihuLGkpe0V0KG8pKHVlKHEoW25dLE4oZSkpLHIpKS5zdWJzY3JpYmUoaSl9KX1mdW5jdGlvbiBSZSgpe2Zvcih2YXIgZT1bXSx0PTA7dDxhcmd1bWVudHMubGVuZ3RoO3QrKyllW3RdPWFyZ3VtZW50c1t0XTtyZXR1cm4gS28uYXBwbHkodm9pZCAwLHEoW10sTihlKSkpfWZ1bmN0aW9uIGN0KGUpe3ZhciB0LHI9MS8wLG87cmV0dXJuIGUhPW51bGwmJih0eXBlb2YgZT09Im9iamVjdCI/KHQ9ZS5jb3VudCxyPXQ9PT12b2lkIDA/MS8wOnQsbz1lLmRlbGF5KTpyPWUpLHI8PTA/ZnVuY3Rpb24oKXtyZXR1cm4gU306RShmdW5jdGlvbihuLGkpe3ZhciBhPTAscyxwPWZ1bmN0aW9uKCl7aWYocz09bnVsbHx8cy51bnN1YnNjcmliZSgpLHM9bnVsbCxvIT1udWxsKXt2YXIgbD10eXBlb2Ygbz09Im51bWJlciI/TGUobyk6VShvKGEpKSxmPVQoaSxmdW5jdGlvbigpe2YudW5zdWJzY3JpYmUoKSxjKCl9KTtsLnN1YnNjcmliZShmKX1lbHNlIGMoKX0sYz1mdW5jdGlvbigpe3ZhciBsPSExO3M9bi5zdWJzY3JpYmUoVChpLHZvaWQgMCxmdW5jdGlvbigpeysrYTxyP3M/cCgpOmw9ITA6aS5jb21wbGV0ZSgpfSkpLGwmJnAoKX07YygpfSl9ZnVuY3Rpb24gRnIoZSx0KXtyZXR1cm4gRSh6byhlLHQsYXJndW1lbnRzLmxlbmd0aD49MiwhMCkpfWZ1bmN0aW9uIHBlKGUpe2U9PT12b2lkIDAmJihlPXt9KTt2YXIgdD1lLmNvbm5lY3RvcixyPXQ9PT12b2lkIDA/ZnVuY3Rpb24oKXtyZXR1cm4gbmV3IGd9OnQsbz1lLnJlc2V0T25FcnJvcixuPW89PT12b2lkIDA/ITA6byxpPWUucmVzZXRPbkNvbXBsZXRlLGE9aT09PXZvaWQgMD8hMDppLHM9ZS5yZXNldE9uUmVmQ291bnRaZXJvLHA9cz09PXZvaWQgMD8hMDpzO3JldHVybiBmdW5jdGlvbihjKXt2YXIgbCxmLHUsZD0wLHk9ITEsTD0hMSxYPWZ1bmN0aW9uKCl7Zj09bnVsbHx8Zi51bnN1YnNjcmliZSgpLGY9dm9pZCAwfSx0ZT1mdW5jdGlvbigpe1goKSxsPXU9dm9pZCAwLHk9TD0hMX0sSj1mdW5jdGlvbigpe3ZhciBrPWw7dGUoKSxrPT1udWxsfHxrLnVuc3Vic2NyaWJlKCl9O3JldHVybiBFKGZ1bmN0aW9uKGssZnQpe2QrKywhTCYmIXkmJlgoKTt2YXIgcWU9dT11IT1udWxsP3U6cigpO2Z0LmFkZChmdW5jdGlvbigpe2QtLSxkPT09MCYmIUwmJiF5JiYoZj1VcihKLHApKX0pLHFlLnN1YnNjcmliZShmdCksIWwmJmQ+MCYmKGw9bmV3IGF0KHtuZXh0OmZ1bmN0aW9uKEZlKXtyZXR1cm4gcWUubmV4dChGZSl9LGVycm9yOmZ1bmN0aW9uKEZlKXtMPSEwLFgoKSxmPVVyKHRlLG4sRmUpLHFlLmVycm9yKEZlKX0sY29tcGxldGU6ZnVuY3Rpb24oKXt5PSEwLFgoKSxmPVVyKHRlLGEpLHFlLmNvbXBsZXRlKCl9fSksVShrKS5zdWJzY3JpYmUobCkpfSkoYyl9fWZ1bmN0aW9uIFVyKGUsdCl7Zm9yKHZhciByPVtdLG89MjtvPGFyZ3VtZW50cy5sZW5ndGg7bysrKXJbby0yXT1hcmd1bWVudHNbb107aWYodD09PSEwKXtlKCk7cmV0dXJufWlmKHQhPT0hMSl7dmFyIG49bmV3IGF0KHtuZXh0OmZ1bmN0aW9uKCl7bi51bnN1YnNjcmliZSgpLGUoKX19KTtyZXR1cm4gVSh0LmFwcGx5KHZvaWQgMCxxKFtdLE4ocikpKSkuc3Vic2NyaWJlKG4pfX1mdW5jdGlvbiBHKGUsdCxyKXt2YXIgbyxuLGksYSxzPSExO3JldHVybiBlJiZ0eXBlb2YgZT09Im9iamVjdCI/KG89ZS5idWZmZXJTaXplLGE9bz09PXZvaWQgMD8xLzA6byxuPWUud2luZG93VGltZSx0PW49PT12b2lkIDA/MS8wOm4saT1lLnJlZkNvdW50LHM9aT09PXZvaWQgMD8hMTppLHI9ZS5zY2hlZHVsZXIpOmE9ZSE9bnVsbD9lOjEvMCxwZSh7Y29ubmVjdG9yOmZ1bmN0aW9uKCl7cmV0dXJuIG5ldyBDdChhLHQscil9LHJlc2V0T25FcnJvcjohMCxyZXNldE9uQ29tcGxldGU6ITEscmVzZXRPblJlZkNvdW50WmVybzpzfSl9ZnVuY3Rpb24gQ2UoZSl7cmV0dXJuIGIoZnVuY3Rpb24odCxyKXtyZXR1cm4gZTw9cn0pfWZ1bmN0aW9uIFdyKGUpe3JldHVybiBFKGZ1bmN0aW9uKHQscil7dmFyIG89ITEsbj1UKHIsZnVuY3Rpb24oKXtuPT1udWxsfHxuLnVuc3Vic2NyaWJlKCksbz0hMH0sYmUpO1UoZSkuc3Vic2NyaWJlKG4pLHQuc3Vic2NyaWJlKFQocixmdW5jdGlvbihpKXtyZXR1cm4gbyYmci5uZXh0KGkpfSkpfSl9ZnVuY3Rpb24gUSgpe2Zvcih2YXIgZT1bXSx0PTA7dDxhcmd1bWVudHMubGVuZ3RoO3QrKyllW3RdPWFyZ3VtZW50c1t0XTt2YXIgcj1rZShlKTtyZXR1cm4gRShmdW5jdGlvbihvLG4peyhyP1dlKGUsbyxyKTpXZShlLG8pKS5zdWJzY3JpYmUobil9KX1mdW5jdGlvbiB2KGUsdCl7cmV0dXJuIEUoZnVuY3Rpb24ocixvKXt2YXIgbj1udWxsLGk9MCxhPSExLHM9ZnVuY3Rpb24oKXtyZXR1cm4gYSYmIW4mJm8uY29tcGxldGUoKX07ci5zdWJzY3JpYmUoVChvLGZ1bmN0aW9uKHApe249PW51bGx8fG4udW5zdWJzY3JpYmUoKTt2YXIgYz0wLGw9aSsrO1UoZShwLGwpKS5zdWJzY3JpYmUobj1UKG8sZnVuY3Rpb24oZil7cmV0dXJuIG8ubmV4dCh0P3QocCxmLGwsYysrKTpmKX0sZnVuY3Rpb24oKXtuPW51bGwscygpfSkpfSxmdW5jdGlvbigpe2E9ITAscygpfSkpfSl9ZnVuY3Rpb24gVyhlKXtyZXR1cm4gRShmdW5jdGlvbih0LHIpe1UoZSkuc3Vic2NyaWJlKFQocixmdW5jdGlvbigpe3JldHVybiByLmNvbXBsZXRlKCl9LGJlKSksIXIuY2xvc2VkJiZ0LnN1YnNjcmliZShyKX0pfWZ1bmN0aW9uIERyKGUsdCl7cmV0dXJuIHQ9PT12b2lkIDAmJih0PSExKSxFKGZ1bmN0aW9uKHIsbyl7dmFyIG49MDtyLnN1YnNjcmliZShUKG8sZnVuY3Rpb24oaSl7dmFyIGE9ZShpLG4rKyk7KGF8fHQpJiZvLm5leHQoaSksIWEmJm8uY29tcGxldGUoKX0pKX0pfWZ1bmN0aW9uIHcoZSx0LHIpe3ZhciBvPUgoZSl8fHR8fHI/e25leHQ6ZSxlcnJvcjp0LGNvbXBsZXRlOnJ9OmU7cmV0dXJuIG8/RShmdW5jdGlvbihuLGkpe3ZhciBhOyhhPW8uc3Vic2NyaWJlKT09PW51bGx8fGE9PT12b2lkIDB8fGEuY2FsbChvKTt2YXIgcz0hMDtuLnN1YnNjcmliZShUKGksZnVuY3Rpb24ocCl7dmFyIGM7KGM9by5uZXh0KT09PW51bGx8fGM9PT12b2lkIDB8fGMuY2FsbChvLHApLGkubmV4dChwKX0sZnVuY3Rpb24oKXt2YXIgcDtzPSExLChwPW8uY29tcGxldGUpPT09bnVsbHx8cD09PXZvaWQgMHx8cC5jYWxsKG8pLGkuY29tcGxldGUoKX0sZnVuY3Rpb24ocCl7dmFyIGM7cz0hMSwoYz1vLmVycm9yKT09PW51bGx8fGM9PT12b2lkIDB8fGMuY2FsbChvLHApLGkuZXJyb3IocCl9LGZ1bmN0aW9uKCl7dmFyIHAsYztzJiYoKHA9by51bnN1YnNjcmliZSk9PT1udWxsfHxwPT09dm9pZCAwfHxwLmNhbGwobykpLChjPW8uZmluYWxpemUpPT09bnVsbHx8Yz09PXZvaWQgMHx8Yy5jYWxsKG8pfSkpfSk6bGV9ZnVuY3Rpb24gWW8oZSx0KXtyZXR1cm4gRShmdW5jdGlvbihyLG8pe3ZhciBuPXQhPW51bGw/dDp7fSxpPW4ubGVhZGluZyxhPWk9PT12b2lkIDA/ITA6aSxzPW4udHJhaWxpbmcscD1zPT09dm9pZCAwPyExOnMsYz0hMSxsPW51bGwsZj1udWxsLHU9ITEsZD1mdW5jdGlvbigpe2Y9PW51bGx8fGYudW5zdWJzY3JpYmUoKSxmPW51bGwscCYmKFgoKSx1JiZvLmNvbXBsZXRlKCkpfSx5PWZ1bmN0aW9uKCl7Zj1udWxsLHUmJm8uY29tcGxldGUoKX0sTD1mdW5jdGlvbih0ZSl7cmV0dXJuIGY9VShlKHRlKSkuc3Vic2NyaWJlKFQobyxkLHkpKX0sWD1mdW5jdGlvbigpe2lmKGMpe2M9ITE7dmFyIHRlPWw7bD1udWxsLG8ubmV4dCh0ZSksIXUmJkwodGUpfX07ci5zdWJzY3JpYmUoVChvLGZ1bmN0aW9uKHRlKXtjPSEwLGw9dGUsIShmJiYhZi5jbG9zZWQpJiYoYT9YKCk6TCh0ZSkpfSxmdW5jdGlvbigpe3U9ITAsIShwJiZjJiZmJiYhZi5jbG9zZWQpJiZvLmNvbXBsZXRlKCl9KSl9KX1mdW5jdGlvbiBwdChlLHQscil7dD09PXZvaWQgMCYmKHQ9c2UpO3ZhciBvPUxlKGUsdCk7cmV0dXJuIFlvKGZ1bmN0aW9uKCl7cmV0dXJuIG99LHIpfWZ1bmN0aW9uIHJlKCl7Zm9yKHZhciBlPVtdLHQ9MDt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKWVbdF09YXJndW1lbnRzW3RdO3ZhciByPVhlKGUpO3JldHVybiBFKGZ1bmN0aW9uKG8sbil7Zm9yKHZhciBpPWUubGVuZ3RoLGE9bmV3IEFycmF5KGkpLHM9ZS5tYXAoZnVuY3Rpb24oKXtyZXR1cm4hMX0pLHA9ITEsYz1mdW5jdGlvbihmKXtVKGVbZl0pLnN1YnNjcmliZShUKG4sZnVuY3Rpb24odSl7YVtmXT11LCFwJiYhc1tmXSYmKHNbZl09ITAsKHA9cy5ldmVyeShsZSkpJiYocz1udWxsKSl9LGJlKSl9LGw9MDtsPGk7bCsrKWMobCk7by5zdWJzY3JpYmUoVChuLGZ1bmN0aW9uKGYpe2lmKHApe3ZhciB1PXEoW2ZdLE4oYSkpO24ubmV4dChyP3IuYXBwbHkodm9pZCAwLHEoW10sTih1KSkpOnUpfX0pKX0pfWZ1bmN0aW9uIEJvKCl7Zm9yKHZhciBlPVtdLHQ9MDt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKWVbdF09YXJndW1lbnRzW3RdO3JldHVybiBFKGZ1bmN0aW9uKHIsbyl7c3QuYXBwbHkodm9pZCAwLHEoW3JdLE4oZSkpKS5zdWJzY3JpYmUobyl9KX1mdW5jdGlvbiBWcigpe2Zvcih2YXIgZT1bXSx0PTA7dDxhcmd1bWVudHMubGVuZ3RoO3QrKyllW3RdPWFyZ3VtZW50c1t0XTtyZXR1cm4gQm8uYXBwbHkodm9pZCAwLHEoW10sTihlKSkpfWZ1bmN0aW9uIEdvKCl7bGV0IGU9bmV3IEN0KDEpO3JldHVybiBoKGRvY3VtZW50LCJET01Db250ZW50TG9hZGVkIix7b25jZTohMH0pLnN1YnNjcmliZSgoKT0+ZS5uZXh0KGRvY3VtZW50KSksZX1mdW5jdGlvbiBQKGUsdD1kb2N1bWVudCl7cmV0dXJuIEFycmF5LmZyb20odC5xdWVyeVNlbGVjdG9yQWxsKGUpKX1mdW5jdGlvbiBSKGUsdD1kb2N1bWVudCl7bGV0IHI9ZmUoZSx0KTtpZih0eXBlb2Ygcj09InVuZGVmaW5lZCIpdGhyb3cgbmV3IFJlZmVyZW5jZUVycm9yKGBNaXNzaW5nIGVsZW1lbnQ6IGV4cGVjdGVkICIke2V9IiB0byBiZSBwcmVzZW50YCk7cmV0dXJuIHJ9ZnVuY3Rpb24gZmUoZSx0PWRvY3VtZW50KXtyZXR1cm4gdC5xdWVyeVNlbGVjdG9yKGUpfHx2b2lkIDB9ZnVuY3Rpb24gSWUoKXt2YXIgZSx0LHIsbztyZXR1cm4obz0ocj0odD0oZT1kb2N1bWVudC5hY3RpdmVFbGVtZW50KT09bnVsbD92b2lkIDA6ZS5zaGFkb3dSb290KT09bnVsbD92b2lkIDA6dC5hY3RpdmVFbGVtZW50KSE9bnVsbD9yOmRvY3VtZW50LmFjdGl2ZUVsZW1lbnQpIT1udWxsP286dm9pZCAwfXZhciB3YT1PKGgoZG9jdW1lbnQuYm9keSwiZm9jdXNpbiIpLGgoZG9jdW1lbnQuYm9keSwiZm9jdXNvdXQiKSkucGlwZShfZSgxKSxRKHZvaWQgMCksbSgoKT0+SWUoKXx8ZG9jdW1lbnQuYm9keSksRygxKSk7ZnVuY3Rpb24gZXQoZSl7cmV0dXJuIHdhLnBpcGUobSh0PT5lLmNvbnRhaW5zKHQpKSxLKCkpfWZ1bmN0aW9uICR0KGUsdCl7cmV0dXJuIEMoKCk9Pk8oaChlLCJtb3VzZWVudGVyIikucGlwZShtKCgpPT4hMCkpLGgoZSwibW91c2VsZWF2ZSIpLnBpcGUobSgoKT0+ITEpKSkucGlwZSh0P0h0KHI9PkxlKCshcip0KSk6bGUsUShlLm1hdGNoZXMoIjpob3ZlciIpKSkpfWZ1bmN0aW9uIEpvKGUsdCl7aWYodHlwZW9mIHQ9PSJzdHJpbmcifHx0eXBlb2YgdD09Im51bWJlciIpZS5pbm5lckhUTUwrPXQudG9TdHJpbmcoKTtlbHNlIGlmKHQgaW5zdGFuY2VvZiBOb2RlKWUuYXBwZW5kQ2hpbGQodCk7ZWxzZSBpZihBcnJheS5pc0FycmF5KHQpKWZvcihsZXQgciBvZiB0KUpvKGUscil9ZnVuY3Rpb24geChlLHQsLi4ucil7bGV0IG89ZG9jdW1lbnQuY3JlYXRlRWxlbWVudChlKTtpZih0KWZvcihsZXQgbiBvZiBPYmplY3Qua2V5cyh0KSl0eXBlb2YgdFtuXSE9InVuZGVmaW5lZCImJih0eXBlb2YgdFtuXSE9ImJvb2xlYW4iP28uc2V0QXR0cmlidXRlKG4sdFtuXSk6by5zZXRBdHRyaWJ1dGUobiwiIikpO2ZvcihsZXQgbiBvZiByKUpvKG8sbik7cmV0dXJuIG99ZnVuY3Rpb24gc3IoZSl7aWYoZT45OTkpe2xldCB0PSsoKGUtOTUwKSUxZTM+OTkpO3JldHVybmAkeygoZSsxZS02KS8xZTMpLnRvRml4ZWQodCl9a2B9ZWxzZSByZXR1cm4gZS50b1N0cmluZygpfWZ1bmN0aW9uIFR0KGUpe2xldCB0PXgoInNjcmlwdCIse3NyYzplfSk7cmV0dXJuIEMoKCk9Pihkb2N1bWVudC5oZWFkLmFwcGVuZENoaWxkKHQpLE8oaCh0LCJsb2FkIiksaCh0LCJlcnJvciIpLnBpcGUodigoKT0+JHIoKCk9Pm5ldyBSZWZlcmVuY2VFcnJvcihgSW52YWxpZCBzY3JpcHQ6ICR7ZX1gKSkpKSkucGlwZShtKCgpPT57fSksXygoKT0+ZG9jdW1lbnQuaGVhZC5yZW1vdmVDaGlsZCh0KSksVGUoMSkpKSl9dmFyIFhvPW5ldyBnLFRhPUMoKCk9PnR5cGVvZiBSZXNpemVPYnNlcnZlcj09InVuZGVmaW5lZCI/VHQoImh0dHBzOi8vdW5wa2cuY29tL3Jlc2l6ZS1vYnNlcnZlci1wb2x5ZmlsbCIpOkkodm9pZCAwKSkucGlwZShtKCgpPT5uZXcgUmVzaXplT2JzZXJ2ZXIoZT0+ZS5mb3JFYWNoKHQ9PlhvLm5leHQodCkpKSksdihlPT5PKFllLEkoZSkpLnBpcGUoXygoKT0+ZS5kaXNjb25uZWN0KCkpKSksRygxKSk7ZnVuY3Rpb24gY2UoZSl7cmV0dXJue3dpZHRoOmUub2Zmc2V0V2lkdGgsaGVpZ2h0OmUub2Zmc2V0SGVpZ2h0fX1mdW5jdGlvbiBnZShlKXtsZXQgdD1lO2Zvcig7dC5jbGllbnRXaWR0aD09PTAmJnQucGFyZW50RWxlbWVudDspdD10LnBhcmVudEVsZW1lbnQ7cmV0dXJuIFRhLnBpcGUodyhyPT5yLm9ic2VydmUodCkpLHYocj0+WG8ucGlwZShiKG89Pm8udGFyZ2V0PT09dCksXygoKT0+ci51bm9ic2VydmUodCkpKSksbSgoKT0+Y2UoZSkpLFEoY2UoZSkpKX1mdW5jdGlvbiBTdChlKXtyZXR1cm57d2lkdGg6ZS5zY3JvbGxXaWR0aCxoZWlnaHQ6ZS5zY3JvbGxIZWlnaHR9fWZ1bmN0aW9uIGNyKGUpe2xldCB0PWUucGFyZW50RWxlbWVudDtmb3IoO3QmJihlLnNjcm9sbFdpZHRoPD10LnNjcm9sbFdpZHRoJiZlLnNjcm9sbEhlaWdodDw9dC5zY3JvbGxIZWlnaHQpOyl0PShlPXQpLnBhcmVudEVsZW1lbnQ7cmV0dXJuIHQ/ZTp2b2lkIDB9ZnVuY3Rpb24gWm8oZSl7bGV0IHQ9W10scj1lLnBhcmVudEVsZW1lbnQ7Zm9yKDtyOykoZS5jbGllbnRXaWR0aD5yLmNsaWVudFdpZHRofHxlLmNsaWVudEhlaWdodD5yLmNsaWVudEhlaWdodCkmJnQucHVzaChyKSxyPShlPXIpLnBhcmVudEVsZW1lbnQ7cmV0dXJuIHQubGVuZ3RoPT09MCYmdC5wdXNoKGRvY3VtZW50LmRvY3VtZW50RWxlbWVudCksdH1mdW5jdGlvbiBWZShlKXtyZXR1cm57eDplLm9mZnNldExlZnQseTplLm9mZnNldFRvcH19ZnVuY3Rpb24gZW4oZSl7bGV0IHQ9ZS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtyZXR1cm57eDp0Lngrd2luZG93LnNjcm9sbFgseTp0Lnkrd2luZG93LnNjcm9sbFl9fWZ1bmN0aW9uIHRuKGUpe3JldHVybiBPKGgod2luZG93LCJsb2FkIiksaCh3aW5kb3csInJlc2l6ZSIpKS5waXBlKE1lKDAsbWUpLG0oKCk9PlZlKGUpKSxRKFZlKGUpKSl9ZnVuY3Rpb24gcHIoZSl7cmV0dXJue3g6ZS5zY3JvbGxMZWZ0LHk6ZS5zY3JvbGxUb3B9fWZ1bmN0aW9uIE5lKGUpe3JldHVybiBPKGgoZSwic2Nyb2xsIiksaCh3aW5kb3csInNjcm9sbCIpLGgod2luZG93LCJyZXNpemUiKSkucGlwZShNZSgwLG1lKSxtKCgpPT5wcihlKSksUShwcihlKSkpfXZhciBybj1uZXcgZyxTYT1DKCgpPT5JKG5ldyBJbnRlcnNlY3Rpb25PYnNlcnZlcihlPT57Zm9yKGxldCB0IG9mIGUpcm4ubmV4dCh0KX0se3RocmVzaG9sZDowfSkpKS5waXBlKHYoZT0+TyhZZSxJKGUpKS5waXBlKF8oKCk9PmUuZGlzY29ubmVjdCgpKSkpLEcoMSkpO2Z1bmN0aW9uIHR0KGUpe3JldHVybiBTYS5waXBlKHcodD0+dC5vYnNlcnZlKGUpKSx2KHQ9PnJuLnBpcGUoYigoe3RhcmdldDpyfSk9PnI9PT1lKSxfKCgpPT50LnVub2JzZXJ2ZShlKSksbSgoe2lzSW50ZXJzZWN0aW5nOnJ9KT0+cikpKSl9ZnVuY3Rpb24gb24oZSx0PTE2KXtyZXR1cm4gTmUoZSkucGlwZShtKCh7eTpyfSk9PntsZXQgbz1jZShlKSxuPVN0KGUpO3JldHVybiByPj1uLmhlaWdodC1vLmhlaWdodC10fSksSygpKX12YXIgbHI9e2RyYXdlcjpSKCJbZGF0YS1tZC10b2dnbGU9ZHJhd2VyXSIpLHNlYXJjaDpSKCJbZGF0YS1tZC10b2dnbGU9c2VhcmNoXSIpfTtmdW5jdGlvbiBubihlKXtyZXR1cm4gbHJbZV0uY2hlY2tlZH1mdW5jdGlvbiBKZShlLHQpe2xyW2VdLmNoZWNrZWQhPT10JiZscltlXS5jbGljaygpfWZ1bmN0aW9uIHplKGUpe2xldCB0PWxyW2VdO3JldHVybiBoKHQsImNoYW5nZSIpLnBpcGUobSgoKT0+dC5jaGVja2VkKSxRKHQuY2hlY2tlZCkpfWZ1bmN0aW9uIE9hKGUsdCl7c3dpdGNoKGUuY29uc3RydWN0b3Ipe2Nhc2UgSFRNTElucHV0RWxlbWVudDpyZXR1cm4gZS50eXBlPT09InJhZGlvIj8vXkFycm93Ly50ZXN0KHQpOiEwO2Nhc2UgSFRNTFNlbGVjdEVsZW1lbnQ6Y2FzZSBIVE1MVGV4dEFyZWFFbGVtZW50OnJldHVybiEwO2RlZmF1bHQ6cmV0dXJuIGUuaXNDb250ZW50RWRpdGFibGV9fWZ1bmN0aW9uIExhKCl7cmV0dXJuIE8oaCh3aW5kb3csImNvbXBvc2l0aW9uc3RhcnQiKS5waXBlKG0oKCk9PiEwKSksaCh3aW5kb3csImNvbXBvc2l0aW9uZW5kIikucGlwZShtKCgpPT4hMSkpKS5waXBlKFEoITEpKX1mdW5jdGlvbiBhbigpe2xldCBlPWgod2luZG93LCJrZXlkb3duIikucGlwZShiKHQ9PiEodC5tZXRhS2V5fHx0LmN0cmxLZXkpKSxtKHQ9Pih7bW9kZTpubigic2VhcmNoIik/InNlYXJjaCI6Imdsb2JhbCIsdHlwZTp0LmtleSxjbGFpbSgpe3QucHJldmVudERlZmF1bHQoKSx0LnN0b3BQcm9wYWdhdGlvbigpfX0pKSxiKCh7bW9kZTp0LHR5cGU6cn0pPT57aWYodD09PSJnbG9iYWwiKXtsZXQgbz1JZSgpO2lmKHR5cGVvZiBvIT0idW5kZWZpbmVkIilyZXR1cm4hT2EobyxyKX1yZXR1cm4hMH0pLHBlKCkpO3JldHVybiBMYSgpLnBpcGUodih0PT50P1M6ZSkpfWZ1bmN0aW9uIHllKCl7cmV0dXJuIG5ldyBVUkwobG9jYXRpb24uaHJlZil9ZnVuY3Rpb24gbHQoZSx0PSExKXtpZihCKCJuYXZpZ2F0aW9uLmluc3RhbnQiKSYmIXQpe2xldCByPXgoImEiLHtocmVmOmUuaHJlZn0pO2RvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQociksci5jbGljaygpLHIucmVtb3ZlKCl9ZWxzZSBsb2NhdGlvbi5ocmVmPWUuaHJlZn1mdW5jdGlvbiBzbigpe3JldHVybiBuZXcgZ31mdW5jdGlvbiBjbigpe3JldHVybiBsb2NhdGlvbi5oYXNoLnNsaWNlKDEpfWZ1bmN0aW9uIHBuKGUpe2xldCB0PXgoImEiLHtocmVmOmV9KTt0LmFkZEV2ZW50TGlzdGVuZXIoImNsaWNrIixyPT5yLnN0b3BQcm9wYWdhdGlvbigpKSx0LmNsaWNrKCl9ZnVuY3Rpb24gTWEoZSl7cmV0dXJuIE8oaCh3aW5kb3csImhhc2hjaGFuZ2UiKSxlKS5waXBlKG0oY24pLFEoY24oKSksYih0PT50Lmxlbmd0aD4wKSxHKDEpKX1mdW5jdGlvbiBsbihlKXtyZXR1cm4gTWEoZSkucGlwZShtKHQ9PmZlKGBbaWQ9IiR7dH0iXWApKSxiKHQ9PnR5cGVvZiB0IT0idW5kZWZpbmVkIikpfWZ1bmN0aW9uIFB0KGUpe2xldCB0PW1hdGNoTWVkaWEoZSk7cmV0dXJuIGFyKHI9PnQuYWRkTGlzdGVuZXIoKCk9PnIodC5tYXRjaGVzKSkpLnBpcGUoUSh0Lm1hdGNoZXMpKX1mdW5jdGlvbiBtbigpe2xldCBlPW1hdGNoTWVkaWEoInByaW50Iik7cmV0dXJuIE8oaCh3aW5kb3csImJlZm9yZXByaW50IikucGlwZShtKCgpPT4hMCkpLGgod2luZG93LCJhZnRlcnByaW50IikucGlwZShtKCgpPT4hMSkpKS5waXBlKFEoZS5tYXRjaGVzKSl9ZnVuY3Rpb24gTnIoZSx0KXtyZXR1cm4gZS5waXBlKHYocj0+cj90KCk6UykpfWZ1bmN0aW9uIHpyKGUsdCl7cmV0dXJuIG5ldyBqKHI9PntsZXQgbz1uZXcgWE1MSHR0cFJlcXVlc3Q7cmV0dXJuIG8ub3BlbigiR0VUIixgJHtlfWApLG8ucmVzcG9uc2VUeXBlPSJibG9iIixvLmFkZEV2ZW50TGlzdGVuZXIoImxvYWQiLCgpPT57by5zdGF0dXM+PTIwMCYmby5zdGF0dXM8MzAwPyhyLm5leHQoby5yZXNwb25zZSksci5jb21wbGV0ZSgpKTpyLmVycm9yKG5ldyBFcnJvcihvLnN0YXR1c1RleHQpKX0pLG8uYWRkRXZlbnRMaXN0ZW5lcigiZXJyb3IiLCgpPT57ci5lcnJvcihuZXcgRXJyb3IoIk5ldHdvcmsgZXJyb3IiKSl9KSxvLmFkZEV2ZW50TGlzdGVuZXIoImFib3J0IiwoKT0+e3IuY29tcGxldGUoKX0pLHR5cGVvZih0PT1udWxsP3ZvaWQgMDp0LnByb2dyZXNzJCkhPSJ1bmRlZmluZWQiJiYoby5hZGRFdmVudExpc3RlbmVyKCJwcm9ncmVzcyIsbj0+e3ZhciBpO2lmKG4ubGVuZ3RoQ29tcHV0YWJsZSl0LnByb2dyZXNzJC5uZXh0KG4ubG9hZGVkL24udG90YWwqMTAwKTtlbHNle2xldCBhPShpPW8uZ2V0UmVzcG9uc2VIZWFkZXIoIkNvbnRlbnQtTGVuZ3RoIikpIT1udWxsP2k6MDt0LnByb2dyZXNzJC5uZXh0KG4ubG9hZGVkLythKjEwMCl9fSksdC5wcm9ncmVzcyQubmV4dCg1KSksby5zZW5kKCksKCk9Pm8uYWJvcnQoKX0pfWZ1bmN0aW9uIGplKGUsdCl7cmV0dXJuIHpyKGUsdCkucGlwZSh2KHI9PnIudGV4dCgpKSxtKHI9PkpTT04ucGFyc2UocikpLEcoMSkpfWZ1bmN0aW9uIGZuKGUsdCl7bGV0IHI9bmV3IERPTVBhcnNlcjtyZXR1cm4genIoZSx0KS5waXBlKHYobz0+by50ZXh0KCkpLG0obz0+ci5wYXJzZUZyb21TdHJpbmcobywidGV4dC9odG1sIikpLEcoMSkpfWZ1bmN0aW9uIHVuKGUsdCl7bGV0IHI9bmV3IERPTVBhcnNlcjtyZXR1cm4genIoZSx0KS5waXBlKHYobz0+by50ZXh0KCkpLG0obz0+ci5wYXJzZUZyb21TdHJpbmcobywidGV4dC94bWwiKSksRygxKSl9ZnVuY3Rpb24gZG4oKXtyZXR1cm57eDpNYXRoLm1heCgwLHNjcm9sbFgpLHk6TWF0aC5tYXgoMCxzY3JvbGxZKX19ZnVuY3Rpb24gaG4oKXtyZXR1cm4gTyhoKHdpbmRvdywic2Nyb2xsIix7cGFzc2l2ZTohMH0pLGgod2luZG93LCJyZXNpemUiLHtwYXNzaXZlOiEwfSkpLnBpcGUobShkbiksUShkbigpKSl9ZnVuY3Rpb24gYm4oKXtyZXR1cm57d2lkdGg6aW5uZXJXaWR0aCxoZWlnaHQ6aW5uZXJIZWlnaHR9fWZ1bmN0aW9uIHZuKCl7cmV0dXJuIGgod2luZG93LCJyZXNpemUiLHtwYXNzaXZlOiEwfSkucGlwZShtKGJuKSxRKGJuKCkpKX1mdW5jdGlvbiBnbigpe3JldHVybiB6KFtobigpLHZuKCldKS5waXBlKG0oKFtlLHRdKT0+KHtvZmZzZXQ6ZSxzaXplOnR9KSksRygxKSl9ZnVuY3Rpb24gbXIoZSx7dmlld3BvcnQkOnQsaGVhZGVyJDpyfSl7bGV0IG89dC5waXBlKGVlKCJzaXplIikpLG49eihbbyxyXSkucGlwZShtKCgpPT5WZShlKSkpO3JldHVybiB6KFtyLHQsbl0pLnBpcGUobSgoW3toZWlnaHQ6aX0se29mZnNldDphLHNpemU6c30se3g6cCx5OmN9XSk9Pih7b2Zmc2V0Ont4OmEueC1wLHk6YS55LWMraX0sc2l6ZTpzfSkpKX1mdW5jdGlvbiBfYShlKXtyZXR1cm4gaChlLCJtZXNzYWdlIix0PT50LmRhdGEpfWZ1bmN0aW9uIEFhKGUpe2xldCB0PW5ldyBnO3JldHVybiB0LnN1YnNjcmliZShyPT5lLnBvc3RNZXNzYWdlKHIpKSx0fWZ1bmN0aW9uIHluKGUsdD1uZXcgV29ya2VyKGUpKXtsZXQgcj1fYSh0KSxvPUFhKHQpLG49bmV3IGc7bi5zdWJzY3JpYmUobyk7bGV0IGk9by5waXBlKFooKSxpZSghMCkpO3JldHVybiBuLnBpcGUoWigpLFJlKHIucGlwZShXKGkpKSkscGUoKSl9dmFyIENhPVIoIiNfX2NvbmZpZyIpLE90PUpTT04ucGFyc2UoQ2EudGV4dENvbnRlbnQpO090LmJhc2U9YCR7bmV3IFVSTChPdC5iYXNlLHllKCkpfWA7ZnVuY3Rpb24geGUoKXtyZXR1cm4gT3R9ZnVuY3Rpb24gQihlKXtyZXR1cm4gT3QuZmVhdHVyZXMuaW5jbHVkZXMoZSl9ZnVuY3Rpb24gRWUoZSx0KXtyZXR1cm4gdHlwZW9mIHQhPSJ1bmRlZmluZWQiP090LnRyYW5zbGF0aW9uc1tlXS5yZXBsYWNlKCIjIix0LnRvU3RyaW5nKCkpOk90LnRyYW5zbGF0aW9uc1tlXX1mdW5jdGlvbiBTZShlLHQ9ZG9jdW1lbnQpe3JldHVybiBSKGBbZGF0YS1tZC1jb21wb25lbnQ9JHtlfV1gLHQpfWZ1bmN0aW9uIGFlKGUsdD1kb2N1bWVudCl7cmV0dXJuIFAoYFtkYXRhLW1kLWNvbXBvbmVudD0ke2V9XWAsdCl9ZnVuY3Rpb24ga2EoZSl7bGV0IHQ9UigiLm1kLXR5cGVzZXQgPiA6Zmlyc3QtY2hpbGQiLGUpO3JldHVybiBoKHQsImNsaWNrIix7b25jZTohMH0pLnBpcGUobSgoKT0+UigiLm1kLXR5cGVzZXQiLGUpKSxtKHI9Pih7aGFzaDpfX21kX2hhc2goci5pbm5lckhUTUwpfSkpKX1mdW5jdGlvbiB4bihlKXtpZighQigiYW5ub3VuY2UuZGlzbWlzcyIpfHwhZS5jaGlsZEVsZW1lbnRDb3VudClyZXR1cm4gUztpZighZS5oaWRkZW4pe2xldCB0PVIoIi5tZC10eXBlc2V0IixlKTtfX21kX2hhc2godC5pbm5lckhUTUwpPT09X19tZF9nZXQoIl9fYW5ub3VuY2UiKSYmKGUuaGlkZGVuPSEwKX1yZXR1cm4gQygoKT0+e2xldCB0PW5ldyBnO3JldHVybiB0LnN1YnNjcmliZSgoe2hhc2g6cn0pPT57ZS5oaWRkZW49ITAsX19tZF9zZXQoIl9fYW5ub3VuY2UiLHIpfSksa2EoZSkucGlwZSh3KHI9PnQubmV4dChyKSksXygoKT0+dC5jb21wbGV0ZSgpKSxtKHI9PiQoe3JlZjplfSxyKSkpfSl9ZnVuY3Rpb24gSGEoZSx7dGFyZ2V0JDp0fSl7cmV0dXJuIHQucGlwZShtKHI9Pih7aGlkZGVuOnIhPT1lfSkpKX1mdW5jdGlvbiBFbihlLHQpe2xldCByPW5ldyBnO3JldHVybiByLnN1YnNjcmliZSgoe2hpZGRlbjpvfSk9PntlLmhpZGRlbj1vfSksSGEoZSx0KS5waXBlKHcobz0+ci5uZXh0KG8pKSxfKCgpPT5yLmNvbXBsZXRlKCkpLG0obz0+JCh7cmVmOmV9LG8pKSl9ZnVuY3Rpb24gUnQoZSx0KXtyZXR1cm4gdD09PSJpbmxpbmUiP3goImRpdiIse2NsYXNzOiJtZC10b29sdGlwIG1kLXRvb2x0aXAtLWlubGluZSIsaWQ6ZSxyb2xlOiJ0b29sdGlwIn0seCgiZGl2Iix7Y2xhc3M6Im1kLXRvb2x0aXBfX2lubmVyIG1kLXR5cGVzZXQifSkpOngoImRpdiIse2NsYXNzOiJtZC10b29sdGlwIixpZDplLHJvbGU6InRvb2x0aXAifSx4KCJkaXYiLHtjbGFzczoibWQtdG9vbHRpcF9faW5uZXIgbWQtdHlwZXNldCJ9KSl9ZnVuY3Rpb24gd24oLi4uZSl7cmV0dXJuIHgoImRpdiIse2NsYXNzOiJtZC10b29sdGlwMiIscm9sZToidG9vbHRpcCJ9LHgoImRpdiIse2NsYXNzOiJtZC10b29sdGlwMl9faW5uZXIgbWQtdHlwZXNldCJ9LGUpKX1mdW5jdGlvbiBUbihlLHQpe2lmKHQ9dD9gJHt0fV9hbm5vdGF0aW9uXyR7ZX1gOnZvaWQgMCx0KXtsZXQgcj10P2AjJHt0fWA6dm9pZCAwO3JldHVybiB4KCJhc2lkZSIse2NsYXNzOiJtZC1hbm5vdGF0aW9uIix0YWJJbmRleDowfSxSdCh0KSx4KCJhIix7aHJlZjpyLGNsYXNzOiJtZC1hbm5vdGF0aW9uX19pbmRleCIsdGFiSW5kZXg6LTF9LHgoInNwYW4iLHsiZGF0YS1tZC1hbm5vdGF0aW9uLWlkIjplfSkpKX1lbHNlIHJldHVybiB4KCJhc2lkZSIse2NsYXNzOiJtZC1hbm5vdGF0aW9uIix0YWJJbmRleDowfSxSdCh0KSx4KCJzcGFuIix7Y2xhc3M6Im1kLWFubm90YXRpb25fX2luZGV4Iix0YWJJbmRleDotMX0seCgic3BhbiIseyJkYXRhLW1kLWFubm90YXRpb24taWQiOmV9KSkpfWZ1bmN0aW9uIFNuKGUpe3JldHVybiB4KCJidXR0b24iLHtjbGFzczoibWQtY2xpcGJvYXJkIG1kLWljb24iLHRpdGxlOkVlKCJjbGlwYm9hcmQuY29weSIpLCJkYXRhLWNsaXBib2FyZC10YXJnZXQiOmAjJHtlfSA+IGNvZGVgfSl9dmFyIExuPU10KHFyKCkpO2Z1bmN0aW9uIFFyKGUsdCl7bGV0IHI9dCYyLG89dCYxLG49T2JqZWN0LmtleXMoZS50ZXJtcykuZmlsdGVyKHA9PiFlLnRlcm1zW3BdKS5yZWR1Y2UoKHAsYyk9PlsuLi5wLHgoImRlbCIsbnVsbCwoMCxMbi5kZWZhdWx0KShjKSksIiAiXSxbXSkuc2xpY2UoMCwtMSksaT14ZSgpLGE9bmV3IFVSTChlLmxvY2F0aW9uLGkuYmFzZSk7Qigic2VhcmNoLmhpZ2hsaWdodCIpJiZhLnNlYXJjaFBhcmFtcy5zZXQoImgiLE9iamVjdC5lbnRyaWVzKGUudGVybXMpLmZpbHRlcigoWyxwXSk9PnApLnJlZHVjZSgocCxbY10pPT5gJHtwfSAke2N9YC50cmltKCksIiIpKTtsZXR7dGFnczpzfT14ZSgpO3JldHVybiB4KCJhIix7aHJlZjpgJHthfWAsY2xhc3M6Im1kLXNlYXJjaC1yZXN1bHRfX2xpbmsiLHRhYkluZGV4Oi0xfSx4KCJhcnRpY2xlIix7Y2xhc3M6Im1kLXNlYXJjaC1yZXN1bHRfX2FydGljbGUgbWQtdHlwZXNldCIsImRhdGEtbWQtc2NvcmUiOmUuc2NvcmUudG9GaXhlZCgyKX0scj4wJiZ4KCJkaXYiLHtjbGFzczoibWQtc2VhcmNoLXJlc3VsdF9faWNvbiBtZC1pY29uIn0pLHI+MCYmeCgiaDEiLG51bGwsZS50aXRsZSkscjw9MCYmeCgiaDIiLG51bGwsZS50aXRsZSksbz4wJiZlLnRleHQubGVuZ3RoPjAmJmUudGV4dCxlLnRhZ3MmJngoIm5hdiIse2NsYXNzOiJtZC10YWdzIn0sZS50YWdzLm1hcChwPT57bGV0IGM9cz9wIGluIHM/YG1kLXRhZy1pY29uIG1kLXRhZy0tJHtzW3BdfWA6Im1kLXRhZy1pY29uIjoiIjtyZXR1cm4geCgic3BhbiIse2NsYXNzOmBtZC10YWcgJHtjfWB9LHApfSkpLG8+MCYmbi5sZW5ndGg+MCYmeCgicCIse2NsYXNzOiJtZC1zZWFyY2gtcmVzdWx0X190ZXJtcyJ9LEVlKCJzZWFyY2gucmVzdWx0LnRlcm0ubWlzc2luZyIpLCI6ICIsLi4ubikpKX1mdW5jdGlvbiBNbihlKXtsZXQgdD1lWzBdLnNjb3JlLHI9Wy4uLmVdLG89eGUoKSxuPXIuZmluZEluZGV4KGw9PiFgJHtuZXcgVVJMKGwubG9jYXRpb24sby5iYXNlKX1gLmluY2x1ZGVzKCIjIikpLFtpXT1yLnNwbGljZShuLDEpLGE9ci5maW5kSW5kZXgobD0+bC5zY29yZTx0KTthPT09LTEmJihhPXIubGVuZ3RoKTtsZXQgcz1yLnNsaWNlKDAsYSkscD1yLnNsaWNlKGEpLGM9W1FyKGksMnwrKCFuJiZhPT09MCkpLC4uLnMubWFwKGw9PlFyKGwsMSkpLC4uLnAubGVuZ3RoP1t4KCJkZXRhaWxzIix7Y2xhc3M6Im1kLXNlYXJjaC1yZXN1bHRfX21vcmUifSx4KCJzdW1tYXJ5Iix7dGFiSW5kZXg6LTF9LHgoImRpdiIsbnVsbCxwLmxlbmd0aD4wJiZwLmxlbmd0aD09PTE/RWUoInNlYXJjaC5yZXN1bHQubW9yZS5vbmUiKTpFZSgic2VhcmNoLnJlc3VsdC5tb3JlLm90aGVyIixwLmxlbmd0aCkpKSwuLi5wLm1hcChsPT5RcihsLDEpKSldOltdXTtyZXR1cm4geCgibGkiLHtjbGFzczoibWQtc2VhcmNoLXJlc3VsdF9faXRlbSJ9LGMpfWZ1bmN0aW9uIF9uKGUpe3JldHVybiB4KCJ1bCIse2NsYXNzOiJtZC1zb3VyY2VfX2ZhY3RzIn0sT2JqZWN0LmVudHJpZXMoZSkubWFwKChbdCxyXSk9PngoImxpIix7Y2xhc3M6YG1kLXNvdXJjZV9fZmFjdCBtZC1zb3VyY2VfX2ZhY3QtLSR7dH1gfSx0eXBlb2Ygcj09Im51bWJlciI/c3Iocik6cikpKX1mdW5jdGlvbiBLcihlKXtsZXQgdD1gdGFiYmVkLWNvbnRyb2wgdGFiYmVkLWNvbnRyb2wtLSR7ZX1gO3JldHVybiB4KCJkaXYiLHtjbGFzczp0LGhpZGRlbjohMH0seCgiYnV0dG9uIix7Y2xhc3M6InRhYmJlZC1idXR0b24iLHRhYkluZGV4Oi0xLCJhcmlhLWhpZGRlbiI6InRydWUifSkpfWZ1bmN0aW9uIEFuKGUpe3JldHVybiB4KCJkaXYiLHtjbGFzczoibWQtdHlwZXNldF9fc2Nyb2xsd3JhcCJ9LHgoImRpdiIse2NsYXNzOiJtZC10eXBlc2V0X190YWJsZSJ9LGUpKX1mdW5jdGlvbiBSYShlKXt2YXIgbztsZXQgdD14ZSgpLHI9bmV3IFVSTChgLi4vJHtlLnZlcnNpb259L2AsdC5iYXNlKTtyZXR1cm4geCgibGkiLHtjbGFzczoibWQtdmVyc2lvbl9faXRlbSJ9LHgoImEiLHtocmVmOmAke3J9YCxjbGFzczoibWQtdmVyc2lvbl9fbGluayJ9LGUudGl0bGUsKChvPXQudmVyc2lvbik9PW51bGw/dm9pZCAwOm8uYWxpYXMpJiZlLmFsaWFzZXMubGVuZ3RoPjAmJngoInNwYW4iLHtjbGFzczoibWQtdmVyc2lvbl9fYWxpYXMifSxlLmFsaWFzZXNbMF0pKSl9ZnVuY3Rpb24gQ24oZSx0KXt2YXIgbztsZXQgcj14ZSgpO3JldHVybiBlPWUuZmlsdGVyKG49Pnt2YXIgaTtyZXR1cm4hKChpPW4ucHJvcGVydGllcykhPW51bGwmJmkuaGlkZGVuKX0pLHgoImRpdiIse2NsYXNzOiJtZC12ZXJzaW9uIn0seCgiYnV0dG9uIix7Y2xhc3M6Im1kLXZlcnNpb25fX2N1cnJlbnQiLCJhcmlhLWxhYmVsIjpFZSgic2VsZWN0LnZlcnNpb24iKX0sdC50aXRsZSwoKG89ci52ZXJzaW9uKT09bnVsbD92b2lkIDA6by5hbGlhcykmJnQuYWxpYXNlcy5sZW5ndGg+MCYmeCgic3BhbiIse2NsYXNzOiJtZC12ZXJzaW9uX19hbGlhcyJ9LHQuYWxpYXNlc1swXSkpLHgoInVsIix7Y2xhc3M6Im1kLXZlcnNpb25fX2xpc3QifSxlLm1hcChSYSkpKX12YXIgSWE9MDtmdW5jdGlvbiBqYShlKXtsZXQgdD16KFtldChlKSwkdChlKV0pLnBpcGUobSgoW28sbl0pPT5vfHxuKSxLKCkpLHI9QygoKT0+Wm8oZSkpLnBpcGUobmUoTmUpLHB0KDEpLEhlKHQpLG0oKCk9PmVuKGUpKSk7cmV0dXJuIHQucGlwZShBZShvPT5vKSx2KCgpPT56KFt0LHJdKSksbSgoW28sbl0pPT4oe2FjdGl2ZTpvLG9mZnNldDpufSkpLHBlKCkpfWZ1bmN0aW9uIEZhKGUsdCl7bGV0e2NvbnRlbnQkOnIsdmlld3BvcnQkOm99PXQsbj1gX190b29sdGlwMl8ke0lhKyt9YDtyZXR1cm4gQygoKT0+e2xldCBpPW5ldyBnLGE9bmV3IF9yKCExKTtpLnBpcGUoWigpLGllKCExKSkuc3Vic2NyaWJlKGEpO2xldCBzPWEucGlwZShIdChjPT5MZSgrIWMqMjUwLGtyKSksSygpLHYoYz0+Yz9yOlMpLHcoYz0+Yy5pZD1uKSxwZSgpKTt6KFtpLnBpcGUobSgoe2FjdGl2ZTpjfSk9PmMpKSxzLnBpcGUodihjPT4kdChjLDI1MCkpLFEoITEpKV0pLnBpcGUobShjPT5jLnNvbWUobD0+bCkpKS5zdWJzY3JpYmUoYSk7bGV0IHA9YS5waXBlKGIoYz0+YykscmUocyxvKSxtKChbYyxsLHtzaXplOmZ9XSk9PntsZXQgdT1lLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLGQ9dS53aWR0aC8yO2lmKGwucm9sZT09PSJ0b29sdGlwIilyZXR1cm57eDpkLHk6OCt1LmhlaWdodH07aWYodS55Pj1mLmhlaWdodC8yKXtsZXR7aGVpZ2h0Onl9PWNlKGwpO3JldHVybnt4OmQseTotMTYteX19ZWxzZSByZXR1cm57eDpkLHk6MTYrdS5oZWlnaHR9fSkpO3JldHVybiB6KFtzLGkscF0pLnN1YnNjcmliZSgoW2Mse29mZnNldDpsfSxmXSk9PntjLnN0eWxlLnNldFByb3BlcnR5KCItLW1kLXRvb2x0aXAtaG9zdC14IixgJHtsLnh9cHhgKSxjLnN0eWxlLnNldFByb3BlcnR5KCItLW1kLXRvb2x0aXAtaG9zdC15IixgJHtsLnl9cHhgKSxjLnN0eWxlLnNldFByb3BlcnR5KCItLW1kLXRvb2x0aXAteCIsYCR7Zi54fXB4YCksYy5zdHlsZS5zZXRQcm9wZXJ0eSgiLS1tZC10b29sdGlwLXkiLGAke2YueX1weGApLGMuY2xhc3NMaXN0LnRvZ2dsZSgibWQtdG9vbHRpcDItLXRvcCIsZi55PDApLGMuY2xhc3NMaXN0LnRvZ2dsZSgibWQtdG9vbHRpcDItLWJvdHRvbSIsZi55Pj0wKX0pLGEucGlwZShiKGM9PmMpLHJlKHMsKGMsbCk9PmwpLGIoYz0+Yy5yb2xlPT09InRvb2x0aXAiKSkuc3Vic2NyaWJlKGM9PntsZXQgbD1jZShSKCI6c2NvcGUgPiAqIixjKSk7Yy5zdHlsZS5zZXRQcm9wZXJ0eSgiLS1tZC10b29sdGlwLXdpZHRoIixgJHtsLndpZHRofXB4YCksYy5zdHlsZS5zZXRQcm9wZXJ0eSgiLS1tZC10b29sdGlwLXRhaWwiLCIwcHgiKX0pLGEucGlwZShLKCksdmUobWUpLHJlKHMpKS5zdWJzY3JpYmUoKFtjLGxdKT0+e2wuY2xhc3NMaXN0LnRvZ2dsZSgibWQtdG9vbHRpcDItLWFjdGl2ZSIsYyl9KSx6KFthLnBpcGUoYihjPT5jKSksc10pLnN1YnNjcmliZSgoW2MsbF0pPT57bC5yb2xlPT09ImRpYWxvZyI/KGUuc2V0QXR0cmlidXRlKCJhcmlhLWNvbnRyb2xzIixuKSxlLnNldEF0dHJpYnV0ZSgiYXJpYS1oYXNwb3B1cCIsImRpYWxvZyIpKTplLnNldEF0dHJpYnV0ZSgiYXJpYS1kZXNjcmliZWRieSIsbil9KSxhLnBpcGUoYihjPT4hYykpLnN1YnNjcmliZSgoKT0+e2UucmVtb3ZlQXR0cmlidXRlKCJhcmlhLWNvbnRyb2xzIiksZS5yZW1vdmVBdHRyaWJ1dGUoImFyaWEtZGVzY3JpYmVkYnkiKSxlLnJlbW92ZUF0dHJpYnV0ZSgiYXJpYS1oYXNwb3B1cCIpfSksamEoZSkucGlwZSh3KGM9PmkubmV4dChjKSksXygoKT0+aS5jb21wbGV0ZSgpKSxtKGM9PiQoe3JlZjplfSxjKSkpfSl9ZnVuY3Rpb24gbXQoZSx7dmlld3BvcnQkOnR9LHI9ZG9jdW1lbnQuYm9keSl7cmV0dXJuIEZhKGUse2NvbnRlbnQkOm5ldyBqKG89PntsZXQgbj1lLnRpdGxlLGk9d24obik7cmV0dXJuIG8ubmV4dChpKSxlLnJlbW92ZUF0dHJpYnV0ZSgidGl0bGUiKSxyLmFwcGVuZChpKSwoKT0+e2kucmVtb3ZlKCksZS5zZXRBdHRyaWJ1dGUoInRpdGxlIixuKX19KSx2aWV3cG9ydCQ6dH0pfWZ1bmN0aW9uIFVhKGUsdCl7bGV0IHI9QygoKT0+eihbdG4oZSksTmUodCldKSkucGlwZShtKChbe3g6byx5Om59LGldKT0+e2xldHt3aWR0aDphLGhlaWdodDpzfT1jZShlKTtyZXR1cm57eDpvLWkueCthLzIseTpuLWkueStzLzJ9fSkpO3JldHVybiBldChlKS5waXBlKHYobz0+ci5waXBlKG0obj0+KHthY3RpdmU6byxvZmZzZXQ6bn0pKSxUZSgrIW98fDEvMCkpKSl9ZnVuY3Rpb24ga24oZSx0LHt0YXJnZXQkOnJ9KXtsZXRbbyxuXT1BcnJheS5mcm9tKGUuY2hpbGRyZW4pO3JldHVybiBDKCgpPT57bGV0IGk9bmV3IGcsYT1pLnBpcGUoWigpLGllKCEwKSk7cmV0dXJuIGkuc3Vic2NyaWJlKHtuZXh0KHtvZmZzZXQ6c30pe2Uuc3R5bGUuc2V0UHJvcGVydHkoIi0tbWQtdG9vbHRpcC14IixgJHtzLnh9cHhgKSxlLnN0eWxlLnNldFByb3BlcnR5KCItLW1kLXRvb2x0aXAteSIsYCR7cy55fXB4YCl9LGNvbXBsZXRlKCl7ZS5zdHlsZS5yZW1vdmVQcm9wZXJ0eSgiLS1tZC10b29sdGlwLXgiKSxlLnN0eWxlLnJlbW92ZVByb3BlcnR5KCItLW1kLXRvb2x0aXAteSIpfX0pLHR0KGUpLnBpcGUoVyhhKSkuc3Vic2NyaWJlKHM9PntlLnRvZ2dsZUF0dHJpYnV0ZSgiZGF0YS1tZC12aXNpYmxlIixzKX0pLE8oaS5waXBlKGIoKHthY3RpdmU6c30pPT5zKSksaS5waXBlKF9lKDI1MCksYigoe2FjdGl2ZTpzfSk9PiFzKSkpLnN1YnNjcmliZSh7bmV4dCh7YWN0aXZlOnN9KXtzP2UucHJlcGVuZChvKTpvLnJlbW92ZSgpfSxjb21wbGV0ZSgpe2UucHJlcGVuZChvKX19KSxpLnBpcGUoTWUoMTYsbWUpKS5zdWJzY3JpYmUoKHthY3RpdmU6c30pPT57by5jbGFzc0xpc3QudG9nZ2xlKCJtZC10b29sdGlwLS1hY3RpdmUiLHMpfSksaS5waXBlKHB0KDEyNSxtZSksYigoKT0+ISFlLm9mZnNldFBhcmVudCksbSgoKT0+ZS5vZmZzZXRQYXJlbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkpLG0oKHt4OnN9KT0+cykpLnN1YnNjcmliZSh7bmV4dChzKXtzP2Uuc3R5bGUuc2V0UHJvcGVydHkoIi0tbWQtdG9vbHRpcC0wIixgJHstc31weGApOmUuc3R5bGUucmVtb3ZlUHJvcGVydHkoIi0tbWQtdG9vbHRpcC0wIil9LGNvbXBsZXRlKCl7ZS5zdHlsZS5yZW1vdmVQcm9wZXJ0eSgiLS1tZC10b29sdGlwLTAiKX19KSxoKG4sImNsaWNrIikucGlwZShXKGEpLGIocz0+IShzLm1ldGFLZXl8fHMuY3RybEtleSkpKS5zdWJzY3JpYmUocz0+e3Muc3RvcFByb3BhZ2F0aW9uKCkscy5wcmV2ZW50RGVmYXVsdCgpfSksaChuLCJtb3VzZWRvd24iKS5waXBlKFcoYSkscmUoaSkpLnN1YnNjcmliZSgoW3Mse2FjdGl2ZTpwfV0pPT57dmFyIGM7aWYocy5idXR0b24hPT0wfHxzLm1ldGFLZXl8fHMuY3RybEtleSlzLnByZXZlbnREZWZhdWx0KCk7ZWxzZSBpZihwKXtzLnByZXZlbnREZWZhdWx0KCk7bGV0IGw9ZS5wYXJlbnRFbGVtZW50LmNsb3Nlc3QoIi5tZC1hbm5vdGF0aW9uIik7bCBpbnN0YW5jZW9mIEhUTUxFbGVtZW50P2wuZm9jdXMoKTooYz1JZSgpKT09bnVsbHx8Yy5ibHVyKCl9fSksci5waXBlKFcoYSksYihzPT5zPT09byksR2UoMTI1KSkuc3Vic2NyaWJlKCgpPT5lLmZvY3VzKCkpLFVhKGUsdCkucGlwZSh3KHM9PmkubmV4dChzKSksXygoKT0+aS5jb21wbGV0ZSgpKSxtKHM9PiQoe3JlZjplfSxzKSkpfSl9ZnVuY3Rpb24gV2EoZSl7cmV0dXJuIGUudGFnTmFtZT09PSJDT0RFIj9QKCIuYywgLmMxLCAuY20iLGUpOltlXX1mdW5jdGlvbiBEYShlKXtsZXQgdD1bXTtmb3IobGV0IHIgb2YgV2EoZSkpe2xldCBvPVtdLG49ZG9jdW1lbnQuY3JlYXRlTm9kZUl0ZXJhdG9yKHIsTm9kZUZpbHRlci5TSE9XX1RFWFQpO2ZvcihsZXQgaT1uLm5leHROb2RlKCk7aTtpPW4ubmV4dE5vZGUoKSlvLnB1c2goaSk7Zm9yKGxldCBpIG9mIG8pe2xldCBhO2Zvcig7YT0vKFwoXGQrXCkpKCEpPy8uZXhlYyhpLnRleHRDb250ZW50KTspe2xldFsscyxwXT1hO2lmKHR5cGVvZiBwPT0idW5kZWZpbmVkIil7bGV0IGM9aS5zcGxpdFRleHQoYS5pbmRleCk7aT1jLnNwbGl0VGV4dChzLmxlbmd0aCksdC5wdXNoKGMpfWVsc2V7aS50ZXh0Q29udGVudD1zLHQucHVzaChpKTticmVha319fX1yZXR1cm4gdH1mdW5jdGlvbiBIbihlLHQpe3QuYXBwZW5kKC4uLkFycmF5LmZyb20oZS5jaGlsZE5vZGVzKSl9ZnVuY3Rpb24gZnIoZSx0LHt0YXJnZXQkOnIscHJpbnQkOm99KXtsZXQgbj10LmNsb3Nlc3QoIltpZF0iKSxpPW49PW51bGw/dm9pZCAwOm4uaWQsYT1uZXcgTWFwO2ZvcihsZXQgcyBvZiBEYSh0KSl7bGV0WyxwXT1zLnRleHRDb250ZW50Lm1hdGNoKC9cKChcZCspXCkvKTtmZShgOnNjb3BlID4gbGk6bnRoLWNoaWxkKCR7cH0pYCxlKSYmKGEuc2V0KHAsVG4ocCxpKSkscy5yZXBsYWNlV2l0aChhLmdldChwKSkpfXJldHVybiBhLnNpemU9PT0wP1M6QygoKT0+e2xldCBzPW5ldyBnLHA9cy5waXBlKFooKSxpZSghMCkpLGM9W107Zm9yKGxldFtsLGZdb2YgYSljLnB1c2goW1IoIi5tZC10eXBlc2V0IixmKSxSKGA6c2NvcGUgPiBsaTpudGgtY2hpbGQoJHtsfSlgLGUpXSk7cmV0dXJuIG8ucGlwZShXKHApKS5zdWJzY3JpYmUobD0+e2UuaGlkZGVuPSFsLGUuY2xhc3NMaXN0LnRvZ2dsZSgibWQtYW5ub3RhdGlvbi1saXN0IixsKTtmb3IobGV0W2YsdV1vZiBjKWw/SG4oZix1KTpIbih1LGYpfSksTyguLi5bLi4uYV0ubWFwKChbLGxdKT0+a24obCx0LHt0YXJnZXQkOnJ9KSkpLnBpcGUoXygoKT0+cy5jb21wbGV0ZSgpKSxwZSgpKX0pfWZ1bmN0aW9uICRuKGUpe2lmKGUubmV4dEVsZW1lbnRTaWJsaW5nKXtsZXQgdD1lLm5leHRFbGVtZW50U2libGluZztpZih0LnRhZ05hbWU9PT0iT0wiKXJldHVybiB0O2lmKHQudGFnTmFtZT09PSJQIiYmIXQuY2hpbGRyZW4ubGVuZ3RoKXJldHVybiAkbih0KX19ZnVuY3Rpb24gUG4oZSx0KXtyZXR1cm4gQygoKT0+e2xldCByPSRuKGUpO3JldHVybiB0eXBlb2YgciE9InVuZGVmaW5lZCI/ZnIocixlLHQpOlN9KX12YXIgUm49TXQoQnIoKSk7dmFyIFZhPTA7ZnVuY3Rpb24gSW4oZSl7aWYoZS5uZXh0RWxlbWVudFNpYmxpbmcpe2xldCB0PWUubmV4dEVsZW1lbnRTaWJsaW5nO2lmKHQudGFnTmFtZT09PSJPTCIpcmV0dXJuIHQ7aWYodC50YWdOYW1lPT09IlAiJiYhdC5jaGlsZHJlbi5sZW5ndGgpcmV0dXJuIEluKHQpfX1mdW5jdGlvbiBOYShlKXtyZXR1cm4gZ2UoZSkucGlwZShtKCh7d2lkdGg6dH0pPT4oe3Njcm9sbGFibGU6U3QoZSkud2lkdGg+dH0pKSxlZSgic2Nyb2xsYWJsZSIpKX1mdW5jdGlvbiBqbihlLHQpe2xldHttYXRjaGVzOnJ9PW1hdGNoTWVkaWEoIihob3ZlcikiKSxvPUMoKCk9PntsZXQgbj1uZXcgZyxpPW4ucGlwZShqcigxKSk7bi5zdWJzY3JpYmUoKHtzY3JvbGxhYmxlOmN9KT0+e2MmJnI/ZS5zZXRBdHRyaWJ1dGUoInRhYmluZGV4IiwiMCIpOmUucmVtb3ZlQXR0cmlidXRlKCJ0YWJpbmRleCIpfSk7bGV0IGE9W107aWYoUm4uZGVmYXVsdC5pc1N1cHBvcnRlZCgpJiYoZS5jbG9zZXN0KCIuY29weSIpfHxCKCJjb250ZW50LmNvZGUuY29weSIpJiYhZS5jbG9zZXN0KCIubm8tY29weSIpKSl7bGV0IGM9ZS5jbG9zZXN0KCJwcmUiKTtjLmlkPWBfX2NvZGVfJHtWYSsrfWA7bGV0IGw9U24oYy5pZCk7Yy5pbnNlcnRCZWZvcmUobCxlKSxCKCJjb250ZW50LnRvb2x0aXBzIikmJmEucHVzaChtdChsLHt2aWV3cG9ydCR9KSl9bGV0IHM9ZS5jbG9zZXN0KCIuaGlnaGxpZ2h0Iik7aWYocyBpbnN0YW5jZW9mIEhUTUxFbGVtZW50KXtsZXQgYz1JbihzKTtpZih0eXBlb2YgYyE9InVuZGVmaW5lZCImJihzLmNsYXNzTGlzdC5jb250YWlucygiYW5ub3RhdGUiKXx8QigiY29udGVudC5jb2RlLmFubm90YXRlIikpKXtsZXQgbD1mcihjLGUsdCk7YS5wdXNoKGdlKHMpLnBpcGUoVyhpKSxtKCh7d2lkdGg6ZixoZWlnaHQ6dX0pPT5mJiZ1KSxLKCksdihmPT5mP2w6UykpKX19cmV0dXJuIFAoIjpzY29wZSA+IHNwYW5baWRdIixlKS5sZW5ndGgmJmUuY2xhc3NMaXN0LmFkZCgibWQtY29kZV9fY29udGVudCIpLE5hKGUpLnBpcGUodyhjPT5uLm5leHQoYykpLF8oKCk9Pm4uY29tcGxldGUoKSksbShjPT4kKHtyZWY6ZX0sYykpLFJlKC4uLmEpKX0pO3JldHVybiBCKCJjb250ZW50LmxhenkiKT90dChlKS5waXBlKGIobj0+biksVGUoMSksdigoKT0+bykpOm99ZnVuY3Rpb24gemEoZSx7dGFyZ2V0JDp0LHByaW50JDpyfSl7bGV0IG89ITA7cmV0dXJuIE8odC5waXBlKG0obj0+bi5jbG9zZXN0KCJkZXRhaWxzOm5vdChbb3Blbl0pIikpLGIobj0+ZT09PW4pLG0oKCk9Pih7YWN0aW9uOiJvcGVuIixyZXZlYWw6ITB9KSkpLHIucGlwZShiKG49Pm58fCFvKSx3KCgpPT5vPWUub3BlbiksbShuPT4oe2FjdGlvbjpuPyJvcGVuIjoiY2xvc2UifSkpKSl9ZnVuY3Rpb24gRm4oZSx0KXtyZXR1cm4gQygoKT0+e2xldCByPW5ldyBnO3JldHVybiByLnN1YnNjcmliZSgoe2FjdGlvbjpvLHJldmVhbDpufSk9PntlLnRvZ2dsZUF0dHJpYnV0ZSgib3BlbiIsbz09PSJvcGVuIiksbiYmZS5zY3JvbGxJbnRvVmlldygpfSksemEoZSx0KS5waXBlKHcobz0+ci5uZXh0KG8pKSxfKCgpPT5yLmNvbXBsZXRlKCkpLG0obz0+JCh7cmVmOmV9LG8pKSl9KX12YXIgVW49Ii5ub2RlIGNpcmNsZSwubm9kZSBlbGxpcHNlLC5ub2RlIHBhdGgsLm5vZGUgcG9seWdvbiwubm9kZSByZWN0e2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1ub2RlLWJnLWNvbG9yKTtzdHJva2U6dmFyKC0tbWQtbWVybWFpZC1ub2RlLWZnLWNvbG9yKX1tYXJrZXJ7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLWVkZ2UtY29sb3IpIWltcG9ydGFudH0uZWRnZUxhYmVsIC5sYWJlbCByZWN0e2ZpbGw6IzAwMDB9LmxhYmVse2NvbG9yOnZhcigtLW1kLW1lcm1haWQtbGFiZWwtZmctY29sb3IpO2ZvbnQtZmFtaWx5OnZhcigtLW1kLW1lcm1haWQtZm9udC1mYW1pbHkpfS5sYWJlbCBmb3JlaWduT2JqZWN0e2xpbmUtaGVpZ2h0Om5vcm1hbDtvdmVyZmxvdzp2aXNpYmxlfS5sYWJlbCBkaXYgLmVkZ2VMYWJlbHtjb2xvcjp2YXIoLS1tZC1tZXJtYWlkLWxhYmVsLWZnLWNvbG9yKX0uZWRnZUxhYmVsLC5lZGdlTGFiZWwgcCwubGFiZWwgZGl2IC5lZGdlTGFiZWx7YmFja2dyb3VuZC1jb2xvcjp2YXIoLS1tZC1tZXJtYWlkLWxhYmVsLWJnLWNvbG9yKX0uZWRnZUxhYmVsLC5lZGdlTGFiZWwgcHtmaWxsOnZhcigtLW1kLW1lcm1haWQtbGFiZWwtYmctY29sb3IpO2NvbG9yOnZhcigtLW1kLW1lcm1haWQtZWRnZS1jb2xvcil9LmVkZ2VQYXRoIC5wYXRoLC5mbG93Y2hhcnQtbGlua3tzdHJva2U6dmFyKC0tbWQtbWVybWFpZC1lZGdlLWNvbG9yKTtzdHJva2Utd2lkdGg6LjA1cmVtfS5lZGdlUGF0aCAuYXJyb3doZWFkUGF0aHtmaWxsOnZhcigtLW1kLW1lcm1haWQtZWRnZS1jb2xvcik7c3Ryb2tlOm5vbmV9LmNsdXN0ZXIgcmVjdHtmaWxsOnZhcigtLW1kLWRlZmF1bHQtZmctY29sb3ItLWxpZ2h0ZXN0KTtzdHJva2U6dmFyKC0tbWQtZGVmYXVsdC1mZy1jb2xvci0tbGlnaHRlcil9LmNsdXN0ZXIgc3Bhbntjb2xvcjp2YXIoLS1tZC1tZXJtYWlkLWxhYmVsLWZnLWNvbG9yKTtmb250LWZhbWlseTp2YXIoLS1tZC1tZXJtYWlkLWZvbnQtZmFtaWx5KX1nICNmbG93Y2hhcnQtY2lyY2xlRW5kLGcgI2Zsb3djaGFydC1jaXJjbGVTdGFydCxnICNmbG93Y2hhcnQtY3Jvc3NFbmQsZyAjZmxvd2NoYXJ0LWNyb3NzU3RhcnQsZyAjZmxvd2NoYXJ0LXBvaW50RW5kLGcgI2Zsb3djaGFydC1wb2ludFN0YXJ0e3N0cm9rZTpub25lfWcuY2xhc3NHcm91cCBsaW5lLGcuY2xhc3NHcm91cCByZWN0e2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1ub2RlLWJnLWNvbG9yKTtzdHJva2U6dmFyKC0tbWQtbWVybWFpZC1ub2RlLWZnLWNvbG9yKX1nLmNsYXNzR3JvdXAgdGV4dHtmaWxsOnZhcigtLW1kLW1lcm1haWQtbGFiZWwtZmctY29sb3IpO2ZvbnQtZmFtaWx5OnZhcigtLW1kLW1lcm1haWQtZm9udC1mYW1pbHkpfS5jbGFzc0xhYmVsIC5ib3h7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLWxhYmVsLWJnLWNvbG9yKTtiYWNrZ3JvdW5kLWNvbG9yOnZhcigtLW1kLW1lcm1haWQtbGFiZWwtYmctY29sb3IpO29wYWNpdHk6MX0uY2xhc3NMYWJlbCAubGFiZWx7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLWxhYmVsLWZnLWNvbG9yKTtmb250LWZhbWlseTp2YXIoLS1tZC1tZXJtYWlkLWZvbnQtZmFtaWx5KX0ubm9kZSAuZGl2aWRlcntzdHJva2U6dmFyKC0tbWQtbWVybWFpZC1ub2RlLWZnLWNvbG9yKX0ucmVsYXRpb257c3Ryb2tlOnZhcigtLW1kLW1lcm1haWQtZWRnZS1jb2xvcil9LmNhcmRpbmFsaXR5e2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1sYWJlbC1mZy1jb2xvcik7Zm9udC1mYW1pbHk6dmFyKC0tbWQtbWVybWFpZC1mb250LWZhbWlseSl9LmNhcmRpbmFsaXR5IHRleHR7ZmlsbDppbmhlcml0IWltcG9ydGFudH1kZWZzICNjbGFzc0RpYWdyYW0tY29tcG9zaXRpb25FbmQsZGVmcyAjY2xhc3NEaWFncmFtLWNvbXBvc2l0aW9uU3RhcnQsZGVmcyAjY2xhc3NEaWFncmFtLWRlcGVuZGVuY3lFbmQsZGVmcyAjY2xhc3NEaWFncmFtLWRlcGVuZGVuY3lTdGFydCxkZWZzICNjbGFzc0RpYWdyYW0tZXh0ZW5zaW9uRW5kLGRlZnMgI2NsYXNzRGlhZ3JhbS1leHRlbnNpb25TdGFydHtmaWxsOnZhcigtLW1kLW1lcm1haWQtZWRnZS1jb2xvcikhaW1wb3J0YW50O3N0cm9rZTp2YXIoLS1tZC1tZXJtYWlkLWVkZ2UtY29sb3IpIWltcG9ydGFudH1kZWZzICNjbGFzc0RpYWdyYW0tYWdncmVnYXRpb25FbmQsZGVmcyAjY2xhc3NEaWFncmFtLWFnZ3JlZ2F0aW9uU3RhcnR7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLWxhYmVsLWJnLWNvbG9yKSFpbXBvcnRhbnQ7c3Ryb2tlOnZhcigtLW1kLW1lcm1haWQtZWRnZS1jb2xvcikhaW1wb3J0YW50fWcuc3RhdGVHcm91cCByZWN0e2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1ub2RlLWJnLWNvbG9yKTtzdHJva2U6dmFyKC0tbWQtbWVybWFpZC1ub2RlLWZnLWNvbG9yKX1nLnN0YXRlR3JvdXAgLnN0YXRlLXRpdGxle2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1sYWJlbC1mZy1jb2xvcikhaW1wb3J0YW50O2ZvbnQtZmFtaWx5OnZhcigtLW1kLW1lcm1haWQtZm9udC1mYW1pbHkpfWcuc3RhdGVHcm91cCAuY29tcG9zaXR7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLWxhYmVsLWJnLWNvbG9yKX0ubm9kZUxhYmVsLC5ub2RlTGFiZWwgcHtjb2xvcjp2YXIoLS1tZC1tZXJtYWlkLWxhYmVsLWZnLWNvbG9yKTtmb250LWZhbWlseTp2YXIoLS1tZC1tZXJtYWlkLWZvbnQtZmFtaWx5KX1hIC5ub2RlTGFiZWx7dGV4dC1kZWNvcmF0aW9uOnVuZGVybGluZX0ubm9kZSBjaXJjbGUuc3RhdGUtZW5kLC5ub2RlIGNpcmNsZS5zdGF0ZS1zdGFydCwuc3RhcnQtc3RhdGV7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLWVkZ2UtY29sb3IpO3N0cm9rZTpub25lfS5lbmQtc3RhdGUtaW5uZXIsLmVuZC1zdGF0ZS1vdXRlcntmaWxsOnZhcigtLW1kLW1lcm1haWQtZWRnZS1jb2xvcil9LmVuZC1zdGF0ZS1pbm5lciwubm9kZSBjaXJjbGUuc3RhdGUtZW5ke3N0cm9rZTp2YXIoLS1tZC1tZXJtYWlkLWxhYmVsLWJnLWNvbG9yKX0udHJhbnNpdGlvbntzdHJva2U6dmFyKC0tbWQtbWVybWFpZC1lZGdlLWNvbG9yKX1baWRePXN0YXRlLWZvcmtdIHJlY3QsW2lkXj1zdGF0ZS1qb2luXSByZWN0e2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1lZGdlLWNvbG9yKSFpbXBvcnRhbnQ7c3Ryb2tlOm5vbmUhaW1wb3J0YW50fS5zdGF0ZWRpYWdyYW0tY2x1c3Rlci5zdGF0ZWRpYWdyYW0tY2x1c3RlciAuaW5uZXJ7ZmlsbDp2YXIoLS1tZC1kZWZhdWx0LWJnLWNvbG9yKX0uc3RhdGVkaWFncmFtLWNsdXN0ZXIgcmVjdHtmaWxsOnZhcigtLW1kLW1lcm1haWQtbm9kZS1iZy1jb2xvcik7c3Ryb2tlOnZhcigtLW1kLW1lcm1haWQtbm9kZS1mZy1jb2xvcil9LnN0YXRlZGlhZ3JhbS1zdGF0ZSByZWN0LmRpdmlkZXJ7ZmlsbDp2YXIoLS1tZC1kZWZhdWx0LWZnLWNvbG9yLS1saWdodGVzdCk7c3Ryb2tlOnZhcigtLW1kLWRlZmF1bHQtZmctY29sb3ItLWxpZ2h0ZXIpfWRlZnMgI3N0YXRlZGlhZ3JhbS1iYXJiRW5ke3N0cm9rZTp2YXIoLS1tZC1tZXJtYWlkLWVkZ2UtY29sb3IpfS5hdHRyaWJ1dGVCb3hFdmVuLC5hdHRyaWJ1dGVCb3hPZGR7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLW5vZGUtYmctY29sb3IpO3N0cm9rZTp2YXIoLS1tZC1tZXJtYWlkLW5vZGUtZmctY29sb3IpfS5lbnRpdHlCb3h7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLWxhYmVsLWJnLWNvbG9yKTtzdHJva2U6dmFyKC0tbWQtbWVybWFpZC1ub2RlLWZnLWNvbG9yKX0uZW50aXR5TGFiZWx7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLWxhYmVsLWZnLWNvbG9yKTtmb250LWZhbWlseTp2YXIoLS1tZC1tZXJtYWlkLWZvbnQtZmFtaWx5KX0ucmVsYXRpb25zaGlwTGFiZWxCb3h7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLWxhYmVsLWJnLWNvbG9yKTtmaWxsLW9wYWNpdHk6MTtiYWNrZ3JvdW5kLWNvbG9yOnZhcigtLW1kLW1lcm1haWQtbGFiZWwtYmctY29sb3IpO29wYWNpdHk6MX0ucmVsYXRpb25zaGlwTGFiZWx7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLWxhYmVsLWZnLWNvbG9yKX0ucmVsYXRpb25zaGlwTGluZXtzdHJva2U6dmFyKC0tbWQtbWVybWFpZC1lZGdlLWNvbG9yKX1kZWZzICNPTkVfT1JfTU9SRV9FTkQgKixkZWZzICNPTkVfT1JfTU9SRV9TVEFSVCAqLGRlZnMgI09OTFlfT05FX0VORCAqLGRlZnMgI09OTFlfT05FX1NUQVJUICosZGVmcyAjWkVST19PUl9NT1JFX0VORCAqLGRlZnMgI1pFUk9fT1JfTU9SRV9TVEFSVCAqLGRlZnMgI1pFUk9fT1JfT05FX0VORCAqLGRlZnMgI1pFUk9fT1JfT05FX1NUQVJUICp7c3Ryb2tlOnZhcigtLW1kLW1lcm1haWQtZWRnZS1jb2xvcikhaW1wb3J0YW50fWRlZnMgI1pFUk9fT1JfTU9SRV9FTkQgY2lyY2xlLGRlZnMgI1pFUk9fT1JfTU9SRV9TVEFSVCBjaXJjbGV7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLWxhYmVsLWJnLWNvbG9yKX0uYWN0b3J7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLXNlcXVlbmNlLWFjdG9yLWJnLWNvbG9yKTtzdHJva2U6dmFyKC0tbWQtbWVybWFpZC1zZXF1ZW5jZS1hY3Rvci1ib3JkZXItY29sb3IpfXRleHQuYWN0b3I+dHNwYW57ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLXNlcXVlbmNlLWFjdG9yLWZnLWNvbG9yKTtmb250LWZhbWlseTp2YXIoLS1tZC1tZXJtYWlkLWZvbnQtZmFtaWx5KX1saW5le3N0cm9rZTp2YXIoLS1tZC1tZXJtYWlkLXNlcXVlbmNlLWFjdG9yLWxpbmUtY29sb3IpfS5hY3Rvci1tYW4gY2lyY2xlLC5hY3Rvci1tYW4gbGluZXtmaWxsOnZhcigtLW1kLW1lcm1haWQtc2VxdWVuY2UtYWN0b3JtYW4tYmctY29sb3IpO3N0cm9rZTp2YXIoLS1tZC1tZXJtYWlkLXNlcXVlbmNlLWFjdG9ybWFuLWxpbmUtY29sb3IpfS5tZXNzYWdlTGluZTAsLm1lc3NhZ2VMaW5lMXtzdHJva2U6dmFyKC0tbWQtbWVybWFpZC1zZXF1ZW5jZS1tZXNzYWdlLWxpbmUtY29sb3IpfS5ub3Rle2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1zZXF1ZW5jZS1ub3RlLWJnLWNvbG9yKTtzdHJva2U6dmFyKC0tbWQtbWVybWFpZC1zZXF1ZW5jZS1ub3RlLWJvcmRlci1jb2xvcil9Lmxvb3BUZXh0LC5sb29wVGV4dD50c3BhbiwubWVzc2FnZVRleHQsLm5vdGVUZXh0PnRzcGFue3N0cm9rZTpub25lO2ZvbnQtZmFtaWx5OnZhcigtLW1kLW1lcm1haWQtZm9udC1mYW1pbHkpIWltcG9ydGFudH0ubWVzc2FnZVRleHR7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLXNlcXVlbmNlLW1lc3NhZ2UtZmctY29sb3IpfS5sb29wVGV4dCwubG9vcFRleHQ+dHNwYW57ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLXNlcXVlbmNlLWxvb3AtZmctY29sb3IpfS5ub3RlVGV4dD50c3BhbntmaWxsOnZhcigtLW1kLW1lcm1haWQtc2VxdWVuY2Utbm90ZS1mZy1jb2xvcil9I2Fycm93aGVhZCBwYXRoe2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1zZXF1ZW5jZS1tZXNzYWdlLWxpbmUtY29sb3IpO3N0cm9rZTpub25lfS5sb29wTGluZXtmaWxsOnZhcigtLW1kLW1lcm1haWQtc2VxdWVuY2UtbG9vcC1iZy1jb2xvcik7c3Ryb2tlOnZhcigtLW1kLW1lcm1haWQtc2VxdWVuY2UtbG9vcC1ib3JkZXItY29sb3IpfS5sYWJlbEJveHtmaWxsOnZhcigtLW1kLW1lcm1haWQtc2VxdWVuY2UtbGFiZWwtYmctY29sb3IpO3N0cm9rZTpub25lfS5sYWJlbFRleHQsLmxhYmVsVGV4dD5zcGFue2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1zZXF1ZW5jZS1sYWJlbC1mZy1jb2xvcik7Zm9udC1mYW1pbHk6dmFyKC0tbWQtbWVybWFpZC1mb250LWZhbWlseSl9LnNlcXVlbmNlTnVtYmVye2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1zZXF1ZW5jZS1udW1iZXItZmctY29sb3IpfXJlY3QucmVjdHtmaWxsOnZhcigtLW1kLW1lcm1haWQtc2VxdWVuY2UtYm94LWJnLWNvbG9yKTtzdHJva2U6bm9uZX1yZWN0LnJlY3QrdGV4dC50ZXh0e2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1zZXF1ZW5jZS1ib3gtZmctY29sb3IpfWRlZnMgI3NlcXVlbmNlbnVtYmVye2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1zZXF1ZW5jZS1udW1iZXItYmctY29sb3IpIWltcG9ydGFudH0iO3ZhciBHcixRYT0wO2Z1bmN0aW9uIEthKCl7cmV0dXJuIHR5cGVvZiBtZXJtYWlkPT0idW5kZWZpbmVkInx8bWVybWFpZCBpbnN0YW5jZW9mIEVsZW1lbnQ/VHQoImh0dHBzOi8vdW5wa2cuY29tL21lcm1haWRAMTEvZGlzdC9tZXJtYWlkLm1pbi5qcyIpOkkodm9pZCAwKX1mdW5jdGlvbiBXbihlKXtyZXR1cm4gZS5jbGFzc0xpc3QucmVtb3ZlKCJtZXJtYWlkIiksR3J8fChHcj1LYSgpLnBpcGUodygoKT0+bWVybWFpZC5pbml0aWFsaXplKHtzdGFydE9uTG9hZDohMSx0aGVtZUNTUzpVbixzZXF1ZW5jZTp7YWN0b3JGb250U2l6ZToiMTZweCIsbWVzc2FnZUZvbnRTaXplOiIxNnB4Iixub3RlRm9udFNpemU6IjE2cHgifX0pKSxtKCgpPT57fSksRygxKSkpLEdyLnN1YnNjcmliZSgoKT0+Y28odGhpcyxudWxsLGZ1bmN0aW9uKigpe2UuY2xhc3NMaXN0LmFkZCgibWVybWFpZCIpO2xldCB0PWBfX21lcm1haWRfJHtRYSsrfWAscj14KCJkaXYiLHtjbGFzczoibWVybWFpZCJ9KSxvPWUudGV4dENvbnRlbnQse3N2ZzpuLGZuOml9PXlpZWxkIG1lcm1haWQucmVuZGVyKHQsbyksYT1yLmF0dGFjaFNoYWRvdyh7bW9kZToiY2xvc2VkIn0pO2EuaW5uZXJIVE1MPW4sZS5yZXBsYWNlV2l0aChyKSxpPT1udWxsfHxpKGEpfSkpLEdyLnBpcGUobSgoKT0+KHtyZWY6ZX0pKSl9dmFyIERuPXgoInRhYmxlIik7ZnVuY3Rpb24gVm4oZSl7cmV0dXJuIGUucmVwbGFjZVdpdGgoRG4pLERuLnJlcGxhY2VXaXRoKEFuKGUpKSxJKHtyZWY6ZX0pfWZ1bmN0aW9uIFlhKGUpe2xldCB0PWUuZmluZChyPT5yLmNoZWNrZWQpfHxlWzBdO3JldHVybiBPKC4uLmUubWFwKHI9PmgociwiY2hhbmdlIikucGlwZShtKCgpPT5SKGBsYWJlbFtmb3I9IiR7ci5pZH0iXWApKSkpKS5waXBlKFEoUihgbGFiZWxbZm9yPSIke3QuaWR9Il1gKSksbShyPT4oe2FjdGl2ZTpyfSkpKX1mdW5jdGlvbiBObihlLHt2aWV3cG9ydCQ6dCx0YXJnZXQkOnJ9KXtsZXQgbz1SKCIudGFiYmVkLWxhYmVscyIsZSksbj1QKCI6c2NvcGUgPiBpbnB1dCIsZSksaT1LcigicHJldiIpO2UuYXBwZW5kKGkpO2xldCBhPUtyKCJuZXh0Iik7cmV0dXJuIGUuYXBwZW5kKGEpLEMoKCk9PntsZXQgcz1uZXcgZyxwPXMucGlwZShaKCksaWUoITApKTt6KFtzLGdlKGUpLHR0KGUpXSkucGlwZShXKHApLE1lKDEsbWUpKS5zdWJzY3JpYmUoe25leHQoW3thY3RpdmU6Y30sbF0pe2xldCBmPVZlKGMpLHt3aWR0aDp1fT1jZShjKTtlLnN0eWxlLnNldFByb3BlcnR5KCItLW1kLWluZGljYXRvci14IixgJHtmLnh9cHhgKSxlLnN0eWxlLnNldFByb3BlcnR5KCItLW1kLWluZGljYXRvci13aWR0aCIsYCR7dX1weGApO2xldCBkPXByKG8pOyhmLng8ZC54fHxmLngrdT5kLngrbC53aWR0aCkmJm8uc2Nyb2xsVG8oe2xlZnQ6TWF0aC5tYXgoMCxmLngtMTYpLGJlaGF2aW9yOiJzbW9vdGgifSl9LGNvbXBsZXRlKCl7ZS5zdHlsZS5yZW1vdmVQcm9wZXJ0eSgiLS1tZC1pbmRpY2F0b3IteCIpLGUuc3R5bGUucmVtb3ZlUHJvcGVydHkoIi0tbWQtaW5kaWNhdG9yLXdpZHRoIil9fSkseihbTmUobyksZ2UobyldKS5waXBlKFcocCkpLnN1YnNjcmliZSgoW2MsbF0pPT57bGV0IGY9U3Qobyk7aS5oaWRkZW49Yy54PDE2LGEuaGlkZGVuPWMueD5mLndpZHRoLWwud2lkdGgtMTZ9KSxPKGgoaSwiY2xpY2siKS5waXBlKG0oKCk9Pi0xKSksaChhLCJjbGljayIpLnBpcGUobSgoKT0+MSkpKS5waXBlKFcocCkpLnN1YnNjcmliZShjPT57bGV0e3dpZHRoOmx9PWNlKG8pO28uc2Nyb2xsQnkoe2xlZnQ6bCpjLGJlaGF2aW9yOiJzbW9vdGgifSl9KSxyLnBpcGUoVyhwKSxiKGM9Pm4uaW5jbHVkZXMoYykpKS5zdWJzY3JpYmUoYz0+Yy5jbGljaygpKSxvLmNsYXNzTGlzdC5hZGQoInRhYmJlZC1sYWJlbHMtLWxpbmtlZCIpO2ZvcihsZXQgYyBvZiBuKXtsZXQgbD1SKGBsYWJlbFtmb3I9IiR7Yy5pZH0iXWApO2wucmVwbGFjZUNoaWxkcmVuKHgoImEiLHtocmVmOmAjJHtsLmh0bWxGb3J9YCx0YWJJbmRleDotMX0sLi4uQXJyYXkuZnJvbShsLmNoaWxkTm9kZXMpKSksaChsLmZpcnN0RWxlbWVudENoaWxkLCJjbGljayIpLnBpcGUoVyhwKSxiKGY9PiEoZi5tZXRhS2V5fHxmLmN0cmxLZXkpKSx3KGY9PntmLnByZXZlbnREZWZhdWx0KCksZi5zdG9wUHJvcGFnYXRpb24oKX0pKS5zdWJzY3JpYmUoKCk9PntoaXN0b3J5LnJlcGxhY2VTdGF0ZSh7fSwiIixgIyR7bC5odG1sRm9yfWApLGwuY2xpY2soKX0pfXJldHVybiBCKCJjb250ZW50LnRhYnMubGluayIpJiZzLnBpcGUoQ2UoMSkscmUodCkpLnN1YnNjcmliZSgoW3thY3RpdmU6Y30se29mZnNldDpsfV0pPT57bGV0IGY9Yy5pbm5lclRleHQudHJpbSgpO2lmKGMuaGFzQXR0cmlidXRlKCJkYXRhLW1kLXN3aXRjaGluZyIpKWMucmVtb3ZlQXR0cmlidXRlKCJkYXRhLW1kLXN3aXRjaGluZyIpO2Vsc2V7bGV0IHU9ZS5vZmZzZXRUb3AtbC55O2ZvcihsZXQgeSBvZiBQKCJbZGF0YS10YWJzXSIpKWZvcihsZXQgTCBvZiBQKCI6c2NvcGUgPiBpbnB1dCIseSkpe2xldCBYPVIoYGxhYmVsW2Zvcj0iJHtMLmlkfSJdYCk7aWYoWCE9PWMmJlguaW5uZXJUZXh0LnRyaW0oKT09PWYpe1guc2V0QXR0cmlidXRlKCJkYXRhLW1kLXN3aXRjaGluZyIsIiIpLEwuY2xpY2soKTticmVha319d2luZG93LnNjcm9sbFRvKHt0b3A6ZS5vZmZzZXRUb3AtdX0pO2xldCBkPV9fbWRfZ2V0KCJfX3RhYnMiKXx8W107X19tZF9zZXQoIl9fdGFicyIsWy4uLm5ldyBTZXQoW2YsLi4uZF0pXSl9fSkscy5waXBlKFcocCkpLnN1YnNjcmliZSgoKT0+e2ZvcihsZXQgYyBvZiBQKCJhdWRpbywgdmlkZW8iLGUpKWMucGF1c2UoKX0pLFlhKG4pLnBpcGUodyhjPT5zLm5leHQoYykpLF8oKCk9PnMuY29tcGxldGUoKSksbShjPT4kKHtyZWY6ZX0sYykpKX0pLnBpcGUoS2Uoc2UpKX1mdW5jdGlvbiB6bihlLHt2aWV3cG9ydCQ6dCx0YXJnZXQkOnIscHJpbnQkOm99KXtyZXR1cm4gTyguLi5QKCIuYW5ub3RhdGU6bm90KC5oaWdobGlnaHQpIixlKS5tYXAobj0+UG4obix7dGFyZ2V0JDpyLHByaW50JDpvfSkpLC4uLlAoInByZTpub3QoLm1lcm1haWQpID4gY29kZSIsZSkubWFwKG49PmpuKG4se3RhcmdldCQ6cixwcmludCQ6b30pKSwuLi5QKCJwcmUubWVybWFpZCIsZSkubWFwKG49PlduKG4pKSwuLi5QKCJ0YWJsZTpub3QoW2NsYXNzXSkiLGUpLm1hcChuPT5WbihuKSksLi4uUCgiZGV0YWlscyIsZSkubWFwKG49PkZuKG4se3RhcmdldCQ6cixwcmludCQ6b30pKSwuLi5QKCJbZGF0YS10YWJzXSIsZSkubWFwKG49Pk5uKG4se3ZpZXdwb3J0JDp0LHRhcmdldCQ6cn0pKSwuLi5QKCJbdGl0bGVdIixlKS5maWx0ZXIoKCk9PkIoImNvbnRlbnQudG9vbHRpcHMiKSkubWFwKG49Pm10KG4se3ZpZXdwb3J0JDp0fSkpKX1mdW5jdGlvbiBCYShlLHthbGVydCQ6dH0pe3JldHVybiB0LnBpcGUodihyPT5PKEkoITApLEkoITEpLnBpcGUoR2UoMmUzKSkpLnBpcGUobShvPT4oe21lc3NhZ2U6cixhY3RpdmU6b30pKSkpKX1mdW5jdGlvbiBxbihlLHQpe2xldCByPVIoIi5tZC10eXBlc2V0IixlKTtyZXR1cm4gQygoKT0+e2xldCBvPW5ldyBnO3JldHVybiBvLnN1YnNjcmliZSgoe21lc3NhZ2U6bixhY3RpdmU6aX0pPT57ZS5jbGFzc0xpc3QudG9nZ2xlKCJtZC1kaWFsb2ctLWFjdGl2ZSIsaSksci50ZXh0Q29udGVudD1ufSksQmEoZSx0KS5waXBlKHcobj0+by5uZXh0KG4pKSxfKCgpPT5vLmNvbXBsZXRlKCkpLG0obj0+JCh7cmVmOmV9LG4pKSl9KX12YXIgR2E9MDtmdW5jdGlvbiBKYShlLHQpe2RvY3VtZW50LmJvZHkuYXBwZW5kKGUpO2xldHt3aWR0aDpyfT1jZShlKTtlLnN0eWxlLnNldFByb3BlcnR5KCItLW1kLXRvb2x0aXAtd2lkdGgiLGAke3J9cHhgKSxlLnJlbW92ZSgpO2xldCBvPWNyKHQpLG49dHlwZW9mIG8hPSJ1bmRlZmluZWQiP05lKG8pOkkoe3g6MCx5OjB9KSxpPU8oZXQodCksJHQodCkpLnBpcGUoSygpKTtyZXR1cm4geihbaSxuXSkucGlwZShtKChbYSxzXSk9PntsZXR7eDpwLHk6Y309VmUodCksbD1jZSh0KSxmPXQuY2xvc2VzdCgidGFibGUiKTtyZXR1cm4gZiYmdC5wYXJlbnRFbGVtZW50JiYocCs9Zi5vZmZzZXRMZWZ0K3QucGFyZW50RWxlbWVudC5vZmZzZXRMZWZ0LGMrPWYub2Zmc2V0VG9wK3QucGFyZW50RWxlbWVudC5vZmZzZXRUb3ApLHthY3RpdmU6YSxvZmZzZXQ6e3g6cC1zLngrbC53aWR0aC8yLXIvMix5OmMtcy55K2wuaGVpZ2h0Kzh9fX0pKX1mdW5jdGlvbiBRbihlKXtsZXQgdD1lLnRpdGxlO2lmKCF0Lmxlbmd0aClyZXR1cm4gUztsZXQgcj1gX190b29sdGlwXyR7R2ErK31gLG89UnQociwiaW5saW5lIiksbj1SKCIubWQtdHlwZXNldCIsbyk7cmV0dXJuIG4uaW5uZXJIVE1MPXQsQygoKT0+e2xldCBpPW5ldyBnO3JldHVybiBpLnN1YnNjcmliZSh7bmV4dCh7b2Zmc2V0OmF9KXtvLnN0eWxlLnNldFByb3BlcnR5KCItLW1kLXRvb2x0aXAteCIsYCR7YS54fXB4YCksby5zdHlsZS5zZXRQcm9wZXJ0eSgiLS1tZC10b29sdGlwLXkiLGAke2EueX1weGApfSxjb21wbGV0ZSgpe28uc3R5bGUucmVtb3ZlUHJvcGVydHkoIi0tbWQtdG9vbHRpcC14Iiksby5zdHlsZS5yZW1vdmVQcm9wZXJ0eSgiLS1tZC10b29sdGlwLXkiKX19KSxPKGkucGlwZShiKCh7YWN0aXZlOmF9KT0+YSkpLGkucGlwZShfZSgyNTApLGIoKHthY3RpdmU6YX0pPT4hYSkpKS5zdWJzY3JpYmUoe25leHQoe2FjdGl2ZTphfSl7YT8oZS5pbnNlcnRBZGphY2VudEVsZW1lbnQoImFmdGVyZW5kIixvKSxlLnNldEF0dHJpYnV0ZSgiYXJpYS1kZXNjcmliZWRieSIsciksZS5yZW1vdmVBdHRyaWJ1dGUoInRpdGxlIikpOihvLnJlbW92ZSgpLGUucmVtb3ZlQXR0cmlidXRlKCJhcmlhLWRlc2NyaWJlZGJ5IiksZS5zZXRBdHRyaWJ1dGUoInRpdGxlIix0KSl9LGNvbXBsZXRlKCl7by5yZW1vdmUoKSxlLnJlbW92ZUF0dHJpYnV0ZSgiYXJpYS1kZXNjcmliZWRieSIpLGUuc2V0QXR0cmlidXRlKCJ0aXRsZSIsdCl9fSksaS5waXBlKE1lKDE2LG1lKSkuc3Vic2NyaWJlKCh7YWN0aXZlOmF9KT0+e28uY2xhc3NMaXN0LnRvZ2dsZSgibWQtdG9vbHRpcC0tYWN0aXZlIixhKX0pLGkucGlwZShwdCgxMjUsbWUpLGIoKCk9PiEhZS5vZmZzZXRQYXJlbnQpLG0oKCk9PmUub2Zmc2V0UGFyZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpKSxtKCh7eDphfSk9PmEpKS5zdWJzY3JpYmUoe25leHQoYSl7YT9vLnN0eWxlLnNldFByb3BlcnR5KCItLW1kLXRvb2x0aXAtMCIsYCR7LWF9cHhgKTpvLnN0eWxlLnJlbW92ZVByb3BlcnR5KCItLW1kLXRvb2x0aXAtMCIpfSxjb21wbGV0ZSgpe28uc3R5bGUucmVtb3ZlUHJvcGVydHkoIi0tbWQtdG9vbHRpcC0wIil9fSksSmEobyxlKS5waXBlKHcoYT0+aS5uZXh0KGEpKSxfKCgpPT5pLmNvbXBsZXRlKCkpLG0oYT0+JCh7cmVmOmV9LGEpKSl9KS5waXBlKEtlKHNlKSl9ZnVuY3Rpb24gWGEoe3ZpZXdwb3J0JDplfSl7aWYoIUIoImhlYWRlci5hdXRvaGlkZSIpKXJldHVybiBJKCExKTtsZXQgdD1lLnBpcGUobSgoe29mZnNldDp7eTpufX0pPT5uKSxCZSgyLDEpLG0oKFtuLGldKT0+W248aSxpXSksZWUoMCkpLHI9eihbZSx0XSkucGlwZShiKChbe29mZnNldDpufSxbLGldXSk9Pk1hdGguYWJzKGktbi55KT4xMDApLG0oKFssW25dXSk9Pm4pLEsoKSksbz16ZSgic2VhcmNoIik7cmV0dXJuIHooW2Usb10pLnBpcGUobSgoW3tvZmZzZXQ6bn0saV0pPT5uLnk+NDAwJiYhaSksSygpLHYobj0+bj9yOkkoITEpKSxRKCExKSl9ZnVuY3Rpb24gS24oZSx0KXtyZXR1cm4gQygoKT0+eihbZ2UoZSksWGEodCldKSkucGlwZShtKChbe2hlaWdodDpyfSxvXSk9Pih7aGVpZ2h0OnIsaGlkZGVuOm99KSksSygocixvKT0+ci5oZWlnaHQ9PT1vLmhlaWdodCYmci5oaWRkZW49PT1vLmhpZGRlbiksRygxKSl9ZnVuY3Rpb24gWW4oZSx7aGVhZGVyJDp0LG1haW4kOnJ9KXtyZXR1cm4gQygoKT0+e2xldCBvPW5ldyBnLG49by5waXBlKFooKSxpZSghMCkpO28ucGlwZShlZSgiYWN0aXZlIiksSGUodCkpLnN1YnNjcmliZSgoW3thY3RpdmU6YX0se2hpZGRlbjpzfV0pPT57ZS5jbGFzc0xpc3QudG9nZ2xlKCJtZC1oZWFkZXItLXNoYWRvdyIsYSYmIXMpLGUuaGlkZGVuPXN9KTtsZXQgaT11ZShQKCJbdGl0bGVdIixlKSkucGlwZShiKCgpPT5CKCJjb250ZW50LnRvb2x0aXBzIikpLG5lKGE9PlFuKGEpKSk7cmV0dXJuIHIuc3Vic2NyaWJlKG8pLHQucGlwZShXKG4pLG0oYT0+JCh7cmVmOmV9LGEpKSxSZShpLnBpcGUoVyhuKSkpKX0pfWZ1bmN0aW9uIFphKGUse3ZpZXdwb3J0JDp0LGhlYWRlciQ6cn0pe3JldHVybiBtcihlLHt2aWV3cG9ydCQ6dCxoZWFkZXIkOnJ9KS5waXBlKG0oKHtvZmZzZXQ6e3k6b319KT0+e2xldHtoZWlnaHQ6bn09Y2UoZSk7cmV0dXJue2FjdGl2ZTpvPj1ufX0pLGVlKCJhY3RpdmUiKSl9ZnVuY3Rpb24gQm4oZSx0KXtyZXR1cm4gQygoKT0+e2xldCByPW5ldyBnO3Iuc3Vic2NyaWJlKHtuZXh0KHthY3RpdmU6bn0pe2UuY2xhc3NMaXN0LnRvZ2dsZSgibWQtaGVhZGVyX190aXRsZS0tYWN0aXZlIixuKX0sY29tcGxldGUoKXtlLmNsYXNzTGlzdC5yZW1vdmUoIm1kLWhlYWRlcl9fdGl0bGUtLWFjdGl2ZSIpfX0pO2xldCBvPWZlKCIubWQtY29udGVudCBoMSIpO3JldHVybiB0eXBlb2Ygbz09InVuZGVmaW5lZCI/UzpaYShvLHQpLnBpcGUodyhuPT5yLm5leHQobikpLF8oKCk9PnIuY29tcGxldGUoKSksbShuPT4kKHtyZWY6ZX0sbikpKX0pfWZ1bmN0aW9uIEduKGUse3ZpZXdwb3J0JDp0LGhlYWRlciQ6cn0pe2xldCBvPXIucGlwZShtKCh7aGVpZ2h0Oml9KT0+aSksSygpKSxuPW8ucGlwZSh2KCgpPT5nZShlKS5waXBlKG0oKHtoZWlnaHQ6aX0pPT4oe3RvcDplLm9mZnNldFRvcCxib3R0b206ZS5vZmZzZXRUb3AraX0pKSxlZSgiYm90dG9tIikpKSk7cmV0dXJuIHooW28sbix0XSkucGlwZShtKChbaSx7dG9wOmEsYm90dG9tOnN9LHtvZmZzZXQ6e3k6cH0sc2l6ZTp7aGVpZ2h0OmN9fV0pPT4oYz1NYXRoLm1heCgwLGMtTWF0aC5tYXgoMCxhLXAsaSktTWF0aC5tYXgoMCxjK3AtcykpLHtvZmZzZXQ6YS1pLGhlaWdodDpjLGFjdGl2ZTphLWk8PXB9KSksSygoaSxhKT0+aS5vZmZzZXQ9PT1hLm9mZnNldCYmaS5oZWlnaHQ9PT1hLmhlaWdodCYmaS5hY3RpdmU9PT1hLmFjdGl2ZSkpfWZ1bmN0aW9uIGVzKGUpe2xldCB0PV9fbWRfZ2V0KCJfX3BhbGV0dGUiKXx8e2luZGV4OmUuZmluZEluZGV4KG89Pm1hdGNoTWVkaWEoby5nZXRBdHRyaWJ1dGUoImRhdGEtbWQtY29sb3ItbWVkaWEiKSkubWF0Y2hlcyl9LHI9TWF0aC5tYXgoMCxNYXRoLm1pbih0LmluZGV4LGUubGVuZ3RoLTEpKTtyZXR1cm4gSSguLi5lKS5waXBlKG5lKG89PmgobywiY2hhbmdlIikucGlwZShtKCgpPT5vKSkpLFEoZVtyXSksbShvPT4oe2luZGV4OmUuaW5kZXhPZihvKSxjb2xvcjp7bWVkaWE6by5nZXRBdHRyaWJ1dGUoImRhdGEtbWQtY29sb3ItbWVkaWEiKSxzY2hlbWU6by5nZXRBdHRyaWJ1dGUoImRhdGEtbWQtY29sb3Itc2NoZW1lIikscHJpbWFyeTpvLmdldEF0dHJpYnV0ZSgiZGF0YS1tZC1jb2xvci1wcmltYXJ5IiksYWNjZW50Om8uZ2V0QXR0cmlidXRlKCJkYXRhLW1kLWNvbG9yLWFjY2VudCIpfX0pKSxHKDEpKX1mdW5jdGlvbiBKbihlKXtsZXQgdD1QKCJpbnB1dCIsZSkscj14KCJtZXRhIix7bmFtZToidGhlbWUtY29sb3IifSk7ZG9jdW1lbnQuaGVhZC5hcHBlbmRDaGlsZChyKTtsZXQgbz14KCJtZXRhIix7bmFtZToiY29sb3Itc2NoZW1lIn0pO2RvY3VtZW50LmhlYWQuYXBwZW5kQ2hpbGQobyk7bGV0IG49UHQoIihwcmVmZXJzLWNvbG9yLXNjaGVtZTogbGlnaHQpIik7cmV0dXJuIEMoKCk9PntsZXQgaT1uZXcgZztyZXR1cm4gaS5zdWJzY3JpYmUoYT0+e2lmKGRvY3VtZW50LmJvZHkuc2V0QXR0cmlidXRlKCJkYXRhLW1kLWNvbG9yLXN3aXRjaGluZyIsIiIpLGEuY29sb3IubWVkaWE9PT0iKHByZWZlcnMtY29sb3Itc2NoZW1lKSIpe2xldCBzPW1hdGNoTWVkaWEoIihwcmVmZXJzLWNvbG9yLXNjaGVtZTogbGlnaHQpIikscD1kb2N1bWVudC5xdWVyeVNlbGVjdG9yKHMubWF0Y2hlcz8iW2RhdGEtbWQtY29sb3ItbWVkaWE9JyhwcmVmZXJzLWNvbG9yLXNjaGVtZTogbGlnaHQpJ10iOiJbZGF0YS1tZC1jb2xvci1tZWRpYT0nKHByZWZlcnMtY29sb3Itc2NoZW1lOiBkYXJrKSddIik7YS5jb2xvci5zY2hlbWU9cC5nZXRBdHRyaWJ1dGUoImRhdGEtbWQtY29sb3Itc2NoZW1lIiksYS5jb2xvci5wcmltYXJ5PXAuZ2V0QXR0cmlidXRlKCJkYXRhLW1kLWNvbG9yLXByaW1hcnkiKSxhLmNvbG9yLmFjY2VudD1wLmdldEF0dHJpYnV0ZSgiZGF0YS1tZC1jb2xvci1hY2NlbnQiKX1mb3IobGV0W3MscF1vZiBPYmplY3QuZW50cmllcyhhLmNvbG9yKSlkb2N1bWVudC5ib2R5LnNldEF0dHJpYnV0ZShgZGF0YS1tZC1jb2xvci0ke3N9YCxwKTtmb3IobGV0IHM9MDtzPHQubGVuZ3RoO3MrKyl7bGV0IHA9dFtzXS5uZXh0RWxlbWVudFNpYmxpbmc7cCBpbnN0YW5jZW9mIEhUTUxFbGVtZW50JiYocC5oaWRkZW49YS5pbmRleCE9PXMpfV9fbWRfc2V0KCJfX3BhbGV0dGUiLGEpfSksaChlLCJrZXlkb3duIikucGlwZShiKGE9PmEua2V5PT09IkVudGVyIikscmUoaSwoYSxzKT0+cykpLnN1YnNjcmliZSgoe2luZGV4OmF9KT0+e2E9KGErMSkldC5sZW5ndGgsdFthXS5jbGljaygpLHRbYV0uZm9jdXMoKX0pLGkucGlwZShtKCgpPT57bGV0IGE9U2UoImhlYWRlciIpLHM9d2luZG93LmdldENvbXB1dGVkU3R5bGUoYSk7cmV0dXJuIG8uY29udGVudD1zLmNvbG9yU2NoZW1lLHMuYmFja2dyb3VuZENvbG9yLm1hdGNoKC9cZCsvZykubWFwKHA9PigrcCkudG9TdHJpbmcoMTYpLnBhZFN0YXJ0KDIsIjAiKSkuam9pbigiIil9KSkuc3Vic2NyaWJlKGE9PnIuY29udGVudD1gIyR7YX1gKSxpLnBpcGUodmUoc2UpKS5zdWJzY3JpYmUoKCk9Pntkb2N1bWVudC5ib2R5LnJlbW92ZUF0dHJpYnV0ZSgiZGF0YS1tZC1jb2xvci1zd2l0Y2hpbmciKX0pLGVzKHQpLnBpcGUoVyhuLnBpcGUoQ2UoMSkpKSxjdCgpLHcoYT0+aS5uZXh0KGEpKSxfKCgpPT5pLmNvbXBsZXRlKCkpLG0oYT0+JCh7cmVmOmV9LGEpKSl9KX1mdW5jdGlvbiBYbihlLHtwcm9ncmVzcyQ6dH0pe3JldHVybiBDKCgpPT57bGV0IHI9bmV3IGc7cmV0dXJuIHIuc3Vic2NyaWJlKCh7dmFsdWU6b30pPT57ZS5zdHlsZS5zZXRQcm9wZXJ0eSgiLS1tZC1wcm9ncmVzcy12YWx1ZSIsYCR7b31gKX0pLHQucGlwZSh3KG89PnIubmV4dCh7dmFsdWU6b30pKSxfKCgpPT5yLmNvbXBsZXRlKCkpLG0obz0+KHtyZWY6ZSx2YWx1ZTpvfSkpKX0pfXZhciBKcj1NdChCcigpKTtmdW5jdGlvbiB0cyhlKXtlLnNldEF0dHJpYnV0ZSgiZGF0YS1tZC1jb3B5aW5nIiwiIik7bGV0IHQ9ZS5jbG9zZXN0KCJbZGF0YS1jb3B5XSIpLHI9dD90LmdldEF0dHJpYnV0ZSgiZGF0YS1jb3B5Iik6ZS5pbm5lclRleHQ7cmV0dXJuIGUucmVtb3ZlQXR0cmlidXRlKCJkYXRhLW1kLWNvcHlpbmciKSxyLnRyaW1FbmQoKX1mdW5jdGlvbiBabih7YWxlcnQkOmV9KXtKci5kZWZhdWx0LmlzU3VwcG9ydGVkKCkmJm5ldyBqKHQ9PntuZXcgSnIuZGVmYXVsdCgiW2RhdGEtY2xpcGJvYXJkLXRhcmdldF0sIFtkYXRhLWNsaXBib2FyZC10ZXh0XSIse3RleHQ6cj0+ci5nZXRBdHRyaWJ1dGUoImRhdGEtY2xpcGJvYXJkLXRleHQiKXx8dHMoUihyLmdldEF0dHJpYnV0ZSgiZGF0YS1jbGlwYm9hcmQtdGFyZ2V0IikpKX0pLm9uKCJzdWNjZXNzIixyPT50Lm5leHQocikpfSkucGlwZSh3KHQ9Pnt0LnRyaWdnZXIuZm9jdXMoKX0pLG0oKCk9PkVlKCJjbGlwYm9hcmQuY29waWVkIikpKS5zdWJzY3JpYmUoZSl9ZnVuY3Rpb24gZWkoZSx0KXtyZXR1cm4gZS5wcm90b2NvbD10LnByb3RvY29sLGUuaG9zdG5hbWU9dC5ob3N0bmFtZSxlfWZ1bmN0aW9uIHJzKGUsdCl7bGV0IHI9bmV3IE1hcDtmb3IobGV0IG8gb2YgUCgidXJsIixlKSl7bGV0IG49UigibG9jIixvKSxpPVtlaShuZXcgVVJMKG4udGV4dENvbnRlbnQpLHQpXTtyLnNldChgJHtpWzBdfWAsaSk7Zm9yKGxldCBhIG9mIFAoIltyZWw9YWx0ZXJuYXRlXSIsbykpe2xldCBzPWEuZ2V0QXR0cmlidXRlKCJocmVmIik7cyE9bnVsbCYmaS5wdXNoKGVpKG5ldyBVUkwocyksdCkpfX1yZXR1cm4gcn1mdW5jdGlvbiB1cihlKXtyZXR1cm4gdW4obmV3IFVSTCgic2l0ZW1hcC54bWwiLGUpKS5waXBlKG0odD0+cnModCxuZXcgVVJMKGUpKSksZGUoKCk9PkkobmV3IE1hcCkpKX1mdW5jdGlvbiBvcyhlLHQpe2lmKCEoZS50YXJnZXQgaW5zdGFuY2VvZiBFbGVtZW50KSlyZXR1cm4gUztsZXQgcj1lLnRhcmdldC5jbG9zZXN0KCJhIik7aWYocj09PW51bGwpcmV0dXJuIFM7aWYoci50YXJnZXR8fGUubWV0YUtleXx8ZS5jdHJsS2V5KXJldHVybiBTO2xldCBvPW5ldyBVUkwoci5ocmVmKTtyZXR1cm4gby5zZWFyY2g9by5oYXNoPSIiLHQuaGFzKGAke299YCk/KGUucHJldmVudERlZmF1bHQoKSxJKG5ldyBVUkwoci5ocmVmKSkpOlN9ZnVuY3Rpb24gdGkoZSl7bGV0IHQ9bmV3IE1hcDtmb3IobGV0IHIgb2YgUCgiOnNjb3BlID4gKiIsZS5oZWFkKSl0LnNldChyLm91dGVySFRNTCxyKTtyZXR1cm4gdH1mdW5jdGlvbiByaShlKXtmb3IobGV0IHQgb2YgUCgiW2hyZWZdLCBbc3JjXSIsZSkpZm9yKGxldCByIG9mWyJocmVmIiwic3JjIl0pe2xldCBvPXQuZ2V0QXR0cmlidXRlKHIpO2lmKG8mJiEvXig/OlthLXpdKzopP1wvXC8vaS50ZXN0KG8pKXt0W3JdPXRbcl07YnJlYWt9fXJldHVybiBJKGUpfWZ1bmN0aW9uIG5zKGUpe2ZvcihsZXQgbyBvZlsiW2RhdGEtbWQtY29tcG9uZW50PWFubm91bmNlXSIsIltkYXRhLW1kLWNvbXBvbmVudD1jb250YWluZXJdIiwiW2RhdGEtbWQtY29tcG9uZW50PWhlYWRlci10b3BpY10iLCJbZGF0YS1tZC1jb21wb25lbnQ9b3V0ZGF0ZWRdIiwiW2RhdGEtbWQtY29tcG9uZW50PWxvZ29dIiwiW2RhdGEtbWQtY29tcG9uZW50PXNraXBdIiwuLi5CKCJuYXZpZ2F0aW9uLnRhYnMuc3RpY2t5Iik/WyJbZGF0YS1tZC1jb21wb25lbnQ9dGFic10iXTpbXV0pe2xldCBuPWZlKG8pLGk9ZmUobyxlKTt0eXBlb2YgbiE9InVuZGVmaW5lZCImJnR5cGVvZiBpIT0idW5kZWZpbmVkIiYmbi5yZXBsYWNlV2l0aChpKX1sZXQgdD10aShkb2N1bWVudCk7Zm9yKGxldFtvLG5db2YgdGkoZSkpdC5oYXMobyk/dC5kZWxldGUobyk6ZG9jdW1lbnQuaGVhZC5hcHBlbmRDaGlsZChuKTtmb3IobGV0IG8gb2YgdC52YWx1ZXMoKSl7bGV0IG49by5nZXRBdHRyaWJ1dGUoIm5hbWUiKTtuIT09InRoZW1lLWNvbG9yIiYmbiE9PSJjb2xvci1zY2hlbWUiJiZvLnJlbW92ZSgpfWxldCByPVNlKCJjb250YWluZXIiKTtyZXR1cm4gV2UoUCgic2NyaXB0IixyKSkucGlwZSh2KG89PntsZXQgbj1lLmNyZWF0ZUVsZW1lbnQoInNjcmlwdCIpO2lmKG8uc3JjKXtmb3IobGV0IGkgb2Ygby5nZXRBdHRyaWJ1dGVOYW1lcygpKW4uc2V0QXR0cmlidXRlKGksby5nZXRBdHRyaWJ1dGUoaSkpO3JldHVybiBvLnJlcGxhY2VXaXRoKG4pLG5ldyBqKGk9PntuLm9ubG9hZD0oKT0+aS5jb21wbGV0ZSgpfSl9ZWxzZSByZXR1cm4gbi50ZXh0Q29udGVudD1vLnRleHRDb250ZW50LG8ucmVwbGFjZVdpdGgobiksU30pLFooKSxpZShkb2N1bWVudCkpfWZ1bmN0aW9uIG9pKHtsb2NhdGlvbiQ6ZSx2aWV3cG9ydCQ6dCxwcm9ncmVzcyQ6cn0pe2xldCBvPXhlKCk7aWYobG9jYXRpb24ucHJvdG9jb2w9PT0iZmlsZToiKXJldHVybiBTO2xldCBuPXVyKG8uYmFzZSk7SShkb2N1bWVudCkuc3Vic2NyaWJlKHJpKTtsZXQgaT1oKGRvY3VtZW50LmJvZHksImNsaWNrIikucGlwZShIZShuKSx2KChbcCxjXSk9Pm9zKHAsYykpLHBlKCkpLGE9aCh3aW5kb3csInBvcHN0YXRlIikucGlwZShtKHllKSxwZSgpKTtpLnBpcGUocmUodCkpLnN1YnNjcmliZSgoW3Ase29mZnNldDpjfV0pPT57aGlzdG9yeS5yZXBsYWNlU3RhdGUoYywiIiksaGlzdG9yeS5wdXNoU3RhdGUobnVsbCwiIixwKX0pLE8oaSxhKS5zdWJzY3JpYmUoZSk7bGV0IHM9ZS5waXBlKGVlKCJwYXRobmFtZSIpLHYocD0+Zm4ocCx7cHJvZ3Jlc3MkOnJ9KS5waXBlKGRlKCgpPT4obHQocCwhMCksUykpKSksdihyaSksdihucykscGUoKSk7cmV0dXJuIE8ocy5waXBlKHJlKGUsKHAsYyk9PmMpKSxzLnBpcGUodigoKT0+ZSksZWUoInBhdGhuYW1lIiksdigoKT0+ZSksZWUoImhhc2giKSksZS5waXBlKEsoKHAsYyk9PnAucGF0aG5hbWU9PT1jLnBhdGhuYW1lJiZwLmhhc2g9PT1jLmhhc2gpLHYoKCk9PmkpLHcoKCk9Pmhpc3RvcnkuYmFjaygpKSkpLnN1YnNjcmliZShwPT57dmFyIGMsbDtoaXN0b3J5LnN0YXRlIT09bnVsbHx8IXAuaGFzaD93aW5kb3cuc2Nyb2xsVG8oMCwobD0oYz1oaXN0b3J5LnN0YXRlKT09bnVsbD92b2lkIDA6Yy55KSE9bnVsbD9sOjApOihoaXN0b3J5LnNjcm9sbFJlc3RvcmF0aW9uPSJhdXRvIixwbihwLmhhc2gpLGhpc3Rvcnkuc2Nyb2xsUmVzdG9yYXRpb249Im1hbnVhbCIpfSksZS5zdWJzY3JpYmUoKCk9PntoaXN0b3J5LnNjcm9sbFJlc3RvcmF0aW9uPSJtYW51YWwifSksaCh3aW5kb3csImJlZm9yZXVubG9hZCIpLnN1YnNjcmliZSgoKT0+e2hpc3Rvcnkuc2Nyb2xsUmVzdG9yYXRpb249ImF1dG8ifSksdC5waXBlKGVlKCJvZmZzZXQiKSxfZSgxMDApKS5zdWJzY3JpYmUoKHtvZmZzZXQ6cH0pPT57aGlzdG9yeS5yZXBsYWNlU3RhdGUocCwiIil9KSxzfXZhciBuaT1NdChxcigpKTtmdW5jdGlvbiBpaShlKXtsZXQgdD1lLnNlcGFyYXRvci5zcGxpdCgifCIpLm1hcChuPT5uLnJlcGxhY2UoLyhcKFw/WyE9PF1bXildK1wpKS9nLCIiKS5sZW5ndGg9PT0wPyJcdUZGRkQiOm4pLmpvaW4oInwiKSxyPW5ldyBSZWdFeHAodCwiaW1nIiksbz0obixpLGEpPT5gJHtpfTxtYXJrIGRhdGEtbWQtaGlnaGxpZ2h0PiR7YX08L21hcms+YDtyZXR1cm4gbj0+e249bi5yZXBsYWNlKC9bXHMqK1wtOn5eXSsvZywiICIpLnRyaW0oKTtsZXQgaT1uZXcgUmVnRXhwKGAoXnwke2Uuc2VwYXJhdG9yfXwpKCR7bi5yZXBsYWNlKC9bfFxce30oKVtcXV4kKyo/Li1dL2csIlxcJCYiKS5yZXBsYWNlKHIsInwiKX0pYCwiaW1nIik7cmV0dXJuIGE9PigwLG5pLmRlZmF1bHQpKGEpLnJlcGxhY2UoaSxvKS5yZXBsYWNlKC88XC9tYXJrPihccyspPG1hcmtbXj5dKj4vaW1nLCIkMSIpfX1mdW5jdGlvbiBqdChlKXtyZXR1cm4gZS50eXBlPT09MX1mdW5jdGlvbiBkcihlKXtyZXR1cm4gZS50eXBlPT09M31mdW5jdGlvbiBhaShlLHQpe2xldCByPXluKGUpO3JldHVybiBPKEkobG9jYXRpb24ucHJvdG9jb2whPT0iZmlsZToiKSx6ZSgic2VhcmNoIikpLnBpcGUoQWUobz0+byksdigoKT0+dCkpLnN1YnNjcmliZSgoe2NvbmZpZzpvLGRvY3M6bn0pPT5yLm5leHQoe3R5cGU6MCxkYXRhOntjb25maWc6byxkb2NzOm4sb3B0aW9uczp7c3VnZ2VzdDpCKCJzZWFyY2guc3VnZ2VzdCIpfX19KSkscn1mdW5jdGlvbiBzaShlKXt2YXIgbDtsZXR7c2VsZWN0ZWRWZXJzaW9uU2l0ZW1hcDp0LHNlbGVjdGVkVmVyc2lvbkJhc2VVUkw6cixjdXJyZW50TG9jYXRpb246byxjdXJyZW50QmFzZVVSTDpufT1lLGk9KGw9WHIobikpPT1udWxsP3ZvaWQgMDpsLnBhdGhuYW1lO2lmKGk9PT12b2lkIDApcmV0dXJuO2xldCBhPXNzKG8ucGF0aG5hbWUsaSk7aWYoYT09PXZvaWQgMClyZXR1cm47bGV0IHM9cHModC5rZXlzKCkpO2lmKCF0LmhhcyhzKSlyZXR1cm47bGV0IHA9WHIoYSxzKTtpZighcHx8IXQuaGFzKHAuaHJlZikpcmV0dXJuO2xldCBjPVhyKGEscik7aWYoYylyZXR1cm4gYy5oYXNoPW8uaGFzaCxjLnNlYXJjaD1vLnNlYXJjaCxjfWZ1bmN0aW9uIFhyKGUsdCl7dHJ5e3JldHVybiBuZXcgVVJMKGUsdCl9Y2F0Y2gocil7cmV0dXJufX1mdW5jdGlvbiBzcyhlLHQpe2lmKGUuc3RhcnRzV2l0aCh0KSlyZXR1cm4gZS5zbGljZSh0Lmxlbmd0aCl9ZnVuY3Rpb24gY3MoZSx0KXtsZXQgcj1NYXRoLm1pbihlLmxlbmd0aCx0Lmxlbmd0aCksbztmb3Iobz0wO288ciYmZVtvXT09PXRbb107KytvKTtyZXR1cm4gb31mdW5jdGlvbiBwcyhlKXtsZXQgdDtmb3IobGV0IHIgb2YgZSl0PT09dm9pZCAwP3Q9cjp0PXQuc2xpY2UoMCxjcyh0LHIpKTtyZXR1cm4gdCE9bnVsbD90OiIifWZ1bmN0aW9uIGNpKHtkb2N1bWVudCQ6ZX0pe2xldCB0PXhlKCkscj1qZShuZXcgVVJMKCIuLi92ZXJzaW9ucy5qc29uIix0LmJhc2UpKS5waXBlKGRlKCgpPT5TKSksbz1yLnBpcGUobShuPT57bGV0WyxpXT10LmJhc2UubWF0Y2goLyhbXi9dKylcLz8kLyk7cmV0dXJuIG4uZmluZCgoe3ZlcnNpb246YSxhbGlhc2VzOnN9KT0+YT09PWl8fHMuaW5jbHVkZXMoaSkpfHxuWzBdfSkpO3IucGlwZShtKG49Pm5ldyBNYXAobi5tYXAoaT0+W2Ake25ldyBVUkwoYC4uLyR7aS52ZXJzaW9ufS9gLHQuYmFzZSl9YCxpXSkpKSx2KG49PmgoZG9jdW1lbnQuYm9keSwiY2xpY2siKS5waXBlKGIoaT0+IWkubWV0YUtleSYmIWkuY3RybEtleSkscmUobyksdigoW2ksYV0pPT57aWYoaS50YXJnZXQgaW5zdGFuY2VvZiBFbGVtZW50KXtsZXQgcz1pLnRhcmdldC5jbG9zZXN0KCJhIik7aWYocyYmIXMudGFyZ2V0JiZuLmhhcyhzLmhyZWYpKXtsZXQgcD1zLmhyZWY7cmV0dXJuIWkudGFyZ2V0LmNsb3Nlc3QoIi5tZC12ZXJzaW9uIikmJm4uZ2V0KHApPT09YT9TOihpLnByZXZlbnREZWZhdWx0KCksSShuZXcgVVJMKHApKSl9fXJldHVybiBTfSksdihpPT51cihpKS5waXBlKG0oYT0+e3ZhciBzO3JldHVybihzPXNpKHtzZWxlY3RlZFZlcnNpb25TaXRlbWFwOmEsc2VsZWN0ZWRWZXJzaW9uQmFzZVVSTDppLGN1cnJlbnRMb2NhdGlvbjp5ZSgpLGN1cnJlbnRCYXNlVVJMOnQuYmFzZX0pKSE9bnVsbD9zOml9KSkpKSkpLnN1YnNjcmliZShuPT5sdChuLCEwKSkseihbcixvXSkuc3Vic2NyaWJlKChbbixpXSk9PntSKCIubWQtaGVhZGVyX190b3BpYyIpLmFwcGVuZENoaWxkKENuKG4saSkpfSksZS5waXBlKHYoKCk9Pm8pKS5zdWJzY3JpYmUobj0+e3ZhciBhO2xldCBpPV9fbWRfZ2V0KCJfX291dGRhdGVkIixzZXNzaW9uU3RvcmFnZSk7aWYoaT09PW51bGwpe2k9ITA7bGV0IHM9KChhPXQudmVyc2lvbik9PW51bGw/dm9pZCAwOmEuZGVmYXVsdCl8fCJsYXRlc3QiO0FycmF5LmlzQXJyYXkocyl8fChzPVtzXSk7ZTpmb3IobGV0IHAgb2Ygcylmb3IobGV0IGMgb2Ygbi5hbGlhc2VzLmNvbmNhdChuLnZlcnNpb24pKWlmKG5ldyBSZWdFeHAocCwiaSIpLnRlc3QoYykpe2k9ITE7YnJlYWsgZX1fX21kX3NldCgiX19vdXRkYXRlZCIsaSxzZXNzaW9uU3RvcmFnZSl9aWYoaSlmb3IobGV0IHMgb2YgYWUoIm91dGRhdGVkIikpcy5oaWRkZW49ITF9KX1mdW5jdGlvbiBscyhlLHt3b3JrZXIkOnR9KXtsZXR7c2VhcmNoUGFyYW1zOnJ9PXllKCk7ci5oYXMoInEiKSYmKEplKCJzZWFyY2giLCEwKSxlLnZhbHVlPXIuZ2V0KCJxIiksZS5mb2N1cygpLHplKCJzZWFyY2giKS5waXBlKEFlKGk9PiFpKSkuc3Vic2NyaWJlKCgpPT57bGV0IGk9eWUoKTtpLnNlYXJjaFBhcmFtcy5kZWxldGUoInEiKSxoaXN0b3J5LnJlcGxhY2VTdGF0ZSh7fSwiIixgJHtpfWApfSkpO2xldCBvPWV0KGUpLG49Tyh0LnBpcGUoQWUoanQpKSxoKGUsImtleXVwIiksbykucGlwZShtKCgpPT5lLnZhbHVlKSxLKCkpO3JldHVybiB6KFtuLG9dKS5waXBlKG0oKFtpLGFdKT0+KHt2YWx1ZTppLGZvY3VzOmF9KSksRygxKSl9ZnVuY3Rpb24gcGkoZSx7d29ya2VyJDp0fSl7bGV0IHI9bmV3IGcsbz1yLnBpcGUoWigpLGllKCEwKSk7eihbdC5waXBlKEFlKGp0KSkscl0sKGksYSk9PmEpLnBpcGUoZWUoInZhbHVlIikpLnN1YnNjcmliZSgoe3ZhbHVlOml9KT0+dC5uZXh0KHt0eXBlOjIsZGF0YTppfSkpLHIucGlwZShlZSgiZm9jdXMiKSkuc3Vic2NyaWJlKCh7Zm9jdXM6aX0pPT57aSYmSmUoInNlYXJjaCIsaSl9KSxoKGUuZm9ybSwicmVzZXQiKS5waXBlKFcobykpLnN1YnNjcmliZSgoKT0+ZS5mb2N1cygpKTtsZXQgbj1SKCJoZWFkZXIgW2Zvcj1fX3NlYXJjaF0iKTtyZXR1cm4gaChuLCJjbGljayIpLnN1YnNjcmliZSgoKT0+ZS5mb2N1cygpKSxscyhlLHt3b3JrZXIkOnR9KS5waXBlKHcoaT0+ci5uZXh0KGkpKSxfKCgpPT5yLmNvbXBsZXRlKCkpLG0oaT0+JCh7cmVmOmV9LGkpKSxHKDEpKX1mdW5jdGlvbiBsaShlLHt3b3JrZXIkOnQscXVlcnkkOnJ9KXtsZXQgbz1uZXcgZyxuPW9uKGUucGFyZW50RWxlbWVudCkucGlwZShiKEJvb2xlYW4pKSxpPWUucGFyZW50RWxlbWVudCxhPVIoIjpzY29wZSA+IDpmaXJzdC1jaGlsZCIsZSkscz1SKCI6c2NvcGUgPiA6bGFzdC1jaGlsZCIsZSk7emUoInNlYXJjaCIpLnN1YnNjcmliZShsPT5zLnNldEF0dHJpYnV0ZSgicm9sZSIsbD8ibGlzdCI6InByZXNlbnRhdGlvbiIpKSxvLnBpcGUocmUociksV3IodC5waXBlKEFlKGp0KSkpKS5zdWJzY3JpYmUoKFt7aXRlbXM6bH0se3ZhbHVlOmZ9XSk9Pntzd2l0Y2gobC5sZW5ndGgpe2Nhc2UgMDphLnRleHRDb250ZW50PWYubGVuZ3RoP0VlKCJzZWFyY2gucmVzdWx0Lm5vbmUiKTpFZSgic2VhcmNoLnJlc3VsdC5wbGFjZWhvbGRlciIpO2JyZWFrO2Nhc2UgMTphLnRleHRDb250ZW50PUVlKCJzZWFyY2gucmVzdWx0Lm9uZSIpO2JyZWFrO2RlZmF1bHQ6bGV0IHU9c3IobC5sZW5ndGgpO2EudGV4dENvbnRlbnQ9RWUoInNlYXJjaC5yZXN1bHQub3RoZXIiLHUpfX0pO2xldCBwPW8ucGlwZSh3KCgpPT5zLmlubmVySFRNTD0iIiksdigoe2l0ZW1zOmx9KT0+TyhJKC4uLmwuc2xpY2UoMCwxMCkpLEkoLi4ubC5zbGljZSgxMCkpLnBpcGUoQmUoNCksVnIobiksdigoW2ZdKT0+ZikpKSksbShNbikscGUoKSk7cmV0dXJuIHAuc3Vic2NyaWJlKGw9PnMuYXBwZW5kQ2hpbGQobCkpLHAucGlwZShuZShsPT57bGV0IGY9ZmUoImRldGFpbHMiLGwpO3JldHVybiB0eXBlb2YgZj09InVuZGVmaW5lZCI/UzpoKGYsInRvZ2dsZSIpLnBpcGUoVyhvKSxtKCgpPT5mKSl9KSkuc3Vic2NyaWJlKGw9PntsLm9wZW49PT0hMSYmbC5vZmZzZXRUb3A8PWkuc2Nyb2xsVG9wJiZpLnNjcm9sbFRvKHt0b3A6bC5vZmZzZXRUb3B9KX0pLHQucGlwZShiKGRyKSxtKCh7ZGF0YTpsfSk9PmwpKS5waXBlKHcobD0+by5uZXh0KGwpKSxfKCgpPT5vLmNvbXBsZXRlKCkpLG0obD0+JCh7cmVmOmV9LGwpKSl9ZnVuY3Rpb24gbXMoZSx7cXVlcnkkOnR9KXtyZXR1cm4gdC5waXBlKG0oKHt2YWx1ZTpyfSk9PntsZXQgbz15ZSgpO3JldHVybiBvLmhhc2g9IiIscj1yLnJlcGxhY2UoL1xzKy9nLCIrIikucmVwbGFjZSgvJi9nLCIlMjYiKS5yZXBsYWNlKC89L2csIiUzRCIpLG8uc2VhcmNoPWBxPSR7cn1gLHt1cmw6b319KSl9ZnVuY3Rpb24gbWkoZSx0KXtsZXQgcj1uZXcgZyxvPXIucGlwZShaKCksaWUoITApKTtyZXR1cm4gci5zdWJzY3JpYmUoKHt1cmw6bn0pPT57ZS5zZXRBdHRyaWJ1dGUoImRhdGEtY2xpcGJvYXJkLXRleHQiLGUuaHJlZiksZS5ocmVmPWAke259YH0pLGgoZSwiY2xpY2siKS5waXBlKFcobykpLnN1YnNjcmliZShuPT5uLnByZXZlbnREZWZhdWx0KCkpLG1zKGUsdCkucGlwZSh3KG49PnIubmV4dChuKSksXygoKT0+ci5jb21wbGV0ZSgpKSxtKG49PiQoe3JlZjplfSxuKSkpfWZ1bmN0aW9uIGZpKGUse3dvcmtlciQ6dCxrZXlib2FyZCQ6cn0pe2xldCBvPW5ldyBnLG49U2UoInNlYXJjaC1xdWVyeSIpLGk9TyhoKG4sImtleWRvd24iKSxoKG4sImZvY3VzIikpLnBpcGUodmUoc2UpLG0oKCk9Pm4udmFsdWUpLEsoKSk7cmV0dXJuIG8ucGlwZShIZShpKSxtKChbe3N1Z2dlc3Q6c30scF0pPT57bGV0IGM9cC5zcGxpdCgvKFtccy1dKykvKTtpZihzIT1udWxsJiZzLmxlbmd0aCYmY1tjLmxlbmd0aC0xXSl7bGV0IGw9c1tzLmxlbmd0aC0xXTtsLnN0YXJ0c1dpdGgoY1tjLmxlbmd0aC0xXSkmJihjW2MubGVuZ3RoLTFdPWwpfWVsc2UgYy5sZW5ndGg9MDtyZXR1cm4gY30pKS5zdWJzY3JpYmUocz0+ZS5pbm5lckhUTUw9cy5qb2luKCIiKS5yZXBsYWNlKC9ccy9nLCImbmJzcDsiKSksci5waXBlKGIoKHttb2RlOnN9KT0+cz09PSJzZWFyY2giKSkuc3Vic2NyaWJlKHM9Pntzd2l0Y2gocy50eXBlKXtjYXNlIkFycm93UmlnaHQiOmUuaW5uZXJUZXh0Lmxlbmd0aCYmbi5zZWxlY3Rpb25TdGFydD09PW4udmFsdWUubGVuZ3RoJiYobi52YWx1ZT1lLmlubmVyVGV4dCk7YnJlYWt9fSksdC5waXBlKGIoZHIpLG0oKHtkYXRhOnN9KT0+cykpLnBpcGUodyhzPT5vLm5leHQocykpLF8oKCk9Pm8uY29tcGxldGUoKSksbSgoKT0+KHtyZWY6ZX0pKSl9ZnVuY3Rpb24gdWkoZSx7aW5kZXgkOnQsa2V5Ym9hcmQkOnJ9KXtsZXQgbz14ZSgpO3RyeXtsZXQgbj1haShvLnNlYXJjaCx0KSxpPVNlKCJzZWFyY2gtcXVlcnkiLGUpLGE9U2UoInNlYXJjaC1yZXN1bHQiLGUpO2goZSwiY2xpY2siKS5waXBlKGIoKHt0YXJnZXQ6cH0pPT5wIGluc3RhbmNlb2YgRWxlbWVudCYmISFwLmNsb3Nlc3QoImEiKSkpLnN1YnNjcmliZSgoKT0+SmUoInNlYXJjaCIsITEpKSxyLnBpcGUoYigoe21vZGU6cH0pPT5wPT09InNlYXJjaCIpKS5zdWJzY3JpYmUocD0+e2xldCBjPUllKCk7c3dpdGNoKHAudHlwZSl7Y2FzZSJFbnRlciI6aWYoYz09PWkpe2xldCBsPW5ldyBNYXA7Zm9yKGxldCBmIG9mIFAoIjpmaXJzdC1jaGlsZCBbaHJlZl0iLGEpKXtsZXQgdT1mLmZpcnN0RWxlbWVudENoaWxkO2wuc2V0KGYscGFyc2VGbG9hdCh1LmdldEF0dHJpYnV0ZSgiZGF0YS1tZC1zY29yZSIpKSl9aWYobC5zaXplKXtsZXRbW2ZdXT1bLi4ubF0uc29ydCgoWyx1XSxbLGRdKT0+ZC11KTtmLmNsaWNrKCl9cC5jbGFpbSgpfWJyZWFrO2Nhc2UiRXNjYXBlIjpjYXNlIlRhYiI6SmUoInNlYXJjaCIsITEpLGkuYmx1cigpO2JyZWFrO2Nhc2UiQXJyb3dVcCI6Y2FzZSJBcnJvd0Rvd24iOmlmKHR5cGVvZiBjPT0idW5kZWZpbmVkIilpLmZvY3VzKCk7ZWxzZXtsZXQgbD1baSwuLi5QKCI6bm90KGRldGFpbHMpID4gW2hyZWZdLCBzdW1tYXJ5LCBkZXRhaWxzW29wZW5dIFtocmVmXSIsYSldLGY9TWF0aC5tYXgoMCwoTWF0aC5tYXgoMCxsLmluZGV4T2YoYykpK2wubGVuZ3RoKyhwLnR5cGU9PT0iQXJyb3dVcCI/LTE6MSkpJWwubGVuZ3RoKTtsW2ZdLmZvY3VzKCl9cC5jbGFpbSgpO2JyZWFrO2RlZmF1bHQ6aSE9PUllKCkmJmkuZm9jdXMoKX19KSxyLnBpcGUoYigoe21vZGU6cH0pPT5wPT09Imdsb2JhbCIpKS5zdWJzY3JpYmUocD0+e3N3aXRjaChwLnR5cGUpe2Nhc2UiZiI6Y2FzZSJzIjpjYXNlIi8iOmkuZm9jdXMoKSxpLnNlbGVjdCgpLHAuY2xhaW0oKTticmVha319KTtsZXQgcz1waShpLHt3b3JrZXIkOm59KTtyZXR1cm4gTyhzLGxpKGEse3dvcmtlciQ6bixxdWVyeSQ6c30pKS5waXBlKFJlKC4uLmFlKCJzZWFyY2gtc2hhcmUiLGUpLm1hcChwPT5taShwLHtxdWVyeSQ6c30pKSwuLi5hZSgic2VhcmNoLXN1Z2dlc3QiLGUpLm1hcChwPT5maShwLHt3b3JrZXIkOm4sa2V5Ym9hcmQkOnJ9KSkpKX1jYXRjaChuKXtyZXR1cm4gZS5oaWRkZW49ITAsWWV9fWZ1bmN0aW9uIGRpKGUse2luZGV4JDp0LGxvY2F0aW9uJDpyfSl7cmV0dXJuIHooW3Qsci5waXBlKFEoeWUoKSksYihvPT4hIW8uc2VhcmNoUGFyYW1zLmdldCgiaCIpKSldKS5waXBlKG0oKFtvLG5dKT0+aWkoby5jb25maWcpKG4uc2VhcmNoUGFyYW1zLmdldCgiaCIpKSksbShvPT57dmFyIGE7bGV0IG49bmV3IE1hcCxpPWRvY3VtZW50LmNyZWF0ZU5vZGVJdGVyYXRvcihlLE5vZGVGaWx0ZXIuU0hPV19URVhUKTtmb3IobGV0IHM9aS5uZXh0Tm9kZSgpO3M7cz1pLm5leHROb2RlKCkpaWYoKGE9cy5wYXJlbnRFbGVtZW50KSE9bnVsbCYmYS5vZmZzZXRIZWlnaHQpe2xldCBwPXMudGV4dENvbnRlbnQsYz1vKHApO2MubGVuZ3RoPnAubGVuZ3RoJiZuLnNldChzLGMpfWZvcihsZXRbcyxwXW9mIG4pe2xldHtjaGlsZE5vZGVzOmN9PXgoInNwYW4iLG51bGwscCk7cy5yZXBsYWNlV2l0aCguLi5BcnJheS5mcm9tKGMpKX1yZXR1cm57cmVmOmUsbm9kZXM6bn19KSl9ZnVuY3Rpb24gZnMoZSx7dmlld3BvcnQkOnQsbWFpbiQ6cn0pe2xldCBvPWUuY2xvc2VzdCgiLm1kLWdyaWQiKSxuPW8ub2Zmc2V0VG9wLW8ucGFyZW50RWxlbWVudC5vZmZzZXRUb3A7cmV0dXJuIHooW3IsdF0pLnBpcGUobSgoW3tvZmZzZXQ6aSxoZWlnaHQ6YX0se29mZnNldDp7eTpzfX1dKT0+KGE9YStNYXRoLm1pbihuLE1hdGgubWF4KDAscy1pKSktbix7aGVpZ2h0OmEsbG9ja2VkOnM+PWkrbn0pKSxLKChpLGEpPT5pLmhlaWdodD09PWEuaGVpZ2h0JiZpLmxvY2tlZD09PWEubG9ja2VkKSl9ZnVuY3Rpb24gWnIoZSxvKXt2YXIgbj1vLHtoZWFkZXIkOnR9PW4scj1zbyhuLFsiaGVhZGVyJCJdKTtsZXQgaT1SKCIubWQtc2lkZWJhcl9fc2Nyb2xsd3JhcCIsZSkse3k6YX09VmUoaSk7cmV0dXJuIEMoKCk9PntsZXQgcz1uZXcgZyxwPXMucGlwZShaKCksaWUoITApKSxjPXMucGlwZShNZSgwLG1lKSk7cmV0dXJuIGMucGlwZShyZSh0KSkuc3Vic2NyaWJlKHtuZXh0KFt7aGVpZ2h0Omx9LHtoZWlnaHQ6Zn1dKXtpLnN0eWxlLmhlaWdodD1gJHtsLTIqYX1weGAsZS5zdHlsZS50b3A9YCR7Zn1weGB9LGNvbXBsZXRlKCl7aS5zdHlsZS5oZWlnaHQ9IiIsZS5zdHlsZS50b3A9IiJ9fSksYy5waXBlKEFlKCkpLnN1YnNjcmliZSgoKT0+e2ZvcihsZXQgbCBvZiBQKCIubWQtbmF2X19saW5rLS1hY3RpdmVbaHJlZl0iLGUpKXtpZighbC5jbGllbnRIZWlnaHQpY29udGludWU7bGV0IGY9bC5jbG9zZXN0KCIubWQtc2lkZWJhcl9fc2Nyb2xsd3JhcCIpO2lmKHR5cGVvZiBmIT0idW5kZWZpbmVkIil7bGV0IHU9bC5vZmZzZXRUb3AtZi5vZmZzZXRUb3Ase2hlaWdodDpkfT1jZShmKTtmLnNjcm9sbFRvKHt0b3A6dS1kLzJ9KX19fSksdWUoUCgibGFiZWxbdGFiaW5kZXhdIixlKSkucGlwZShuZShsPT5oKGwsImNsaWNrIikucGlwZSh2ZShzZSksbSgoKT0+bCksVyhwKSkpKS5zdWJzY3JpYmUobD0+e2xldCBmPVIoYFtpZD0iJHtsLmh0bWxGb3J9Il1gKTtSKGBbYXJpYS1sYWJlbGxlZGJ5PSIke2wuaWR9Il1gKS5zZXRBdHRyaWJ1dGUoImFyaWEtZXhwYW5kZWQiLGAke2YuY2hlY2tlZH1gKX0pLGZzKGUscikucGlwZSh3KGw9PnMubmV4dChsKSksXygoKT0+cy5jb21wbGV0ZSgpKSxtKGw9PiQoe3JlZjplfSxsKSkpfSl9ZnVuY3Rpb24gaGkoZSx0KXtpZih0eXBlb2YgdCE9InVuZGVmaW5lZCIpe2xldCByPWBodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zLyR7ZX0vJHt0fWA7cmV0dXJuIHN0KGplKGAke3J9L3JlbGVhc2VzL2xhdGVzdGApLnBpcGUoZGUoKCk9PlMpLG0obz0+KHt2ZXJzaW9uOm8udGFnX25hbWV9KSksRGUoe30pKSxqZShyKS5waXBlKGRlKCgpPT5TKSxtKG89Pih7c3RhcnM6by5zdGFyZ2F6ZXJzX2NvdW50LGZvcmtzOm8uZm9ya3NfY291bnR9KSksRGUoe30pKSkucGlwZShtKChbbyxuXSk9PiQoJCh7fSxvKSxuKSkpfWVsc2V7bGV0IHI9YGh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vdXNlcnMvJHtlfWA7cmV0dXJuIGplKHIpLnBpcGUobShvPT4oe3JlcG9zaXRvcmllczpvLnB1YmxpY19yZXBvc30pKSxEZSh7fSkpfX1mdW5jdGlvbiBiaShlLHQpe2xldCByPWBodHRwczovLyR7ZX0vYXBpL3Y0L3Byb2plY3RzLyR7ZW5jb2RlVVJJQ29tcG9uZW50KHQpfWA7cmV0dXJuIHN0KGplKGAke3J9L3JlbGVhc2VzL3Blcm1hbGluay9sYXRlc3RgKS5waXBlKGRlKCgpPT5TKSxtKCh7dGFnX25hbWU6b30pPT4oe3ZlcnNpb246b30pKSxEZSh7fSkpLGplKHIpLnBpcGUoZGUoKCk9PlMpLG0oKHtzdGFyX2NvdW50Om8sZm9ya3NfY291bnQ6bn0pPT4oe3N0YXJzOm8sZm9ya3M6bn0pKSxEZSh7fSkpKS5waXBlKG0oKFtvLG5dKT0+JCgkKHt9LG8pLG4pKSl9ZnVuY3Rpb24gdmkoZSl7bGV0IHQ9ZS5tYXRjaCgvXi4rZ2l0aHViXC5jb21cLyhbXi9dKylcLz8oW14vXSspPy9pKTtpZih0KXtsZXRbLHIsb109dDtyZXR1cm4gaGkocixvKX1pZih0PWUubWF0Y2goL14uKz8oW14vXSpnaXRsYWJbXi9dKylcLyguKz8pXC8/JC9pKSx0KXtsZXRbLHIsb109dDtyZXR1cm4gYmkocixvKX1yZXR1cm4gU312YXIgdXM7ZnVuY3Rpb24gZHMoZSl7cmV0dXJuIHVzfHwodXM9QygoKT0+e2xldCB0PV9fbWRfZ2V0KCJfX3NvdXJjZSIsc2Vzc2lvblN0b3JhZ2UpO2lmKHQpcmV0dXJuIEkodCk7aWYoYWUoImNvbnNlbnQiKS5sZW5ndGgpe2xldCBvPV9fbWRfZ2V0KCJfX2NvbnNlbnQiKTtpZighKG8mJm8uZ2l0aHViKSlyZXR1cm4gU31yZXR1cm4gdmkoZS5ocmVmKS5waXBlKHcobz0+X19tZF9zZXQoIl9fc291cmNlIixvLHNlc3Npb25TdG9yYWdlKSkpfSkucGlwZShkZSgoKT0+UyksYih0PT5PYmplY3Qua2V5cyh0KS5sZW5ndGg+MCksbSh0PT4oe2ZhY3RzOnR9KSksRygxKSkpfWZ1bmN0aW9uIGdpKGUpe2xldCB0PVIoIjpzY29wZSA+IDpsYXN0LWNoaWxkIixlKTtyZXR1cm4gQygoKT0+e2xldCByPW5ldyBnO3JldHVybiByLnN1YnNjcmliZSgoe2ZhY3RzOm99KT0+e3QuYXBwZW5kQ2hpbGQoX24obykpLHQuY2xhc3NMaXN0LmFkZCgibWQtc291cmNlX19yZXBvc2l0b3J5LS1hY3RpdmUiKX0pLGRzKGUpLnBpcGUodyhvPT5yLm5leHQobykpLF8oKCk9PnIuY29tcGxldGUoKSksbShvPT4kKHtyZWY6ZX0sbykpKX0pfWZ1bmN0aW9uIGhzKGUse3ZpZXdwb3J0JDp0LGhlYWRlciQ6cn0pe3JldHVybiBnZShkb2N1bWVudC5ib2R5KS5waXBlKHYoKCk9Pm1yKGUse2hlYWRlciQ6cix2aWV3cG9ydCQ6dH0pKSxtKCh7b2Zmc2V0Ont5Om99fSk9Pih7aGlkZGVuOm8+PTEwfSkpLGVlKCJoaWRkZW4iKSl9ZnVuY3Rpb24geWkoZSx0KXtyZXR1cm4gQygoKT0+e2xldCByPW5ldyBnO3JldHVybiByLnN1YnNjcmliZSh7bmV4dCh7aGlkZGVuOm99KXtlLmhpZGRlbj1vfSxjb21wbGV0ZSgpe2UuaGlkZGVuPSExfX0pLChCKCJuYXZpZ2F0aW9uLnRhYnMuc3RpY2t5Iik/SSh7aGlkZGVuOiExfSk6aHMoZSx0KSkucGlwZSh3KG89PnIubmV4dChvKSksXygoKT0+ci5jb21wbGV0ZSgpKSxtKG89PiQoe3JlZjplfSxvKSkpfSl9ZnVuY3Rpb24gYnMoZSx7dmlld3BvcnQkOnQsaGVhZGVyJDpyfSl7bGV0IG89bmV3IE1hcCxuPVAoIi5tZC1uYXZfX2xpbmsiLGUpO2ZvcihsZXQgcyBvZiBuKXtsZXQgcD1kZWNvZGVVUklDb21wb25lbnQocy5oYXNoLnN1YnN0cmluZygxKSksYz1mZShgW2lkPSIke3B9Il1gKTt0eXBlb2YgYyE9InVuZGVmaW5lZCImJm8uc2V0KHMsYyl9bGV0IGk9ci5waXBlKGVlKCJoZWlnaHQiKSxtKCh7aGVpZ2h0OnN9KT0+e2xldCBwPVNlKCJtYWluIiksYz1SKCI6c2NvcGUgPiA6Zmlyc3QtY2hpbGQiLHApO3JldHVybiBzKy44KihjLm9mZnNldFRvcC1wLm9mZnNldFRvcCl9KSxwZSgpKTtyZXR1cm4gZ2UoZG9jdW1lbnQuYm9keSkucGlwZShlZSgiaGVpZ2h0IiksdihzPT5DKCgpPT57bGV0IHA9W107cmV0dXJuIEkoWy4uLm9dLnJlZHVjZSgoYyxbbCxmXSk9Pntmb3IoO3AubGVuZ3RoJiZvLmdldChwW3AubGVuZ3RoLTFdKS50YWdOYW1lPj1mLnRhZ05hbWU7KXAucG9wKCk7bGV0IHU9Zi5vZmZzZXRUb3A7Zm9yKDshdSYmZi5wYXJlbnRFbGVtZW50OylmPWYucGFyZW50RWxlbWVudCx1PWYub2Zmc2V0VG9wO2xldCBkPWYub2Zmc2V0UGFyZW50O2Zvcig7ZDtkPWQub2Zmc2V0UGFyZW50KXUrPWQub2Zmc2V0VG9wO3JldHVybiBjLnNldChbLi4ucD1bLi4ucCxsXV0ucmV2ZXJzZSgpLHUpfSxuZXcgTWFwKSl9KS5waXBlKG0ocD0+bmV3IE1hcChbLi4ucF0uc29ydCgoWyxjXSxbLGxdKT0+Yy1sKSkpLEhlKGkpLHYoKFtwLGNdKT0+dC5waXBlKEZyKChbbCxmXSx7b2Zmc2V0Ont5OnV9LHNpemU6ZH0pPT57bGV0IHk9dStkLmhlaWdodD49TWF0aC5mbG9vcihzLmhlaWdodCk7Zm9yKDtmLmxlbmd0aDspe2xldFssTF09ZlswXTtpZihMLWM8dXx8eSlsPVsuLi5sLGYuc2hpZnQoKV07ZWxzZSBicmVha31mb3IoO2wubGVuZ3RoOyl7bGV0WyxMXT1sW2wubGVuZ3RoLTFdO2lmKEwtYz49dSYmIXkpZj1bbC5wb3AoKSwuLi5mXTtlbHNlIGJyZWFrfXJldHVybltsLGZdfSxbW10sWy4uLnBdXSksSygobCxmKT0+bFswXT09PWZbMF0mJmxbMV09PT1mWzFdKSkpKSkpLnBpcGUobSgoW3MscF0pPT4oe3ByZXY6cy5tYXAoKFtjXSk9PmMpLG5leHQ6cC5tYXAoKFtjXSk9PmMpfSkpLFEoe3ByZXY6W10sbmV4dDpbXX0pLEJlKDIsMSksbSgoW3MscF0pPT5zLnByZXYubGVuZ3RoPHAucHJldi5sZW5ndGg/e3ByZXY6cC5wcmV2LnNsaWNlKE1hdGgubWF4KDAscy5wcmV2Lmxlbmd0aC0xKSxwLnByZXYubGVuZ3RoKSxuZXh0OltdfTp7cHJldjpwLnByZXYuc2xpY2UoLTEpLG5leHQ6cC5uZXh0LnNsaWNlKDAscC5uZXh0Lmxlbmd0aC1zLm5leHQubGVuZ3RoKX0pKX1mdW5jdGlvbiB4aShlLHt2aWV3cG9ydCQ6dCxoZWFkZXIkOnIsbWFpbiQ6byx0YXJnZXQkOm59KXtyZXR1cm4gQygoKT0+e2xldCBpPW5ldyBnLGE9aS5waXBlKFooKSxpZSghMCkpO2lmKGkuc3Vic2NyaWJlKCh7cHJldjpzLG5leHQ6cH0pPT57Zm9yKGxldFtjXW9mIHApYy5jbGFzc0xpc3QucmVtb3ZlKCJtZC1uYXZfX2xpbmstLXBhc3NlZCIpLGMuY2xhc3NMaXN0LnJlbW92ZSgibWQtbmF2X19saW5rLS1hY3RpdmUiKTtmb3IobGV0W2MsW2xdXW9mIHMuZW50cmllcygpKWwuY2xhc3NMaXN0LmFkZCgibWQtbmF2X19saW5rLS1wYXNzZWQiKSxsLmNsYXNzTGlzdC50b2dnbGUoIm1kLW5hdl9fbGluay0tYWN0aXZlIixjPT09cy5sZW5ndGgtMSl9KSxCKCJ0b2MuZm9sbG93Iikpe2xldCBzPU8odC5waXBlKF9lKDEpLG0oKCk9Pnt9KSksdC5waXBlKF9lKDI1MCksbSgoKT0+InNtb290aCIpKSk7aS5waXBlKGIoKHtwcmV2OnB9KT0+cC5sZW5ndGg+MCksSGUoby5waXBlKHZlKHNlKSkpLHJlKHMpKS5zdWJzY3JpYmUoKFtbe3ByZXY6cH1dLGNdKT0+e2xldFtsXT1wW3AubGVuZ3RoLTFdO2lmKGwub2Zmc2V0SGVpZ2h0KXtsZXQgZj1jcihsKTtpZih0eXBlb2YgZiE9InVuZGVmaW5lZCIpe2xldCB1PWwub2Zmc2V0VG9wLWYub2Zmc2V0VG9wLHtoZWlnaHQ6ZH09Y2UoZik7Zi5zY3JvbGxUbyh7dG9wOnUtZC8yLGJlaGF2aW9yOmN9KX19fSl9cmV0dXJuIEIoIm5hdmlnYXRpb24udHJhY2tpbmciKSYmdC5waXBlKFcoYSksZWUoIm9mZnNldCIpLF9lKDI1MCksQ2UoMSksVyhuLnBpcGUoQ2UoMSkpKSxjdCh7ZGVsYXk6MjUwfSkscmUoaSkpLnN1YnNjcmliZSgoWyx7cHJldjpzfV0pPT57bGV0IHA9eWUoKSxjPXNbcy5sZW5ndGgtMV07aWYoYyYmYy5sZW5ndGgpe2xldFtsXT1jLHtoYXNoOmZ9PW5ldyBVUkwobC5ocmVmKTtwLmhhc2ghPT1mJiYocC5oYXNoPWYsaGlzdG9yeS5yZXBsYWNlU3RhdGUoe30sIiIsYCR7cH1gKSl9ZWxzZSBwLmhhc2g9IiIsaGlzdG9yeS5yZXBsYWNlU3RhdGUoe30sIiIsYCR7cH1gKX0pLGJzKGUse3ZpZXdwb3J0JDp0LGhlYWRlciQ6cn0pLnBpcGUodyhzPT5pLm5leHQocykpLF8oKCk9PmkuY29tcGxldGUoKSksbShzPT4kKHtyZWY6ZX0scykpKX0pfWZ1bmN0aW9uIHZzKGUse3ZpZXdwb3J0JDp0LG1haW4kOnIsdGFyZ2V0JDpvfSl7bGV0IG49dC5waXBlKG0oKHtvZmZzZXQ6e3k6YX19KT0+YSksQmUoMiwxKSxtKChbYSxzXSk9PmE+cyYmcz4wKSxLKCkpLGk9ci5waXBlKG0oKHthY3RpdmU6YX0pPT5hKSk7cmV0dXJuIHooW2ksbl0pLnBpcGUobSgoW2Esc10pPT4hKGEmJnMpKSxLKCksVyhvLnBpcGUoQ2UoMSkpKSxpZSghMCksY3Qoe2RlbGF5OjI1MH0pLG0oYT0+KHtoaWRkZW46YX0pKSl9ZnVuY3Rpb24gRWkoZSx7dmlld3BvcnQkOnQsaGVhZGVyJDpyLG1haW4kOm8sdGFyZ2V0JDpufSl7bGV0IGk9bmV3IGcsYT1pLnBpcGUoWigpLGllKCEwKSk7cmV0dXJuIGkuc3Vic2NyaWJlKHtuZXh0KHtoaWRkZW46c30pe2UuaGlkZGVuPXMscz8oZS5zZXRBdHRyaWJ1dGUoInRhYmluZGV4IiwiLTEiKSxlLmJsdXIoKSk6ZS5yZW1vdmVBdHRyaWJ1dGUoInRhYmluZGV4Iil9LGNvbXBsZXRlKCl7ZS5zdHlsZS50b3A9IiIsZS5oaWRkZW49ITAsZS5yZW1vdmVBdHRyaWJ1dGUoInRhYmluZGV4Iil9fSksci5waXBlKFcoYSksZWUoImhlaWdodCIpKS5zdWJzY3JpYmUoKHtoZWlnaHQ6c30pPT57ZS5zdHlsZS50b3A9YCR7cysxNn1weGB9KSxoKGUsImNsaWNrIikuc3Vic2NyaWJlKHM9PntzLnByZXZlbnREZWZhdWx0KCksd2luZG93LnNjcm9sbFRvKHt0b3A6MH0pfSksdnMoZSx7dmlld3BvcnQkOnQsbWFpbiQ6byx0YXJnZXQkOm59KS5waXBlKHcocz0+aS5uZXh0KHMpKSxfKCgpPT5pLmNvbXBsZXRlKCkpLG0ocz0+JCh7cmVmOmV9LHMpKSl9ZnVuY3Rpb24gd2koe2RvY3VtZW50JDplLHZpZXdwb3J0JDp0fSl7ZS5waXBlKHYoKCk9PlAoIi5tZC1lbGxpcHNpcyIpKSxuZShyPT50dChyKS5waXBlKFcoZS5waXBlKENlKDEpKSksYihvPT5vKSxtKCgpPT5yKSxUZSgxKSkpLGIocj0+ci5vZmZzZXRXaWR0aDxyLnNjcm9sbFdpZHRoKSxuZShyPT57bGV0IG89ci5pbm5lclRleHQsbj1yLmNsb3Nlc3QoImEiKXx8cjtyZXR1cm4gbi50aXRsZT1vLEIoImNvbnRlbnQudG9vbHRpcHMiKT9tdChuLHt2aWV3cG9ydCQ6dH0pLnBpcGUoVyhlLnBpcGUoQ2UoMSkpKSxfKCgpPT5uLnJlbW92ZUF0dHJpYnV0ZSgidGl0bGUiKSkpOlN9KSkuc3Vic2NyaWJlKCksQigiY29udGVudC50b29sdGlwcyIpJiZlLnBpcGUodigoKT0+UCgiLm1kLXN0YXR1cyIpKSxuZShyPT5tdChyLHt2aWV3cG9ydCQ6dH0pKSkuc3Vic2NyaWJlKCl9ZnVuY3Rpb24gVGkoe2RvY3VtZW50JDplLHRhYmxldCQ6dH0pe2UucGlwZSh2KCgpPT5QKCIubWQtdG9nZ2xlLS1pbmRldGVybWluYXRlIikpLHcocj0+e3IuaW5kZXRlcm1pbmF0ZT0hMCxyLmNoZWNrZWQ9ITF9KSxuZShyPT5oKHIsImNoYW5nZSIpLnBpcGUoRHIoKCk9PnIuY2xhc3NMaXN0LmNvbnRhaW5zKCJtZC10b2dnbGUtLWluZGV0ZXJtaW5hdGUiKSksbSgoKT0+cikpKSxyZSh0KSkuc3Vic2NyaWJlKChbcixvXSk9PntyLmNsYXNzTGlzdC5yZW1vdmUoIm1kLXRvZ2dsZS0taW5kZXRlcm1pbmF0ZSIpLG8mJihyLmNoZWNrZWQ9ITEpfSl9ZnVuY3Rpb24gZ3MoKXtyZXR1cm4vKGlQYWR8aVBob25lfGlQb2QpLy50ZXN0KG5hdmlnYXRvci51c2VyQWdlbnQpfWZ1bmN0aW9uIFNpKHtkb2N1bWVudCQ6ZX0pe2UucGlwZSh2KCgpPT5QKCJbZGF0YS1tZC1zY3JvbGxmaXhdIikpLHcodD0+dC5yZW1vdmVBdHRyaWJ1dGUoImRhdGEtbWQtc2Nyb2xsZml4IikpLGIoZ3MpLG5lKHQ9PmgodCwidG91Y2hzdGFydCIpLnBpcGUobSgoKT0+dCkpKSkuc3Vic2NyaWJlKHQ9PntsZXQgcj10LnNjcm9sbFRvcDtyPT09MD90LnNjcm9sbFRvcD0xOnIrdC5vZmZzZXRIZWlnaHQ9PT10LnNjcm9sbEhlaWdodCYmKHQuc2Nyb2xsVG9wPXItMSl9KX1mdW5jdGlvbiBPaSh7dmlld3BvcnQkOmUsdGFibGV0JDp0fSl7eihbemUoInNlYXJjaCIpLHRdKS5waXBlKG0oKFtyLG9dKT0+ciYmIW8pLHYocj0+SShyKS5waXBlKEdlKHI/NDAwOjEwMCkpKSxyZShlKSkuc3Vic2NyaWJlKChbcix7b2Zmc2V0Ont5Om99fV0pPT57aWYocilkb2N1bWVudC5ib2R5LnNldEF0dHJpYnV0ZSgiZGF0YS1tZC1zY3JvbGxsb2NrIiwiIiksZG9jdW1lbnQuYm9keS5zdHlsZS50b3A9YC0ke299cHhgO2Vsc2V7bGV0IG49LTEqcGFyc2VJbnQoZG9jdW1lbnQuYm9keS5zdHlsZS50b3AsMTApO2RvY3VtZW50LmJvZHkucmVtb3ZlQXR0cmlidXRlKCJkYXRhLW1kLXNjcm9sbGxvY2siKSxkb2N1bWVudC5ib2R5LnN0eWxlLnRvcD0iIixuJiZ3aW5kb3cuc2Nyb2xsVG8oMCxuKX19KX1PYmplY3QuZW50cmllc3x8KE9iamVjdC5lbnRyaWVzPWZ1bmN0aW9uKGUpe2xldCB0PVtdO2ZvcihsZXQgciBvZiBPYmplY3Qua2V5cyhlKSl0LnB1c2goW3IsZVtyXV0pO3JldHVybiB0fSk7T2JqZWN0LnZhbHVlc3x8KE9iamVjdC52YWx1ZXM9ZnVuY3Rpb24oZSl7bGV0IHQ9W107Zm9yKGxldCByIG9mIE9iamVjdC5rZXlzKGUpKXQucHVzaChlW3JdKTtyZXR1cm4gdH0pO3R5cGVvZiBFbGVtZW50IT0idW5kZWZpbmVkIiYmKEVsZW1lbnQucHJvdG90eXBlLnNjcm9sbFRvfHwoRWxlbWVudC5wcm90b3R5cGUuc2Nyb2xsVG89ZnVuY3Rpb24oZSx0KXt0eXBlb2YgZT09Im9iamVjdCI/KHRoaXMuc2Nyb2xsTGVmdD1lLmxlZnQsdGhpcy5zY3JvbGxUb3A9ZS50b3ApOih0aGlzLnNjcm9sbExlZnQ9ZSx0aGlzLnNjcm9sbFRvcD10KX0pLEVsZW1lbnQucHJvdG90eXBlLnJlcGxhY2VXaXRofHwoRWxlbWVudC5wcm90b3R5cGUucmVwbGFjZVdpdGg9ZnVuY3Rpb24oLi4uZSl7bGV0IHQ9dGhpcy5wYXJlbnROb2RlO2lmKHQpe2UubGVuZ3RoPT09MCYmdC5yZW1vdmVDaGlsZCh0aGlzKTtmb3IobGV0IHI9ZS5sZW5ndGgtMTtyPj0wO3ItLSl7bGV0IG89ZVtyXTt0eXBlb2Ygbz09InN0cmluZyI/bz1kb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShvKTpvLnBhcmVudE5vZGUmJm8ucGFyZW50Tm9kZS5yZW1vdmVDaGlsZChvKSxyP3QuaW5zZXJ0QmVmb3JlKHRoaXMucHJldmlvdXNTaWJsaW5nLG8pOnQucmVwbGFjZUNoaWxkKG8sdGhpcyl9fX0pKTtmdW5jdGlvbiB5cygpe3JldHVybiBsb2NhdGlvbi5wcm90b2NvbD09PSJmaWxlOiI/VHQoYCR7bmV3IFVSTCgic2VhcmNoL3NlYXJjaF9pbmRleC5qcyIsZW8uYmFzZSl9YCkucGlwZShtKCgpPT5fX2luZGV4KSxHKDEpKTpqZShuZXcgVVJMKCJzZWFyY2gvc2VhcmNoX2luZGV4Lmpzb24iLGVvLmJhc2UpKX1kb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY2xhc3NMaXN0LnJlbW92ZSgibm8tanMiKTtkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY2xhc3NMaXN0LmFkZCgianMiKTt2YXIgb3Q9R28oKSxVdD1zbigpLEx0PWxuKFV0KSx0bz1hbigpLE9lPWduKCksaHI9UHQoIihtaW4td2lkdGg6IDk2MHB4KSIpLE1pPVB0KCIobWluLXdpZHRoOiAxMjIwcHgpIiksX2k9bW4oKSxlbz14ZSgpLEFpPWRvY3VtZW50LmZvcm1zLm5hbWVkSXRlbSgic2VhcmNoIik/eXMoKTpZZSxybz1uZXcgZztabih7YWxlcnQkOnJvfSk7dmFyIG9vPW5ldyBnO0IoIm5hdmlnYXRpb24uaW5zdGFudCIpJiZvaSh7bG9jYXRpb24kOlV0LHZpZXdwb3J0JDpPZSxwcm9ncmVzcyQ6b299KS5zdWJzY3JpYmUob3QpO3ZhciBMaTsoKExpPWVvLnZlcnNpb24pPT1udWxsP3ZvaWQgMDpMaS5wcm92aWRlcik9PT0ibWlrZSImJmNpKHtkb2N1bWVudCQ6b3R9KTtPKFV0LEx0KS5waXBlKEdlKDEyNSkpLnN1YnNjcmliZSgoKT0+e0plKCJkcmF3ZXIiLCExKSxKZSgic2VhcmNoIiwhMSl9KTt0by5waXBlKGIoKHttb2RlOmV9KT0+ZT09PSJnbG9iYWwiKSkuc3Vic2NyaWJlKGU9Pntzd2l0Y2goZS50eXBlKXtjYXNlInAiOmNhc2UiLCI6bGV0IHQ9ZmUoImxpbmtbcmVsPXByZXZdIik7dHlwZW9mIHQhPSJ1bmRlZmluZWQiJiZsdCh0KTticmVhaztjYXNlIm4iOmNhc2UiLiI6bGV0IHI9ZmUoImxpbmtbcmVsPW5leHRdIik7dHlwZW9mIHIhPSJ1bmRlZmluZWQiJiZsdChyKTticmVhaztjYXNlIkVudGVyIjpsZXQgbz1JZSgpO28gaW5zdGFuY2VvZiBIVE1MTGFiZWxFbGVtZW50JiZvLmNsaWNrKCl9fSk7d2koe3ZpZXdwb3J0JDpPZSxkb2N1bWVudCQ6b3R9KTtUaSh7ZG9jdW1lbnQkOm90LHRhYmxldCQ6aHJ9KTtTaSh7ZG9jdW1lbnQkOm90fSk7T2koe3ZpZXdwb3J0JDpPZSx0YWJsZXQkOmhyfSk7dmFyIHJ0PUtuKFNlKCJoZWFkZXIiKSx7dmlld3BvcnQkOk9lfSksRnQ9b3QucGlwZShtKCgpPT5TZSgibWFpbiIpKSx2KGU9PkduKGUse3ZpZXdwb3J0JDpPZSxoZWFkZXIkOnJ0fSkpLEcoMSkpLHhzPU8oLi4uYWUoImNvbnNlbnQiKS5tYXAoZT0+RW4oZSx7dGFyZ2V0JDpMdH0pKSwuLi5hZSgiZGlhbG9nIikubWFwKGU9PnFuKGUse2FsZXJ0JDpyb30pKSwuLi5hZSgicGFsZXR0ZSIpLm1hcChlPT5KbihlKSksLi4uYWUoInByb2dyZXNzIikubWFwKGU9PlhuKGUse3Byb2dyZXNzJDpvb30pKSwuLi5hZSgic2VhcmNoIikubWFwKGU9PnVpKGUse2luZGV4JDpBaSxrZXlib2FyZCQ6dG99KSksLi4uYWUoInNvdXJjZSIpLm1hcChlPT5naShlKSkpLEVzPUMoKCk9Pk8oLi4uYWUoImFubm91bmNlIikubWFwKGU9PnhuKGUpKSwuLi5hZSgiY29udGVudCIpLm1hcChlPT56bihlLHt2aWV3cG9ydCQ6T2UsdGFyZ2V0JDpMdCxwcmludCQ6X2l9KSksLi4uYWUoImNvbnRlbnQiKS5tYXAoZT0+Qigic2VhcmNoLmhpZ2hsaWdodCIpP2RpKGUse2luZGV4JDpBaSxsb2NhdGlvbiQ6VXR9KTpTKSwuLi5hZSgiaGVhZGVyIikubWFwKGU9PlluKGUse3ZpZXdwb3J0JDpPZSxoZWFkZXIkOnJ0LG1haW4kOkZ0fSkpLC4uLmFlKCJoZWFkZXItdGl0bGUiKS5tYXAoZT0+Qm4oZSx7dmlld3BvcnQkOk9lLGhlYWRlciQ6cnR9KSksLi4uYWUoInNpZGViYXIiKS5tYXAoZT0+ZS5nZXRBdHRyaWJ1dGUoImRhdGEtbWQtdHlwZSIpPT09Im5hdmlnYXRpb24iP05yKE1pLCgpPT5acihlLHt2aWV3cG9ydCQ6T2UsaGVhZGVyJDpydCxtYWluJDpGdH0pKTpOcihociwoKT0+WnIoZSx7dmlld3BvcnQkOk9lLGhlYWRlciQ6cnQsbWFpbiQ6RnR9KSkpLC4uLmFlKCJ0YWJzIikubWFwKGU9PnlpKGUse3ZpZXdwb3J0JDpPZSxoZWFkZXIkOnJ0fSkpLC4uLmFlKCJ0b2MiKS5tYXAoZT0+eGkoZSx7dmlld3BvcnQkOk9lLGhlYWRlciQ6cnQsbWFpbiQ6RnQsdGFyZ2V0JDpMdH0pKSwuLi5hZSgidG9wIikubWFwKGU9PkVpKGUse3ZpZXdwb3J0JDpPZSxoZWFkZXIkOnJ0LG1haW4kOkZ0LHRhcmdldCQ6THR9KSkpKSxDaT1vdC5waXBlKHYoKCk9PkVzKSxSZSh4cyksRygxKSk7Q2kuc3Vic2NyaWJlKCk7d2luZG93LmRvY3VtZW50JD1vdDt3aW5kb3cubG9jYXRpb24kPVV0O3dpbmRvdy50YXJnZXQkPUx0O3dpbmRvdy5rZXlib2FyZCQ9dG87d2luZG93LnZpZXdwb3J0JD1PZTt3aW5kb3cudGFibGV0JD1ocjt3aW5kb3cuc2NyZWVuJD1NaTt3aW5kb3cucHJpbnQkPV9pO3dpbmRvdy5hbGVydCQ9cm87d2luZG93LnByb2dyZXNzJD1vbzt3aW5kb3cuY29tcG9uZW50JD1DaTt9KSgpOwovLyMgc291cmNlTWFwcGluZ1VSTD1idW5kbGUuODNmNzNiNDMubWluLmpzLm1hcAoK"></script><!--URL:../assets/javascripts/bundle.83f73b43.min.js-->
<script src="data:text/javascript;base64,LyogCkphdmFzY3JpcHQgZnVuY3Rpb25zIHRvIGhlbHAgbWFrZSB0aGUgcHJpbnQgcGFnZSBtb3JlIFBERiBmcmllbmRseQoqLwoKLyoKR2VuZXJhdGVzIGEgdGFibGUgb2YgY29udGVudHMgZm9yIHRoZSBwcmludCBzaXRlIHBhZ2UuCk9ubHkgY2FsbGVkIHdoZW4gcHJpbnQtc2l0ZS1wbHVnaW4gb3B0aW9uICdhZGRfdGFibGVfb2ZfY29udGVudHMnIGlzIHNldCB0byB0cnVlCiovCmZ1bmN0aW9uIGdlbmVyYXRlX3RvYygpIHsKCiAgdmFyIFRvQyA9ICIiCgogIHZhciBuZXdMaW5lLCBlbCwgdGl0bGUsIGxpbms7CgogIGNvbnN0IHRvY19lbGVtZW50cyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoCiAgICAiI3ByaW50LXNpdGUtcGFnZSBoMS5uYXYtc2VjdGlvbi10aXRsZSwgI3ByaW50LXNpdGUtcGFnZSBoMS5uYXYtc2VjdGlvbi10aXRsZS1lbmQsIiArCiAgICAiI3ByaW50LXNpdGUtcGFnZSBoMi5uYXYtc2VjdGlvbi10aXRsZSwgI3ByaW50LXNpdGUtcGFnZSBoMi5uYXYtc2VjdGlvbi10aXRsZS1lbmQsIiArCiAgICAiI3ByaW50LXNpdGUtcGFnZSBoMy5uYXYtc2VjdGlvbi10aXRsZSwgI3ByaW50LXNpdGUtcGFnZSBoMy5uYXYtc2VjdGlvbi10aXRsZS1lbmQsIiArCiAgICAiI3ByaW50LXNpdGUtcGFnZSBoNC5uYXYtc2VjdGlvbi10aXRsZSwgI3ByaW50LXNpdGUtcGFnZSBoNC5uYXYtc2VjdGlvbi10aXRsZS1lbmQsIiArCiAgICAiI3ByaW50LXNpdGUtcGFnZSBoNS5uYXYtc2VjdGlvbi10aXRsZSwgI3ByaW50LXNpdGUtcGFnZSBoNS5uYXYtc2VjdGlvbi10aXRsZS1lbmQsIiArCiAgICAiI3ByaW50LXNpdGUtcGFnZSBoNi5uYXYtc2VjdGlvbi10aXRsZSwgI3ByaW50LXNpdGUtcGFnZSBoNi5uYXYtc2VjdGlvbi10aXRsZS1lbmQsIiArCiAgICAic2VjdGlvbi5wcmludC1wYWdlIGgxLHNlY3Rpb24ucHJpbnQtcGFnZSBoMixzZWN0aW9uLnByaW50LXBhZ2UgaDMsIiArCiAgICAic2VjdGlvbi5wcmludC1wYWdlIGg0LHNlY3Rpb24ucHJpbnQtcGFnZSBoNSxzZWN0aW9uLnByaW50LXBhZ2UgaDYiKQogIAogIHZhciBjdXJyZW50X2hlYWRpbmdfZGVwdGggPSAwOwogIHZhciBjdXJyZW50X3NlY3Rpb25fZGVwdGggPSAwOwoKICAvLyBFeHRyYWN0IHRhYmxlIG9mIGNvbnRlbnRzIGRlcHRoCiAgLy8gYmFzaWNhbGx5IHBsdWdpbiBzZXR0aW5nLCBwYXNzZWQgdmlhIGEgZGF0YSBhdHRyaWJ1dGUKICB2YXIgdG9jX2RlcHRoID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoInByaW50LXBhZ2UtdG9jIikuZ2V0QXR0cmlidXRlKCJkYXRhLXRvYy1kZXB0aCIpCgogIGZvciAodmFyIGkgPSAwOyBpIDwgdG9jX2VsZW1lbnRzLmxlbmd0aDsgaSsrKSB7CiAgICAKICAgIC8vIEdldCB0aGUgaW5mbyBmcm9tIHRoZSBlbGVtZW50CiAgICBlbCA9IHRvY19lbGVtZW50c1tpXQogICAgbGluayA9ICIjIiArIGVsLmlkOwogICAgdGFnID0gZWwudGFnTmFtZQogICAgdGFnX2xldmVsID0gdGFnLnN1YnN0cmluZygxKQogICAgLy8gR2V0IHRoZSB0ZXh0IG9mIGEgaGVhZGluZwogICAgLy8gV2UgdXNlIC5maXJzdENoaWxkLm5vZGVWYWx1ZSBpbnN0ZWFkIG9mIC5pbm5lclRleHQKICAgIC8vIGJlY2F1c2Ugb2YgZWxlbWVudHMgbGlrZToKICAgIC8vIDxoMSBpZD0iaW5kZXgtbWtkb2NzLXByaW50LXNpdGUtcGx1Z2luIj4KICAgIC8vICAgICBta2RvY3MtcHJpbnQtc2l0ZS1wbHVnaW48YSBjbGFzcz0iaGVhZGVybGluayIgaHJlZj0iI2luZGV4LW1rZG9jcy1wcmludC1zaXRlLXBsdWdpbiIgdGl0bGU9IlBlcm1hbmVudCBsaW5rIj7ihrU8L2E+CiAgICAvLyAgPC9oMT4KICAgIHRpdGxlID0gZWwuZmlyc3RDaGlsZC5ub2RlVmFsdWU7CiAgICBpZiAoICEgdGl0bGUgKSB7CiAgICAgIGNvbnRpbnVlOwogICAgfQoKICAgIC8vIERvbid0IHB1dCB0aGUgdG9jIGgxIGluIHRoZSB0b2MKICAgIGlmICggZWwuY2xhc3NMaXN0LmNvbnRhaW5zKCdwcmludC1wYWdlLXRvYy10aXRsZScpICkgewogICAgICBjb250aW51ZTsKICAgIH0KICAgIC8vIElnbm9yZSB0aGUgTWtEb2NzIGtleWJvYXJkIE1vZGVsCiAgICBpZiAoIGVsLmlkLmluZGV4T2YoImtleWJvYXJkTW9kYWxMYWJlbCIpID4gLTEgKSB7CiAgICAgIGNvbnRpbnVlOwogICAgfQoKICAgIC8vIHByaW50LXNpdGUtcGx1Z2luIGhhcyBhIHNldHRpbmcgdG8gY29udHJvbCBUT0MgZGVwdGgKICAgIGlmICggdGFnX2xldmVsID4gdG9jX2RlcHRoICkgewogICAgICBjb250aW51ZTsKICAgIH0KCiAgICBpZiAoZWwuY2xhc3NMaXN0LmNvbnRhaW5zKCduYXYtc2VjdGlvbi10aXRsZScpICkgewogICAgICAvLyBVc2UgdGhlIHRhZyBsZXZlbCBvZiB0aGUgZmlyc3QgaXRlbSBpbiB0aGUgc2VjdGlvbiB0byBjbG9zZSBvZmYgYW55IG5lc3RlZCA8dWw+CiAgICAgIGVsID0gdG9jX2VsZW1lbnRzW2krMV0KICAgICAgbGluayA9ICIjIiArIGVsLmlkOwogICAgICB0YWcgPSBlbC50YWdOYW1lCiAgICAgIHRhZ19sZXZlbCA9IHRhZy5zdWJzdHJpbmcoMSkKICAgICAgd2hpbGUgKHRhZ19sZXZlbCA+IGN1cnJlbnRfaGVhZGluZ19kZXB0aCkgewogICAgICAgIGN1cnJlbnRfaGVhZGluZ19kZXB0aCsrOwogICAgICAgIFRvQyArPSAiPHVsIGNsYXNzPSdwcmludC1zaXRlLXRvYy1sZXZlbC0iICsgY3VycmVudF9oZWFkaW5nX2RlcHRoICsgIic+IjsKICAgICAgfQogICAgICB3aGlsZSAodGFnX2xldmVsIDwgY3VycmVudF9oZWFkaW5nX2RlcHRoKSB7CiAgICAgICAgY3VycmVudF9oZWFkaW5nX2RlcHRoLS07CiAgICAgICAgVG9DICs9ICI8L3VsPiI7IAogICAgICB9CgogICAgICAvLyBJbnNlcnQgYSBzZWN0aW9uIGhlYWRpbmcgPGxpPiBpdGVtLCBob3dldmVyIGRlZXBseSB3ZSBhcmUgbmVzdGVkLgogICAgICBjdXJyZW50X3NlY3Rpb25fZGVwdGgrKzsKICAgICAgLy8gSW5zZXJ0IGl0ZW0gYXMgYSBzZWN0aW9uIHRpdGxlIGluIHRoZSBjdXJyZW50IGxpc3QKICAgICAgVG9DICs9ICI8bGkgY2xhc3M9J3RvYy1uYXYtc2VjdGlvbi10aXRsZSB0b2MtbmF2LXNlY3Rpb24tdGl0bGUtbGV2ZWwtIiArIChjdXJyZW50X3NlY3Rpb25fZGVwdGgpICsgIic+IiArIHRpdGxlICsgIjwvbGk+IjsKICAgICAgCiAgICAgIC8vIFN0YXJ0IGEgbmV3IHVsIGZvciB0aGUgc2VjdGlvbgogICAgICBUb0MgKz0gIjx1bCBjbGFzcz0ncHJpbnQtc2l0ZS10b2MtbGV2ZWwtIiArIGN1cnJlbnRfaGVhZGluZ19kZXB0aCArICIgdG9jLXNlY3Rpb24tbGluZS1ib3JkZXInPiI7CiAgICAgIGNvbnRpbnVlOwogICAgfQoKCiAgICBpZiAoZWwuY2xhc3NMaXN0LmNvbnRhaW5zKCduYXYtc2VjdGlvbi10aXRsZS1lbmQnKSApIHsKCiAgICAgIGN1cnJlbnRfc2VjdGlvbl9kZXB0aC0tOwogICAgICAvLyBDbG9zZSB0aGUgc3BlY2lhbCBzZWN0aW9uIHVsCiAgICAgIFRvQyArPSAiPC91bD4iOwoKICAgICAgY29udGludWU7CiAgICB9CgogICAgd2hpbGUgKHRhZ19sZXZlbCA+IGN1cnJlbnRfaGVhZGluZ19kZXB0aCkgewogICAgICBjdXJyZW50X2hlYWRpbmdfZGVwdGgrKzsKICAgICAgVG9DICs9ICI8dWwgY2xhc3M9J3ByaW50LXNpdGUtdG9jLWxldmVsLSIgKyBjdXJyZW50X2hlYWRpbmdfZGVwdGggKyAiJz4iOwogICAgfQogICAgd2hpbGUgKHRhZ19sZXZlbCA8IGN1cnJlbnRfaGVhZGluZ19kZXB0aCkgewogICAgICBjdXJyZW50X2hlYWRpbmdfZGVwdGgtLTsKICAgICAgVG9DICs9ICI8L3VsPiI7IAogICAgfQoKCiAgICBuZXdMaW5lID0gIjxsaT4iICsKICAgICAgIjxhIGhyZWY9JyIgKyBsaW5rICsgIic+IiArCiAgICAgICAgdGl0bGUgKwogICAgICAiPC9hPiIgKwogICAgIjwvbGk+IjsKCiAgICBUb0MgKz0gbmV3TGluZTsKCiAgfTsKCiAgVG9DICs9ICI8L3VsPiIKCiAgZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgiI3ByaW50LXBhZ2UtdG9jIG5hdiIpWzBdLmluc2VydEFkamFjZW50SFRNTCgiYmVmb3JlZW5kIiwgVG9DKTsKCn0="></script><!--URL:../js/print-site.js-->
</body></html><!--Generated by HTMLArk 2024-12-13 11:26:56.169245. Original URL public_html/print_page/index.html-->