mirror of
https://gitlab.easter-eggs.com/ee/ldapsaisie.git
synced 2024-11-16 07:23:01 +01:00
8396 lines
No EOL
942 KiB
HTML
8396 lines
No EOL
942 KiB
HTML
<!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 <brenard@easter-eggs.com / brenard@zionetrix.net>" name="author"/>
|
||
<link href="https://ldapsaisie.org/doc/print_page/" rel="canonical"/>
|
||
<link href="../assets/images/favicon.png" rel="icon"/>
|
||
<meta content="mkdocs-1.5.3, mkdocs-material-9.4.4" 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%207V5h4v2H2Z%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%206h7v2H2v-2Z%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%206h7v2H2v-2Z%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%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%40media%20%28hover%3Anone%29%7B.md-typeset%20abbr%5Btitle%5D%3Afocus%3Aafter%2C.md-typeset%20abbr%5Btitle%5D%3Ahover%3Aafter%7Bbackground-color%3Avar%28--md-default-fg-color%29%3Bborder-radius%3A.1rem%3Bbox-shadow%3Avar%28--md-shadow-z3%29%3Bcolor%3Avar%28--md-default-bg-color%29%3Bcontent%3Aattr%28title%29%3Bfont-size%3A.7rem%3Bleft%3A.8rem%3Bmargin-top%3A2em%3Bpadding%3A.2rem%20.3rem%3Bposition%3Aabsolute%3Bright%3A.8rem%7D%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%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%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-webkit-fit-content%3Bwidth%3A-moz-fit-content%3Bwidth%3Afit-content%7D.md-typeset%20figure%20img%7Bdisplay%3Ablock%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%7Bdisplay%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%7Bborder-radius%3A100%25%3Bdisplay%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%7Bfilter%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%202v14h2V3h12V1Z%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%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%7Balign-content%3Abaseline%3Bdisplay%3Aflex%3Bflex-wrap%3Awrap%3Bjustify-content%3Acenter%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.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%7D%5Bdir%3Drtl%5D%20.md-header__title%7Bmargin-right%3A1rem%7D%5Bdir%3Dltr%5D%20.md-header__title%7Bmargin-right%3A.4rem%7D%5Bdir%3Drtl%5D%20.md-header__title%7Bmargin-left%3A.4rem%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%2011h12Z%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%206-1.41-1.42Z%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%209h14V7H3v2m0%204h14v-2H3v2m0%204h14v-2H3v2m16%200h2v-2h-2v2m0-10v2h2V7h-2m0%206h2v-2h-2v2Z%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%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%3Achecked~.md-nav%2C.md-nav__toggle%3Aindeterminate~.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__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-nav__toggle%3Aindeterminate~.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%7Bmargin-left%3A-.6rem%7D%5Bdir%3Drtl%5D%20.md-nav--lifted%3E.md-nav__list%3E.md-nav__item%3E.md-nav%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.md-nav--integrated%3E.md-nav__list%3E.md-nav__item--active%3Anot%28.md-nav__item--nested%29%7Bpadding%3A0%20.6rem%7D.md-nav--integrated%3E.md-nav__list%3E.md-nav__item--active%3Anot%28.md-nav__item--nested%29%3E.md-nav__link%7Bpadding%3A0%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__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%7Bposition%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.82V8l-6-6m6.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%2022l-3.08-3.1m-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.5Z%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%200ZM5%203.25a.75.75%200%201%200-1.5%200%20.75.75%200%200%200%201.5%200Zm6.75.75a.75.75%200%201%200%200-1.5.75.75%200%200%200%200%201.5Zm-3%208.75a.75.75%200%201%200-1.5%200%20.75.75%200%200%200%201.5%200Z%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.495%202.495%200%200%201%202%2011.5Zm10.5-1h-8a1%201%200%200%200-1%201v6.708A2.486%202.486%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.249.249%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.25Zm0%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-.41L8%202.694Z%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.752%201.752%200%200%201%201%207.775Zm1.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-2Z%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%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-2v6Z%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.68L23%2012m-10%205h-2v-2h2v2m0-4h-2V7h2v6Z%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-5V3H9m0%205h2v9H9V8m4%200h2v9h-2V8Z%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-12V5l-9-4m0%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.3Z%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%204h-2M9.53%209l-1.06%206h6l1.06-6h-6Z%22/%3E%3C/svg%3E%27%29%7D.md-typeset%20.md-tags%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%202Z%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%202Z%22/%3E%3C/svg%3E%27%29%3B--md-tooltip-width%3A20rem%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.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-weight%3A400%3Boutline%3Anone%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%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.4.2%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%202023%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__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.06l6.06-6.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%201c-1.3%200-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-2Z%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%202Z%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.58.58%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.27Z%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.59%2021%207Z%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-10Z%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%202%201%2021Z%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%2012%2019%206.41Z%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.5V20M12%202c2.75%200%205.1%201%207.05%202.95C21%206.9%2022%209.25%2022%2012s-1%205.1-2.95%207.05C17.1%2021%2014.75%2022%2012%2022s-5.1-1-7.05-2.95C3%2017.1%202%2014.75%202%2012s1-5.1%202.95-7.05C6.9%203%209.25%202%2012%202Z%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-2v-1m10-8v6c0%205.5-3.8%2010.7-9%2012-5.2-1.3-9-6.5-9-12V5l9-4%209%204m-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-1h2v-1m-6%202h2v-1h-2v1Z%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-4V4h1V2H7m4%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-4V4h4v3Z%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-4V7H5v6h3l-2%204Z%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%2013H21V7h-2Z%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%7D.md-typeset%20div.arithmatex%3E%2A%7Bmargin-left%3Aauto%21important%3Bmargin-right%3Aauto%21important%3Bpadding%3A0%20.8rem%3Btouch-action%3Aauto%3Bwidth%3A-webkit-min-content%3Bwidth%3Amin-content%7D.md-typeset%20div.arithmatex%3E%2A%20mjx-container%7Bmargin%3A0%21important%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%206-1.41-1.42Z%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%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%7Bdisplay%3Ainline-flex%3Bheight%3A1.125em%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%3A1.125em%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%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%206%201.41-1.42Z%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%206-1.41-1.42Z%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-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%2012Zm16.28-2.72a.751.751%200%200%200-.018-1.042.751.751%200%200%200-1.042-.018l-5.97%205.97-2.47-2.47a.751.751%200%200%200-1.042.018.751.751%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%2012Zm16.28-2.72a.751.751%200%200%200-.018-1.042.751.751%200%200%200-1.042-.018l-5.97%205.97-2.47-2.47a.751.751%200%200%200-1.042.018.751.751%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%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%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.bd3936ea.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--light%3A%234287ff26%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.356b1318.min.css-->
|
||
<link crossorigin="" href="https://fonts.gstatic.com" rel="preconnect"/>
|
||
<link href="data:text/css; charset=utf-8;base64,QGZvbnQtZmFjZSB7CiAgZm9udC1mYW1pbHk6ICdSb2JvdG8nOwogIGZvbnQtc3R5bGU6IGl0YWxpYzsKICBmb250LXdlaWdodDogMzAwOwogIGZvbnQtZGlzcGxheTogZmFsbGJhY2s7CiAgc3JjOiB1cmwoaHR0cHM6Ly9mb250cy5nc3RhdGljLmNvbS9zL3JvYm90by92MzAvS0ZPakNucUV1OTJGcjFNdTUxVGpBU2M2Q3NFLnR0ZikgZm9ybWF0KCd0cnVldHlwZScpOwp9CkBmb250LWZhY2UgewogIGZvbnQtZmFtaWx5OiAnUm9ib3RvJzsKICBmb250LXN0eWxlOiBpdGFsaWM7CiAgZm9udC13ZWlnaHQ6IDQwMDsKICBmb250LWRpc3BsYXk6IGZhbGxiYWNrOwogIHNyYzogdXJsKGh0dHBzOi8vZm9udHMuZ3N0YXRpYy5jb20vcy9yb2JvdG8vdjMwL0tGT2tDbnFFdTkyRnIxTXU1MXhJSXpjLnR0ZikgZm9ybWF0KCd0cnVldHlwZScpOwp9CkBmb250LWZhY2UgewogIGZvbnQtZmFtaWx5OiAnUm9ib3RvJzsKICBmb250LXN0eWxlOiBpdGFsaWM7CiAgZm9udC13ZWlnaHQ6IDcwMDsKICBmb250LWRpc3BsYXk6IGZhbGxiYWNrOwogIHNyYzogdXJsKGh0dHBzOi8vZm9udHMuZ3N0YXRpYy5jb20vcy9yb2JvdG8vdjMwL0tGT2pDbnFFdTkyRnIxTXU1MVR6QmljNkNzRS50dGYpIGZvcm1hdCgndHJ1ZXR5cGUnKTsKfQpAZm9udC1mYWNlIHsKICBmb250LWZhbWlseTogJ1JvYm90byc7CiAgZm9udC1zdHlsZTogbm9ybWFsOwogIGZvbnQtd2VpZ2h0OiAzMDA7CiAgZm9udC1kaXNwbGF5OiBmYWxsYmFjazsKICBzcmM6IHVybChodHRwczovL2ZvbnRzLmdzdGF0aWMuY29tL3Mvcm9ib3RvL3YzMC9LRk9sQ25xRXU5MkZyMU1tU1U1ZkJCYzkudHRmKSBmb3JtYXQoJ3RydWV0eXBlJyk7Cn0KQGZvbnQtZmFjZSB7CiAgZm9udC1mYW1pbHk6ICdSb2JvdG8nOwogIGZvbnQtc3R5bGU6IG5vcm1hbDsKICBmb250LXdlaWdodDogNDAwOwogIGZvbnQtZGlzcGxheTogZmFsbGJhY2s7CiAgc3JjOiB1cmwoaHR0cHM6Ly9mb250cy5nc3RhdGljLmNvbS9zL3JvYm90by92MzAvS0ZPbUNucUV1OTJGcjFNdTRteFAudHRmKSBmb3JtYXQoJ3RydWV0eXBlJyk7Cn0KQGZvbnQtZmFjZSB7CiAgZm9udC1mYW1pbHk6ICdSb2JvdG8nOwogIGZvbnQtc3R5bGU6IG5vcm1hbDsKICBmb250LXdlaWdodDogNzAwOwogIGZvbnQtZGlzcGxheTogZmFsbGJhY2s7CiAgc3JjOiB1cmwoaHR0cHM6Ly9mb250cy5nc3RhdGljLmNvbS9zL3JvYm90by92MzAvS0ZPbENucUV1OTJGcjFNbVdVbGZCQmM5LnR0ZikgZm9ybWF0KCd0cnVldHlwZScpOwp9CkBmb250LWZhY2UgewogIGZvbnQtZmFtaWx5OiAnUm9ib3RvIE1vbm8nOwogIGZvbnQtc3R5bGU6IGl0YWxpYzsKICBmb250LXdlaWdodDogNDAwOwogIGZvbnQtZGlzcGxheTogZmFsbGJhY2s7CiAgc3JjOiB1cmwoaHR0cHM6Ly9mb250cy5nc3RhdGljLmNvbS9zL3JvYm90b21vbm8vdjIzL0wweG9ERjR4bFZNRi1CZlI4YlhNSWpoT3NYRy1xMm9ldUZvcUZybG5BTlc2Q3B3LnR0ZikgZm9ybWF0KCd0cnVldHlwZScpOwp9CkBmb250LWZhY2UgewogIGZvbnQtZmFtaWx5OiAnUm9ib3RvIE1vbm8nOwogIGZvbnQtc3R5bGU6IGl0YWxpYzsKICBmb250LXdlaWdodDogNzAwOwogIGZvbnQtZGlzcGxheTogZmFsbGJhY2s7CiAgc3JjOiB1cmwoaHR0cHM6Ly9mb250cy5nc3RhdGljLmNvbS9zL3JvYm90b21vbm8vdjIzL0wweG9ERjR4bFZNRi1CZlI4YlhNSWpoT3NYRy1xMm9ldUZvcUZybUFCOVc2Q3B3LnR0ZikgZm9ybWF0KCd0cnVldHlwZScpOwp9CkBmb250LWZhY2UgewogIGZvbnQtZmFtaWx5OiAnUm9ib3RvIE1vbm8nOwogIGZvbnQtc3R5bGU6IG5vcm1hbDsKICBmb250LXdlaWdodDogNDAwOwogIGZvbnQtZGlzcGxheTogZmFsbGJhY2s7CiAgc3JjOiB1cmwoaHR0cHM6Ly9mb250cy5nc3RhdGljLmNvbS9zL3JvYm90b21vbm8vdjIzL0wweHVERjR4bFZNRi1CZlI4YlhNSWhKSGc0NW13Z0dFRmwwXzN2cV9ST1c5LnR0ZikgZm9ybWF0KCd0cnVldHlwZScpOwp9CkBmb250LWZhY2UgewogIGZvbnQtZmFtaWx5OiAnUm9ib3RvIE1vbm8nOwogIGZvbnQtc3R5bGU6IG5vcm1hbDsKICBmb250LXdlaWdodDogNzAwOwogIGZvbnQtZGlzcGxheTogZmFsbGJhY2s7CiAgc3JjOiB1cmwoaHR0cHM6Ly9mb250cy5nc3RhdGljLmNvbS9zL3JvYm90b21vbm8vdjIzL0wweHVERjR4bFZNRi1CZlI4YlhNSWhKSGc0NW13Z0dFRmwwX09mMl9ST1c5LnR0ZikgZm9ybWF0KCd0cnVldHlwZScpOwp9Cg==" 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 6h18v2H3V6m0 5h18v2H3v-2m0 5h18v2H3v-2Z"></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>La librairie <a href="https://pear.php.net/package/Net_FTP">Net_FTP</a> (nécessaire pour le fonctionnement du
|
||
<a href="#conf-configuration-des-lsaddons">LSaddon</a> FTP, paquet <code>php-console-table</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-console-table</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 & 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 d’une 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 l’application 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 d’une installation par à partir des sources, le script <code>upgradeFromGit.sh</code> permet d’automatiser
|
||
la mise à jour, à condition que vous ayez suivi la procédure d’installation à ce sujet.</p>
|
||
<p>Ce script s’occupera 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 d’une 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 l’application, le script vous notifiera en cas de changement intervenu dans le fichier
|
||
fourni avec l’application 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 l’application 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 -> 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' => 'LSpeople',
|
||
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a>'authObjectFilter' => '(|(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' => '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' => array (
|
||
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-1-2" id="__codelineno-1-2" name="__codelineno-1-2"></a> 'LSobjects' => array(
|
||
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-1-3" id="__codelineno-1-3" name="__codelineno-1-3"></a> 'LSpeople' => array(
|
||
<a href="#upgrade-2_4_1-to-3_0_0-__codelineno-1-4" id="__codelineno-1-4" name="__codelineno-1-4"></a> 'filter' => '(|(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' => '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> : L’utilisation 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 d’identifier la source des logs. Ce mécanisme
|
||
permet la configuration d’un 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 à
|
||
l’inverse en exclure d’autres.</p>
|
||
<ul>
|
||
<li>Pour vos classes personnalisées : si celles-ci héritent d’une classe standard, il est fort
|
||
probable qu’il soit possible d’utiliser 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 d’utiliser la classe <code>LSlog_staticLoggerClass</code> qui facilite l’implémentation.</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p>Pour vos <a href="#conf-configuration-des-lsaddons">LSaddons</a> : il est conseillé d’utiliser 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 d’appeler 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]") -> 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 l’inclusion 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, l’entê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"><</span><span class="nt">html</span><span class="p">></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"><</span><span class="nt">head</span><span class="p">></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"></</span><span class="nt">head</span><span class="p">></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"><</span><span class="nt">body</span><span class="p">></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"></</span><span class="nt">body</span><span class="p">></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"></</span><span class="nt">html</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-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> <link rel="stylesheet" type="text/css" href="{css name='custom.css'}" media="screen" title="Normal" />
|
||
<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>d’ajouter des infos dans <code><head></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>d’ajouter 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 l’application 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">&&</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&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&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&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&dn=$dn</code> devient <code>object/LSpeople/$dn/remove</code></p>
|
||
<p>Avec validation : <code>remove.php?LSobject=LSpeople&dn=$dn&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&dn=$dn&customAction=$customAction</code>
|
||
devient <code>object/LSpeople/$dn/customAction/$customAction</code></p>
|
||
<p>Avec validation :
|
||
<code>custom_action.php?LSobject=LSpeople&dn=$dn&customAction=$customAction&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&customAction=$customAction</code>
|
||
devient <code>object/LSpeople/customAction/$customAction</code></p>
|
||
<p>Avec validation :
|
||
<code>custom_search_action.php?LSobject=LSpeople&customAction=$customAction&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' => 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' => [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'=> 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' => [boolean],</span>
|
||
<a href="#conf-global-ldap-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a><span class="x"> 'useAuthzProxyControl' => [boolean],</span>
|
||
<a href="#conf-global-ldap-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a><span class="x"> 'LSauth' => array (</span>
|
||
<a href="#conf-global-ldap-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a><span class="x"> 'method' => [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' => [LSauth method],</span>
|
||
<a href="#conf-global-ldap-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a><span class="x"> 'LSobjects' => 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]' => array(</span>
|
||
<a href="#conf-global-ldap-__codelineno-0-17" id="__codelineno-0-17" name="__codelineno-0-17"></a><span class="x"> 'filter' => '[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' => [callable],</span>
|
||
<a href="#conf-global-ldap-__codelineno-0-19" id="__codelineno-0-19" name="__codelineno-0-19"></a><span class="x"> 'password_attribute' => '[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' => [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' => [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' => 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' => [boolean],</span>
|
||
<a href="#conf-global-ldap-__codelineno-0-29" id="__codelineno-0-29" name="__codelineno-0-29"></a><span class="x"> 'cacheSearch' => [boolean],</span>
|
||
<a href="#conf-global-ldap-__codelineno-0-30" id="__codelineno-0-30" name="__codelineno-0-30"></a><span class="x"> 'globalSearch' => [boolean],</span>
|
||
<a href="#conf-global-ldap-__codelineno-0-31" id="__codelineno-0-31" name="__codelineno-0-31"></a><span class="x"> 'LSaccess' => 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' => 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' => [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' => 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' => [view],</span>
|
||
<a href="#conf-global-ldap-__codelineno-0-44" id="__codelineno-0-44" name="__codelineno-0-44"></a><span class="x"> 'emailSender' => [email],</span>
|
||
<a href="#conf-global-ldap-__codelineno-0-45" id="__codelineno-0-45" name="__codelineno-0-45"></a><span class="x"> 'keepLSsessionActive' => [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' => array (
|
||
<a href="#conf-global-ldap-lsprofile-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> [nom d'un LSprofile] => array (
|
||
<a href="#conf-global-ldap-lsprofile-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> [label] => [label du LSprofile],
|
||
<a href="#conf-global-ldap-lsprofile-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> [basedn] => [dn utilisateur],
|
||
<a href="#conf-global-ldap-lsprofile-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a> [autre basedn] => array (
|
||
<a href="#conf-global-ldap-lsprofile-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a> [dn d'un utilisateur] => NULL,
|
||
<a href="#conf-global-ldap-lsprofile-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a> [autre dn] => 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' => [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' => [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' => [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' => 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] => array (
|
||
<a href="#conf-global-ldap-lsprofile-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a> 'attr' => [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' => [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' => [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' => [basedn de recherche],
|
||
<a href="#conf-global-ldap-lsprofile-__codelineno-0-21" id="__codelineno-0-21" name="__codelineno-0-21"></a> 'params' => [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] => array (
|
||
<a href="#conf-global-ldap-lsprofile-__codelineno-0-24" id="__codelineno-0-24" name="__codelineno-0-24"></a> 'filters' => 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' => [nom du LSobject],
|
||
<a href="#conf-global-ldap-lsprofile-__codelineno-0-27" id="__codelineno-0-27" name="__codelineno-0-27"></a> 'attr' => [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' => [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' => [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' => [basedn de recherche],
|
||
<a href="#conf-global-ldap-lsprofile-__codelineno-0-33" id="__codelineno-0-33" name="__codelineno-0-33"></a> 'params' => [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' => array (
|
||
<a href="#conf-global-ldap-lsprofile-__codelineno-1-2" id="__codelineno-1-2" name="__codelineno-1-2"></a> [nom du LSprofile] => array (
|
||
<a href="#conf-global-ldap-lsprofile-__codelineno-1-3" id="__codelineno-1-3" name="__codelineno-1-3"></a> [basedn] => [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] => array (
|
||
<a href="#conf-global-ldap-lsprofile-__codelineno-1-6" id="__codelineno-1-6" name="__codelineno-1-6"></a> [dn d'un utilisateur] => NULL,
|
||
<a href="#conf-global-ldap-lsprofile-__codelineno-1-7" id="__codelineno-1-7" name="__codelineno-1-7"></a> [dn d'un utilisateur 2] => 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' => array (
|
||
<a href="#conf-global-ldap-lsprofile-__codelineno-2-2" id="__codelineno-2-2" name="__codelineno-2-2"></a> [nom du LSprofile] => array (
|
||
<a href="#conf-global-ldap-lsprofile-__codelineno-2-3" id="__codelineno-2-3" name="__codelineno-2-3"></a> [basedn] => array (
|
||
<a href="#conf-global-ldap-lsprofile-__codelineno-2-4" id="__codelineno-2-4" name="__codelineno-2-4"></a> [DN d'un object] => array (
|
||
<a href="#conf-global-ldap-lsprofile-__codelineno-2-5" id="__codelineno-2-5" name="__codelineno-2-5"></a> 'attr' => [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' => [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' => [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' => array (
|
||
<a href="#conf-global-ldap-lsprofile-__codelineno-3-2" id="__codelineno-3-2" name="__codelineno-3-2"></a> [nom d'un LSprofile] => array (
|
||
<a href="#conf-global-ldap-lsprofile-__codelineno-3-3" id="__codelineno-3-3" name="__codelineno-3-3"></a> 'LSobjects' => 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] => array (
|
||
<a href="#conf-global-ldap-lsprofile-__codelineno-3-6" id="__codelineno-3-6" name="__codelineno-3-6"></a> 'attr' => [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' => [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' => [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' => [format du basedn de recherche],
|
||
<a href="#conf-global-ldap-lsprofile-__codelineno-3-12" id="__codelineno-3-12" name="__codelineno-3-12"></a> 'params' => [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' => 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' => [nom du LSobject],
|
||
<a href="#conf-global-ldap-lsprofile-__codelineno-3-18" id="__codelineno-3-18" name="__codelineno-3-18"></a> 'attr' => [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' => [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' => [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' => [format du basedn de recherche],
|
||
<a href="#conf-global-ldap-lsprofile-__codelineno-3-24" id="__codelineno-3-24" name="__codelineno-3-24"></a> 'params' => [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' => 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]' => array(
|
||
<a href="#conf-global-ldap-subdn-__codelineno-1-4" id="__codelineno-1-4" name="__codelineno-1-4"></a> 'dn' => '[basedn du sous-niveau]',
|
||
<a href="#conf-global-ldap-subdn-__codelineno-1-5" id="__codelineno-1-5" name="__codelineno-1-5"></a> 'nologin' => 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' => 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' => array(
|
||
<a href="#conf-global-ldap-subdn-__codelineno-1-14" id="__codelineno-1-14" name="__codelineno-1-14"></a> '[type d'LSobject]' => 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' => '[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' => '[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' => 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' => 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' => 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' => array(
|
||
<a href="#conf-global-ldap-recoverpassword-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'mailAttr' => '[attribut mail]',
|
||
<a href="#conf-global-ldap-recoverpassword-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> 'recoveryHashAttr' => '[attribut hash]',
|
||
<a href="#conf-global-ldap-recoverpassword-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> 'recoveryEmailSender' => '[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' => 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' => '[sujet du mail]',
|
||
<a href="#conf-global-ldap-recoverpassword-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a> 'msg' => "[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' => 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' => '[sujet du mail]',
|
||
<a href="#conf-global-ldap-recoverpassword-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a> 'msg' => "[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' => [booléen],</span>
|
||
<a href="#conf-global-lslog-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a><span class="x"> 'level' => '[niveau]',</span>
|
||
<a href="#conf-global-lslog-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a><span class="x"> 'handlers' => array(</span>
|
||
<a href="#conf-global-lslog-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a><span class="x"> '[handler 1]',</span>
|
||
<a href="#conf-global-lslog-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a><span class="x"> array (</span>
|
||
<a href="#conf-global-lslog-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a><span class="x"> 'handler' => [handler 2],</span>
|
||
<a href="#conf-global-lslog-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a><span class="x"> 'enabled' => [booléen],</span>
|
||
<a href="#conf-global-lslog-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a><span class="x"> 'level' => '[niveau]',</span>
|
||
<a href="#conf-global-lslog-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a><span class="x"> 'loggers' => array('logger1', [...]),</span>
|
||
<a href="#conf-global-lslog-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a><span class="x"> 'excluded_loggers' => array('logger2', [...]),</span>
|
||
<a href="#conf-global-lslog-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a><span class="x"> 'format' => '[LSformat]',</span>
|
||
<a href="#conf-global-lslog-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a><span class="x"> 'cli_format' => '[LSformat]',</span>
|
||
<a href="#conf-global-lslog-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a><span class="x"> 'datetime_prefix' => [booléen],</span>
|
||
<a href="#conf-global-lslog-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a><span class="x"> 'datetime_format' => '[format date()]',</span>
|
||
<a href="#conf-global-lslog-__codelineno-0-16" id="__codelineno-0-16" name="__codelineno-0-16"></a><span class="x"> // Autres paramètres propre à ce handler</span>
|
||
<a href="#conf-global-lslog-__codelineno-0-17" id="__codelineno-0-17" name="__codelineno-0-17"></a><span class="x"> [...]</span>
|
||
<a href="#conf-global-lslog-__codelineno-0-18" id="__codelineno-0-18" name="__codelineno-0-18"></a><span class="x"> ),</span>
|
||
<a href="#conf-global-lslog-__codelineno-0-19" id="__codelineno-0-19" name="__codelineno-0-19"></a><span class="x"> [...]</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"> 'loggers' => array (</span>
|
||
<a href="#conf-global-lslog-__codelineno-0-22" id="__codelineno-0-22" name="__codelineno-0-22"></a><span class="x"> 'logger1' => array (</span>
|
||
<a href="#conf-global-lslog-__codelineno-0-23" id="__codelineno-0-23" name="__codelineno-0-23"></a><span class="x"> 'level' => 'DEBUG',</span>
|
||
<a href="#conf-global-lslog-__codelineno-0-24" id="__codelineno-0-24" name="__codelineno-0-24"></a><span class="x"> ),</span>
|
||
<a href="#conf-global-lslog-__codelineno-0-25" id="__codelineno-0-25" name="__codelineno-0-25"></a><span class="x"> 'logger2' => array (</span>
|
||
<a href="#conf-global-lslog-__codelineno-0-26" id="__codelineno-0-26" name="__codelineno-0-26"></a><span class="x"> 'enabled' => false,</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"> [...]</span>
|
||
<a href="#conf-global-lslog-__codelineno-0-29" id="__codelineno-0-29" name="__codelineno-0-29"></a><span class="x"> );</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>
|
||
</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>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' => [type],</span>
|
||
<a href="#conf-global-lslog-__codelineno-1-3" id="__codelineno-1-3" name="__codelineno-1-3"></a><span class="x"> 'level' => '[niveau]',</span>
|
||
<a href="#conf-global-lslog-__codelineno-1-4" id="__codelineno-1-4" name="__codelineno-1-4"></a><span class="x"> 'loggers' => 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' => array('logger2', [...]),</span>
|
||
<a href="#conf-global-lslog-__codelineno-1-6" id="__codelineno-1-6" name="__codelineno-1-6"></a><span class="x"> 'format' => '[LSformat]',</span>
|
||
<a href="#conf-global-lslog-__codelineno-1-7" id="__codelineno-1-7" name="__codelineno-1-7"></a><span class="x"> 'cli_format' => '[LSformat]',</span>
|
||
<a href="#conf-global-lslog-__codelineno-1-8" id="__codelineno-1-8" name="__codelineno-1-8"></a><span class="x"> 'datetime_prefix' => [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' => '[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' => 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' => '[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' => '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' => [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' => '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' => '[callable]',</span>
|
||
<a href="#conf-lsobject-__codelineno-1-15" id="__codelineno-1-15" name="__codelineno-1-15"></a><span class="x"> 'container_auto_create' => 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' => [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' => 'function1',</span>
|
||
<a href="#conf-lsobject-__codelineno-1-23" id="__codelineno-1-23" name="__codelineno-1-23"></a><span class="x"> 'after_modify' => 'function2',</span>
|
||
<a href="#conf-lsobject-__codelineno-1-24" id="__codelineno-1-24" name="__codelineno-1-24"></a><span class="x"> 'after_create' => 'function3',</span>
|
||
<a href="#conf-lsobject-__codelineno-1-25" id="__codelineno-1-25" name="__codelineno-1-25"></a><span class="x"> 'after_delete' => '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' => 'objet1',</span>
|
||
<a href="#conf-lsobject-__codelineno-1-28" id="__codelineno-1-28" name="__codelineno-1-28"></a><span class="x"> 'display_name_format' => '[format]',</span>
|
||
<a href="#conf-lsobject-__codelineno-1-29" id="__codelineno-1-29" name="__codelineno-1-29"></a><span class="x"> 'displayAttrName' => '[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' => 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' => 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' => 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' => 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' => [booleen],</span>
|
||
<a href="#conf-lsobject-__codelineno-1-52" id="__codelineno-1-52" name="__codelineno-1-52"></a><span class="x"> 'globalSearch_extraDisplayedColumns' => [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' => 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' => 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' => 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' => array (
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> 'label' => '[label de l'attr1',
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a> 'displayAttrName' => '[booleen]',
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a> 'help_info' => '[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' => '[booleen]',
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a> 'ldap_type' => 'ldaptype1',
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a> 'ldap_options' => 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' => 'htmltype1',
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a> 'html_options' => 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' => '[No set value label]',
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-17" id="__codelineno-0-17" name="__codelineno-0-17"></a> 'multiple' => 0,
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-18" id="__codelineno-0-18" name="__codelineno-0-18"></a> 'required' => 1,
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-19" id="__codelineno-0-19" name="__codelineno-0-19"></a> 'generate_function' => 'fonction1',
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-20" id="__codelineno-0-20" name="__codelineno-0-20"></a> 'generate_value_format' => '[LSformat]',
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-21" id="__codelineno-0-21" name="__codelineno-0-21"></a> 'default_value' => 'valeur1',
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-22" id="__codelineno-0-22" name="__codelineno-0-22"></a> 'check_data' => array (
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-23" id="__codelineno-0-23" name="__codelineno-0-23"></a> // Régle de vérification syntaxique des données saisies
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-24" id="__codelineno-0-24" name="__codelineno-0-24"></a> ),
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-25" id="__codelineno-0-25" name="__codelineno-0-25"></a> 'validation' => array (
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-26" id="__codelineno-0-26" name="__codelineno-0-26"></a> // Règle de vérification d'intégrité des données saisies
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-27" id="__codelineno-0-27" name="__codelineno-0-27"></a> ),
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-28" id="__codelineno-0-28" name="__codelineno-0-28"></a> 'rights' => array(
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-29" id="__codelineno-0-29" name="__codelineno-0-29"></a> 'LSprofile1' => 'droit1',
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-30" id="__codelineno-0-30" name="__codelineno-0-30"></a> 'LSprofile2' => 'droit2',
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-31" id="__codelineno-0-31" name="__codelineno-0-31"></a> ...
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-32" id="__codelineno-0-32" name="__codelineno-0-32"></a> ),
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-33" id="__codelineno-0-33" name="__codelineno-0-33"></a> 'view' => 1,
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-34" id="__codelineno-0-34" name="__codelineno-0-34"></a> 'form' => array (
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-35" id="__codelineno-0-35" name="__codelineno-0-35"></a> 'create' => 1,
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-36" id="__codelineno-0-36" name="__codelineno-0-36"></a> 'modify' => 0,
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-37" id="__codelineno-0-37" name="__codelineno-0-37"></a> ...
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-38" id="__codelineno-0-38" name="__codelineno-0-38"></a> ),
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-39" id="__codelineno-0-39" name="__codelineno-0-39"></a> 'dependAttrs' => array(
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-40" id="__codelineno-0-40" name="__codelineno-0-40"></a> // Attributs en dépendance
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-41" id="__codelineno-0-41" name="__codelineno-0-41"></a> ),
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-42" id="__codelineno-0-42" name="__codelineno-0-42"></a> 'onDisplay' => 'fonction2'
|
||
<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> 'before_modify' => 'function1',
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-45" id="__codelineno-0-45" name="__codelineno-0-45"></a> 'after_modify' => 'function2'
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-46" id="__codelineno-0-46" name="__codelineno-0-46"></a> ),
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-47" id="__codelineno-0-47" name="__codelineno-0-47"></a> /* ----------- end -----------*/
|
||
<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>);
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-50" id="__codelineno-0-50" name="__codelineno-0-50"></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>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' => 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' => '[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' => '[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' => array (
|
||
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_date-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'timestamp' => [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' => 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" & "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' => '[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' => array (
|
||
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_naivedate-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'format' => '[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' => array (
|
||
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_password-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'encode' => '[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' => '[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' => '[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' => '[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' => '[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' => '[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 >= 7.2)</li>
|
||
<li><code>argon2id</code> (PHP >= 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' => array (
|
||
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-2" id="__codelineno-2-2" name="__codelineno-2-2"></a> 'label' => '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' => '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' => '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' => array (
|
||
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-6" id="__codelineno-2-6" name="__codelineno-2-6"></a> 'components' => array (
|
||
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-7" id="__codelineno-2-7" name="__codelineno-2-7"></a> 'time' => array (
|
||
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-8" id="__codelineno-2-8" name="__codelineno-2-8"></a> 'label' => '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' => 'text',
|
||
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-10" id="__codelineno-2-10" name="__codelineno-2-10"></a> 'required' => true,
|
||
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-11" id="__codelineno-2-11" name="__codelineno-2-11"></a> 'multiple' => 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' => array (
|
||
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-14" id="__codelineno-2-14" name="__codelineno-2-14"></a> 'label' => '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' => 'text',
|
||
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-16" id="__codelineno-2-16" name="__codelineno-2-16"></a> 'required' => true,
|
||
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-17" id="__codelineno-2-17" name="__codelineno-2-17"></a> 'multiple' => 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' => array (
|
||
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-20" id="__codelineno-2-20" name="__codelineno-2-20"></a> 'label' => 'Length',
|
||
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-21" id="__codelineno-2-21" name="__codelineno-2-21"></a> 'type' => 'text',
|
||
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-22" id="__codelineno-2-22" name="__codelineno-2-22"></a> 'required' => true,
|
||
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-23" id="__codelineno-2-23" name="__codelineno-2-23"></a> 'multiple' => 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' => array (
|
||
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-26" id="__codelineno-2-26" name="__codelineno-2-26"></a> 'label' => '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' => 'text',
|
||
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-28" id="__codelineno-2-28" name="__codelineno-2-28"></a> 'required' => true,
|
||
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-29" id="__codelineno-2-29" name="__codelineno-2-29"></a> 'multiple' => 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' => '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' => 1,
|
||
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-35" id="__codelineno-2-35" name="__codelineno-2-35"></a> 'rights' => array(
|
||
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_pwdhistory-__codelineno-2-36" id="__codelineno-2-36" name="__codelineno-2-36"></a> 'admin' => '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' => 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' => 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' => '[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' => '[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' => array (
|
||
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_date-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'format' => '[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' => '[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' => '[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' => '[Booleen]',
|
||
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_date-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a> 'showTodayButton' => '[Booleen]',
|
||
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_date-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a> 'style' => '[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' => array (
|
||
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_date-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a> '[value]' => '[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_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' => array (
|
||
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-1-2" id="__codelineno-1-2" name="__codelineno-1-2"></a> 'components' => 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]' => array (
|
||
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-1-4" id="__codelineno-1-4" name="__codelineno-1-4"></a> 'label' => '[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' => '[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' => '[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' => [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' => [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' => => 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]' => array (
|
||
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-1-14" id="__codelineno-1-14" name="__codelineno-1-14"></a> 'label' => '[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' => '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' => [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' => 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' => [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' => array(
|
||
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_labeledvalue-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'labels' => 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' => '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' => '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' => [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' => array(
|
||
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_mail-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'disableMailSending' => [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' => array (
|
||
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_maildir-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'LSform' => array (
|
||
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_maildir-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> '[LSform1]' => [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]' => [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' => "[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' => "[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' => array(
|
||
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_mailquota-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'suffix' => '[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' => array(
|
||
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'isLoginPassword' => [booleen],
|
||
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> 'generationTool' => [booleen],
|
||
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> 'autoGenerate' => [booleen],
|
||
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_password-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a> 'length' => [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' => 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' => [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' => '[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' => [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' => "/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' => "[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' => [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' => [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' => [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' => "[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' => 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' => "[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' => "[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' => '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' => '[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' => 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' => 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' => 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' => 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' => '[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' => 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' => '[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' => '[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' => '[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' => 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' => 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' => [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' => 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' => 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é]' => '[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' => 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' => '[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' => '[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' => '[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' => '[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' => '[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' => '[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' => '[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' => '[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' => '[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' => 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]' => '[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]' => '[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' => 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' => [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' => '[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' => '[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' => '[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' => 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é]' => '[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' => 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' => [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' => [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' => [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' => '[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>&$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' => 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 => 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' => '[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' => '[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' => '[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' => '[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' => '[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' => [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' => [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' => '[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' => 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' => '[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' => [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' => [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' => [booleen],
|
||
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a> 'replaceSpaces' => "[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' => [booleen],
|
||
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a> 'lowerCase' => [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' => 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' => '[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' => 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' => '[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' => '[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' => '[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' => '[LSformat]',
|
||
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-__codelineno-0-22" id="__codelineno-0-22" name="__codelineno-0-22"></a> 'onlyAccessible' => [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' => array(
|
||
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_valuewithunit-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> 'units' => array (
|
||
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_valuewithunit-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> '[facteur1]' => '[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]' => '[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' => [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' => [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' => '[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' => '[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' => [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' => [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 => Octet, 1024 => 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' => 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' => 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' => array (
|
||
<a href="#conf-lsobject-lsattribute-check_data-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a> '[regle1]' => array(
|
||
<a href="#conf-lsobject-lsattribute-check_data-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> 'msg' => "[Message d'erreur]",
|
||
<a href="#conf-lsobject-lsattribute-check_data-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> 'params' => 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-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>( ) . \ / \ * \ ^ \ ? # ! @ $ % + = , " ' > < ~ [ ] { }</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://github.com/bjeavons/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 cimpris 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>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>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>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' => 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' => "[LSformat du message d'erreur]",
|
||
<a href="#conf-lsobject-lsattribute-validation-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a> 'filter' => '[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' => '[Type d'LSobject recherché]',
|
||
<a href="#conf-lsobject-lsattribute-validation-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a> 'basedn' => '[BaseDn de la recherche]',
|
||
<a href="#conf-lsobject-lsattribute-validation-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a> 'scope' => '[Scope de la recherche]',
|
||
<a href="#conf-lsobject-lsattribute-validation-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a> 'result' => '[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' => '[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' => 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' => "[LSformat du message d'erreur]",
|
||
<a href="#conf-lsobject-lsattribute-validation-__codelineno-1-5" id="__codelineno-1-5" name="__codelineno-1-5"></a> 'function' => '[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' => 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' => array(
|
||
<a href="#conf-lsobject-container_auto_create-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a> 'attr1' => 'val1',
|
||
<a href="#conf-lsobject-container_auto_create-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a> 'attr2' => 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' => array(
|
||
<a href="#conf-lsobject-customactions-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> 'label' => '[label l'action]',
|
||
<a href="#conf-lsobject-customactions-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> 'hideLabel' => '[booléen]',
|
||
<a href="#conf-lsobject-customactions-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a> 'helpInfo' => '[label d'aide]',
|
||
<a href="#conf-lsobject-customactions-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a> 'icon' => '[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' => '[fonction à exécuter]',
|
||
<a href="#conf-lsobject-customactions-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a> 'question_format' => '[LSformat de la question de confirmation]',
|
||
<a href="#conf-lsobject-customactions-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a> 'onSuccessMsgFormat' => '[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' => '[booléen]',
|
||
<a href="#conf-lsobject-customactions-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a> 'noConfirmation' => '[booléen]',
|
||
<a href="#conf-lsobject-customactions-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a> 'redirectToObjectList' => '[booléen]',
|
||
<a href="#conf-lsobject-customactions-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a> 'noRedirect' => '[booléen]',
|
||
<a href="#conf-lsobject-customactions-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a> 'rights' => array(
|
||
<a href="#conf-lsobject-customactions-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a> 'LSprofile1',
|
||
<a href="#conf-lsobject-customactions-__codelineno-0-16" id="__codelineno-0-16" name="__codelineno-0-16"></a> 'LSprofile2',
|
||
<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> )
|
||
<a href="#conf-lsobject-customactions-__codelineno-0-19" id="__codelineno-0-19" name="__codelineno-0-19"></a> )
|
||
<a href="#conf-lsobject-customactions-__codelineno-0-20" id="__codelineno-0-20" name="__codelineno-0-20"></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>
|
||
<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> */
|
||
<a href="#conf-lsobject-customactions-__codelineno-1-11" id="__codelineno-1-11" name="__codelineno-1-11"></a>function maFonction ($object) {
|
||
<a href="#conf-lsobject-customactions-__codelineno-1-12" id="__codelineno-1-12" name="__codelineno-1-12"></a>
|
||
<a href="#conf-lsobject-customactions-__codelineno-1-13" id="__codelineno-1-13" name="__codelineno-1-13"></a> // Actions
|
||
<a href="#conf-lsobject-customactions-__codelineno-1-14" id="__codelineno-1-14" name="__codelineno-1-14"></a>
|
||
<a href="#conf-lsobject-customactions-__codelineno-1-15" id="__codelineno-1-15" name="__codelineno-1-15"></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>
|
||
<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' => array(</span>
|
||
<a href="#conf-lsobject-lsrelation-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a><span class="x"> 'label' => '[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' => "[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' => '[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' => '[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' => '[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' => '[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' => '[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' => 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' => '[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' => '[methode2]',</span>
|
||
<a href="#conf-lsobject-lsrelation-__codelineno-0-18" id="__codelineno-0-18" name="__codelineno-0-18"></a><span class="x"> 'update_function' => '[methode3]',</span>
|
||
<a href="#conf-lsobject-lsrelation-__codelineno-0-19" id="__codelineno-0-19" name="__codelineno-0-19"></a><span class="x"> 'remove_function' => '[methode4]',</span>
|
||
<a href="#conf-lsobject-lsrelation-__codelineno-0-20" id="__codelineno-0-20" name="__codelineno-0-20"></a><span class="x"> 'rename_function' => '[methode5]',</span>
|
||
<a href="#conf-lsobject-lsrelation-__codelineno-0-21" id="__codelineno-0-21" name="__codelineno-0-21"></a><span class="x"> 'canEdit_function' => '[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' => array(</span>
|
||
<a href="#conf-lsobject-lsrelation-__codelineno-0-24" id="__codelineno-0-24" name="__codelineno-0-24"></a><span class="x"> 'LSprofile1' => 'r',</span>
|
||
<a href="#conf-lsobject-lsrelation-__codelineno-0-25" id="__codelineno-0-25" name="__codelineno-0-25"></a><span class="x"> 'LSprofile2' => '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' => [booléen],
|
||
<a href="#conf-lsobject-lsform-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> 'layout' => 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' => 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' => array(</span>
|
||
<a href="#conf-lsobject-lsform-__codelineno-1-3" id="__codelineno-1-3" name="__codelineno-1-3"></a><span class="x"> 'label' => '[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' => 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' => 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' => array(</span>
|
||
<a href="#conf-lsobject-lsform-__codelineno-2-3" id="__codelineno-2-3" name="__codelineno-2-3"></a><span class="x"> 'label' => '[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' => [booleen],</span>
|
||
<a href="#conf-lsobject-lsform-__codelineno-2-5" id="__codelineno-2-5" name="__codelineno-2-5"></a><span class="x"> 'displayedElements' => 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' => array (</span>
|
||
<a href="#conf-lsobject-lsform-__codelineno-2-11" id="__codelineno-2-11" name="__codelineno-2-11"></a><span class="x"> 'attr3' => [value],</span>
|
||
<a href="#conf-lsobject-lsform-__codelineno-2-12" id="__codelineno-2-12" name="__codelineno-2-12"></a><span class="x"> 'attr4' => [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' => [booleen],</span>
|
||
<a href="#conf-lsobject-lsform-__codelineno-2-16" id="__codelineno-2-16" name="__codelineno-2-16"></a><span class="x"> 'requiredAttributes' => 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' => 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' => 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' => array(</span>
|
||
<a href="#conf-lsobject-lssearch-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a><span class="x"> 'searchLSformat' => '[LSformat]',</span>
|
||
<a href="#conf-lsobject-lssearch-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a><span class="x"> 'approxLSformat' => '[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' => 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' => '[string]',</span>
|
||
<a href="#conf-lsobject-lssearch-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a><span class="x"> 'sizelimit' => [integer],</span>
|
||
<a href="#conf-lsobject-lssearch-__codelineno-0-16" id="__codelineno-0-16" name="__codelineno-0-16"></a><span class="x"> 'recursive' => [boolean],</span>
|
||
<a href="#conf-lsobject-lssearch-__codelineno-0-17" id="__codelineno-0-17" name="__codelineno-0-17"></a><span class="x"> 'approx' => [boolean],</span>
|
||
<a href="#conf-lsobject-lssearch-__codelineno-0-18" id="__codelineno-0-18" name="__codelineno-0-18"></a><span class="x"> 'withoutCache' => [boolean],</span>
|
||
<a href="#conf-lsobject-lssearch-__codelineno-0-19" id="__codelineno-0-19" name="__codelineno-0-19"></a><span class="x"> 'onlyAccessible' => [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' => [displayName|subDn],</span>
|
||
<a href="#conf-lsobject-lssearch-__codelineno-0-22" id="__codelineno-0-22" name="__codelineno-0-22"></a><span class="x"> 'sortDirection' => [ASC|DESC],</span>
|
||
<a href="#conf-lsobject-lssearch-__codelineno-0-23" id="__codelineno-0-23" name="__codelineno-0-23"></a><span class="x"> 'sortlimit' => [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' => [LSformat],</span>
|
||
<a href="#conf-lsobject-lssearch-__codelineno-0-26" id="__codelineno-0-26" name="__codelineno-0-26"></a><span class="x"> 'nbObjectsByPage' => [integer],</span>
|
||
<a href="#conf-lsobject-lssearch-__codelineno-0-27" id="__codelineno-0-27" name="__codelineno-0-27"></a><span class="x"> 'nbObjectsByPageChoices' => 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' => '[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' => array(</span>
|
||
<a href="#conf-lsobject-lssearch-__codelineno-0-31" id="__codelineno-0-31" name="__codelineno-0-31"></a><span class="x"> 'filter1' => 'label filter1',</span>
|
||
<a href="#conf-lsobject-lssearch-__codelineno-0-32" id="__codelineno-0-32" name="__codelineno-0-32"></a><span class="x"> 'filter2' => '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' => array(</span>
|
||
<a href="#conf-lsobject-lssearch-__codelineno-0-35" id="__codelineno-0-35" name="__codelineno-0-35"></a><span class="x"> 'col1' => array(</span>
|
||
<a href="#conf-lsobject-lssearch-__codelineno-0-36" id="__codelineno-0-36" name="__codelineno-0-36"></a><span class="x"> 'label' => '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' => '[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' => array(</span>
|
||
<a href="#conf-lsobject-lssearch-__codelineno-0-40" id="__codelineno-0-40" name="__codelineno-0-40"></a><span class="x"> 'label' => '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' => '[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' => 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' => [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' => array(</span>
|
||
<a href="#conf-lsobject-lssearch-__codelineno-0-46" id="__codelineno-0-46" name="__codelineno-0-46"></a><span class="x"> 'label' => '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' => '[LSformat]',</span>
|
||
<a href="#conf-lsobject-lssearch-__codelineno-0-48" id="__codelineno-0-48" name="__codelineno-0-48"></a><span class="x"> 'alternativeLSformats' => 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' => '[LSformat]',</span>
|
||
<a href="#conf-lsobject-lssearch-__codelineno-0-53" id="__codelineno-0-53" name="__codelineno-0-53"></a><span class="x"> 'formaterFunction' => '[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' => '[CSS style]',</span>
|
||
<a href="#conf-lsobject-lssearch-__codelineno-0-55" id="__codelineno-0-55" name="__codelineno-0-55"></a><span class="x"> 'visibleTo' => 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' => 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">);</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>(& (&(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>
|
||
<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' => array(
|
||
<a href="#conf-lsobject-lssearch-__codelineno-6-3" id="__codelineno-6-3" name="__codelineno-6-3"></a> 'label' => '[label l'action]',
|
||
<a href="#conf-lsobject-lssearch-__codelineno-6-4" id="__codelineno-6-4" name="__codelineno-6-4"></a> 'hideLabel' => '[booléen]',
|
||
<a href="#conf-lsobject-lssearch-__codelineno-6-5" id="__codelineno-6-5" name="__codelineno-6-5"></a> 'icon' => '[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' => '[fonction à exécuter]',
|
||
<a href="#conf-lsobject-lssearch-__codelineno-6-7" id="__codelineno-6-7" name="__codelineno-6-7"></a> 'question_format' => '[LSformat de la question de confirmation]',
|
||
<a href="#conf-lsobject-lssearch-__codelineno-6-8" id="__codelineno-6-8" name="__codelineno-6-8"></a> 'onSuccessMsgFormat' => '[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' => '[booléen]',
|
||
<a href="#conf-lsobject-lssearch-__codelineno-6-10" id="__codelineno-6-10" name="__codelineno-6-10"></a> 'noConfirmation' => '[booléen]',
|
||
<a href="#conf-lsobject-lssearch-__codelineno-6-11" id="__codelineno-6-11" name="__codelineno-6-11"></a> 'redirectToObjectList' => '[booléen]',
|
||
<a href="#conf-lsobject-lssearch-__codelineno-6-12" id="__codelineno-6-12" name="__codelineno-6-12"></a> 'rights' => 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 -> 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 -> 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]' => array (
|
||
<a href="#conf-lsobject-ioformat-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a> 'label' => '[Label du type de fichier]',
|
||
<a href="#conf-lsobject-ioformat-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a> 'driver' => '[Pilote d'ioFormat utilisé]',
|
||
<a href="#conf-lsobject-ioformat-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a> 'driver_options' => 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' => '[Booléen]',
|
||
<a href="#conf-lsobject-ioformat-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a> 'fields => array (
|
||
<a href="#conf-lsobject-ioformat-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a> '[champ 1]' => '[attribut 1]',
|
||
<a href="#conf-lsobject-ioformat-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a> '[champ 2]' => '[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' => array (
|
||
<a href="#conf-lsobject-ioformat-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a> '[attribute 3]' => '[LSformat]',
|
||
<a href="#conf-lsobject-ioformat-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a> '[attribute 4]' => array('[LSformat1]', '[LSformat2]', ...)
|
||
<a href="#conf-lsobject-ioformat-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a> '[attribute 5]' => 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' => array('function1', 'function2'),
|
||
<a href="#conf-lsobject-ioformat-__codelineno-0-21" id="__codelineno-0-21" name="__codelineno-0-21"></a> 'after_import' => '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' => '[délimiteur]',
|
||
<a href="#conf-lsobject-ioformat-__codelineno-1-3" id="__codelineno-1-3" name="__codelineno-1-3"></a> 'enclosure' => '[caractère d'encadrement de texte]',
|
||
<a href="#conf-lsobject-ioformat-__codelineno-1-4" id="__codelineno-1-4" name="__codelineno-1-4"></a> 'length' => [longueur maximale d'une ligne],
|
||
<a href="#conf-lsobject-ioformat-__codelineno-1-5" id="__codelineno-1-5" name="__codelineno-1-5"></a> 'escape' => '[caractère d'échappement]',
|
||
<a href="#conf-lsobject-ioformat-__codelineno-1-6" id="__codelineno-1-6" name="__codelineno-1-6"></a> 'multiple_value_delimiter' => '[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 (&$ioFormat, &$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' => "[/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' => [boolean],</span>
|
||
<a href="#conf-lsobject-ioformat-__codelineno-4-4" id="__codelineno-4-4" name="__codelineno-4-4"></a><span class="x"> 'justTry' => [boolean],</span>
|
||
<a href="#conf-lsobject-ioformat-__codelineno-4-5" id="__codelineno-4-5" name="__codelineno-4-5"></a><span class="x"> 'objectsData' => 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' => array(</span>
|
||
<a href="#conf-lsobject-ioformat-__codelineno-4-9" id="__codelineno-4-9" name="__codelineno-4-9"></a><span class="x"> 'success' => [boolean],</span>
|
||
<a href="#conf-lsobject-ioformat-__codelineno-4-10" id="__codelineno-4-10" name="__codelineno-4-10"></a><span class="x"> 'LSobject' => "[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' => "[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' => [boolean],</span>
|
||
<a href="#conf-lsobject-ioformat-__codelineno-4-13" id="__codelineno-4-13" name="__codelineno-4-13"></a><span class="x"> 'justTry' => [boolean],</span>
|
||
<a href="#conf-lsobject-ioformat-__codelineno-4-14" id="__codelineno-4-14" name="__codelineno-4-14"></a><span class="x"> 'imported' => 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' => 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' => 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' => [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' => array (</span>
|
||
<a href="#conf-lsobject-ioformat-__codelineno-4-20" id="__codelineno-4-20" name="__codelineno-4-20"></a><span class="x"> 'globals' => 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' => array(</span>
|
||
<a href="#conf-lsobject-ioformat-__codelineno-4-22" id="__codelineno-4-22" name="__codelineno-4-22"></a><span class="x"> 'attr1' => 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' => array (</span>
|
||
<a href="#conf-lsaddon-lsaddon_accesslog-__codelineno-2-4" id="__codelineno-2-4" name="__codelineno-2-4"></a><span class="x"> 'showObjectAccessLogs' => array (</span>
|
||
<a href="#conf-lsaddon-lsaddon_accesslog-__codelineno-2-5" id="__codelineno-2-5" name="__codelineno-2-5"></a><span class="x"> 'function' => 'showObjectAccessLogs',</span>
|
||
<a href="#conf-lsaddon-lsaddon_accesslog-__codelineno-2-6" id="__codelineno-2-6" name="__codelineno-2-6"></a><span class="x"> 'label' => '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' => true,</span>
|
||
<a href="#conf-lsaddon-lsaddon_accesslog-__codelineno-2-8" id="__codelineno-2-8" name="__codelineno-2-8"></a><span class="x"> 'noConfirmation' => true,</span>
|
||
<a href="#conf-lsaddon-lsaddon_accesslog-__codelineno-2-9" id="__codelineno-2-9" name="__codelineno-2-9"></a><span class="x"> 'disableOnSuccessMsg' => true,</span>
|
||
<a href="#conf-lsaddon-lsaddon_accesslog-__codelineno-2-10" id="__codelineno-2-10" name="__codelineno-2-10"></a><span class="x"> 'icon' => 'clock',</span>
|
||
<a href="#conf-lsaddon-lsaddon_accesslog-__codelineno-2-11" id="__codelineno-2-11" name="__codelineno-2-11"></a><span class="x"> 'rights' => 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' => array (</span>
|
||
<a href="#conf-lsaddon-lsaddon_exportsearchresultascsv-__codelineno-1-4" id="__codelineno-1-4" name="__codelineno-1-4"></a><span class="x"> 'exportSearchResultAsCSV' => array (</span>
|
||
<a href="#conf-lsaddon-lsaddon_exportsearchresultascsv-__codelineno-1-5" id="__codelineno-1-5" name="__codelineno-1-5"></a><span class="x"> 'label' => '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' => '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' => 'exportSearchResultAsCSV',</span>
|
||
<a href="#conf-lsaddon-lsaddon_exportsearchresultascsv-__codelineno-1-8" id="__codelineno-1-8" name="__codelineno-1-8"></a><span class="x"> 'noConfirmation' => true,</span>
|
||
<a href="#conf-lsaddon-lsaddon_exportsearchresultascsv-__codelineno-1-9" id="__codelineno-1-9" name="__codelineno-1-9"></a><span class="x"> 'disableOnSuccessMsg' => true,</span>
|
||
<a href="#conf-lsaddon-lsaddon_exportsearchresultascsv-__codelineno-1-10" id="__codelineno-1-10" name="__codelineno-1-10"></a><span class="x"> 'rights' => 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' => array (</span>
|
||
<a href="#conf-lsaddon-lsaddon_impersonate-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a><span class="x"> 'impersonate' => array (</span>
|
||
<a href="#conf-lsaddon-lsaddon_impersonate-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a><span class="x"> 'function' => 'impersonate',</span>
|
||
<a href="#conf-lsaddon-lsaddon_impersonate-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a><span class="x"> 'label' => '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' => True,</span>
|
||
<a href="#conf-lsaddon-lsaddon_impersonate-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a><span class="x"> 'noConfirmation' => true,</span>
|
||
<a href="#conf-lsaddon-lsaddon_impersonate-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a><span class="x"> 'disableOnSuccessMsg' => true,</span>
|
||
<a href="#conf-lsaddon-lsaddon_impersonate-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a><span class="x"> 'icon' => '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' => 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'envoie de mail. 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. 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>
|
||
</code></pre></div>
|
||
<p>Cet <a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a> offre la possibilité d'utilisé 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> <string> $to,
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-1-3" id="__codelineno-1-3" name="__codelineno-1-3"></a> <string> $subject,
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-1-4" id="__codelineno-1-4" name="__codelineno-1-4"></a> <string> $msg,
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-1-5" id="__codelineno-1-5" name="__codelineno-1-5"></a> <array(string)> $headers,
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-1-6" id="__codelineno-1-6" name="__codelineno-1-6"></a> <array> $attachments,
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-1-7" id="__codelineno-1-7" name="__codelineno-1-7"></a> <string> $eol,
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-1-8" id="__codelineno-1-8" name="__codelineno-1-8"></a> <string> $encoding,
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-1-9" id="__codelineno-1-9" name="__codelineno-1-9"></a> <boolean> $html
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-1-10" id="__codelineno-1-10" name="__codelineno-1-10"></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' => array (</span>
|
||
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-1-4" id="__codelineno-1-4" name="__codelineno-1-4"></a><span class="x"> 'showmailquotausage' => array (</span>
|
||
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-1-5" id="__codelineno-1-5" name="__codelineno-1-5"></a><span class="x"> 'function' => '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' => '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' => true,</span>
|
||
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-1-8" id="__codelineno-1-8" name="__codelineno-1-8"></a><span class="x"> 'disableOnSuccessMsg' => true,</span>
|
||
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-1-9" id="__codelineno-1-9" name="__codelineno-1-9"></a><span class="x"> 'icon' => 'mail',</span>
|
||
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-1-10" id="__codelineno-1-10" name="__codelineno-1-10"></a><span class="x"> 'rights' => 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&server_id=0&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' => array (</span>
|
||
<a href="#conf-lsaddon-lsaddon_phpldapadmin-__codelineno-1-4" id="__codelineno-1-4" name="__codelineno-1-4"></a><span class="x"> 'redirectPhpLdapAdmin' => array (</span>
|
||
<a href="#conf-lsaddon-lsaddon_phpldapadmin-__codelineno-1-5" id="__codelineno-1-5" name="__codelineno-1-5"></a><span class="x"> 'function' => 'redirectToPhpLdapAdmin',</span>
|
||
<a href="#conf-lsaddon-lsaddon_phpldapadmin-__codelineno-1-6" id="__codelineno-1-6" name="__codelineno-1-6"></a><span class="x"> 'label' => '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' => True,</span>
|
||
<a href="#conf-lsaddon-lsaddon_phpldapadmin-__codelineno-1-8" id="__codelineno-1-8" name="__codelineno-1-8"></a><span class="x"> 'noConfirmation' => true,</span>
|
||
<a href="#conf-lsaddon-lsaddon_phpldapadmin-__codelineno-1-9" id="__codelineno-1-9" name="__codelineno-1-9"></a><span class="x"> 'disableOnSuccessMsg' => true,</span>
|
||
<a href="#conf-lsaddon-lsaddon_phpldapadmin-__codelineno-1-10" id="__codelineno-1-10" name="__codelineno-1-10"></a><span class="x"> 'icon' => 'phpldapadmin',</span>
|
||
<a href="#conf-lsaddon-lsaddon_phpldapadmin-__codelineno-1-11" id="__codelineno-1-11" name="__codelineno-1-11"></a><span class="x"> 'rights' => 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' => 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' => array (
|
||
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a> 'label' => 'Password expiration',
|
||
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a> 'generateFunction' => 'ppolicy_extraDisplayColumn_password_expiration',
|
||
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a> 'additionalAttrs' => array('pwdChangedTime', 'pwdPolicySubentry'),
|
||
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a> 'escape' => false,
|
||
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a> 'cssStyle' => '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' => array (</span>
|
||
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-1-4" id="__codelineno-1-4" name="__codelineno-1-4"></a><span class="x"> 'exportPpolicyInfo' => array (</span>
|
||
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-1-5" id="__codelineno-1-5" name="__codelineno-1-5"></a><span class="x"> 'label' => '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' => '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' => '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' => true,</span>
|
||
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-1-9" id="__codelineno-1-9" name="__codelineno-1-9"></a><span class="x"> 'disableOnSuccessMsg' => true,</span>
|
||
<a href="#conf-lsaddon-lsaddon_ppolicy-__codelineno-1-10" id="__codelineno-1-10" name="__codelineno-1-10"></a><span class="x"> 'rights' => 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' => array (</span>
|
||
<a href="#conf-lsaddon-lsaddon_showsupportinfo-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a><span class="x"> 'showMySupportInfo' => array (</span>
|
||
<a href="#conf-lsaddon-lsaddon_showsupportinfo-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a><span class="x"> 'function' => 'showMySupportInfo',</span>
|
||
<a href="#conf-lsaddon-lsaddon_showsupportinfo-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a><span class="x"> 'label' => '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' => True,</span>
|
||
<a href="#conf-lsaddon-lsaddon_showsupportinfo-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a><span class="x"> 'noConfirmation' => true,</span>
|
||
<a href="#conf-lsaddon-lsaddon_showsupportinfo-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a><span class="x"> 'disableOnSuccessMsg' => true,</span>
|
||
<a href="#conf-lsaddon-lsaddon_showsupportinfo-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a><span class="x"> 'icon' => 'terminal',</span>
|
||
<a href="#conf-lsaddon-lsaddon_showsupportinfo-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a><span class="x"> 'rights' => 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' => array (</span>
|
||
<a href="#conf-lsaddon-lsaddon_showtechinfo-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a><span class="x"> 'showTechInfo' => array (</span>
|
||
<a href="#conf-lsaddon-lsaddon_showtechinfo-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a><span class="x"> 'function' => 'showTechInfo',</span>
|
||
<a href="#conf-lsaddon-lsaddon_showtechinfo-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a><span class="x"> 'label' => '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' => True,</span>
|
||
<a href="#conf-lsaddon-lsaddon_showtechinfo-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a><span class="x"> 'noConfirmation' => true,</span>
|
||
<a href="#conf-lsaddon-lsaddon_showtechinfo-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a><span class="x"> 'disableOnSuccessMsg' => true,</span>
|
||
<a href="#conf-lsaddon-lsaddon_showtechinfo-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a><span class="x"> 'icon' => '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' => 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.</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&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&personalTitle=M.&givenName=foo&sn=bar&cn=Foo Bar&mail=foo.bar@example.com&userPassword=Y0urS3cr3t&lsGodfatherDn[]=uid=admin,ou=people,o=ls&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&sn=bar&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]/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-5-1" id="__codelineno-5-1" name="__codelineno-5-1"></a># curl -u username:secret --data-binary @/path/to/input.file 'https://ldapsaisie/api/1.0/object/LSpeople/import?ioFormat=mycsv&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> "success": false,
|
||
<a href="#api-__codelineno-5-4" id="__codelineno-5-4" name="__codelineno-5-4"></a> "LSobject": "LSpeople",
|
||
<a href="#api-__codelineno-5-5" id="__codelineno-5-5" name="__codelineno-5-5"></a> "ioFormat": "mycsv",
|
||
<a href="#api-__codelineno-5-6" id="__codelineno-5-6" name="__codelineno-5-6"></a> "updateIfExists": false,
|
||
<a href="#api-__codelineno-5-7" id="__codelineno-5-7" name="__codelineno-5-7"></a> "justTry": false,
|
||
<a href="#api-__codelineno-5-8" id="__codelineno-5-8" name="__codelineno-5-8"></a> "imported": {
|
||
<a href="#api-__codelineno-5-9" id="__codelineno-5-9" name="__codelineno-5-9"></a> "uid=rturin,ou=people,o=ls": "M. Roger TURIN"
|
||
<a href="#api-__codelineno-5-10" id="__codelineno-5-10" name="__codelineno-5-10"></a> },
|
||
<a href="#api-__codelineno-5-11" id="__codelineno-5-11" name="__codelineno-5-11"></a> "updated": [],
|
||
<a href="#api-__codelineno-5-12" id="__codelineno-5-12" name="__codelineno-5-12"></a> "errors": [
|
||
<a href="#api-__codelineno-5-13" id="__codelineno-5-13" name="__codelineno-5-13"></a> {
|
||
<a href="#api-__codelineno-5-14" id="__codelineno-5-14" name="__codelineno-5-14"></a> "data": {
|
||
<a href="#api-__codelineno-5-15" id="__codelineno-5-15" name="__codelineno-5-15"></a> "uid": [
|
||
<a href="#api-__codelineno-5-16" id="__codelineno-5-16" name="__codelineno-5-16"></a> "lmartin"
|
||
<a href="#api-__codelineno-5-17" id="__codelineno-5-17" name="__codelineno-5-17"></a> ],
|
||
<a href="#api-__codelineno-5-18" id="__codelineno-5-18" name="__codelineno-5-18"></a> "personalTitle": [
|
||
<a href="#api-__codelineno-5-19" id="__codelineno-5-19" name="__codelineno-5-19"></a> "Mme"
|
||
<a href="#api-__codelineno-5-20" id="__codelineno-5-20" name="__codelineno-5-20"></a> ],
|
||
<a href="#api-__codelineno-5-21" id="__codelineno-5-21" name="__codelineno-5-21"></a> "givenName": [
|
||
<a href="#api-__codelineno-5-22" id="__codelineno-5-22" name="__codelineno-5-22"></a> "Ludivine"
|
||
<a href="#api-__codelineno-5-23" id="__codelineno-5-23" name="__codelineno-5-23"></a> ],
|
||
<a href="#api-__codelineno-5-24" id="__codelineno-5-24" name="__codelineno-5-24"></a> "sn": [
|
||
<a href="#api-__codelineno-5-25" id="__codelineno-5-25" name="__codelineno-5-25"></a> "MARTIN"
|
||
<a href="#api-__codelineno-5-26" id="__codelineno-5-26" name="__codelineno-5-26"></a> ],
|
||
<a href="#api-__codelineno-5-27" id="__codelineno-5-27" name="__codelineno-5-27"></a> "mail": [
|
||
<a href="#api-__codelineno-5-28" id="__codelineno-5-28" name="__codelineno-5-28"></a> "lmartin@gmail.com"
|
||
<a href="#api-__codelineno-5-29" id="__codelineno-5-29" name="__codelineno-5-29"></a> ],
|
||
<a href="#api-__codelineno-5-30" id="__codelineno-5-30" name="__codelineno-5-30"></a> "userPassword": [
|
||
<a href="#api-__codelineno-5-31" id="__codelineno-5-31" name="__codelineno-5-31"></a> "123Yh%uT"
|
||
<a href="#api-__codelineno-5-32" id="__codelineno-5-32" name="__codelineno-5-32"></a> ],
|
||
<a href="#api-__codelineno-5-33" id="__codelineno-5-33" name="__codelineno-5-33"></a> "gidNumber": [
|
||
<a href="#api-__codelineno-5-34" id="__codelineno-5-34" name="__codelineno-5-34"></a> "102009"
|
||
<a href="#api-__codelineno-5-35" id="__codelineno-5-35" name="__codelineno-5-35"></a> ],
|
||
<a href="#api-__codelineno-5-36" id="__codelineno-5-36" name="__codelineno-5-36"></a> "loginShell": [
|
||
<a href="#api-__codelineno-5-37" id="__codelineno-5-37" name="__codelineno-5-37"></a> "no"
|
||
<a href="#api-__codelineno-5-38" id="__codelineno-5-38" name="__codelineno-5-38"></a> ],
|
||
<a href="#api-__codelineno-5-39" id="__codelineno-5-39" name="__codelineno-5-39"></a> "cn": [
|
||
<a href="#api-__codelineno-5-40" id="__codelineno-5-40" name="__codelineno-5-40"></a> "Mme Ludivine MARTIN"
|
||
<a href="#api-__codelineno-5-41" id="__codelineno-5-41" name="__codelineno-5-41"></a> ]
|
||
<a href="#api-__codelineno-5-42" id="__codelineno-5-42" name="__codelineno-5-42"></a> },
|
||
<a href="#api-__codelineno-5-43" id="__codelineno-5-43" name="__codelineno-5-43"></a> "errors": {
|
||
<a href="#api-__codelineno-5-44" id="__codelineno-5-44" name="__codelineno-5-44"></a> "globals": [
|
||
<a href="#api-__codelineno-5-45" id="__codelineno-5-45" name="__codelineno-5-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-5-46" id="__codelineno-5-46" name="__codelineno-5-46"></a> ],
|
||
<a href="#api-__codelineno-5-47" id="__codelineno-5-47" name="__codelineno-5-47"></a> "attrs": []
|
||
<a href="#api-__codelineno-5-48" id="__codelineno-5-48" name="__codelineno-5-48"></a> }
|
||
<a href="#api-__codelineno-5-49" id="__codelineno-5-49" name="__codelineno-5-49"></a> }
|
||
<a href="#api-__codelineno-5-50" id="__codelineno-5-50" name="__codelineno-5-50"></a> ],
|
||
<a href="#api-__codelineno-5-51" id="__codelineno-5-51" name="__codelineno-5-51"></a> "messages": [
|
||
<a href="#api-__codelineno-5-52" id="__codelineno-5-52" name="__codelineno-5-52"></a> "Le mail de notification a \u00e9t\u00e9 envoy\u00e9."
|
||
<a href="#api-__codelineno-5-53" id="__codelineno-5-53" name="__codelineno-5-53"></a> ]
|
||
<a href="#api-__codelineno-5-54" id="__codelineno-5-54" name="__codelineno-5-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-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/export?ioFormat=mycsv&pretty'
|
||
<a href="#api-__codelineno-6-2" id="__codelineno-6-2" name="__codelineno-6-2"></a>login;civility;firstname;name;mail;password;gid;shell
|
||
<a href="#api-__codelineno-6-3" id="__codelineno-6-3" name="__codelineno-6-3"></a>hmartin;M.;Henri;MARTIN;henri.martin@ls.com;********;102001;no
|
||
<a href="#api-__codelineno-6-4" id="__codelineno-6-4" name="__codelineno-6-4"></a>s.ldapsaisie;M.;Secretariat;LdapSaisie;secretariat@ldapsaisie.biz;********;70000;no
|
||
<a href="#api-__codelineno-6-5" id="__codelineno-6-5" name="__codelineno-6-5"></a>ls;M.;Ldap;Saisie;ldap.saisie@ls.com;********;102001;no
|
||
<a href="#api-__codelineno-6-6" id="__codelineno-6-6" name="__codelineno-6-6"></a>erwpa;M.;Erwan;PAGEARD;erwan.page@ldapsaisie.biz;********;102009;no
|
||
<a href="#api-__codelineno-6-7" id="__codelineno-6-7" name="__codelineno-6-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-7-1" id="__codelineno-7-1" name="__codelineno-7-1"></a># curl -u username:secret 'https://ldapsaisie/api/1.0/object/LSpeople/uid=foo.bar,ou=people,o=ls/relation/groups?pretty&add[]=cn=ls,ou=groups,o=ls&add[]=cn=invite,ou=groups,o=ls'
|
||
<a href="#api-__codelineno-7-2" id="__codelineno-7-2" name="__codelineno-7-2"></a>{
|
||
<a href="#api-__codelineno-7-3" id="__codelineno-7-3" name="__codelineno-7-3"></a> "dn": "uid=foo.bar,ou=people,o=ls",
|
||
<a href="#api-__codelineno-7-4" id="__codelineno-7-4" name="__codelineno-7-4"></a> "type": "LSpeople",
|
||
<a href="#api-__codelineno-7-5" id="__codelineno-7-5" name="__codelineno-7-5"></a> "name": "Foo Bar",
|
||
<a href="#api-__codelineno-7-6" id="__codelineno-7-6" name="__codelineno-7-6"></a> "relation": "groups",
|
||
<a href="#api-__codelineno-7-7" id="__codelineno-7-7" name="__codelineno-7-7"></a> "success": true,
|
||
<a href="#api-__codelineno-7-8" id="__codelineno-7-8" name="__codelineno-7-8"></a> "relatedObjects": [
|
||
<a href="#api-__codelineno-7-9" id="__codelineno-7-9" name="__codelineno-7-9"></a> "cn=ls,ou=groups,o=ls",
|
||
<a href="#api-__codelineno-7-10" id="__codelineno-7-10" name="__codelineno-7-10"></a> "cn=invite,ou=groups,o=ls"
|
||
<a href="#api-__codelineno-7-11" id="__codelineno-7-11" name="__codelineno-7-11"></a> ],
|
||
<a href="#api-__codelineno-7-12" id="__codelineno-7-12" name="__codelineno-7-12"></a> "messages": [
|
||
<a href="#api-__codelineno-7-13" id="__codelineno-7-13" name="__codelineno-7-13"></a> "Objects in relation updated."
|
||
<a href="#api-__codelineno-7-14" id="__codelineno-7-14" name="__codelineno-7-14"></a> ]
|
||
<a href="#api-__codelineno-7-15" id="__codelineno-7-15" name="__codelineno-7-15"></a>}
|
||
</code></pre></div>
|
||
</li>
|
||
</ul></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"><?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 <my.email@example.com></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 <my.email@example.com></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">=></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">=></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 & 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"><?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 <my.email@example.com></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 & 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>
|
||
<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 vue 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>
|
||
<p>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.</p>
|
||
<p>Cette méthode 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 autre argument 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 si 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'écrire 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></li>
|
||
</ul>
|
||
<p>Autocomplétion du nom d'une classe PHP.</p>
|
||
<ul>
|
||
<li><code>LScli :: autocomplete_addon_name()</code></li>
|
||
</ul>
|
||
<p>Autocomplétion du nom d'un <a href="#conf-configuration-des-lsaddons">LSaddon</a>.</p>
|
||
<ul>
|
||
<li><code>LScli :: autocomplete_int()</code></li>
|
||
</ul>
|
||
<p>Autocomplétion d'un nombre entier.</p>
|
||
<ul>
|
||
<li><code>LScli :: autocomplete_LSobject_types()</code></li>
|
||
</ul>
|
||
<p>Autocomplétion du nom d'un type d'<a href="#conf-configuration-lsobject">LSobject</a>.</p>
|
||
<ul>
|
||
<li><code>LScli :: autocomplete_LSobject_dn()</code></li>
|
||
</ul>
|
||
<p>Autocomplétion du DN d'un type précis d'<a href="#conf-configuration-lsobject">LSobject</a> de
|
||
l'annuaire.</p>
|
||
<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>
|
||
</li>
|
||
</ul>
|
||
<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><?php
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a>function LSaddon_myaddon_support() {
|
||
<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> $retval=true;
|
||
<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> // Some check
|
||
<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> if ($retval) {
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a> if (php_sapi_name() == 'cli') {
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a> LScli :: add_command(
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a> 'my_custom_cli_cmd', // The CLI command name (required)
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a> 'cli_my_custom_cli_cmd', // The CLI command handler (must be callable, required)
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a> 'My custom CLI command', // A short description of what this command does (required)
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a> '[arg1] [arg2] [...]', // A short list of commands available arguments show in usage message
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a> // (optional, default: false)
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-16" id="__codelineno-0-16" name="__codelineno-0-16"></a> 'This command permit to ...', // A long description of what this command does (optional, default:
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-17" id="__codelineno-0-17" name="__codelineno-0-17"></a> // false)
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-18" id="__codelineno-0-18" name="__codelineno-0-18"></a> true, // Permit to define if this command need connection to LDAP server
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-19" id="__codelineno-0-19" name="__codelineno-0-19"></a> // (optional, default: true)
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-20" id="__codelineno-0-20" name="__codelineno-0-20"></a> 'cli_my_custom_cli_cmd_autocompleter', // Callable of the CLI command arguments autocompleter (optional,
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-21" id="__codelineno-0-21" name="__codelineno-0-21"></a> // default: null)
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-22" id="__codelineno-0-22" name="__codelineno-0-22"></a> true // Allow override if a command already exists with the same name
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-23" id="__codelineno-0-23" name="__codelineno-0-23"></a> // (optional, default: null)
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-24" id="__codelineno-0-24" name="__codelineno-0-24"></a> );
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-25" id="__codelineno-0-25" name="__codelineno-0-25"></a> }
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-26" id="__codelineno-0-26" name="__codelineno-0-26"></a> }
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-27" id="__codelineno-0-27" name="__codelineno-0-27"></a>
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-28" id="__codelineno-0-28" name="__codelineno-0-28"></a> return $retval;
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-29" id="__codelineno-0-29" name="__codelineno-0-29"></a>}
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-30" id="__codelineno-0-30" name="__codelineno-0-30"></a>
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-31" id="__codelineno-0-31" name="__codelineno-0-31"></a>[...]
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-32" id="__codelineno-0-32" name="__codelineno-0-32"></a>
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-33" id="__codelineno-0-33" name="__codelineno-0-33"></a>// Defined CLI commands functions only on CLI context
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-34" id="__codelineno-0-34" name="__codelineno-0-34"></a>if (php_sapi_name() != 'cli')
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-35" id="__codelineno-0-35" name="__codelineno-0-35"></a> return true; // Always return true to avoid some warning in log
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-36" id="__codelineno-0-36" name="__codelineno-0-36"></a>
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-37" id="__codelineno-0-37" name="__codelineno-0-37"></a>/**
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-38" id="__codelineno-0-38" name="__codelineno-0-38"></a> * My addon CLI command my_custom_cli_cmd handler function
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-39" id="__codelineno-0-39" name="__codelineno-0-39"></a> *
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-40" id="__codelineno-0-40" name="__codelineno-0-40"></a> * Description of this CLI command.
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-41" id="__codelineno-0-41" name="__codelineno-0-41"></a> *
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-42" id="__codelineno-0-42" name="__codelineno-0-42"></a> * @param array $command_args Command arguments
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-43" id="__codelineno-0-43" name="__codelineno-0-43"></a> * - Positional arguments :
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-44" id="__codelineno-0-44" name="__codelineno-0-44"></a> * - LSobject
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-45" id="__codelineno-0-45" name="__codelineno-0-45"></a> * - dn
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-46" id="__codelineno-0-46" name="__codelineno-0-46"></a> * - Optional arguments :
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-47" id="__codelineno-0-47" name="__codelineno-0-47"></a> * - -f|--force : Force mode
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-48" id="__codelineno-0-48" name="__codelineno-0-48"></a> *
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-49" id="__codelineno-0-49" name="__codelineno-0-49"></a> * @author My Name <my.email@example.com>
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-50" id="__codelineno-0-50" name="__codelineno-0-50"></a> *
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-51" id="__codelineno-0-51" name="__codelineno-0-51"></a> * @return boolean True on success, false otherwise
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-52" id="__codelineno-0-52" name="__codelineno-0-52"></a> **/
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-53" id="__codelineno-0-53" name="__codelineno-0-53"></a>function cli_my_custom_cli_cmd($command_args) {
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-54" id="__codelineno-0-54" name="__codelineno-0-54"></a> $objType = null;
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-55" id="__codelineno-0-55" name="__codelineno-0-55"></a> $dn = null;
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-56" id="__codelineno-0-56" name="__codelineno-0-56"></a> $force_mode = false;
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-57" id="__codelineno-0-57" name="__codelineno-0-57"></a> foreach ($command_args as $arg) {
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-58" id="__codelineno-0-58" name="__codelineno-0-58"></a> if ($arg == '-f' || $arg == '--force')
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-59" id="__codelineno-0-59" name="__codelineno-0-59"></a> $force_mode = true;
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-60" id="__codelineno-0-60" name="__codelineno-0-60"></a> elseif (is_null($objType)) {
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-61" id="__codelineno-0-61" name="__codelineno-0-61"></a> $objType = $arg;
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-62" id="__codelineno-0-62" name="__codelineno-0-62"></a> }
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-63" id="__codelineno-0-63" name="__codelineno-0-63"></a> elseif (is_null($dn)) {
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-64" id="__codelineno-0-64" name="__codelineno-0-64"></a> $dn = $arg;
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-65" id="__codelineno-0-65" name="__codelineno-0-65"></a> }
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-66" id="__codelineno-0-66" name="__codelineno-0-66"></a> else
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-67" id="__codelineno-0-67" name="__codelineno-0-67"></a> LScli :: usage("Invalid $arg parameter.");
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-68" id="__codelineno-0-68" name="__codelineno-0-68"></a> }
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-69" id="__codelineno-0-69" name="__codelineno-0-69"></a>
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-70" id="__codelineno-0-70" name="__codelineno-0-70"></a> if (is_null($objType) || is_null($dn))
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-71" id="__codelineno-0-71" name="__codelineno-0-71"></a> LScli :: usage('You must provide LSobject type and DN.');
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-72" id="__codelineno-0-72" name="__codelineno-0-72"></a>
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-73" id="__codelineno-0-73" name="__codelineno-0-73"></a> if (!LSsession :: loadLSobject($objType))
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-74" id="__codelineno-0-74" name="__codelineno-0-74"></a> return false;
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-75" id="__codelineno-0-75" name="__codelineno-0-75"></a>
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-76" id="__codelineno-0-76" name="__codelineno-0-76"></a> $obj = new $objType();
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-77" id="__codelineno-0-77" name="__codelineno-0-77"></a> if (!$obj->loadData($dn)) {
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-78" id="__codelineno-0-78" name="__codelineno-0-78"></a> self :: log_fatal("Fail to load object $dn data from LDAP");
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-79" id="__codelineno-0-79" name="__codelineno-0-79"></a> return false;
|
||
<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>
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-82" id="__codelineno-0-82" name="__codelineno-0-82"></a> // Do some stuff on loaded object
|
||
<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>
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-85" id="__codelineno-0-85" name="__codelineno-0-85"></a> return true;
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-86" id="__codelineno-0-86" name="__codelineno-0-86"></a>}
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-87" id="__codelineno-0-87" name="__codelineno-0-87"></a>
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-88" id="__codelineno-0-88" name="__codelineno-0-88"></a>/**
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-89" id="__codelineno-0-89" name="__codelineno-0-89"></a> * Args autocompleter for CLI my_custom_cli_cmd command
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-90" id="__codelineno-0-90" name="__codelineno-0-90"></a> *
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-91" id="__codelineno-0-91" name="__codelineno-0-91"></a> * @param array<string> $command_args List of already typed words of the command
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-92" id="__codelineno-0-92" name="__codelineno-0-92"></a> * @param int $comp_word_num The command word number to autocomplete
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-93" id="__codelineno-0-93" name="__codelineno-0-93"></a> * @param string $comp_word The command word to autocomplete
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-94" id="__codelineno-0-94" name="__codelineno-0-94"></a> * @param array<string> $opts List of global available options
|
||
<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> * @return array<string> List of available options for the word to autocomplete
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-97" id="__codelineno-0-97" name="__codelineno-0-97"></a> **/
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-98" id="__codelineno-0-98" name="__codelineno-0-98"></a>public static function cli_my_custom_cli_cmd_autocompleter($command_args, $comp_word_num, $comp_word, $opts) {
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-99" id="__codelineno-0-99" name="__codelineno-0-99"></a> $opts = array_merge($opts, array ('-f', '--force'));
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-100" id="__codelineno-0-100" name="__codelineno-0-100"></a>
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-101" id="__codelineno-0-101" name="__codelineno-0-101"></a> // Handle positional args
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-102" id="__codelineno-0-102" name="__codelineno-0-102"></a> $objType = null;
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-103" id="__codelineno-0-103" name="__codelineno-0-103"></a> $objType_arg_num = null;
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-104" id="__codelineno-0-104" name="__codelineno-0-104"></a> $dn = null;
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-105" id="__codelineno-0-105" name="__codelineno-0-105"></a> $dn_arg_num = null;
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-106" id="__codelineno-0-106" name="__codelineno-0-106"></a> for ($i=0; $i < count($command_args); $i++) {
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-107" id="__codelineno-0-107" name="__codelineno-0-107"></a> if (!in_array($command_args[$i], $opts)) {
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-108" id="__codelineno-0-108" name="__codelineno-0-108"></a> // If object type not defined
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-109" id="__codelineno-0-109" name="__codelineno-0-109"></a> if (is_null($objType)) {
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-110" id="__codelineno-0-110" name="__codelineno-0-110"></a> // Defined it
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-111" id="__codelineno-0-111" name="__codelineno-0-111"></a> $objType = $command_args[$i];
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-112" id="__codelineno-0-112" name="__codelineno-0-112"></a> LScli :: unquote_word($objType);
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-113" id="__codelineno-0-113" name="__codelineno-0-113"></a> $objType_arg_num = $i;
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-114" id="__codelineno-0-114" name="__codelineno-0-114"></a>
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-115" id="__codelineno-0-115" name="__codelineno-0-115"></a> // Check object type exists
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-116" id="__codelineno-0-116" name="__codelineno-0-116"></a> $objTypes = LScli :: autocomplete_LSobject_types($objType);
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-117" id="__codelineno-0-117" name="__codelineno-0-117"></a>
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-118" id="__codelineno-0-118" name="__codelineno-0-118"></a> // Load it if exist and not trying to complete it
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-119" id="__codelineno-0-119" name="__codelineno-0-119"></a> if (in_array($objType, $objTypes) && $i != $comp_word_num) {
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-120" id="__codelineno-0-120" name="__codelineno-0-120"></a> LSsession :: loadLSobject($objType, false);
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-121" id="__codelineno-0-121" name="__codelineno-0-121"></a> }
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-122" id="__codelineno-0-122" name="__codelineno-0-122"></a> }
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-123" id="__codelineno-0-123" name="__codelineno-0-123"></a> elseif (is_null($dn)) {
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-124" id="__codelineno-0-124" name="__codelineno-0-124"></a> $dn = $command_args[$i];
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-125" id="__codelineno-0-125" name="__codelineno-0-125"></a> LScli :: unquote_word($dn);
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-126" id="__codelineno-0-126" name="__codelineno-0-126"></a> $dn_arg_num = $i;
|
||
<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> }
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-129" id="__codelineno-0-129" name="__codelineno-0-129"></a> }
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-130" id="__codelineno-0-130" name="__codelineno-0-130"></a>
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-131" id="__codelineno-0-131" name="__codelineno-0-131"></a> // If objType not already choiced (or currently autocomplete), add LSobject types to available options
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-132" id="__codelineno-0-132" name="__codelineno-0-132"></a> if (!$objType || $objType_arg_num == $comp_word_num)
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-133" id="__codelineno-0-133" name="__codelineno-0-133"></a> $opts = array_merge($opts, LScli :: autocomplete_LSobject_types($comp_word));
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-134" id="__codelineno-0-134" name="__codelineno-0-134"></a>
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-135" id="__codelineno-0-135" name="__codelineno-0-135"></a> // If dn not alreay choiced (or currently autocomplete), try autocomplete it
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-136" id="__codelineno-0-136" name="__codelineno-0-136"></a> elseif (!$dn || $dn_arg_num == $comp_word_num)
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-137" id="__codelineno-0-137" name="__codelineno-0-137"></a> $opts = array_merge($opts, LScli :: autocomplete_LSobject_dn($objType, $comp_word));
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-138" id="__codelineno-0-138" name="__codelineno-0-138"></a>
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-139" id="__codelineno-0-139" name="__codelineno-0-139"></a> return LScli :: autocomplete_opts($opts, $comp_word);
|
||
<a href="#contrib-addons-cli-commands-__codelineno-0-140" id="__codelineno-0-140" name="__codelineno-0-140"></a>}
|
||
</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>
|
||
</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.f886a092.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+e3ZhciB3aT1PYmplY3QuY3JlYXRlO3ZhciBkcj1PYmplY3QuZGVmaW5lUHJvcGVydHk7dmFyIFNpPU9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3I7dmFyIFRpPU9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzLGt0PU9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMsT2k9T2JqZWN0LmdldFByb3RvdHlwZU9mLGhyPU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHksZW89T2JqZWN0LnByb3RvdHlwZS5wcm9wZXJ0eUlzRW51bWVyYWJsZTt2YXIgWnI9KGUsdCxyKT0+dCBpbiBlP2RyKGUsdCx7ZW51bWVyYWJsZTohMCxjb25maWd1cmFibGU6ITAsd3JpdGFibGU6ITAsdmFsdWU6cn0pOmVbdF09cixSPShlLHQpPT57Zm9yKHZhciByIGluIHR8fCh0PXt9KSloci5jYWxsKHQscikmJlpyKGUscix0W3JdKTtpZihrdClmb3IodmFyIHIgb2Yga3QodCkpZW8uY2FsbCh0LHIpJiZacihlLHIsdFtyXSk7cmV0dXJuIGV9O3ZhciB0bz0oZSx0KT0+e3ZhciByPXt9O2Zvcih2YXIgbyBpbiBlKWhyLmNhbGwoZSxvKSYmdC5pbmRleE9mKG8pPDAmJihyW29dPWVbb10pO2lmKGUhPW51bGwmJmt0KWZvcih2YXIgbyBvZiBrdChlKSl0LmluZGV4T2Yobyk8MCYmZW8uY2FsbChlLG8pJiYocltvXT1lW29dKTtyZXR1cm4gcn07dmFyIGJyPShlLHQpPT4oKT0+KHR8fGUoKHQ9e2V4cG9ydHM6e319KS5leHBvcnRzLHQpLHQuZXhwb3J0cyk7dmFyIE1pPShlLHQscixvKT0+e2lmKHQmJnR5cGVvZiB0PT0ib2JqZWN0Inx8dHlwZW9mIHQ9PSJmdW5jdGlvbiIpZm9yKGxldCBuIG9mIFRpKHQpKSFoci5jYWxsKGUsbikmJm4hPT1yJiZkcihlLG4se2dldDooKT0+dFtuXSxlbnVtZXJhYmxlOiEobz1TaSh0LG4pKXx8by5lbnVtZXJhYmxlfSk7cmV0dXJuIGV9O3ZhciBIdD0oZSx0LHIpPT4ocj1lIT1udWxsP3dpKE9pKGUpKTp7fSxNaSh0fHwhZXx8IWUuX19lc01vZHVsZT9kcihyLCJkZWZhdWx0Iix7dmFsdWU6ZSxlbnVtZXJhYmxlOiEwfSk6cixlKSk7dmFyIG9vPWJyKCh2cixybyk9PnsoZnVuY3Rpb24oZSx0KXt0eXBlb2YgdnI9PSJvYmplY3QiJiZ0eXBlb2Ygcm8hPSJ1bmRlZmluZWQiP3QoKTp0eXBlb2YgZGVmaW5lPT0iZnVuY3Rpb24iJiZkZWZpbmUuYW1kP2RlZmluZSh0KTp0KCl9KSh2cixmdW5jdGlvbigpeyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiBlKHIpe3ZhciBvPSEwLG49ITEsaT1udWxsLHM9e3RleHQ6ITAsc2VhcmNoOiEwLHVybDohMCx0ZWw6ITAsZW1haWw6ITAscGFzc3dvcmQ6ITAsbnVtYmVyOiEwLGRhdGU6ITAsbW9udGg6ITAsd2VlazohMCx0aW1lOiEwLGRhdGV0aW1lOiEwLCJkYXRldGltZS1sb2NhbCI6ITB9O2Z1bmN0aW9uIGEoQyl7cmV0dXJuISEoQyYmQyE9PWRvY3VtZW50JiZDLm5vZGVOYW1lIT09IkhUTUwiJiZDLm5vZGVOYW1lIT09IkJPRFkiJiYiY2xhc3NMaXN0ImluIEMmJiJjb250YWlucyJpbiBDLmNsYXNzTGlzdCl9ZnVuY3Rpb24gYyhDKXt2YXIgaXQ9Qy50eXBlLE5lPUMudGFnTmFtZTtyZXR1cm4hIShOZT09PSJJTlBVVCImJnNbaXRdJiYhQy5yZWFkT25seXx8TmU9PT0iVEVYVEFSRUEiJiYhQy5yZWFkT25seXx8Qy5pc0NvbnRlbnRFZGl0YWJsZSl9ZnVuY3Rpb24gcChDKXtDLmNsYXNzTGlzdC5jb250YWlucygiZm9jdXMtdmlzaWJsZSIpfHwoQy5jbGFzc0xpc3QuYWRkKCJmb2N1cy12aXNpYmxlIiksQy5zZXRBdHRyaWJ1dGUoImRhdGEtZm9jdXMtdmlzaWJsZS1hZGRlZCIsIiIpKX1mdW5jdGlvbiBsKEMpe0MuaGFzQXR0cmlidXRlKCJkYXRhLWZvY3VzLXZpc2libGUtYWRkZWQiKSYmKEMuY2xhc3NMaXN0LnJlbW92ZSgiZm9jdXMtdmlzaWJsZSIpLEMucmVtb3ZlQXR0cmlidXRlKCJkYXRhLWZvY3VzLXZpc2libGUtYWRkZWQiKSl9ZnVuY3Rpb24gZihDKXtDLm1ldGFLZXl8fEMuYWx0S2V5fHxDLmN0cmxLZXl8fChhKHIuYWN0aXZlRWxlbWVudCkmJnAoci5hY3RpdmVFbGVtZW50KSxvPSEwKX1mdW5jdGlvbiB1KEMpe289ITF9ZnVuY3Rpb24gZChDKXthKEMudGFyZ2V0KSYmKG98fGMoQy50YXJnZXQpKSYmcChDLnRhcmdldCl9ZnVuY3Rpb24gdihDKXthKEMudGFyZ2V0KSYmKEMudGFyZ2V0LmNsYXNzTGlzdC5jb250YWlucygiZm9jdXMtdmlzaWJsZSIpfHxDLnRhcmdldC5oYXNBdHRyaWJ1dGUoImRhdGEtZm9jdXMtdmlzaWJsZS1hZGRlZCIpKSYmKG49ITAsd2luZG93LmNsZWFyVGltZW91dChpKSxpPXdpbmRvdy5zZXRUaW1lb3V0KGZ1bmN0aW9uKCl7bj0hMX0sMTAwKSxsKEMudGFyZ2V0KSl9ZnVuY3Rpb24gYihDKXtkb2N1bWVudC52aXNpYmlsaXR5U3RhdGU9PT0iaGlkZGVuIiYmKG4mJihvPSEwKSx6KCkpfWZ1bmN0aW9uIHooKXtkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCJtb3VzZW1vdmUiLEcpLGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoIm1vdXNlZG93biIsRyksZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigibW91c2V1cCIsRyksZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigicG9pbnRlcm1vdmUiLEcpLGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoInBvaW50ZXJkb3duIixHKSxkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCJwb2ludGVydXAiLEcpLGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoInRvdWNobW92ZSIsRyksZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigidG91Y2hzdGFydCIsRyksZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigidG91Y2hlbmQiLEcpfWZ1bmN0aW9uIEsoKXtkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCJtb3VzZW1vdmUiLEcpLGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoIm1vdXNlZG93biIsRyksZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigibW91c2V1cCIsRyksZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigicG9pbnRlcm1vdmUiLEcpLGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoInBvaW50ZXJkb3duIixHKSxkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCJwb2ludGVydXAiLEcpLGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoInRvdWNobW92ZSIsRyksZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigidG91Y2hzdGFydCIsRyksZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigidG91Y2hlbmQiLEcpfWZ1bmN0aW9uIEcoQyl7Qy50YXJnZXQubm9kZU5hbWUmJkMudGFyZ2V0Lm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk9PT0iaHRtbCJ8fChvPSExLEsoKSl9ZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigia2V5ZG93biIsZiwhMCksZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigibW91c2Vkb3duIix1LCEwKSxkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCJwb2ludGVyZG93biIsdSwhMCksZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigidG91Y2hzdGFydCIsdSwhMCksZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigidmlzaWJpbGl0eWNoYW5nZSIsYiwhMCkseigpLHIuYWRkRXZlbnRMaXN0ZW5lcigiZm9jdXMiLGQsITApLHIuYWRkRXZlbnRMaXN0ZW5lcigiYmx1ciIsdiwhMCksci5ub2RlVHlwZT09PU5vZGUuRE9DVU1FTlRfRlJBR01FTlRfTk9ERSYmci5ob3N0P3IuaG9zdC5zZXRBdHRyaWJ1dGUoImRhdGEtanMtZm9jdXMtdmlzaWJsZSIsIiIpOnIubm9kZVR5cGU9PT1Ob2RlLkRPQ1VNRU5UX05PREUmJihkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY2xhc3NMaXN0LmFkZCgianMtZm9jdXMtdmlzaWJsZSIpLGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5zZXRBdHRyaWJ1dGUoImRhdGEtanMtZm9jdXMtdmlzaWJsZSIsIiIpKX1pZih0eXBlb2Ygd2luZG93IT0idW5kZWZpbmVkIiYmdHlwZW9mIGRvY3VtZW50IT0idW5kZWZpbmVkIil7d2luZG93LmFwcGx5Rm9jdXNWaXNpYmxlUG9seWZpbGw9ZTt2YXIgdDt0cnl7dD1uZXcgQ3VzdG9tRXZlbnQoImZvY3VzLXZpc2libGUtcG9seWZpbGwtcmVhZHkiKX1jYXRjaChyKXt0PWRvY3VtZW50LmNyZWF0ZUV2ZW50KCJDdXN0b21FdmVudCIpLHQuaW5pdEN1c3RvbUV2ZW50KCJmb2N1cy12aXNpYmxlLXBvbHlmaWxsLXJlYWR5IiwhMSwhMSx7fSl9d2luZG93LmRpc3BhdGNoRXZlbnQodCl9dHlwZW9mIGRvY3VtZW50IT0idW5kZWZpbmVkIiYmZShkb2N1bWVudCl9KX0pO3ZhciB6cj1icigoT3QsVnIpPT57LyohCiAqIGNsaXBib2FyZC5qcyB2Mi4wLjExCiAqIGh0dHBzOi8vY2xpcGJvYXJkanMuY29tLwogKgogKiBMaWNlbnNlZCBNSVQgwqkgWmVubyBSb2NoYQogKi8oZnVuY3Rpb24odCxyKXt0eXBlb2YgT3Q9PSJvYmplY3QiJiZ0eXBlb2YgVnI9PSJvYmplY3QiP1ZyLmV4cG9ydHM9cigpOnR5cGVvZiBkZWZpbmU9PSJmdW5jdGlvbiImJmRlZmluZS5hbWQ/ZGVmaW5lKFtdLHIpOnR5cGVvZiBPdD09Im9iamVjdCI/T3QuQ2xpcGJvYXJkSlM9cigpOnQuQ2xpcGJvYXJkSlM9cigpfSkoT3QsZnVuY3Rpb24oKXtyZXR1cm4gZnVuY3Rpb24oKXt2YXIgZT17Njg2OmZ1bmN0aW9uKG8sbixpKXsidXNlIHN0cmljdCI7aS5kKG4se2RlZmF1bHQ6ZnVuY3Rpb24oKXtyZXR1cm4gRWl9fSk7dmFyIHM9aSgyNzkpLGE9aS5uKHMpLGM9aSgzNzApLHA9aS5uKGMpLGw9aSg4MTcpLGY9aS5uKGwpO2Z1bmN0aW9uIHUoVSl7dHJ5e3JldHVybiBkb2N1bWVudC5leGVjQ29tbWFuZChVKX1jYXRjaChPKXtyZXR1cm4hMX19dmFyIGQ9ZnVuY3Rpb24oTyl7dmFyIFM9ZigpKE8pO3JldHVybiB1KCJjdXQiKSxTfSx2PWQ7ZnVuY3Rpb24gYihVKXt2YXIgTz1kb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuZ2V0QXR0cmlidXRlKCJkaXIiKT09PSJydGwiLFM9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgidGV4dGFyZWEiKTtTLnN0eWxlLmZvbnRTaXplPSIxMnB0IixTLnN0eWxlLmJvcmRlcj0iMCIsUy5zdHlsZS5wYWRkaW5nPSIwIixTLnN0eWxlLm1hcmdpbj0iMCIsUy5zdHlsZS5wb3NpdGlvbj0iYWJzb2x1dGUiLFMuc3R5bGVbTz8icmlnaHQiOiJsZWZ0Il09Ii05OTk5cHgiO3ZhciAkPXdpbmRvdy5wYWdlWU9mZnNldHx8ZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LnNjcm9sbFRvcDtyZXR1cm4gUy5zdHlsZS50b3A9IiIuY29uY2F0KCQsInB4IiksUy5zZXRBdHRyaWJ1dGUoInJlYWRvbmx5IiwiIiksUy52YWx1ZT1VLFN9dmFyIHo9ZnVuY3Rpb24oTyxTKXt2YXIgJD1iKE8pO1MuY29udGFpbmVyLmFwcGVuZENoaWxkKCQpO3ZhciBGPWYoKSgkKTtyZXR1cm4gdSgiY29weSIpLCQucmVtb3ZlKCksRn0sSz1mdW5jdGlvbihPKXt2YXIgUz1hcmd1bWVudHMubGVuZ3RoPjEmJmFyZ3VtZW50c1sxXSE9PXZvaWQgMD9hcmd1bWVudHNbMV06e2NvbnRhaW5lcjpkb2N1bWVudC5ib2R5fSwkPSIiO3JldHVybiB0eXBlb2YgTz09InN0cmluZyI/JD16KE8sUyk6TyBpbnN0YW5jZW9mIEhUTUxJbnB1dEVsZW1lbnQmJiFbInRleHQiLCJzZWFyY2giLCJ1cmwiLCJ0ZWwiLCJwYXNzd29yZCJdLmluY2x1ZGVzKE89PW51bGw/dm9pZCAwOk8udHlwZSk/JD16KE8udmFsdWUsUyk6KCQ9ZigpKE8pLHUoImNvcHkiKSksJH0sRz1LO2Z1bmN0aW9uIEMoVSl7IkBiYWJlbC9oZWxwZXJzIC0gdHlwZW9mIjtyZXR1cm4gdHlwZW9mIFN5bWJvbD09ImZ1bmN0aW9uIiYmdHlwZW9mIFN5bWJvbC5pdGVyYXRvcj09InN5bWJvbCI/Qz1mdW5jdGlvbihTKXtyZXR1cm4gdHlwZW9mIFN9OkM9ZnVuY3Rpb24oUyl7cmV0dXJuIFMmJnR5cGVvZiBTeW1ib2w9PSJmdW5jdGlvbiImJlMuY29uc3RydWN0b3I9PT1TeW1ib2wmJlMhPT1TeW1ib2wucHJvdG90eXBlPyJzeW1ib2wiOnR5cGVvZiBTfSxDKFUpfXZhciBpdD1mdW5jdGlvbigpe3ZhciBPPWFyZ3VtZW50cy5sZW5ndGg+MCYmYXJndW1lbnRzWzBdIT09dm9pZCAwP2FyZ3VtZW50c1swXTp7fSxTPU8uYWN0aW9uLCQ9Uz09PXZvaWQgMD8iY29weSI6UyxGPU8uY29udGFpbmVyLFE9Ty50YXJnZXQsX2U9Ty50ZXh0O2lmKCQhPT0iY29weSImJiQhPT0iY3V0Iil0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgImFjdGlvbiIgdmFsdWUsIHVzZSBlaXRoZXIgImNvcHkiIG9yICJjdXQiJyk7aWYoUSE9PXZvaWQgMClpZihRJiZDKFEpPT09Im9iamVjdCImJlEubm9kZVR5cGU9PT0xKXtpZigkPT09ImNvcHkiJiZRLmhhc0F0dHJpYnV0ZSgiZGlzYWJsZWQiKSl0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgInRhcmdldCIgYXR0cmlidXRlLiBQbGVhc2UgdXNlICJyZWFkb25seSIgaW5zdGVhZCBvZiAiZGlzYWJsZWQiIGF0dHJpYnV0ZScpO2lmKCQ9PT0iY3V0IiYmKFEuaGFzQXR0cmlidXRlKCJyZWFkb25seSIpfHxRLmhhc0F0dHJpYnV0ZSgiZGlzYWJsZWQiKSkpdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkICJ0YXJnZXQiIGF0dHJpYnV0ZS4gWW91IGNhbid0IGN1dCB0ZXh0IGZyb20gZWxlbWVudHMgd2l0aCAicmVhZG9ubHkiIG9yICJkaXNhYmxlZCIgYXR0cmlidXRlc2ApfWVsc2UgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkICJ0YXJnZXQiIHZhbHVlLCB1c2UgYSB2YWxpZCBFbGVtZW50Jyk7aWYoX2UpcmV0dXJuIEcoX2Use2NvbnRhaW5lcjpGfSk7aWYoUSlyZXR1cm4gJD09PSJjdXQiP3YoUSk6RyhRLHtjb250YWluZXI6Rn0pfSxOZT1pdDtmdW5jdGlvbiBQZShVKXsiQGJhYmVsL2hlbHBlcnMgLSB0eXBlb2YiO3JldHVybiB0eXBlb2YgU3ltYm9sPT0iZnVuY3Rpb24iJiZ0eXBlb2YgU3ltYm9sLml0ZXJhdG9yPT0ic3ltYm9sIj9QZT1mdW5jdGlvbihTKXtyZXR1cm4gdHlwZW9mIFN9OlBlPWZ1bmN0aW9uKFMpe3JldHVybiBTJiZ0eXBlb2YgU3ltYm9sPT0iZnVuY3Rpb24iJiZTLmNvbnN0cnVjdG9yPT09U3ltYm9sJiZTIT09U3ltYm9sLnByb3RvdHlwZT8ic3ltYm9sIjp0eXBlb2YgU30sUGUoVSl9ZnVuY3Rpb24gdWkoVSxPKXtpZighKFUgaW5zdGFuY2VvZiBPKSl0aHJvdyBuZXcgVHlwZUVycm9yKCJDYW5ub3QgY2FsbCBhIGNsYXNzIGFzIGEgZnVuY3Rpb24iKX1mdW5jdGlvbiBYcihVLE8pe2Zvcih2YXIgUz0wO1M8Ty5sZW5ndGg7UysrKXt2YXIgJD1PW1NdOyQuZW51bWVyYWJsZT0kLmVudW1lcmFibGV8fCExLCQuY29uZmlndXJhYmxlPSEwLCJ2YWx1ZSJpbiAkJiYoJC53cml0YWJsZT0hMCksT2JqZWN0LmRlZmluZVByb3BlcnR5KFUsJC5rZXksJCl9fWZ1bmN0aW9uIGRpKFUsTyxTKXtyZXR1cm4gTyYmWHIoVS5wcm90b3R5cGUsTyksUyYmWHIoVSxTKSxVfWZ1bmN0aW9uIGhpKFUsTyl7aWYodHlwZW9mIE8hPSJmdW5jdGlvbiImJk8hPT1udWxsKXRocm93IG5ldyBUeXBlRXJyb3IoIlN1cGVyIGV4cHJlc3Npb24gbXVzdCBlaXRoZXIgYmUgbnVsbCBvciBhIGZ1bmN0aW9uIik7VS5wcm90b3R5cGU9T2JqZWN0LmNyZWF0ZShPJiZPLnByb3RvdHlwZSx7Y29uc3RydWN0b3I6e3ZhbHVlOlUsd3JpdGFibGU6ITAsY29uZmlndXJhYmxlOiEwfX0pLE8mJmZyKFUsTyl9ZnVuY3Rpb24gZnIoVSxPKXtyZXR1cm4gZnI9T2JqZWN0LnNldFByb3RvdHlwZU9mfHxmdW5jdGlvbigkLEYpe3JldHVybiAkLl9fcHJvdG9fXz1GLCR9LGZyKFUsTyl9ZnVuY3Rpb24gYmkoVSl7dmFyIE89eGkoKTtyZXR1cm4gZnVuY3Rpb24oKXt2YXIgJD1BdChVKSxGO2lmKE8pe3ZhciBRPUF0KHRoaXMpLmNvbnN0cnVjdG9yO0Y9UmVmbGVjdC5jb25zdHJ1Y3QoJCxhcmd1bWVudHMsUSl9ZWxzZSBGPSQuYXBwbHkodGhpcyxhcmd1bWVudHMpO3JldHVybiB2aSh0aGlzLEYpfX1mdW5jdGlvbiB2aShVLE8pe3JldHVybiBPJiYoUGUoTyk9PT0ib2JqZWN0Inx8dHlwZW9mIE89PSJmdW5jdGlvbiIpP086Z2koVSl9ZnVuY3Rpb24gZ2koVSl7aWYoVT09PXZvaWQgMCl0aHJvdyBuZXcgUmVmZXJlbmNlRXJyb3IoInRoaXMgaGFzbid0IGJlZW4gaW5pdGlhbGlzZWQgLSBzdXBlcigpIGhhc24ndCBiZWVuIGNhbGxlZCIpO3JldHVybiBVfWZ1bmN0aW9uIHhpKCl7aWYodHlwZW9mIFJlZmxlY3Q9PSJ1bmRlZmluZWQifHwhUmVmbGVjdC5jb25zdHJ1Y3R8fFJlZmxlY3QuY29uc3RydWN0LnNoYW0pcmV0dXJuITE7aWYodHlwZW9mIFByb3h5PT0iZnVuY3Rpb24iKXJldHVybiEwO3RyeXtyZXR1cm4gRGF0ZS5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChSZWZsZWN0LmNvbnN0cnVjdChEYXRlLFtdLGZ1bmN0aW9uKCl7fSkpLCEwfWNhdGNoKFUpe3JldHVybiExfX1mdW5jdGlvbiBBdChVKXtyZXR1cm4gQXQ9T2JqZWN0LnNldFByb3RvdHlwZU9mP09iamVjdC5nZXRQcm90b3R5cGVPZjpmdW5jdGlvbihTKXtyZXR1cm4gUy5fX3Byb3RvX198fE9iamVjdC5nZXRQcm90b3R5cGVPZihTKX0sQXQoVSl9ZnVuY3Rpb24gdXIoVSxPKXt2YXIgUz0iZGF0YS1jbGlwYm9hcmQtIi5jb25jYXQoVSk7aWYoTy5oYXNBdHRyaWJ1dGUoUykpcmV0dXJuIE8uZ2V0QXR0cmlidXRlKFMpfXZhciB5aT1mdW5jdGlvbihVKXtoaShTLFUpO3ZhciBPPWJpKFMpO2Z1bmN0aW9uIFMoJCxGKXt2YXIgUTtyZXR1cm4gdWkodGhpcyxTKSxRPU8uY2FsbCh0aGlzKSxRLnJlc29sdmVPcHRpb25zKEYpLFEubGlzdGVuQ2xpY2soJCksUX1yZXR1cm4gZGkoUyxbe2tleToicmVzb2x2ZU9wdGlvbnMiLHZhbHVlOmZ1bmN0aW9uKCl7dmFyIEY9YXJndW1lbnRzLmxlbmd0aD4wJiZhcmd1bWVudHNbMF0hPT12b2lkIDA/YXJndW1lbnRzWzBdOnt9O3RoaXMuYWN0aW9uPXR5cGVvZiBGLmFjdGlvbj09ImZ1bmN0aW9uIj9GLmFjdGlvbjp0aGlzLmRlZmF1bHRBY3Rpb24sdGhpcy50YXJnZXQ9dHlwZW9mIEYudGFyZ2V0PT0iZnVuY3Rpb24iP0YudGFyZ2V0OnRoaXMuZGVmYXVsdFRhcmdldCx0aGlzLnRleHQ9dHlwZW9mIEYudGV4dD09ImZ1bmN0aW9uIj9GLnRleHQ6dGhpcy5kZWZhdWx0VGV4dCx0aGlzLmNvbnRhaW5lcj1QZShGLmNvbnRhaW5lcik9PT0ib2JqZWN0Ij9GLmNvbnRhaW5lcjpkb2N1bWVudC5ib2R5fX0se2tleToibGlzdGVuQ2xpY2siLHZhbHVlOmZ1bmN0aW9uKEYpe3ZhciBRPXRoaXM7dGhpcy5saXN0ZW5lcj1wKCkoRiwiY2xpY2siLGZ1bmN0aW9uKF9lKXtyZXR1cm4gUS5vbkNsaWNrKF9lKX0pfX0se2tleToib25DbGljayIsdmFsdWU6ZnVuY3Rpb24oRil7dmFyIFE9Ri5kZWxlZ2F0ZVRhcmdldHx8Ri5jdXJyZW50VGFyZ2V0LF9lPXRoaXMuYWN0aW9uKFEpfHwiY29weSIsQ3Q9TmUoe2FjdGlvbjpfZSxjb250YWluZXI6dGhpcy5jb250YWluZXIsdGFyZ2V0OnRoaXMudGFyZ2V0KFEpLHRleHQ6dGhpcy50ZXh0KFEpfSk7dGhpcy5lbWl0KEN0PyJzdWNjZXNzIjoiZXJyb3IiLHthY3Rpb246X2UsdGV4dDpDdCx0cmlnZ2VyOlEsY2xlYXJTZWxlY3Rpb246ZnVuY3Rpb24oKXtRJiZRLmZvY3VzKCksd2luZG93LmdldFNlbGVjdGlvbigpLnJlbW92ZUFsbFJhbmdlcygpfX0pfX0se2tleToiZGVmYXVsdEFjdGlvbiIsdmFsdWU6ZnVuY3Rpb24oRil7cmV0dXJuIHVyKCJhY3Rpb24iLEYpfX0se2tleToiZGVmYXVsdFRhcmdldCIsdmFsdWU6ZnVuY3Rpb24oRil7dmFyIFE9dXIoInRhcmdldCIsRik7aWYoUSlyZXR1cm4gZG9jdW1lbnQucXVlcnlTZWxlY3RvcihRKX19LHtrZXk6ImRlZmF1bHRUZXh0Iix2YWx1ZTpmdW5jdGlvbihGKXtyZXR1cm4gdXIoInRleHQiLEYpfX0se2tleToiZGVzdHJveSIsdmFsdWU6ZnVuY3Rpb24oKXt0aGlzLmxpc3RlbmVyLmRlc3Ryb3koKX19XSxbe2tleToiY29weSIsdmFsdWU6ZnVuY3Rpb24oRil7dmFyIFE9YXJndW1lbnRzLmxlbmd0aD4xJiZhcmd1bWVudHNbMV0hPT12b2lkIDA/YXJndW1lbnRzWzFdOntjb250YWluZXI6ZG9jdW1lbnQuYm9keX07cmV0dXJuIEcoRixRKX19LHtrZXk6ImN1dCIsdmFsdWU6ZnVuY3Rpb24oRil7cmV0dXJuIHYoRil9fSx7a2V5OiJpc1N1cHBvcnRlZCIsdmFsdWU6ZnVuY3Rpb24oKXt2YXIgRj1hcmd1bWVudHMubGVuZ3RoPjAmJmFyZ3VtZW50c1swXSE9PXZvaWQgMD9hcmd1bWVudHNbMF06WyJjb3B5IiwiY3V0Il0sUT10eXBlb2YgRj09InN0cmluZyI/W0ZdOkYsX2U9ISFkb2N1bWVudC5xdWVyeUNvbW1hbmRTdXBwb3J0ZWQ7cmV0dXJuIFEuZm9yRWFjaChmdW5jdGlvbihDdCl7X2U9X2UmJiEhZG9jdW1lbnQucXVlcnlDb21tYW5kU3VwcG9ydGVkKEN0KX0pLF9lfX1dKSxTfShhKCkpLEVpPXlpfSw4Mjg6ZnVuY3Rpb24obyl7dmFyIG49OTtpZih0eXBlb2YgRWxlbWVudCE9InVuZGVmaW5lZCImJiFFbGVtZW50LnByb3RvdHlwZS5tYXRjaGVzKXt2YXIgaT1FbGVtZW50LnByb3RvdHlwZTtpLm1hdGNoZXM9aS5tYXRjaGVzU2VsZWN0b3J8fGkubW96TWF0Y2hlc1NlbGVjdG9yfHxpLm1zTWF0Y2hlc1NlbGVjdG9yfHxpLm9NYXRjaGVzU2VsZWN0b3J8fGkud2Via2l0TWF0Y2hlc1NlbGVjdG9yfWZ1bmN0aW9uIHMoYSxjKXtmb3IoO2EmJmEubm9kZVR5cGUhPT1uOyl7aWYodHlwZW9mIGEubWF0Y2hlcz09ImZ1bmN0aW9uIiYmYS5tYXRjaGVzKGMpKXJldHVybiBhO2E9YS5wYXJlbnROb2RlfX1vLmV4cG9ydHM9c30sNDM4OmZ1bmN0aW9uKG8sbixpKXt2YXIgcz1pKDgyOCk7ZnVuY3Rpb24gYShsLGYsdSxkLHYpe3ZhciBiPXAuYXBwbHkodGhpcyxhcmd1bWVudHMpO3JldHVybiBsLmFkZEV2ZW50TGlzdGVuZXIodSxiLHYpLHtkZXN0cm95OmZ1bmN0aW9uKCl7bC5yZW1vdmVFdmVudExpc3RlbmVyKHUsYix2KX19fWZ1bmN0aW9uIGMobCxmLHUsZCx2KXtyZXR1cm4gdHlwZW9mIGwuYWRkRXZlbnRMaXN0ZW5lcj09ImZ1bmN0aW9uIj9hLmFwcGx5KG51bGwsYXJndW1lbnRzKTp0eXBlb2YgdT09ImZ1bmN0aW9uIj9hLmJpbmQobnVsbCxkb2N1bWVudCkuYXBwbHkobnVsbCxhcmd1bWVudHMpOih0eXBlb2YgbD09InN0cmluZyImJihsPWRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwobCkpLEFycmF5LnByb3RvdHlwZS5tYXAuY2FsbChsLGZ1bmN0aW9uKGIpe3JldHVybiBhKGIsZix1LGQsdil9KSl9ZnVuY3Rpb24gcChsLGYsdSxkKXtyZXR1cm4gZnVuY3Rpb24odil7di5kZWxlZ2F0ZVRhcmdldD1zKHYudGFyZ2V0LGYpLHYuZGVsZWdhdGVUYXJnZXQmJmQuY2FsbChsLHYpfX1vLmV4cG9ydHM9Y30sODc5OmZ1bmN0aW9uKG8sbil7bi5ub2RlPWZ1bmN0aW9uKGkpe3JldHVybiBpIT09dm9pZCAwJiZpIGluc3RhbmNlb2YgSFRNTEVsZW1lbnQmJmkubm9kZVR5cGU9PT0xfSxuLm5vZGVMaXN0PWZ1bmN0aW9uKGkpe3ZhciBzPU9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChpKTtyZXR1cm4gaSE9PXZvaWQgMCYmKHM9PT0iW29iamVjdCBOb2RlTGlzdF0ifHxzPT09IltvYmplY3QgSFRNTENvbGxlY3Rpb25dIikmJiJsZW5ndGgiaW4gaSYmKGkubGVuZ3RoPT09MHx8bi5ub2RlKGlbMF0pKX0sbi5zdHJpbmc9ZnVuY3Rpb24oaSl7cmV0dXJuIHR5cGVvZiBpPT0ic3RyaW5nInx8aSBpbnN0YW5jZW9mIFN0cmluZ30sbi5mbj1mdW5jdGlvbihpKXt2YXIgcz1PYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoaSk7cmV0dXJuIHM9PT0iW29iamVjdCBGdW5jdGlvbl0ifX0sMzcwOmZ1bmN0aW9uKG8sbixpKXt2YXIgcz1pKDg3OSksYT1pKDQzOCk7ZnVuY3Rpb24gYyh1LGQsdil7aWYoIXUmJiFkJiYhdil0aHJvdyBuZXcgRXJyb3IoIk1pc3NpbmcgcmVxdWlyZWQgYXJndW1lbnRzIik7aWYoIXMuc3RyaW5nKGQpKXRocm93IG5ldyBUeXBlRXJyb3IoIlNlY29uZCBhcmd1bWVudCBtdXN0IGJlIGEgU3RyaW5nIik7aWYoIXMuZm4odikpdGhyb3cgbmV3IFR5cGVFcnJvcigiVGhpcmQgYXJndW1lbnQgbXVzdCBiZSBhIEZ1bmN0aW9uIik7aWYocy5ub2RlKHUpKXJldHVybiBwKHUsZCx2KTtpZihzLm5vZGVMaXN0KHUpKXJldHVybiBsKHUsZCx2KTtpZihzLnN0cmluZyh1KSlyZXR1cm4gZih1LGQsdik7dGhyb3cgbmV3IFR5cGVFcnJvcigiRmlyc3QgYXJndW1lbnQgbXVzdCBiZSBhIFN0cmluZywgSFRNTEVsZW1lbnQsIEhUTUxDb2xsZWN0aW9uLCBvciBOb2RlTGlzdCIpfWZ1bmN0aW9uIHAodSxkLHYpe3JldHVybiB1LmFkZEV2ZW50TGlzdGVuZXIoZCx2KSx7ZGVzdHJveTpmdW5jdGlvbigpe3UucmVtb3ZlRXZlbnRMaXN0ZW5lcihkLHYpfX19ZnVuY3Rpb24gbCh1LGQsdil7cmV0dXJuIEFycmF5LnByb3RvdHlwZS5mb3JFYWNoLmNhbGwodSxmdW5jdGlvbihiKXtiLmFkZEV2ZW50TGlzdGVuZXIoZCx2KX0pLHtkZXN0cm95OmZ1bmN0aW9uKCl7QXJyYXkucHJvdG90eXBlLmZvckVhY2guY2FsbCh1LGZ1bmN0aW9uKGIpe2IucmVtb3ZlRXZlbnRMaXN0ZW5lcihkLHYpfSl9fX1mdW5jdGlvbiBmKHUsZCx2KXtyZXR1cm4gYShkb2N1bWVudC5ib2R5LHUsZCx2KX1vLmV4cG9ydHM9Y30sODE3OmZ1bmN0aW9uKG8pe2Z1bmN0aW9uIG4oaSl7dmFyIHM7aWYoaS5ub2RlTmFtZT09PSJTRUxFQ1QiKWkuZm9jdXMoKSxzPWkudmFsdWU7ZWxzZSBpZihpLm5vZGVOYW1lPT09IklOUFVUInx8aS5ub2RlTmFtZT09PSJURVhUQVJFQSIpe3ZhciBhPWkuaGFzQXR0cmlidXRlKCJyZWFkb25seSIpO2F8fGkuc2V0QXR0cmlidXRlKCJyZWFkb25seSIsIiIpLGkuc2VsZWN0KCksaS5zZXRTZWxlY3Rpb25SYW5nZSgwLGkudmFsdWUubGVuZ3RoKSxhfHxpLnJlbW92ZUF0dHJpYnV0ZSgicmVhZG9ubHkiKSxzPWkudmFsdWV9ZWxzZXtpLmhhc0F0dHJpYnV0ZSgiY29udGVudGVkaXRhYmxlIikmJmkuZm9jdXMoKTt2YXIgYz13aW5kb3cuZ2V0U2VsZWN0aW9uKCkscD1kb2N1bWVudC5jcmVhdGVSYW5nZSgpO3Auc2VsZWN0Tm9kZUNvbnRlbnRzKGkpLGMucmVtb3ZlQWxsUmFuZ2VzKCksYy5hZGRSYW5nZShwKSxzPWMudG9TdHJpbmcoKX1yZXR1cm4gc31vLmV4cG9ydHM9bn0sMjc5OmZ1bmN0aW9uKG8pe2Z1bmN0aW9uIG4oKXt9bi5wcm90b3R5cGU9e29uOmZ1bmN0aW9uKGkscyxhKXt2YXIgYz10aGlzLmV8fCh0aGlzLmU9e30pO3JldHVybihjW2ldfHwoY1tpXT1bXSkpLnB1c2goe2ZuOnMsY3R4OmF9KSx0aGlzfSxvbmNlOmZ1bmN0aW9uKGkscyxhKXt2YXIgYz10aGlzO2Z1bmN0aW9uIHAoKXtjLm9mZihpLHApLHMuYXBwbHkoYSxhcmd1bWVudHMpfXJldHVybiBwLl89cyx0aGlzLm9uKGkscCxhKX0sZW1pdDpmdW5jdGlvbihpKXt2YXIgcz1bXS5zbGljZS5jYWxsKGFyZ3VtZW50cywxKSxhPSgodGhpcy5lfHwodGhpcy5lPXt9KSlbaV18fFtdKS5zbGljZSgpLGM9MCxwPWEubGVuZ3RoO2ZvcihjO2M8cDtjKyspYVtjXS5mbi5hcHBseShhW2NdLmN0eCxzKTtyZXR1cm4gdGhpc30sb2ZmOmZ1bmN0aW9uKGkscyl7dmFyIGE9dGhpcy5lfHwodGhpcy5lPXt9KSxjPWFbaV0scD1bXTtpZihjJiZzKWZvcih2YXIgbD0wLGY9Yy5sZW5ndGg7bDxmO2wrKyljW2xdLmZuIT09cyYmY1tsXS5mbi5fIT09cyYmcC5wdXNoKGNbbF0pO3JldHVybiBwLmxlbmd0aD9hW2ldPXA6ZGVsZXRlIGFbaV0sdGhpc319LG8uZXhwb3J0cz1uLG8uZXhwb3J0cy5UaW55RW1pdHRlcj1ufX0sdD17fTtmdW5jdGlvbiByKG8pe2lmKHRbb10pcmV0dXJuIHRbb10uZXhwb3J0czt2YXIgbj10W29dPXtleHBvcnRzOnt9fTtyZXR1cm4gZVtvXShuLG4uZXhwb3J0cyxyKSxuLmV4cG9ydHN9cmV0dXJuIGZ1bmN0aW9uKCl7ci5uPWZ1bmN0aW9uKG8pe3ZhciBuPW8mJm8uX19lc01vZHVsZT9mdW5jdGlvbigpe3JldHVybiBvLmRlZmF1bHR9OmZ1bmN0aW9uKCl7cmV0dXJuIG99O3JldHVybiByLmQobix7YTpufSksbn19KCksZnVuY3Rpb24oKXtyLmQ9ZnVuY3Rpb24obyxuKXtmb3IodmFyIGkgaW4gbilyLm8obixpKSYmIXIubyhvLGkpJiZPYmplY3QuZGVmaW5lUHJvcGVydHkobyxpLHtlbnVtZXJhYmxlOiEwLGdldDpuW2ldfSl9fSgpLGZ1bmN0aW9uKCl7ci5vPWZ1bmN0aW9uKG8sbil7cmV0dXJuIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvLG4pfX0oKSxyKDY4Nil9KCkuZGVmYXVsdH0pfSk7dmFyIE5uPWJyKChHRSxVbik9PnsidXNlIHN0cmljdCI7LyohCiAqIGVzY2FwZS1odG1sCiAqIENvcHlyaWdodChjKSAyMDEyLTIwMTMgVEogSG9sb3dheWNodWsKICogQ29weXJpZ2h0KGMpIDIwMTUgQW5kcmVhcyBMdWJiZQogKiBDb3B5cmlnaHQoYykgMjAxNSBUaWFuY2hlbmcgIlRpbW90aHkiIEd1CiAqIE1JVCBMaWNlbnNlZAogKi92YXIgSGE9L1siJyY8Pl0vO1VuLmV4cG9ydHM9JGE7ZnVuY3Rpb24gJGEoZSl7dmFyIHQ9IiIrZSxyPUhhLmV4ZWModCk7aWYoIXIpcmV0dXJuIHQ7dmFyIG8sbj0iIixpPTAscz0wO2ZvcihpPXIuaW5kZXg7aTx0Lmxlbmd0aDtpKyspe3N3aXRjaCh0LmNoYXJDb2RlQXQoaSkpe2Nhc2UgMzQ6bz0iJnF1b3Q7IjticmVhaztjYXNlIDM4Om89IiZhbXA7IjticmVhaztjYXNlIDM5Om89IiYjMzk7IjticmVhaztjYXNlIDYwOm89IiZsdDsiO2JyZWFrO2Nhc2UgNjI6bz0iJmd0OyI7YnJlYWs7ZGVmYXVsdDpjb250aW51ZX1zIT09aSYmKG4rPXQuc3Vic3RyaW5nKHMsaSkpLHM9aSsxLG4rPW99cmV0dXJuIHMhPT1pP24rdC5zdWJzdHJpbmcocyxpKTpufX0pO3ZhciBUTz1IdChvbygpKTsvKiEgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioKQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uCgpQZXJtaXNzaW9uIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBhbmQvb3IgZGlzdHJpYnV0ZSB0aGlzIHNvZnR3YXJlIGZvciBhbnkKcHVycG9zZSB3aXRoIG9yIHdpdGhvdXQgZmVlIGlzIGhlcmVieSBncmFudGVkLgoKVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEICJBUyBJUyIgQU5EIFRIRSBBVVRIT1IgRElTQ0xBSU1TIEFMTCBXQVJSQU5USUVTIFdJVEgKUkVHQVJEIFRPIFRISVMgU09GVFdBUkUgSU5DTFVESU5HIEFMTCBJTVBMSUVEIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZCkFORCBGSVRORVNTLiBJTiBOTyBFVkVOVCBTSEFMTCBUSEUgQVVUSE9SIEJFIExJQUJMRSBGT1IgQU5ZIFNQRUNJQUwsIERJUkVDVCwKSU5ESVJFQ1QsIE9SIENPTlNFUVVFTlRJQUwgREFNQUdFUyBPUiBBTlkgREFNQUdFUyBXSEFUU09FVkVSIFJFU1VMVElORyBGUk9NCkxPU1MgT0YgVVNFLCBEQVRBIE9SIFBST0ZJVFMsIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBORUdMSUdFTkNFIE9SCk9USEVSIFRPUlRJT1VTIEFDVElPTiwgQVJJU0lORyBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBVU0UgT1IKUEVSRk9STUFOQ0UgT0YgVEhJUyBTT0ZUV0FSRS4KKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiogKi92YXIgZ3I9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gZ3I9T2JqZWN0LnNldFByb3RvdHlwZU9mfHx7X19wcm90b19fOltdfWluc3RhbmNlb2YgQXJyYXkmJmZ1bmN0aW9uKHIsbyl7ci5fX3Byb3RvX189b318fGZ1bmN0aW9uKHIsbyl7Zm9yKHZhciBuIGluIG8pT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG8sbikmJihyW25dPW9bbl0pfSxncihlLHQpfTtmdW5jdGlvbiBpZShlLHQpe2lmKHR5cGVvZiB0IT0iZnVuY3Rpb24iJiZ0IT09bnVsbCl0aHJvdyBuZXcgVHlwZUVycm9yKCJDbGFzcyBleHRlbmRzIHZhbHVlICIrU3RyaW5nKHQpKyIgaXMgbm90IGEgY29uc3RydWN0b3Igb3IgbnVsbCIpO2dyKGUsdCk7ZnVuY3Rpb24gcigpe3RoaXMuY29uc3RydWN0b3I9ZX1lLnByb3RvdHlwZT10PT09bnVsbD9PYmplY3QuY3JlYXRlKHQpOihyLnByb3RvdHlwZT10LnByb3RvdHlwZSxuZXcgcil9ZnVuY3Rpb24gbm8oZSx0LHIsbyl7ZnVuY3Rpb24gbihpKXtyZXR1cm4gaSBpbnN0YW5jZW9mIHI/aTpuZXcgcihmdW5jdGlvbihzKXtzKGkpfSl9cmV0dXJuIG5ldyhyfHwocj1Qcm9taXNlKSkoZnVuY3Rpb24oaSxzKXtmdW5jdGlvbiBhKGwpe3RyeXtwKG8ubmV4dChsKSl9Y2F0Y2goZil7cyhmKX19ZnVuY3Rpb24gYyhsKXt0cnl7cChvLnRocm93KGwpKX1jYXRjaChmKXtzKGYpfX1mdW5jdGlvbiBwKGwpe2wuZG9uZT9pKGwudmFsdWUpOm4obC52YWx1ZSkudGhlbihhLGMpfXAoKG89by5hcHBseShlLHR8fFtdKSkubmV4dCgpKX0pfWZ1bmN0aW9uICR0KGUsdCl7dmFyIHI9e2xhYmVsOjAsc2VudDpmdW5jdGlvbigpe2lmKGlbMF0mMSl0aHJvdyBpWzFdO3JldHVybiBpWzFdfSx0cnlzOltdLG9wczpbXX0sbyxuLGkscztyZXR1cm4gcz17bmV4dDphKDApLHRocm93OmEoMSkscmV0dXJuOmEoMil9LHR5cGVvZiBTeW1ib2w9PSJmdW5jdGlvbiImJihzW1N5bWJvbC5pdGVyYXRvcl09ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc30pLHM7ZnVuY3Rpb24gYShwKXtyZXR1cm4gZnVuY3Rpb24obCl7cmV0dXJuIGMoW3AsbF0pfX1mdW5jdGlvbiBjKHApe2lmKG8pdGhyb3cgbmV3IFR5cGVFcnJvcigiR2VuZXJhdG9yIGlzIGFscmVhZHkgZXhlY3V0aW5nLiIpO2Zvcig7cjspdHJ5e2lmKG89MSxuJiYoaT1wWzBdJjI/bi5yZXR1cm46cFswXT9uLnRocm93fHwoKGk9bi5yZXR1cm4pJiZpLmNhbGwobiksMCk6bi5uZXh0KSYmIShpPWkuY2FsbChuLHBbMV0pKS5kb25lKXJldHVybiBpO3N3aXRjaChuPTAsaSYmKHA9W3BbMF0mMixpLnZhbHVlXSkscFswXSl7Y2FzZSAwOmNhc2UgMTppPXA7YnJlYWs7Y2FzZSA0OnJldHVybiByLmxhYmVsKysse3ZhbHVlOnBbMV0sZG9uZTohMX07Y2FzZSA1OnIubGFiZWwrKyxuPXBbMV0scD1bMF07Y29udGludWU7Y2FzZSA3OnA9ci5vcHMucG9wKCksci50cnlzLnBvcCgpO2NvbnRpbnVlO2RlZmF1bHQ6aWYoaT1yLnRyeXMsIShpPWkubGVuZ3RoPjAmJmlbaS5sZW5ndGgtMV0pJiYocFswXT09PTZ8fHBbMF09PT0yKSl7cj0wO2NvbnRpbnVlfWlmKHBbMF09PT0zJiYoIWl8fHBbMV0+aVswXSYmcFsxXTxpWzNdKSl7ci5sYWJlbD1wWzFdO2JyZWFrfWlmKHBbMF09PT02JiZyLmxhYmVsPGlbMV0pe3IubGFiZWw9aVsxXSxpPXA7YnJlYWt9aWYoaSYmci5sYWJlbDxpWzJdKXtyLmxhYmVsPWlbMl0sci5vcHMucHVzaChwKTticmVha31pWzJdJiZyLm9wcy5wb3AoKSxyLnRyeXMucG9wKCk7Y29udGludWV9cD10LmNhbGwoZSxyKX1jYXRjaChsKXtwPVs2LGxdLG49MH1maW5hbGx5e289aT0wfWlmKHBbMF0mNSl0aHJvdyBwWzFdO3JldHVybnt2YWx1ZTpwWzBdP3BbMV06dm9pZCAwLGRvbmU6ITB9fX1mdW5jdGlvbiB3ZShlKXt2YXIgdD10eXBlb2YgU3ltYm9sPT0iZnVuY3Rpb24iJiZTeW1ib2wuaXRlcmF0b3Iscj10JiZlW3RdLG89MDtpZihyKXJldHVybiByLmNhbGwoZSk7aWYoZSYmdHlwZW9mIGUubGVuZ3RoPT0ibnVtYmVyIilyZXR1cm57bmV4dDpmdW5jdGlvbigpe3JldHVybiBlJiZvPj1lLmxlbmd0aCYmKGU9dm9pZCAwKSx7dmFsdWU6ZSYmZVtvKytdLGRvbmU6IWV9fX07dGhyb3cgbmV3IFR5cGVFcnJvcih0PyJPYmplY3QgaXMgbm90IGl0ZXJhYmxlLiI6IlN5bWJvbC5pdGVyYXRvciBpcyBub3QgZGVmaW5lZC4iKX1mdW5jdGlvbiBOKGUsdCl7dmFyIHI9dHlwZW9mIFN5bWJvbD09ImZ1bmN0aW9uIiYmZVtTeW1ib2wuaXRlcmF0b3JdO2lmKCFyKXJldHVybiBlO3ZhciBvPXIuY2FsbChlKSxuLGk9W10sczt0cnl7Zm9yKDsodD09PXZvaWQgMHx8dC0tID4wKSYmIShuPW8ubmV4dCgpKS5kb25lOylpLnB1c2gobi52YWx1ZSl9Y2F0Y2goYSl7cz17ZXJyb3I6YX19ZmluYWxseXt0cnl7biYmIW4uZG9uZSYmKHI9by5yZXR1cm4pJiZyLmNhbGwobyl9ZmluYWxseXtpZihzKXRocm93IHMuZXJyb3J9fXJldHVybiBpfWZ1bmN0aW9uIEQoZSx0LHIpe2lmKHJ8fGFyZ3VtZW50cy5sZW5ndGg9PT0yKWZvcih2YXIgbz0wLG49dC5sZW5ndGgsaTtvPG47bysrKShpfHwhKG8gaW4gdCkpJiYoaXx8KGk9QXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwodCwwLG8pKSxpW29dPXRbb10pO3JldHVybiBlLmNvbmNhdChpfHxBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbCh0KSl9ZnVuY3Rpb24gWmUoZSl7cmV0dXJuIHRoaXMgaW5zdGFuY2VvZiBaZT8odGhpcy52PWUsdGhpcyk6bmV3IFplKGUpfWZ1bmN0aW9uIGlvKGUsdCxyKXtpZighU3ltYm9sLmFzeW5jSXRlcmF0b3IpdGhyb3cgbmV3IFR5cGVFcnJvcigiU3ltYm9sLmFzeW5jSXRlcmF0b3IgaXMgbm90IGRlZmluZWQuIik7dmFyIG89ci5hcHBseShlLHR8fFtdKSxuLGk9W107cmV0dXJuIG49e30scygibmV4dCIpLHMoInRocm93IikscygicmV0dXJuIiksbltTeW1ib2wuYXN5bmNJdGVyYXRvcl09ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc30sbjtmdW5jdGlvbiBzKHUpe29bdV0mJihuW3VdPWZ1bmN0aW9uKGQpe3JldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbih2LGIpe2kucHVzaChbdSxkLHYsYl0pPjF8fGEodSxkKX0pfSl9ZnVuY3Rpb24gYSh1LGQpe3RyeXtjKG9bdV0oZCkpfWNhdGNoKHYpe2YoaVswXVszXSx2KX19ZnVuY3Rpb24gYyh1KXt1LnZhbHVlIGluc3RhbmNlb2YgWmU/UHJvbWlzZS5yZXNvbHZlKHUudmFsdWUudikudGhlbihwLGwpOmYoaVswXVsyXSx1KX1mdW5jdGlvbiBwKHUpe2EoIm5leHQiLHUpfWZ1bmN0aW9uIGwodSl7YSgidGhyb3ciLHUpfWZ1bmN0aW9uIGYodSxkKXt1KGQpLGkuc2hpZnQoKSxpLmxlbmd0aCYmYShpWzBdWzBdLGlbMF1bMV0pfX1mdW5jdGlvbiBhbyhlKXtpZighU3ltYm9sLmFzeW5jSXRlcmF0b3IpdGhyb3cgbmV3IFR5cGVFcnJvcigiU3ltYm9sLmFzeW5jSXRlcmF0b3IgaXMgbm90IGRlZmluZWQuIik7dmFyIHQ9ZVtTeW1ib2wuYXN5bmNJdGVyYXRvcl0scjtyZXR1cm4gdD90LmNhbGwoZSk6KGU9dHlwZW9mIHdlPT0iZnVuY3Rpb24iP3dlKGUpOmVbU3ltYm9sLml0ZXJhdG9yXSgpLHI9e30sbygibmV4dCIpLG8oInRocm93IiksbygicmV0dXJuIikscltTeW1ib2wuYXN5bmNJdGVyYXRvcl09ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc30scik7ZnVuY3Rpb24gbyhpKXtyW2ldPWVbaV0mJmZ1bmN0aW9uKHMpe3JldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihhLGMpe3M9ZVtpXShzKSxuKGEsYyxzLmRvbmUscy52YWx1ZSl9KX19ZnVuY3Rpb24gbihpLHMsYSxjKXtQcm9taXNlLnJlc29sdmUoYykudGhlbihmdW5jdGlvbihwKXtpKHt2YWx1ZTpwLGRvbmU6YX0pfSxzKX19ZnVuY3Rpb24gayhlKXtyZXR1cm4gdHlwZW9mIGU9PSJmdW5jdGlvbiJ9ZnVuY3Rpb24gYXQoZSl7dmFyIHQ9ZnVuY3Rpb24obyl7RXJyb3IuY2FsbChvKSxvLnN0YWNrPW5ldyBFcnJvcigpLnN0YWNrfSxyPWUodCk7cmV0dXJuIHIucHJvdG90eXBlPU9iamVjdC5jcmVhdGUoRXJyb3IucHJvdG90eXBlKSxyLnByb3RvdHlwZS5jb25zdHJ1Y3Rvcj1yLHJ9dmFyIFJ0PWF0KGZ1bmN0aW9uKGUpe3JldHVybiBmdW5jdGlvbihyKXtlKHRoaXMpLHRoaXMubWVzc2FnZT1yP3IubGVuZ3RoK2AgZXJyb3JzIG9jY3VycmVkIGR1cmluZyB1bnN1YnNjcmlwdGlvbjoKYCtyLm1hcChmdW5jdGlvbihvLG4pe3JldHVybiBuKzErIikgIitvLnRvU3RyaW5nKCl9KS5qb2luKGAKICBgKToiIix0aGlzLm5hbWU9IlVuc3Vic2NyaXB0aW9uRXJyb3IiLHRoaXMuZXJyb3JzPXJ9fSk7ZnVuY3Rpb24gRGUoZSx0KXtpZihlKXt2YXIgcj1lLmluZGV4T2YodCk7MDw9ciYmZS5zcGxpY2UociwxKX19dmFyIEllPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZSh0KXt0aGlzLmluaXRpYWxUZWFyZG93bj10LHRoaXMuY2xvc2VkPSExLHRoaXMuX3BhcmVudGFnZT1udWxsLHRoaXMuX2ZpbmFsaXplcnM9bnVsbH1yZXR1cm4gZS5wcm90b3R5cGUudW5zdWJzY3JpYmU9ZnVuY3Rpb24oKXt2YXIgdCxyLG8sbixpO2lmKCF0aGlzLmNsb3NlZCl7dGhpcy5jbG9zZWQ9ITA7dmFyIHM9dGhpcy5fcGFyZW50YWdlO2lmKHMpaWYodGhpcy5fcGFyZW50YWdlPW51bGwsQXJyYXkuaXNBcnJheShzKSl0cnl7Zm9yKHZhciBhPXdlKHMpLGM9YS5uZXh0KCk7IWMuZG9uZTtjPWEubmV4dCgpKXt2YXIgcD1jLnZhbHVlO3AucmVtb3ZlKHRoaXMpfX1jYXRjaChiKXt0PXtlcnJvcjpifX1maW5hbGx5e3RyeXtjJiYhYy5kb25lJiYocj1hLnJldHVybikmJnIuY2FsbChhKX1maW5hbGx5e2lmKHQpdGhyb3cgdC5lcnJvcn19ZWxzZSBzLnJlbW92ZSh0aGlzKTt2YXIgbD10aGlzLmluaXRpYWxUZWFyZG93bjtpZihrKGwpKXRyeXtsKCl9Y2F0Y2goYil7aT1iIGluc3RhbmNlb2YgUnQ/Yi5lcnJvcnM6W2JdfXZhciBmPXRoaXMuX2ZpbmFsaXplcnM7aWYoZil7dGhpcy5fZmluYWxpemVycz1udWxsO3RyeXtmb3IodmFyIHU9d2UoZiksZD11Lm5leHQoKTshZC5kb25lO2Q9dS5uZXh0KCkpe3ZhciB2PWQudmFsdWU7dHJ5e3NvKHYpfWNhdGNoKGIpe2k9aSE9bnVsbD9pOltdLGIgaW5zdGFuY2VvZiBSdD9pPUQoRChbXSxOKGkpKSxOKGIuZXJyb3JzKSk6aS5wdXNoKGIpfX19Y2F0Y2goYil7bz17ZXJyb3I6Yn19ZmluYWxseXt0cnl7ZCYmIWQuZG9uZSYmKG49dS5yZXR1cm4pJiZuLmNhbGwodSl9ZmluYWxseXtpZihvKXRocm93IG8uZXJyb3J9fX1pZihpKXRocm93IG5ldyBSdChpKX19LGUucHJvdG90eXBlLmFkZD1mdW5jdGlvbih0KXt2YXIgcjtpZih0JiZ0IT09dGhpcylpZih0aGlzLmNsb3NlZClzbyh0KTtlbHNle2lmKHQgaW5zdGFuY2VvZiBlKXtpZih0LmNsb3NlZHx8dC5faGFzUGFyZW50KHRoaXMpKXJldHVybjt0Ll9hZGRQYXJlbnQodGhpcyl9KHRoaXMuX2ZpbmFsaXplcnM9KHI9dGhpcy5fZmluYWxpemVycykhPT1udWxsJiZyIT09dm9pZCAwP3I6W10pLnB1c2godCl9fSxlLnByb3RvdHlwZS5faGFzUGFyZW50PWZ1bmN0aW9uKHQpe3ZhciByPXRoaXMuX3BhcmVudGFnZTtyZXR1cm4gcj09PXR8fEFycmF5LmlzQXJyYXkocikmJnIuaW5jbHVkZXModCl9LGUucHJvdG90eXBlLl9hZGRQYXJlbnQ9ZnVuY3Rpb24odCl7dmFyIHI9dGhpcy5fcGFyZW50YWdlO3RoaXMuX3BhcmVudGFnZT1BcnJheS5pc0FycmF5KHIpPyhyLnB1c2godCkscik6cj9bcix0XTp0fSxlLnByb3RvdHlwZS5fcmVtb3ZlUGFyZW50PWZ1bmN0aW9uKHQpe3ZhciByPXRoaXMuX3BhcmVudGFnZTtyPT09dD90aGlzLl9wYXJlbnRhZ2U9bnVsbDpBcnJheS5pc0FycmF5KHIpJiZEZShyLHQpfSxlLnByb3RvdHlwZS5yZW1vdmU9ZnVuY3Rpb24odCl7dmFyIHI9dGhpcy5fZmluYWxpemVycztyJiZEZShyLHQpLHQgaW5zdGFuY2VvZiBlJiZ0Ll9yZW1vdmVQYXJlbnQodGhpcyl9LGUuRU1QVFk9ZnVuY3Rpb24oKXt2YXIgdD1uZXcgZTtyZXR1cm4gdC5jbG9zZWQ9ITAsdH0oKSxlfSgpO3ZhciB4cj1JZS5FTVBUWTtmdW5jdGlvbiBQdChlKXtyZXR1cm4gZSBpbnN0YW5jZW9mIEllfHxlJiYiY2xvc2VkImluIGUmJmsoZS5yZW1vdmUpJiZrKGUuYWRkKSYmayhlLnVuc3Vic2NyaWJlKX1mdW5jdGlvbiBzbyhlKXtrKGUpP2UoKTplLnVuc3Vic2NyaWJlKCl9dmFyIEFlPXtvblVuaGFuZGxlZEVycm9yOm51bGwsb25TdG9wcGVkTm90aWZpY2F0aW9uOm51bGwsUHJvbWlzZTp2b2lkIDAsdXNlRGVwcmVjYXRlZFN5bmNocm9ub3VzRXJyb3JIYW5kbGluZzohMSx1c2VEZXByZWNhdGVkTmV4dENvbnRleHQ6ITF9O3ZhciBzdD17c2V0VGltZW91dDpmdW5jdGlvbihlLHQpe2Zvcih2YXIgcj1bXSxvPTI7bzxhcmd1bWVudHMubGVuZ3RoO28rKylyW28tMl09YXJndW1lbnRzW29dO3ZhciBuPXN0LmRlbGVnYXRlO3JldHVybiBuIT1udWxsJiZuLnNldFRpbWVvdXQ/bi5zZXRUaW1lb3V0LmFwcGx5KG4sRChbZSx0XSxOKHIpKSk6c2V0VGltZW91dC5hcHBseSh2b2lkIDAsRChbZSx0XSxOKHIpKSl9LGNsZWFyVGltZW91dDpmdW5jdGlvbihlKXt2YXIgdD1zdC5kZWxlZ2F0ZTtyZXR1cm4oKHQ9PW51bGw/dm9pZCAwOnQuY2xlYXJUaW1lb3V0KXx8Y2xlYXJUaW1lb3V0KShlKX0sZGVsZWdhdGU6dm9pZCAwfTtmdW5jdGlvbiBJdChlKXtzdC5zZXRUaW1lb3V0KGZ1bmN0aW9uKCl7dmFyIHQ9QWUub25VbmhhbmRsZWRFcnJvcjtpZih0KXQoZSk7ZWxzZSB0aHJvdyBlfSl9ZnVuY3Rpb24gZmUoKXt9dmFyIGNvPWZ1bmN0aW9uKCl7cmV0dXJuIHlyKCJDIix2b2lkIDAsdm9pZCAwKX0oKTtmdW5jdGlvbiBwbyhlKXtyZXR1cm4geXIoIkUiLHZvaWQgMCxlKX1mdW5jdGlvbiBsbyhlKXtyZXR1cm4geXIoIk4iLGUsdm9pZCAwKX1mdW5jdGlvbiB5cihlLHQscil7cmV0dXJue2tpbmQ6ZSx2YWx1ZTp0LGVycm9yOnJ9fXZhciBldD1udWxsO2Z1bmN0aW9uIGN0KGUpe2lmKEFlLnVzZURlcHJlY2F0ZWRTeW5jaHJvbm91c0Vycm9ySGFuZGxpbmcpe3ZhciB0PSFldDtpZih0JiYoZXQ9e2Vycm9yVGhyb3duOiExLGVycm9yOm51bGx9KSxlKCksdCl7dmFyIHI9ZXQsbz1yLmVycm9yVGhyb3duLG49ci5lcnJvcjtpZihldD1udWxsLG8pdGhyb3cgbn19ZWxzZSBlKCl9ZnVuY3Rpb24gbW8oZSl7QWUudXNlRGVwcmVjYXRlZFN5bmNocm9ub3VzRXJyb3JIYW5kbGluZyYmZXQmJihldC5lcnJvclRocm93bj0hMCxldC5lcnJvcj1lKX12YXIgeHQ9ZnVuY3Rpb24oZSl7aWUodCxlKTtmdW5jdGlvbiB0KHIpe3ZhciBvPWUuY2FsbCh0aGlzKXx8dGhpcztyZXR1cm4gby5pc1N0b3BwZWQ9ITEscj8oby5kZXN0aW5hdGlvbj1yLFB0KHIpJiZyLmFkZChvKSk6by5kZXN0aW5hdGlvbj1DaSxvfXJldHVybiB0LmNyZWF0ZT1mdW5jdGlvbihyLG8sbil7cmV0dXJuIG5ldyB0dChyLG8sbil9LHQucHJvdG90eXBlLm5leHQ9ZnVuY3Rpb24ocil7dGhpcy5pc1N0b3BwZWQ/d3IobG8ociksdGhpcyk6dGhpcy5fbmV4dChyKX0sdC5wcm90b3R5cGUuZXJyb3I9ZnVuY3Rpb24ocil7dGhpcy5pc1N0b3BwZWQ/d3IocG8ociksdGhpcyk6KHRoaXMuaXNTdG9wcGVkPSEwLHRoaXMuX2Vycm9yKHIpKX0sdC5wcm90b3R5cGUuY29tcGxldGU9ZnVuY3Rpb24oKXt0aGlzLmlzU3RvcHBlZD93cihjbyx0aGlzKToodGhpcy5pc1N0b3BwZWQ9ITAsdGhpcy5fY29tcGxldGUoKSl9LHQucHJvdG90eXBlLnVuc3Vic2NyaWJlPWZ1bmN0aW9uKCl7dGhpcy5jbG9zZWR8fCh0aGlzLmlzU3RvcHBlZD0hMCxlLnByb3RvdHlwZS51bnN1YnNjcmliZS5jYWxsKHRoaXMpLHRoaXMuZGVzdGluYXRpb249bnVsbCl9LHQucHJvdG90eXBlLl9uZXh0PWZ1bmN0aW9uKHIpe3RoaXMuZGVzdGluYXRpb24ubmV4dChyKX0sdC5wcm90b3R5cGUuX2Vycm9yPWZ1bmN0aW9uKHIpe3RyeXt0aGlzLmRlc3RpbmF0aW9uLmVycm9yKHIpfWZpbmFsbHl7dGhpcy51bnN1YnNjcmliZSgpfX0sdC5wcm90b3R5cGUuX2NvbXBsZXRlPWZ1bmN0aW9uKCl7dHJ5e3RoaXMuZGVzdGluYXRpb24uY29tcGxldGUoKX1maW5hbGx5e3RoaXMudW5zdWJzY3JpYmUoKX19LHR9KEllKTt2YXIgTGk9RnVuY3Rpb24ucHJvdG90eXBlLmJpbmQ7ZnVuY3Rpb24gRXIoZSx0KXtyZXR1cm4gTGkuY2FsbChlLHQpfXZhciBfaT1mdW5jdGlvbigpe2Z1bmN0aW9uIGUodCl7dGhpcy5wYXJ0aWFsT2JzZXJ2ZXI9dH1yZXR1cm4gZS5wcm90b3R5cGUubmV4dD1mdW5jdGlvbih0KXt2YXIgcj10aGlzLnBhcnRpYWxPYnNlcnZlcjtpZihyLm5leHQpdHJ5e3IubmV4dCh0KX1jYXRjaChvKXtGdChvKX19LGUucHJvdG90eXBlLmVycm9yPWZ1bmN0aW9uKHQpe3ZhciByPXRoaXMucGFydGlhbE9ic2VydmVyO2lmKHIuZXJyb3IpdHJ5e3IuZXJyb3IodCl9Y2F0Y2gobyl7RnQobyl9ZWxzZSBGdCh0KX0sZS5wcm90b3R5cGUuY29tcGxldGU9ZnVuY3Rpb24oKXt2YXIgdD10aGlzLnBhcnRpYWxPYnNlcnZlcjtpZih0LmNvbXBsZXRlKXRyeXt0LmNvbXBsZXRlKCl9Y2F0Y2gocil7RnQocil9fSxlfSgpLHR0PWZ1bmN0aW9uKGUpe2llKHQsZSk7ZnVuY3Rpb24gdChyLG8sbil7dmFyIGk9ZS5jYWxsKHRoaXMpfHx0aGlzLHM7aWYoayhyKXx8IXIpcz17bmV4dDpyIT1udWxsP3I6dm9pZCAwLGVycm9yOm8hPW51bGw/bzp2b2lkIDAsY29tcGxldGU6biE9bnVsbD9uOnZvaWQgMH07ZWxzZXt2YXIgYTtpJiZBZS51c2VEZXByZWNhdGVkTmV4dENvbnRleHQ/KGE9T2JqZWN0LmNyZWF0ZShyKSxhLnVuc3Vic2NyaWJlPWZ1bmN0aW9uKCl7cmV0dXJuIGkudW5zdWJzY3JpYmUoKX0scz17bmV4dDpyLm5leHQmJkVyKHIubmV4dCxhKSxlcnJvcjpyLmVycm9yJiZFcihyLmVycm9yLGEpLGNvbXBsZXRlOnIuY29tcGxldGUmJkVyKHIuY29tcGxldGUsYSl9KTpzPXJ9cmV0dXJuIGkuZGVzdGluYXRpb249bmV3IF9pKHMpLGl9cmV0dXJuIHR9KHh0KTtmdW5jdGlvbiBGdChlKXtBZS51c2VEZXByZWNhdGVkU3luY2hyb25vdXNFcnJvckhhbmRsaW5nP21vKGUpOkl0KGUpfWZ1bmN0aW9uIEFpKGUpe3Rocm93IGV9ZnVuY3Rpb24gd3IoZSx0KXt2YXIgcj1BZS5vblN0b3BwZWROb3RpZmljYXRpb247ciYmc3Quc2V0VGltZW91dChmdW5jdGlvbigpe3JldHVybiByKGUsdCl9KX12YXIgQ2k9e2Nsb3NlZDohMCxuZXh0OmZlLGVycm9yOkFpLGNvbXBsZXRlOmZlfTt2YXIgcHQ9ZnVuY3Rpb24oKXtyZXR1cm4gdHlwZW9mIFN5bWJvbD09ImZ1bmN0aW9uIiYmU3ltYm9sLm9ic2VydmFibGV8fCJAQG9ic2VydmFibGUifSgpO2Z1bmN0aW9uIHVlKGUpe3JldHVybiBlfWZ1bmN0aW9uIGZvKCl7Zm9yKHZhciBlPVtdLHQ9MDt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKWVbdF09YXJndW1lbnRzW3RdO3JldHVybiBTcihlKX1mdW5jdGlvbiBTcihlKXtyZXR1cm4gZS5sZW5ndGg9PT0wP3VlOmUubGVuZ3RoPT09MT9lWzBdOmZ1bmN0aW9uKHIpe3JldHVybiBlLnJlZHVjZShmdW5jdGlvbihvLG4pe3JldHVybiBuKG8pfSxyKX19dmFyIFA9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKHQpe3QmJih0aGlzLl9zdWJzY3JpYmU9dCl9cmV0dXJuIGUucHJvdG90eXBlLmxpZnQ9ZnVuY3Rpb24odCl7dmFyIHI9bmV3IGU7cmV0dXJuIHIuc291cmNlPXRoaXMsci5vcGVyYXRvcj10LHJ9LGUucHJvdG90eXBlLnN1YnNjcmliZT1mdW5jdGlvbih0LHIsbyl7dmFyIG49dGhpcyxpPUhpKHQpP3Q6bmV3IHR0KHQscixvKTtyZXR1cm4gY3QoZnVuY3Rpb24oKXt2YXIgcz1uLGE9cy5vcGVyYXRvcixjPXMuc291cmNlO2kuYWRkKGE/YS5jYWxsKGksYyk6Yz9uLl9zdWJzY3JpYmUoaSk6bi5fdHJ5U3Vic2NyaWJlKGkpKX0pLGl9LGUucHJvdG90eXBlLl90cnlTdWJzY3JpYmU9ZnVuY3Rpb24odCl7dHJ5e3JldHVybiB0aGlzLl9zdWJzY3JpYmUodCl9Y2F0Y2gocil7dC5lcnJvcihyKX19LGUucHJvdG90eXBlLmZvckVhY2g9ZnVuY3Rpb24odCxyKXt2YXIgbz10aGlzO3JldHVybiByPXVvKHIpLG5ldyByKGZ1bmN0aW9uKG4saSl7dmFyIHM9bmV3IHR0KHtuZXh0OmZ1bmN0aW9uKGEpe3RyeXt0KGEpfWNhdGNoKGMpe2koYykscy51bnN1YnNjcmliZSgpfX0sZXJyb3I6aSxjb21wbGV0ZTpufSk7by5zdWJzY3JpYmUocyl9KX0sZS5wcm90b3R5cGUuX3N1YnNjcmliZT1mdW5jdGlvbih0KXt2YXIgcjtyZXR1cm4ocj10aGlzLnNvdXJjZSk9PT1udWxsfHxyPT09dm9pZCAwP3ZvaWQgMDpyLnN1YnNjcmliZSh0KX0sZS5wcm90b3R5cGVbcHRdPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXN9LGUucHJvdG90eXBlLnBpcGU9ZnVuY3Rpb24oKXtmb3IodmFyIHQ9W10scj0wO3I8YXJndW1lbnRzLmxlbmd0aDtyKyspdFtyXT1hcmd1bWVudHNbcl07cmV0dXJuIFNyKHQpKHRoaXMpfSxlLnByb3RvdHlwZS50b1Byb21pc2U9ZnVuY3Rpb24odCl7dmFyIHI9dGhpcztyZXR1cm4gdD11byh0KSxuZXcgdChmdW5jdGlvbihvLG4pe3ZhciBpO3Iuc3Vic2NyaWJlKGZ1bmN0aW9uKHMpe3JldHVybiBpPXN9LGZ1bmN0aW9uKHMpe3JldHVybiBuKHMpfSxmdW5jdGlvbigpe3JldHVybiBvKGkpfSl9KX0sZS5jcmVhdGU9ZnVuY3Rpb24odCl7cmV0dXJuIG5ldyBlKHQpfSxlfSgpO2Z1bmN0aW9uIHVvKGUpe3ZhciB0O3JldHVybih0PWUhPW51bGw/ZTpBZS5Qcm9taXNlKSE9PW51bGwmJnQhPT12b2lkIDA/dDpQcm9taXNlfWZ1bmN0aW9uIGtpKGUpe3JldHVybiBlJiZrKGUubmV4dCkmJmsoZS5lcnJvcikmJmsoZS5jb21wbGV0ZSl9ZnVuY3Rpb24gSGkoZSl7cmV0dXJuIGUmJmUgaW5zdGFuY2VvZiB4dHx8a2koZSkmJlB0KGUpfWZ1bmN0aW9uICRpKGUpe3JldHVybiBrKGU9PW51bGw/dm9pZCAwOmUubGlmdCl9ZnVuY3Rpb24gZyhlKXtyZXR1cm4gZnVuY3Rpb24odCl7aWYoJGkodCkpcmV0dXJuIHQubGlmdChmdW5jdGlvbihyKXt0cnl7cmV0dXJuIGUocix0aGlzKX1jYXRjaChvKXt0aGlzLmVycm9yKG8pfX0pO3Rocm93IG5ldyBUeXBlRXJyb3IoIlVuYWJsZSB0byBsaWZ0IHVua25vd24gT2JzZXJ2YWJsZSB0eXBlIil9fWZ1bmN0aW9uIHkoZSx0LHIsbyxuKXtyZXR1cm4gbmV3IFJpKGUsdCxyLG8sbil9dmFyIFJpPWZ1bmN0aW9uKGUpe2llKHQsZSk7ZnVuY3Rpb24gdChyLG8sbixpLHMsYSl7dmFyIGM9ZS5jYWxsKHRoaXMscil8fHRoaXM7cmV0dXJuIGMub25GaW5hbGl6ZT1zLGMuc2hvdWxkVW5zdWJzY3JpYmU9YSxjLl9uZXh0PW8/ZnVuY3Rpb24ocCl7dHJ5e28ocCl9Y2F0Y2gobCl7ci5lcnJvcihsKX19OmUucHJvdG90eXBlLl9uZXh0LGMuX2Vycm9yPWk/ZnVuY3Rpb24ocCl7dHJ5e2kocCl9Y2F0Y2gobCl7ci5lcnJvcihsKX1maW5hbGx5e3RoaXMudW5zdWJzY3JpYmUoKX19OmUucHJvdG90eXBlLl9lcnJvcixjLl9jb21wbGV0ZT1uP2Z1bmN0aW9uKCl7dHJ5e24oKX1jYXRjaChwKXtyLmVycm9yKHApfWZpbmFsbHl7dGhpcy51bnN1YnNjcmliZSgpfX06ZS5wcm90b3R5cGUuX2NvbXBsZXRlLGN9cmV0dXJuIHQucHJvdG90eXBlLnVuc3Vic2NyaWJlPWZ1bmN0aW9uKCl7dmFyIHI7aWYoIXRoaXMuc2hvdWxkVW5zdWJzY3JpYmV8fHRoaXMuc2hvdWxkVW5zdWJzY3JpYmUoKSl7dmFyIG89dGhpcy5jbG9zZWQ7ZS5wcm90b3R5cGUudW5zdWJzY3JpYmUuY2FsbCh0aGlzKSwhbyYmKChyPXRoaXMub25GaW5hbGl6ZSk9PT1udWxsfHxyPT09dm9pZCAwfHxyLmNhbGwodGhpcykpfX0sdH0oeHQpO3ZhciBsdD17c2NoZWR1bGU6ZnVuY3Rpb24oZSl7dmFyIHQ9cmVxdWVzdEFuaW1hdGlvbkZyYW1lLHI9Y2FuY2VsQW5pbWF0aW9uRnJhbWUsbz1sdC5kZWxlZ2F0ZTtvJiYodD1vLnJlcXVlc3RBbmltYXRpb25GcmFtZSxyPW8uY2FuY2VsQW5pbWF0aW9uRnJhbWUpO3ZhciBuPXQoZnVuY3Rpb24oaSl7cj12b2lkIDAsZShpKX0pO3JldHVybiBuZXcgSWUoZnVuY3Rpb24oKXtyZXR1cm4gcj09bnVsbD92b2lkIDA6cihuKX0pfSxyZXF1ZXN0QW5pbWF0aW9uRnJhbWU6ZnVuY3Rpb24oKXtmb3IodmFyIGU9W10sdD0wO3Q8YXJndW1lbnRzLmxlbmd0aDt0KyspZVt0XT1hcmd1bWVudHNbdF07dmFyIHI9bHQuZGVsZWdhdGU7cmV0dXJuKChyPT1udWxsP3ZvaWQgMDpyLnJlcXVlc3RBbmltYXRpb25GcmFtZSl8fHJlcXVlc3RBbmltYXRpb25GcmFtZSkuYXBwbHkodm9pZCAwLEQoW10sTihlKSkpfSxjYW5jZWxBbmltYXRpb25GcmFtZTpmdW5jdGlvbigpe2Zvcih2YXIgZT1bXSx0PTA7dDxhcmd1bWVudHMubGVuZ3RoO3QrKyllW3RdPWFyZ3VtZW50c1t0XTt2YXIgcj1sdC5kZWxlZ2F0ZTtyZXR1cm4oKHI9PW51bGw/dm9pZCAwOnIuY2FuY2VsQW5pbWF0aW9uRnJhbWUpfHxjYW5jZWxBbmltYXRpb25GcmFtZSkuYXBwbHkodm9pZCAwLEQoW10sTihlKSkpfSxkZWxlZ2F0ZTp2b2lkIDB9O3ZhciBobz1hdChmdW5jdGlvbihlKXtyZXR1cm4gZnVuY3Rpb24oKXtlKHRoaXMpLHRoaXMubmFtZT0iT2JqZWN0VW5zdWJzY3JpYmVkRXJyb3IiLHRoaXMubWVzc2FnZT0ib2JqZWN0IHVuc3Vic2NyaWJlZCJ9fSk7dmFyIHg9ZnVuY3Rpb24oZSl7aWUodCxlKTtmdW5jdGlvbiB0KCl7dmFyIHI9ZS5jYWxsKHRoaXMpfHx0aGlzO3JldHVybiByLmNsb3NlZD0hMSxyLmN1cnJlbnRPYnNlcnZlcnM9bnVsbCxyLm9ic2VydmVycz1bXSxyLmlzU3RvcHBlZD0hMSxyLmhhc0Vycm9yPSExLHIudGhyb3duRXJyb3I9bnVsbCxyfXJldHVybiB0LnByb3RvdHlwZS5saWZ0PWZ1bmN0aW9uKHIpe3ZhciBvPW5ldyBibyh0aGlzLHRoaXMpO3JldHVybiBvLm9wZXJhdG9yPXIsb30sdC5wcm90b3R5cGUuX3Rocm93SWZDbG9zZWQ9ZnVuY3Rpb24oKXtpZih0aGlzLmNsb3NlZCl0aHJvdyBuZXcgaG99LHQucHJvdG90eXBlLm5leHQ9ZnVuY3Rpb24ocil7dmFyIG89dGhpcztjdChmdW5jdGlvbigpe3ZhciBuLGk7aWYoby5fdGhyb3dJZkNsb3NlZCgpLCFvLmlzU3RvcHBlZCl7by5jdXJyZW50T2JzZXJ2ZXJzfHwoby5jdXJyZW50T2JzZXJ2ZXJzPUFycmF5LmZyb20oby5vYnNlcnZlcnMpKTt0cnl7Zm9yKHZhciBzPXdlKG8uY3VycmVudE9ic2VydmVycyksYT1zLm5leHQoKTshYS5kb25lO2E9cy5uZXh0KCkpe3ZhciBjPWEudmFsdWU7Yy5uZXh0KHIpfX1jYXRjaChwKXtuPXtlcnJvcjpwfX1maW5hbGx5e3RyeXthJiYhYS5kb25lJiYoaT1zLnJldHVybikmJmkuY2FsbChzKX1maW5hbGx5e2lmKG4pdGhyb3cgbi5lcnJvcn19fX0pfSx0LnByb3RvdHlwZS5lcnJvcj1mdW5jdGlvbihyKXt2YXIgbz10aGlzO2N0KGZ1bmN0aW9uKCl7aWYoby5fdGhyb3dJZkNsb3NlZCgpLCFvLmlzU3RvcHBlZCl7by5oYXNFcnJvcj1vLmlzU3RvcHBlZD0hMCxvLnRocm93bkVycm9yPXI7Zm9yKHZhciBuPW8ub2JzZXJ2ZXJzO24ubGVuZ3RoOyluLnNoaWZ0KCkuZXJyb3Iocil9fSl9LHQucHJvdG90eXBlLmNvbXBsZXRlPWZ1bmN0aW9uKCl7dmFyIHI9dGhpcztjdChmdW5jdGlvbigpe2lmKHIuX3Rocm93SWZDbG9zZWQoKSwhci5pc1N0b3BwZWQpe3IuaXNTdG9wcGVkPSEwO2Zvcih2YXIgbz1yLm9ic2VydmVycztvLmxlbmd0aDspby5zaGlmdCgpLmNvbXBsZXRlKCl9fSl9LHQucHJvdG90eXBlLnVuc3Vic2NyaWJlPWZ1bmN0aW9uKCl7dGhpcy5pc1N0b3BwZWQ9dGhpcy5jbG9zZWQ9ITAsdGhpcy5vYnNlcnZlcnM9dGhpcy5jdXJyZW50T2JzZXJ2ZXJzPW51bGx9LE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LnByb3RvdHlwZSwib2JzZXJ2ZWQiLHtnZXQ6ZnVuY3Rpb24oKXt2YXIgcjtyZXR1cm4oKHI9dGhpcy5vYnNlcnZlcnMpPT09bnVsbHx8cj09PXZvaWQgMD92b2lkIDA6ci5sZW5ndGgpPjB9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksdC5wcm90b3R5cGUuX3RyeVN1YnNjcmliZT1mdW5jdGlvbihyKXtyZXR1cm4gdGhpcy5fdGhyb3dJZkNsb3NlZCgpLGUucHJvdG90eXBlLl90cnlTdWJzY3JpYmUuY2FsbCh0aGlzLHIpfSx0LnByb3RvdHlwZS5fc3Vic2NyaWJlPWZ1bmN0aW9uKHIpe3JldHVybiB0aGlzLl90aHJvd0lmQ2xvc2VkKCksdGhpcy5fY2hlY2tGaW5hbGl6ZWRTdGF0dXNlcyhyKSx0aGlzLl9pbm5lclN1YnNjcmliZShyKX0sdC5wcm90b3R5cGUuX2lubmVyU3Vic2NyaWJlPWZ1bmN0aW9uKHIpe3ZhciBvPXRoaXMsbj10aGlzLGk9bi5oYXNFcnJvcixzPW4uaXNTdG9wcGVkLGE9bi5vYnNlcnZlcnM7cmV0dXJuIGl8fHM/eHI6KHRoaXMuY3VycmVudE9ic2VydmVycz1udWxsLGEucHVzaChyKSxuZXcgSWUoZnVuY3Rpb24oKXtvLmN1cnJlbnRPYnNlcnZlcnM9bnVsbCxEZShhLHIpfSkpfSx0LnByb3RvdHlwZS5fY2hlY2tGaW5hbGl6ZWRTdGF0dXNlcz1mdW5jdGlvbihyKXt2YXIgbz10aGlzLG49by5oYXNFcnJvcixpPW8udGhyb3duRXJyb3Iscz1vLmlzU3RvcHBlZDtuP3IuZXJyb3IoaSk6cyYmci5jb21wbGV0ZSgpfSx0LnByb3RvdHlwZS5hc09ic2VydmFibGU9ZnVuY3Rpb24oKXt2YXIgcj1uZXcgUDtyZXR1cm4gci5zb3VyY2U9dGhpcyxyfSx0LmNyZWF0ZT1mdW5jdGlvbihyLG8pe3JldHVybiBuZXcgYm8ocixvKX0sdH0oUCk7dmFyIGJvPWZ1bmN0aW9uKGUpe2llKHQsZSk7ZnVuY3Rpb24gdChyLG8pe3ZhciBuPWUuY2FsbCh0aGlzKXx8dGhpcztyZXR1cm4gbi5kZXN0aW5hdGlvbj1yLG4uc291cmNlPW8sbn1yZXR1cm4gdC5wcm90b3R5cGUubmV4dD1mdW5jdGlvbihyKXt2YXIgbyxuOyhuPShvPXRoaXMuZGVzdGluYXRpb24pPT09bnVsbHx8bz09PXZvaWQgMD92b2lkIDA6by5uZXh0KT09PW51bGx8fG49PT12b2lkIDB8fG4uY2FsbChvLHIpfSx0LnByb3RvdHlwZS5lcnJvcj1mdW5jdGlvbihyKXt2YXIgbyxuOyhuPShvPXRoaXMuZGVzdGluYXRpb24pPT09bnVsbHx8bz09PXZvaWQgMD92b2lkIDA6by5lcnJvcik9PT1udWxsfHxuPT09dm9pZCAwfHxuLmNhbGwobyxyKX0sdC5wcm90b3R5cGUuY29tcGxldGU9ZnVuY3Rpb24oKXt2YXIgcixvOyhvPShyPXRoaXMuZGVzdGluYXRpb24pPT09bnVsbHx8cj09PXZvaWQgMD92b2lkIDA6ci5jb21wbGV0ZSk9PT1udWxsfHxvPT09dm9pZCAwfHxvLmNhbGwocil9LHQucHJvdG90eXBlLl9zdWJzY3JpYmU9ZnVuY3Rpb24ocil7dmFyIG8sbjtyZXR1cm4obj0obz10aGlzLnNvdXJjZSk9PT1udWxsfHxvPT09dm9pZCAwP3ZvaWQgMDpvLnN1YnNjcmliZShyKSkhPT1udWxsJiZuIT09dm9pZCAwP246eHJ9LHR9KHgpO3ZhciB5dD17bm93OmZ1bmN0aW9uKCl7cmV0dXJuKHl0LmRlbGVnYXRlfHxEYXRlKS5ub3coKX0sZGVsZWdhdGU6dm9pZCAwfTt2YXIgRXQ9ZnVuY3Rpb24oZSl7aWUodCxlKTtmdW5jdGlvbiB0KHIsbyxuKXtyPT09dm9pZCAwJiYocj0xLzApLG89PT12b2lkIDAmJihvPTEvMCksbj09PXZvaWQgMCYmKG49eXQpO3ZhciBpPWUuY2FsbCh0aGlzKXx8dGhpcztyZXR1cm4gaS5fYnVmZmVyU2l6ZT1yLGkuX3dpbmRvd1RpbWU9byxpLl90aW1lc3RhbXBQcm92aWRlcj1uLGkuX2J1ZmZlcj1bXSxpLl9pbmZpbml0ZVRpbWVXaW5kb3c9ITAsaS5faW5maW5pdGVUaW1lV2luZG93PW89PT0xLzAsaS5fYnVmZmVyU2l6ZT1NYXRoLm1heCgxLHIpLGkuX3dpbmRvd1RpbWU9TWF0aC5tYXgoMSxvKSxpfXJldHVybiB0LnByb3RvdHlwZS5uZXh0PWZ1bmN0aW9uKHIpe3ZhciBvPXRoaXMsbj1vLmlzU3RvcHBlZCxpPW8uX2J1ZmZlcixzPW8uX2luZmluaXRlVGltZVdpbmRvdyxhPW8uX3RpbWVzdGFtcFByb3ZpZGVyLGM9by5fd2luZG93VGltZTtufHwoaS5wdXNoKHIpLCFzJiZpLnB1c2goYS5ub3coKStjKSksdGhpcy5fdHJpbUJ1ZmZlcigpLGUucHJvdG90eXBlLm5leHQuY2FsbCh0aGlzLHIpfSx0LnByb3RvdHlwZS5fc3Vic2NyaWJlPWZ1bmN0aW9uKHIpe3RoaXMuX3Rocm93SWZDbG9zZWQoKSx0aGlzLl90cmltQnVmZmVyKCk7Zm9yKHZhciBvPXRoaXMuX2lubmVyU3Vic2NyaWJlKHIpLG49dGhpcyxpPW4uX2luZmluaXRlVGltZVdpbmRvdyxzPW4uX2J1ZmZlcixhPXMuc2xpY2UoKSxjPTA7YzxhLmxlbmd0aCYmIXIuY2xvc2VkO2MrPWk/MToyKXIubmV4dChhW2NdKTtyZXR1cm4gdGhpcy5fY2hlY2tGaW5hbGl6ZWRTdGF0dXNlcyhyKSxvfSx0LnByb3RvdHlwZS5fdHJpbUJ1ZmZlcj1mdW5jdGlvbigpe3ZhciByPXRoaXMsbz1yLl9idWZmZXJTaXplLG49ci5fdGltZXN0YW1wUHJvdmlkZXIsaT1yLl9idWZmZXIscz1yLl9pbmZpbml0ZVRpbWVXaW5kb3csYT0ocz8xOjIpKm87aWYobzwxLzAmJmE8aS5sZW5ndGgmJmkuc3BsaWNlKDAsaS5sZW5ndGgtYSksIXMpe2Zvcih2YXIgYz1uLm5vdygpLHA9MCxsPTE7bDxpLmxlbmd0aCYmaVtsXTw9YztsKz0yKXA9bDtwJiZpLnNwbGljZSgwLHArMSl9fSx0fSh4KTt2YXIgdm89ZnVuY3Rpb24oZSl7aWUodCxlKTtmdW5jdGlvbiB0KHIsbyl7cmV0dXJuIGUuY2FsbCh0aGlzKXx8dGhpc31yZXR1cm4gdC5wcm90b3R5cGUuc2NoZWR1bGU9ZnVuY3Rpb24ocixvKXtyZXR1cm4gbz09PXZvaWQgMCYmKG89MCksdGhpc30sdH0oSWUpO3ZhciB3dD17c2V0SW50ZXJ2YWw6ZnVuY3Rpb24oZSx0KXtmb3IodmFyIHI9W10sbz0yO288YXJndW1lbnRzLmxlbmd0aDtvKyspcltvLTJdPWFyZ3VtZW50c1tvXTt2YXIgbj13dC5kZWxlZ2F0ZTtyZXR1cm4gbiE9bnVsbCYmbi5zZXRJbnRlcnZhbD9uLnNldEludGVydmFsLmFwcGx5KG4sRChbZSx0XSxOKHIpKSk6c2V0SW50ZXJ2YWwuYXBwbHkodm9pZCAwLEQoW2UsdF0sTihyKSkpfSxjbGVhckludGVydmFsOmZ1bmN0aW9uKGUpe3ZhciB0PXd0LmRlbGVnYXRlO3JldHVybigodD09bnVsbD92b2lkIDA6dC5jbGVhckludGVydmFsKXx8Y2xlYXJJbnRlcnZhbCkoZSl9LGRlbGVnYXRlOnZvaWQgMH07dmFyIGp0PWZ1bmN0aW9uKGUpe2llKHQsZSk7ZnVuY3Rpb24gdChyLG8pe3ZhciBuPWUuY2FsbCh0aGlzLHIsbyl8fHRoaXM7cmV0dXJuIG4uc2NoZWR1bGVyPXIsbi53b3JrPW8sbi5wZW5kaW5nPSExLG59cmV0dXJuIHQucHJvdG90eXBlLnNjaGVkdWxlPWZ1bmN0aW9uKHIsbyl7dmFyIG47aWYobz09PXZvaWQgMCYmKG89MCksdGhpcy5jbG9zZWQpcmV0dXJuIHRoaXM7dGhpcy5zdGF0ZT1yO3ZhciBpPXRoaXMuaWQscz10aGlzLnNjaGVkdWxlcjtyZXR1cm4gaSE9bnVsbCYmKHRoaXMuaWQ9dGhpcy5yZWN5Y2xlQXN5bmNJZChzLGksbykpLHRoaXMucGVuZGluZz0hMCx0aGlzLmRlbGF5PW8sdGhpcy5pZD0obj10aGlzLmlkKSE9PW51bGwmJm4hPT12b2lkIDA/bjp0aGlzLnJlcXVlc3RBc3luY0lkKHMsdGhpcy5pZCxvKSx0aGlzfSx0LnByb3RvdHlwZS5yZXF1ZXN0QXN5bmNJZD1mdW5jdGlvbihyLG8sbil7cmV0dXJuIG49PT12b2lkIDAmJihuPTApLHd0LnNldEludGVydmFsKHIuZmx1c2guYmluZChyLHRoaXMpLG4pfSx0LnByb3RvdHlwZS5yZWN5Y2xlQXN5bmNJZD1mdW5jdGlvbihyLG8sbil7aWYobj09PXZvaWQgMCYmKG49MCksbiE9bnVsbCYmdGhpcy5kZWxheT09PW4mJnRoaXMucGVuZGluZz09PSExKXJldHVybiBvO28hPW51bGwmJnd0LmNsZWFySW50ZXJ2YWwobyl9LHQucHJvdG90eXBlLmV4ZWN1dGU9ZnVuY3Rpb24ocixvKXtpZih0aGlzLmNsb3NlZClyZXR1cm4gbmV3IEVycm9yKCJleGVjdXRpbmcgYSBjYW5jZWxsZWQgYWN0aW9uIik7dGhpcy5wZW5kaW5nPSExO3ZhciBuPXRoaXMuX2V4ZWN1dGUocixvKTtpZihuKXJldHVybiBuO3RoaXMucGVuZGluZz09PSExJiZ0aGlzLmlkIT1udWxsJiYodGhpcy5pZD10aGlzLnJlY3ljbGVBc3luY0lkKHRoaXMuc2NoZWR1bGVyLHRoaXMuaWQsbnVsbCkpfSx0LnByb3RvdHlwZS5fZXhlY3V0ZT1mdW5jdGlvbihyLG8pe3ZhciBuPSExLGk7dHJ5e3RoaXMud29yayhyKX1jYXRjaChzKXtuPSEwLGk9c3x8bmV3IEVycm9yKCJTY2hlZHVsZWQgYWN0aW9uIHRocmV3IGZhbHN5IGVycm9yIil9aWYobilyZXR1cm4gdGhpcy51bnN1YnNjcmliZSgpLGl9LHQucHJvdG90eXBlLnVuc3Vic2NyaWJlPWZ1bmN0aW9uKCl7aWYoIXRoaXMuY2xvc2VkKXt2YXIgcj10aGlzLG89ci5pZCxuPXIuc2NoZWR1bGVyLGk9bi5hY3Rpb25zO3RoaXMud29yaz10aGlzLnN0YXRlPXRoaXMuc2NoZWR1bGVyPW51bGwsdGhpcy5wZW5kaW5nPSExLERlKGksdGhpcyksbyE9bnVsbCYmKHRoaXMuaWQ9dGhpcy5yZWN5Y2xlQXN5bmNJZChuLG8sbnVsbCkpLHRoaXMuZGVsYXk9bnVsbCxlLnByb3RvdHlwZS51bnN1YnNjcmliZS5jYWxsKHRoaXMpfX0sdH0odm8pO3ZhciBUcj1mdW5jdGlvbigpe2Z1bmN0aW9uIGUodCxyKXtyPT09dm9pZCAwJiYocj1lLm5vdyksdGhpcy5zY2hlZHVsZXJBY3Rpb25DdG9yPXQsdGhpcy5ub3c9cn1yZXR1cm4gZS5wcm90b3R5cGUuc2NoZWR1bGU9ZnVuY3Rpb24odCxyLG8pe3JldHVybiByPT09dm9pZCAwJiYocj0wKSxuZXcgdGhpcy5zY2hlZHVsZXJBY3Rpb25DdG9yKHRoaXMsdCkuc2NoZWR1bGUobyxyKX0sZS5ub3c9eXQubm93LGV9KCk7dmFyIFd0PWZ1bmN0aW9uKGUpe2llKHQsZSk7ZnVuY3Rpb24gdChyLG8pe289PT12b2lkIDAmJihvPVRyLm5vdyk7dmFyIG49ZS5jYWxsKHRoaXMscixvKXx8dGhpcztyZXR1cm4gbi5hY3Rpb25zPVtdLG4uX2FjdGl2ZT0hMSxufXJldHVybiB0LnByb3RvdHlwZS5mbHVzaD1mdW5jdGlvbihyKXt2YXIgbz10aGlzLmFjdGlvbnM7aWYodGhpcy5fYWN0aXZlKXtvLnB1c2gocik7cmV0dXJufXZhciBuO3RoaXMuX2FjdGl2ZT0hMDtkbyBpZihuPXIuZXhlY3V0ZShyLnN0YXRlLHIuZGVsYXkpKWJyZWFrO3doaWxlKHI9by5zaGlmdCgpKTtpZih0aGlzLl9hY3RpdmU9ITEsbil7Zm9yKDtyPW8uc2hpZnQoKTspci51bnN1YnNjcmliZSgpO3Rocm93IG59fSx0fShUcik7dmFyIGFlPW5ldyBXdChqdCksT3I9YWU7dmFyIGdvPWZ1bmN0aW9uKGUpe2llKHQsZSk7ZnVuY3Rpb24gdChyLG8pe3ZhciBuPWUuY2FsbCh0aGlzLHIsbyl8fHRoaXM7cmV0dXJuIG4uc2NoZWR1bGVyPXIsbi53b3JrPW8sbn1yZXR1cm4gdC5wcm90b3R5cGUucmVxdWVzdEFzeW5jSWQ9ZnVuY3Rpb24ocixvLG4pe3JldHVybiBuPT09dm9pZCAwJiYobj0wKSxuIT09bnVsbCYmbj4wP2UucHJvdG90eXBlLnJlcXVlc3RBc3luY0lkLmNhbGwodGhpcyxyLG8sbik6KHIuYWN0aW9ucy5wdXNoKHRoaXMpLHIuX3NjaGVkdWxlZHx8KHIuX3NjaGVkdWxlZD1sdC5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUoZnVuY3Rpb24oKXtyZXR1cm4gci5mbHVzaCh2b2lkIDApfSkpKX0sdC5wcm90b3R5cGUucmVjeWNsZUFzeW5jSWQ9ZnVuY3Rpb24ocixvLG4pe3ZhciBpO2lmKG49PT12b2lkIDAmJihuPTApLG4hPW51bGw/bj4wOnRoaXMuZGVsYXk+MClyZXR1cm4gZS5wcm90b3R5cGUucmVjeWNsZUFzeW5jSWQuY2FsbCh0aGlzLHIsbyxuKTt2YXIgcz1yLmFjdGlvbnM7byE9bnVsbCYmKChpPXNbcy5sZW5ndGgtMV0pPT09bnVsbHx8aT09PXZvaWQgMD92b2lkIDA6aS5pZCkhPT1vJiYobHQuY2FuY2VsQW5pbWF0aW9uRnJhbWUobyksci5fc2NoZWR1bGVkPXZvaWQgMCl9LHR9KGp0KTt2YXIgeG89ZnVuY3Rpb24oZSl7aWUodCxlKTtmdW5jdGlvbiB0KCl7cmV0dXJuIGUhPT1udWxsJiZlLmFwcGx5KHRoaXMsYXJndW1lbnRzKXx8dGhpc31yZXR1cm4gdC5wcm90b3R5cGUuZmx1c2g9ZnVuY3Rpb24ocil7dGhpcy5fYWN0aXZlPSEwO3ZhciBvPXRoaXMuX3NjaGVkdWxlZDt0aGlzLl9zY2hlZHVsZWQ9dm9pZCAwO3ZhciBuPXRoaXMuYWN0aW9ucyxpO3I9cnx8bi5zaGlmdCgpO2RvIGlmKGk9ci5leGVjdXRlKHIuc3RhdGUsci5kZWxheSkpYnJlYWs7d2hpbGUoKHI9blswXSkmJnIuaWQ9PT1vJiZuLnNoaWZ0KCkpO2lmKHRoaXMuX2FjdGl2ZT0hMSxpKXtmb3IoOyhyPW5bMF0pJiZyLmlkPT09byYmbi5zaGlmdCgpOylyLnVuc3Vic2NyaWJlKCk7dGhyb3cgaX19LHR9KFd0KTt2YXIgT2U9bmV3IHhvKGdvKTt2YXIgTD1uZXcgUChmdW5jdGlvbihlKXtyZXR1cm4gZS5jb21wbGV0ZSgpfSk7ZnVuY3Rpb24gVXQoZSl7cmV0dXJuIGUmJmsoZS5zY2hlZHVsZSl9ZnVuY3Rpb24gTXIoZSl7cmV0dXJuIGVbZS5sZW5ndGgtMV19ZnVuY3Rpb24gUWUoZSl7cmV0dXJuIGsoTXIoZSkpP2UucG9wKCk6dm9pZCAwfWZ1bmN0aW9uIE1lKGUpe3JldHVybiBVdChNcihlKSk/ZS5wb3AoKTp2b2lkIDB9ZnVuY3Rpb24gTnQoZSx0KXtyZXR1cm4gdHlwZW9mIE1yKGUpPT0ibnVtYmVyIj9lLnBvcCgpOnR9dmFyIG10PWZ1bmN0aW9uKGUpe3JldHVybiBlJiZ0eXBlb2YgZS5sZW5ndGg9PSJudW1iZXIiJiZ0eXBlb2YgZSE9ImZ1bmN0aW9uIn07ZnVuY3Rpb24gRHQoZSl7cmV0dXJuIGsoZT09bnVsbD92b2lkIDA6ZS50aGVuKX1mdW5jdGlvbiBWdChlKXtyZXR1cm4gayhlW3B0XSl9ZnVuY3Rpb24genQoZSl7cmV0dXJuIFN5bWJvbC5hc3luY0l0ZXJhdG9yJiZrKGU9PW51bGw/dm9pZCAwOmVbU3ltYm9sLmFzeW5jSXRlcmF0b3JdKX1mdW5jdGlvbiBxdChlKXtyZXR1cm4gbmV3IFR5cGVFcnJvcigiWW91IHByb3ZpZGVkICIrKGUhPT1udWxsJiZ0eXBlb2YgZT09Im9iamVjdCI/ImFuIGludmFsaWQgb2JqZWN0IjoiJyIrZSsiJyIpKyIgd2hlcmUgYSBzdHJlYW0gd2FzIGV4cGVjdGVkLiBZb3UgY2FuIHByb3ZpZGUgYW4gT2JzZXJ2YWJsZSwgUHJvbWlzZSwgUmVhZGFibGVTdHJlYW0sIEFycmF5LCBBc3luY0l0ZXJhYmxlLCBvciBJdGVyYWJsZS4iKX1mdW5jdGlvbiBQaSgpe3JldHVybiB0eXBlb2YgU3ltYm9sIT0iZnVuY3Rpb24ifHwhU3ltYm9sLml0ZXJhdG9yPyJAQGl0ZXJhdG9yIjpTeW1ib2wuaXRlcmF0b3J9dmFyIEt0PVBpKCk7ZnVuY3Rpb24gUXQoZSl7cmV0dXJuIGsoZT09bnVsbD92b2lkIDA6ZVtLdF0pfWZ1bmN0aW9uIFl0KGUpe3JldHVybiBpbyh0aGlzLGFyZ3VtZW50cyxmdW5jdGlvbigpe3ZhciByLG8sbixpO3JldHVybiAkdCh0aGlzLGZ1bmN0aW9uKHMpe3N3aXRjaChzLmxhYmVsKXtjYXNlIDA6cj1lLmdldFJlYWRlcigpLHMubGFiZWw9MTtjYXNlIDE6cy50cnlzLnB1c2goWzEsLDksMTBdKSxzLmxhYmVsPTI7Y2FzZSAyOnJldHVybls0LFplKHIucmVhZCgpKV07Y2FzZSAzOnJldHVybiBvPXMuc2VudCgpLG49by52YWx1ZSxpPW8uZG9uZSxpP1s0LFplKHZvaWQgMCldOlszLDVdO2Nhc2UgNDpyZXR1cm5bMixzLnNlbnQoKV07Y2FzZSA1OnJldHVybls0LFplKG4pXTtjYXNlIDY6cmV0dXJuWzQscy5zZW50KCldO2Nhc2UgNzpyZXR1cm4gcy5zZW50KCksWzMsMl07Y2FzZSA4OnJldHVyblszLDEwXTtjYXNlIDk6cmV0dXJuIHIucmVsZWFzZUxvY2soKSxbN107Y2FzZSAxMDpyZXR1cm5bMl19fSl9KX1mdW5jdGlvbiBCdChlKXtyZXR1cm4gayhlPT1udWxsP3ZvaWQgMDplLmdldFJlYWRlcil9ZnVuY3Rpb24gSShlKXtpZihlIGluc3RhbmNlb2YgUClyZXR1cm4gZTtpZihlIT1udWxsKXtpZihWdChlKSlyZXR1cm4gSWkoZSk7aWYobXQoZSkpcmV0dXJuIEZpKGUpO2lmKER0KGUpKXJldHVybiBqaShlKTtpZih6dChlKSlyZXR1cm4geW8oZSk7aWYoUXQoZSkpcmV0dXJuIFdpKGUpO2lmKEJ0KGUpKXJldHVybiBVaShlKX10aHJvdyBxdChlKX1mdW5jdGlvbiBJaShlKXtyZXR1cm4gbmV3IFAoZnVuY3Rpb24odCl7dmFyIHI9ZVtwdF0oKTtpZihrKHIuc3Vic2NyaWJlKSlyZXR1cm4gci5zdWJzY3JpYmUodCk7dGhyb3cgbmV3IFR5cGVFcnJvcigiUHJvdmlkZWQgb2JqZWN0IGRvZXMgbm90IGNvcnJlY3RseSBpbXBsZW1lbnQgU3ltYm9sLm9ic2VydmFibGUiKX0pfWZ1bmN0aW9uIEZpKGUpe3JldHVybiBuZXcgUChmdW5jdGlvbih0KXtmb3IodmFyIHI9MDtyPGUubGVuZ3RoJiYhdC5jbG9zZWQ7cisrKXQubmV4dChlW3JdKTt0LmNvbXBsZXRlKCl9KX1mdW5jdGlvbiBqaShlKXtyZXR1cm4gbmV3IFAoZnVuY3Rpb24odCl7ZS50aGVuKGZ1bmN0aW9uKHIpe3QuY2xvc2VkfHwodC5uZXh0KHIpLHQuY29tcGxldGUoKSl9LGZ1bmN0aW9uKHIpe3JldHVybiB0LmVycm9yKHIpfSkudGhlbihudWxsLEl0KX0pfWZ1bmN0aW9uIFdpKGUpe3JldHVybiBuZXcgUChmdW5jdGlvbih0KXt2YXIgcixvO3RyeXtmb3IodmFyIG49d2UoZSksaT1uLm5leHQoKTshaS5kb25lO2k9bi5uZXh0KCkpe3ZhciBzPWkudmFsdWU7aWYodC5uZXh0KHMpLHQuY2xvc2VkKXJldHVybn19Y2F0Y2goYSl7cj17ZXJyb3I6YX19ZmluYWxseXt0cnl7aSYmIWkuZG9uZSYmKG89bi5yZXR1cm4pJiZvLmNhbGwobil9ZmluYWxseXtpZihyKXRocm93IHIuZXJyb3J9fXQuY29tcGxldGUoKX0pfWZ1bmN0aW9uIHlvKGUpe3JldHVybiBuZXcgUChmdW5jdGlvbih0KXtOaShlLHQpLmNhdGNoKGZ1bmN0aW9uKHIpe3JldHVybiB0LmVycm9yKHIpfSl9KX1mdW5jdGlvbiBVaShlKXtyZXR1cm4geW8oWXQoZSkpfWZ1bmN0aW9uIE5pKGUsdCl7dmFyIHIsbyxuLGk7cmV0dXJuIG5vKHRoaXMsdm9pZCAwLHZvaWQgMCxmdW5jdGlvbigpe3ZhciBzLGE7cmV0dXJuICR0KHRoaXMsZnVuY3Rpb24oYyl7c3dpdGNoKGMubGFiZWwpe2Nhc2UgMDpjLnRyeXMucHVzaChbMCw1LDYsMTFdKSxyPWFvKGUpLGMubGFiZWw9MTtjYXNlIDE6cmV0dXJuWzQsci5uZXh0KCldO2Nhc2UgMjppZihvPWMuc2VudCgpLCEhby5kb25lKXJldHVyblszLDRdO2lmKHM9by52YWx1ZSx0Lm5leHQocyksdC5jbG9zZWQpcmV0dXJuWzJdO2MubGFiZWw9MztjYXNlIDM6cmV0dXJuWzMsMV07Y2FzZSA0OnJldHVyblszLDExXTtjYXNlIDU6cmV0dXJuIGE9Yy5zZW50KCksbj17ZXJyb3I6YX0sWzMsMTFdO2Nhc2UgNjpyZXR1cm4gYy50cnlzLnB1c2goWzYsLDksMTBdKSxvJiYhby5kb25lJiYoaT1yLnJldHVybik/WzQsaS5jYWxsKHIpXTpbMyw4XTtjYXNlIDc6Yy5zZW50KCksYy5sYWJlbD04O2Nhc2UgODpyZXR1cm5bMywxMF07Y2FzZSA5OmlmKG4pdGhyb3cgbi5lcnJvcjtyZXR1cm5bN107Y2FzZSAxMDpyZXR1cm5bN107Y2FzZSAxMTpyZXR1cm4gdC5jb21wbGV0ZSgpLFsyXX19KX0pfWZ1bmN0aW9uIHZlKGUsdCxyLG8sbil7bz09PXZvaWQgMCYmKG89MCksbj09PXZvaWQgMCYmKG49ITEpO3ZhciBpPXQuc2NoZWR1bGUoZnVuY3Rpb24oKXtyKCksbj9lLmFkZCh0aGlzLnNjaGVkdWxlKG51bGwsbykpOnRoaXMudW5zdWJzY3JpYmUoKX0sbyk7aWYoZS5hZGQoaSksIW4pcmV0dXJuIGl9ZnVuY3Rpb24gU2UoZSx0KXtyZXR1cm4gdD09PXZvaWQgMCYmKHQ9MCksZyhmdW5jdGlvbihyLG8pe3Iuc3Vic2NyaWJlKHkobyxmdW5jdGlvbihuKXtyZXR1cm4gdmUobyxlLGZ1bmN0aW9uKCl7cmV0dXJuIG8ubmV4dChuKX0sdCl9LGZ1bmN0aW9uKCl7cmV0dXJuIHZlKG8sZSxmdW5jdGlvbigpe3JldHVybiBvLmNvbXBsZXRlKCl9LHQpfSxmdW5jdGlvbihuKXtyZXR1cm4gdmUobyxlLGZ1bmN0aW9uKCl7cmV0dXJuIG8uZXJyb3Iobil9LHQpfSkpfSl9ZnVuY3Rpb24gcnQoZSx0KXtyZXR1cm4gdD09PXZvaWQgMCYmKHQ9MCksZyhmdW5jdGlvbihyLG8pe28uYWRkKGUuc2NoZWR1bGUoZnVuY3Rpb24oKXtyZXR1cm4gci5zdWJzY3JpYmUobyl9LHQpKX0pfWZ1bmN0aW9uIEVvKGUsdCl7cmV0dXJuIEkoZSkucGlwZShydCh0KSxTZSh0KSl9ZnVuY3Rpb24gd28oZSx0KXtyZXR1cm4gSShlKS5waXBlKHJ0KHQpLFNlKHQpKX1mdW5jdGlvbiBTbyhlLHQpe3JldHVybiBuZXcgUChmdW5jdGlvbihyKXt2YXIgbz0wO3JldHVybiB0LnNjaGVkdWxlKGZ1bmN0aW9uKCl7bz09PWUubGVuZ3RoP3IuY29tcGxldGUoKTooci5uZXh0KGVbbysrXSksci5jbG9zZWR8fHRoaXMuc2NoZWR1bGUoKSl9KX0pfWZ1bmN0aW9uIFRvKGUsdCl7cmV0dXJuIG5ldyBQKGZ1bmN0aW9uKHIpe3ZhciBvO3JldHVybiB2ZShyLHQsZnVuY3Rpb24oKXtvPWVbS3RdKCksdmUocix0LGZ1bmN0aW9uKCl7dmFyIG4saSxzO3RyeXtuPW8ubmV4dCgpLGk9bi52YWx1ZSxzPW4uZG9uZX1jYXRjaChhKXtyLmVycm9yKGEpO3JldHVybn1zP3IuY29tcGxldGUoKTpyLm5leHQoaSl9LDAsITApfSksZnVuY3Rpb24oKXtyZXR1cm4gayhvPT1udWxsP3ZvaWQgMDpvLnJldHVybikmJm8ucmV0dXJuKCl9fSl9ZnVuY3Rpb24gR3QoZSx0KXtpZighZSl0aHJvdyBuZXcgRXJyb3IoIkl0ZXJhYmxlIGNhbm5vdCBiZSBudWxsIik7cmV0dXJuIG5ldyBQKGZ1bmN0aW9uKHIpe3ZlKHIsdCxmdW5jdGlvbigpe3ZhciBvPWVbU3ltYm9sLmFzeW5jSXRlcmF0b3JdKCk7dmUocix0LGZ1bmN0aW9uKCl7by5uZXh0KCkudGhlbihmdW5jdGlvbihuKXtuLmRvbmU/ci5jb21wbGV0ZSgpOnIubmV4dChuLnZhbHVlKX0pfSwwLCEwKX0pfSl9ZnVuY3Rpb24gT28oZSx0KXtyZXR1cm4gR3QoWXQoZSksdCl9ZnVuY3Rpb24gTW8oZSx0KXtpZihlIT1udWxsKXtpZihWdChlKSlyZXR1cm4gRW8oZSx0KTtpZihtdChlKSlyZXR1cm4gU28oZSx0KTtpZihEdChlKSlyZXR1cm4gd28oZSx0KTtpZih6dChlKSlyZXR1cm4gR3QoZSx0KTtpZihRdChlKSlyZXR1cm4gVG8oZSx0KTtpZihCdChlKSlyZXR1cm4gT28oZSx0KX10aHJvdyBxdChlKX1mdW5jdGlvbiBnZShlLHQpe3JldHVybiB0P01vKGUsdCk6SShlKX1mdW5jdGlvbiBqKCl7Zm9yKHZhciBlPVtdLHQ9MDt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKWVbdF09YXJndW1lbnRzW3RdO3ZhciByPU1lKGUpO3JldHVybiBnZShlLHIpfWZ1bmN0aW9uIExyKGUsdCl7dmFyIHI9ayhlKT9lOmZ1bmN0aW9uKCl7cmV0dXJuIGV9LG89ZnVuY3Rpb24obil7cmV0dXJuIG4uZXJyb3IocigpKX07cmV0dXJuIG5ldyBQKHQ/ZnVuY3Rpb24obil7cmV0dXJuIHQuc2NoZWR1bGUobywwLG4pfTpvKX12YXIgSnQ9YXQoZnVuY3Rpb24oZSl7cmV0dXJuIGZ1bmN0aW9uKCl7ZSh0aGlzKSx0aGlzLm5hbWU9IkVtcHR5RXJyb3IiLHRoaXMubWVzc2FnZT0ibm8gZWxlbWVudHMgaW4gc2VxdWVuY2UifX0pO2Z1bmN0aW9uIExvKGUpe3JldHVybiBlIGluc3RhbmNlb2YgRGF0ZSYmIWlzTmFOKGUpfWZ1bmN0aW9uIG0oZSx0KXtyZXR1cm4gZyhmdW5jdGlvbihyLG8pe3ZhciBuPTA7ci5zdWJzY3JpYmUoeShvLGZ1bmN0aW9uKGkpe28ubmV4dChlLmNhbGwodCxpLG4rKykpfSkpfSl9dmFyIERpPUFycmF5LmlzQXJyYXk7ZnVuY3Rpb24gVmkoZSx0KXtyZXR1cm4gRGkodCk/ZS5hcHBseSh2b2lkIDAsRChbXSxOKHQpKSk6ZSh0KX1mdW5jdGlvbiBZZShlKXtyZXR1cm4gbShmdW5jdGlvbih0KXtyZXR1cm4gVmkoZSx0KX0pfXZhciB6aT1BcnJheS5pc0FycmF5LHFpPU9iamVjdC5nZXRQcm90b3R5cGVPZixLaT1PYmplY3QucHJvdG90eXBlLFFpPU9iamVjdC5rZXlzO2Z1bmN0aW9uIF9vKGUpe2lmKGUubGVuZ3RoPT09MSl7dmFyIHQ9ZVswXTtpZih6aSh0KSlyZXR1cm57YXJnczp0LGtleXM6bnVsbH07aWYoWWkodCkpe3ZhciByPVFpKHQpO3JldHVybnthcmdzOnIubWFwKGZ1bmN0aW9uKG8pe3JldHVybiB0W29dfSksa2V5czpyfX19cmV0dXJue2FyZ3M6ZSxrZXlzOm51bGx9fWZ1bmN0aW9uIFlpKGUpe3JldHVybiBlJiZ0eXBlb2YgZT09Im9iamVjdCImJnFpKGUpPT09S2l9ZnVuY3Rpb24gQW8oZSx0KXtyZXR1cm4gZS5yZWR1Y2UoZnVuY3Rpb24ocixvLG4pe3JldHVybiByW29dPXRbbl0scn0se30pfWZ1bmN0aW9uIEIoKXtmb3IodmFyIGU9W10sdD0wO3Q8YXJndW1lbnRzLmxlbmd0aDt0KyspZVt0XT1hcmd1bWVudHNbdF07dmFyIHI9TWUoZSksbz1RZShlKSxuPV9vKGUpLGk9bi5hcmdzLHM9bi5rZXlzO2lmKGkubGVuZ3RoPT09MClyZXR1cm4gZ2UoW10scik7dmFyIGE9bmV3IFAoX3IoaSxyLHM/ZnVuY3Rpb24oYyl7cmV0dXJuIEFvKHMsYyl9OnVlKSk7cmV0dXJuIG8/YS5waXBlKFllKG8pKTphfWZ1bmN0aW9uIF9yKGUsdCxyKXtyZXR1cm4gcj09PXZvaWQgMCYmKHI9dWUpLGZ1bmN0aW9uKG8pe0NvKHQsZnVuY3Rpb24oKXtmb3IodmFyIG49ZS5sZW5ndGgsaT1uZXcgQXJyYXkobikscz1uLGE9bixjPWZ1bmN0aW9uKGwpe0NvKHQsZnVuY3Rpb24oKXt2YXIgZj1nZShlW2xdLHQpLHU9ITE7Zi5zdWJzY3JpYmUoeShvLGZ1bmN0aW9uKGQpe2lbbF09ZCx1fHwodT0hMCxhLS0pLGF8fG8ubmV4dChyKGkuc2xpY2UoKSkpfSxmdW5jdGlvbigpey0tc3x8by5jb21wbGV0ZSgpfSkpfSxvKX0scD0wO3A8bjtwKyspYyhwKX0sbyl9fWZ1bmN0aW9uIENvKGUsdCxyKXtlP3ZlKHIsZSx0KTp0KCl9ZnVuY3Rpb24ga28oZSx0LHIsbyxuLGkscyxhKXt2YXIgYz1bXSxwPTAsbD0wLGY9ITEsdT1mdW5jdGlvbigpe2YmJiFjLmxlbmd0aCYmIXAmJnQuY29tcGxldGUoKX0sZD1mdW5jdGlvbihiKXtyZXR1cm4gcDxvP3YoYik6Yy5wdXNoKGIpfSx2PWZ1bmN0aW9uKGIpe2kmJnQubmV4dChiKSxwKys7dmFyIHo9ITE7SShyKGIsbCsrKSkuc3Vic2NyaWJlKHkodCxmdW5jdGlvbihLKXtuPT1udWxsfHxuKEspLGk/ZChLKTp0Lm5leHQoSyl9LGZ1bmN0aW9uKCl7ej0hMH0sdm9pZCAwLGZ1bmN0aW9uKCl7aWYoeil0cnl7cC0tO2Zvcih2YXIgSz1mdW5jdGlvbigpe3ZhciBHPWMuc2hpZnQoKTtzP3ZlKHQscyxmdW5jdGlvbigpe3JldHVybiB2KEcpfSk6dihHKX07Yy5sZW5ndGgmJnA8bzspSygpO3UoKX1jYXRjaChHKXt0LmVycm9yKEcpfX0pKX07cmV0dXJuIGUuc3Vic2NyaWJlKHkodCxkLGZ1bmN0aW9uKCl7Zj0hMCx1KCl9KSksZnVuY3Rpb24oKXthPT1udWxsfHxhKCl9fWZ1bmN0aW9uIHNlKGUsdCxyKXtyZXR1cm4gcj09PXZvaWQgMCYmKHI9MS8wKSxrKHQpP3NlKGZ1bmN0aW9uKG8sbil7cmV0dXJuIG0oZnVuY3Rpb24oaSxzKXtyZXR1cm4gdChvLGksbixzKX0pKEkoZShvLG4pKSl9LHIpOih0eXBlb2YgdD09Im51bWJlciImJihyPXQpLGcoZnVuY3Rpb24obyxuKXtyZXR1cm4ga28obyxuLGUscil9KSl9ZnVuY3Rpb24gZnQoZSl7cmV0dXJuIGU9PT12b2lkIDAmJihlPTEvMCksc2UodWUsZSl9ZnVuY3Rpb24gSG8oKXtyZXR1cm4gZnQoMSl9ZnVuY3Rpb24gRmUoKXtmb3IodmFyIGU9W10sdD0wO3Q8YXJndW1lbnRzLmxlbmd0aDt0KyspZVt0XT1hcmd1bWVudHNbdF07cmV0dXJuIEhvKCkoZ2UoZSxNZShlKSkpfWZ1bmN0aW9uIEgoZSl7cmV0dXJuIG5ldyBQKGZ1bmN0aW9uKHQpe0koZSgpKS5zdWJzY3JpYmUodCl9KX12YXIgQmk9WyJhZGRMaXN0ZW5lciIsInJlbW92ZUxpc3RlbmVyIl0sR2k9WyJhZGRFdmVudExpc3RlbmVyIiwicmVtb3ZlRXZlbnRMaXN0ZW5lciJdLEppPVsib24iLCJvZmYiXTtmdW5jdGlvbiBoKGUsdCxyLG8pe2lmKGsocikmJihvPXIscj12b2lkIDApLG8pcmV0dXJuIGgoZSx0LHIpLnBpcGUoWWUobykpO3ZhciBuPU4oZWEoZSk/R2kubWFwKGZ1bmN0aW9uKGEpe3JldHVybiBmdW5jdGlvbihjKXtyZXR1cm4gZVthXSh0LGMscil9fSk6WGkoZSk/QmkubWFwKCRvKGUsdCkpOlppKGUpP0ppLm1hcCgkbyhlLHQpKTpbXSwyKSxpPW5bMF0scz1uWzFdO2lmKCFpJiZtdChlKSlyZXR1cm4gc2UoZnVuY3Rpb24oYSl7cmV0dXJuIGgoYSx0LHIpfSkoSShlKSk7aWYoIWkpdGhyb3cgbmV3IFR5cGVFcnJvcigiSW52YWxpZCBldmVudCB0YXJnZXQiKTtyZXR1cm4gbmV3IFAoZnVuY3Rpb24oYSl7dmFyIGM9ZnVuY3Rpb24oKXtmb3IodmFyIHA9W10sbD0wO2w8YXJndW1lbnRzLmxlbmd0aDtsKyspcFtsXT1hcmd1bWVudHNbbF07cmV0dXJuIGEubmV4dCgxPHAubGVuZ3RoP3A6cFswXSl9O3JldHVybiBpKGMpLGZ1bmN0aW9uKCl7cmV0dXJuIHMoYyl9fSl9ZnVuY3Rpb24gJG8oZSx0KXtyZXR1cm4gZnVuY3Rpb24ocil7cmV0dXJuIGZ1bmN0aW9uKG8pe3JldHVybiBlW3JdKHQsbyl9fX1mdW5jdGlvbiBYaShlKXtyZXR1cm4gayhlLmFkZExpc3RlbmVyKSYmayhlLnJlbW92ZUxpc3RlbmVyKX1mdW5jdGlvbiBaaShlKXtyZXR1cm4gayhlLm9uKSYmayhlLm9mZil9ZnVuY3Rpb24gZWEoZSl7cmV0dXJuIGsoZS5hZGRFdmVudExpc3RlbmVyKSYmayhlLnJlbW92ZUV2ZW50TGlzdGVuZXIpfWZ1bmN0aW9uIFh0KGUsdCxyKXtyZXR1cm4gcj9YdChlLHQpLnBpcGUoWWUocikpOm5ldyBQKGZ1bmN0aW9uKG8pe3ZhciBuPWZ1bmN0aW9uKCl7Zm9yKHZhciBzPVtdLGE9MDthPGFyZ3VtZW50cy5sZW5ndGg7YSsrKXNbYV09YXJndW1lbnRzW2FdO3JldHVybiBvLm5leHQocy5sZW5ndGg9PT0xP3NbMF06cyl9LGk9ZShuKTtyZXR1cm4gayh0KT9mdW5jdGlvbigpe3JldHVybiB0KG4saSl9OnZvaWQgMH0pfWZ1bmN0aW9uIEJlKGUsdCxyKXtlPT09dm9pZCAwJiYoZT0wKSxyPT09dm9pZCAwJiYocj1Pcik7dmFyIG89LTE7cmV0dXJuIHQhPW51bGwmJihVdCh0KT9yPXQ6bz10KSxuZXcgUChmdW5jdGlvbihuKXt2YXIgaT1MbyhlKT8rZS1yLm5vdygpOmU7aTwwJiYoaT0wKTt2YXIgcz0wO3JldHVybiByLnNjaGVkdWxlKGZ1bmN0aW9uKCl7bi5jbG9zZWR8fChuLm5leHQocysrKSwwPD1vP3RoaXMuc2NoZWR1bGUodm9pZCAwLG8pOm4uY29tcGxldGUoKSl9LGkpfSl9ZnVuY3Rpb24gXygpe2Zvcih2YXIgZT1bXSx0PTA7dDxhcmd1bWVudHMubGVuZ3RoO3QrKyllW3RdPWFyZ3VtZW50c1t0XTt2YXIgcj1NZShlKSxvPU50KGUsMS8wKSxuPWU7cmV0dXJuIG4ubGVuZ3RoP24ubGVuZ3RoPT09MT9JKG5bMF0pOmZ0KG8pKGdlKG4scikpOkx9dmFyIFZlPW5ldyBQKGZlKTt2YXIgdGE9QXJyYXkuaXNBcnJheTtmdW5jdGlvbiB1dChlKXtyZXR1cm4gZS5sZW5ndGg9PT0xJiZ0YShlWzBdKT9lWzBdOmV9ZnVuY3Rpb24gTShlLHQpe3JldHVybiBnKGZ1bmN0aW9uKHIsbyl7dmFyIG49MDtyLnN1YnNjcmliZSh5KG8sZnVuY3Rpb24oaSl7cmV0dXJuIGUuY2FsbCh0LGksbisrKSYmby5uZXh0KGkpfSkpfSl9ZnVuY3Rpb24gU3QoKXtmb3IodmFyIGU9W10sdD0wO3Q8YXJndW1lbnRzLmxlbmd0aDt0KyspZVt0XT1hcmd1bWVudHNbdF07dmFyIHI9UWUoZSksbz11dChlKTtyZXR1cm4gby5sZW5ndGg/bmV3IFAoZnVuY3Rpb24obil7dmFyIGk9by5tYXAoZnVuY3Rpb24oKXtyZXR1cm5bXX0pLHM9by5tYXAoZnVuY3Rpb24oKXtyZXR1cm4hMX0pO24uYWRkKGZ1bmN0aW9uKCl7aT1zPW51bGx9KTtmb3IodmFyIGE9ZnVuY3Rpb24ocCl7SShvW3BdKS5zdWJzY3JpYmUoeShuLGZ1bmN0aW9uKGwpe2lmKGlbcF0ucHVzaChsKSxpLmV2ZXJ5KGZ1bmN0aW9uKHUpe3JldHVybiB1Lmxlbmd0aH0pKXt2YXIgZj1pLm1hcChmdW5jdGlvbih1KXtyZXR1cm4gdS5zaGlmdCgpfSk7bi5uZXh0KHI/ci5hcHBseSh2b2lkIDAsRChbXSxOKGYpKSk6ZiksaS5zb21lKGZ1bmN0aW9uKHUsZCl7cmV0dXJuIXUubGVuZ3RoJiZzW2RdfSkmJm4uY29tcGxldGUoKX19LGZ1bmN0aW9uKCl7c1twXT0hMCwhaVtwXS5sZW5ndGgmJm4uY29tcGxldGUoKX0pKX0sYz0wOyFuLmNsb3NlZCYmYzxvLmxlbmd0aDtjKyspYShjKTtyZXR1cm4gZnVuY3Rpb24oKXtpPXM9bnVsbH19KTpMfWZ1bmN0aW9uIFJvKGUpe3JldHVybiBnKGZ1bmN0aW9uKHQscil7dmFyIG89ITEsbj1udWxsLGk9bnVsbCxzPSExLGE9ZnVuY3Rpb24oKXtpZihpPT1udWxsfHxpLnVuc3Vic2NyaWJlKCksaT1udWxsLG8pe289ITE7dmFyIHA9bjtuPW51bGwsci5uZXh0KHApfXMmJnIuY29tcGxldGUoKX0sYz1mdW5jdGlvbigpe2k9bnVsbCxzJiZyLmNvbXBsZXRlKCl9O3Quc3Vic2NyaWJlKHkocixmdW5jdGlvbihwKXtvPSEwLG49cCxpfHxJKGUocCkpLnN1YnNjcmliZShpPXkocixhLGMpKX0sZnVuY3Rpb24oKXtzPSEwLCghb3x8IWl8fGkuY2xvc2VkKSYmci5jb21wbGV0ZSgpfSkpfSl9ZnVuY3Rpb24gQ2UoZSx0KXtyZXR1cm4gdD09PXZvaWQgMCYmKHQ9YWUpLFJvKGZ1bmN0aW9uKCl7cmV0dXJuIEJlKGUsdCl9KX1mdW5jdGlvbiBMZShlLHQpe3JldHVybiB0PT09dm9pZCAwJiYodD1udWxsKSx0PXQhPW51bGw/dDplLGcoZnVuY3Rpb24ocixvKXt2YXIgbj1bXSxpPTA7ci5zdWJzY3JpYmUoeShvLGZ1bmN0aW9uKHMpe3ZhciBhLGMscCxsLGY9bnVsbDtpKysldD09PTAmJm4ucHVzaChbXSk7dHJ5e2Zvcih2YXIgdT13ZShuKSxkPXUubmV4dCgpOyFkLmRvbmU7ZD11Lm5leHQoKSl7dmFyIHY9ZC52YWx1ZTt2LnB1c2gocyksZTw9di5sZW5ndGgmJihmPWYhPW51bGw/ZjpbXSxmLnB1c2godikpfX1jYXRjaChLKXthPXtlcnJvcjpLfX1maW5hbGx5e3RyeXtkJiYhZC5kb25lJiYoYz11LnJldHVybikmJmMuY2FsbCh1KX1maW5hbGx5e2lmKGEpdGhyb3cgYS5lcnJvcn19aWYoZil0cnl7Zm9yKHZhciBiPXdlKGYpLHo9Yi5uZXh0KCk7IXouZG9uZTt6PWIubmV4dCgpKXt2YXIgdj16LnZhbHVlO0RlKG4sdiksby5uZXh0KHYpfX1jYXRjaChLKXtwPXtlcnJvcjpLfX1maW5hbGx5e3RyeXt6JiYhei5kb25lJiYobD1iLnJldHVybikmJmwuY2FsbChiKX1maW5hbGx5e2lmKHApdGhyb3cgcC5lcnJvcn19fSxmdW5jdGlvbigpe3ZhciBzLGE7dHJ5e2Zvcih2YXIgYz13ZShuKSxwPWMubmV4dCgpOyFwLmRvbmU7cD1jLm5leHQoKSl7dmFyIGw9cC52YWx1ZTtvLm5leHQobCl9fWNhdGNoKGYpe3M9e2Vycm9yOmZ9fWZpbmFsbHl7dHJ5e3AmJiFwLmRvbmUmJihhPWMucmV0dXJuKSYmYS5jYWxsKGMpfWZpbmFsbHl7aWYocyl0aHJvdyBzLmVycm9yfX1vLmNvbXBsZXRlKCl9LHZvaWQgMCxmdW5jdGlvbigpe249bnVsbH0pKX0pfWZ1bmN0aW9uIGRlKGUpe3JldHVybiBnKGZ1bmN0aW9uKHQscil7dmFyIG89bnVsbCxuPSExLGk7bz10LnN1YnNjcmliZSh5KHIsdm9pZCAwLHZvaWQgMCxmdW5jdGlvbihzKXtpPUkoZShzLGRlKGUpKHQpKSksbz8oby51bnN1YnNjcmliZSgpLG89bnVsbCxpLnN1YnNjcmliZShyKSk6bj0hMH0pKSxuJiYoby51bnN1YnNjcmliZSgpLG89bnVsbCxpLnN1YnNjcmliZShyKSl9KX1mdW5jdGlvbiBQbyhlLHQscixvLG4pe3JldHVybiBmdW5jdGlvbihpLHMpe3ZhciBhPXIsYz10LHA9MDtpLnN1YnNjcmliZSh5KHMsZnVuY3Rpb24obCl7dmFyIGY9cCsrO2M9YT9lKGMsbCxmKTooYT0hMCxsKSxvJiZzLm5leHQoYyl9LG4mJmZ1bmN0aW9uKCl7YSYmcy5uZXh0KGMpLHMuY29tcGxldGUoKX0pKX19ZnVuY3Rpb24gQXIoKXtmb3IodmFyIGU9W10sdD0wO3Q8YXJndW1lbnRzLmxlbmd0aDt0KyspZVt0XT1hcmd1bWVudHNbdF07dmFyIHI9UWUoZSk7cmV0dXJuIHI/Zm8oQXIuYXBwbHkodm9pZCAwLEQoW10sTihlKSkpLFllKHIpKTpnKGZ1bmN0aW9uKG8sbil7X3IoRChbb10sTih1dChlKSkpKShuKX0pfWZ1bmN0aW9uIEdlKCl7Zm9yKHZhciBlPVtdLHQ9MDt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKWVbdF09YXJndW1lbnRzW3RdO3JldHVybiBBci5hcHBseSh2b2lkIDAsRChbXSxOKGUpKSl9ZnVuY3Rpb24ga2UoZSx0KXtyZXR1cm4gdD09PXZvaWQgMCYmKHQ9YWUpLGcoZnVuY3Rpb24ocixvKXt2YXIgbj1udWxsLGk9bnVsbCxzPW51bGwsYT1mdW5jdGlvbigpe2lmKG4pe24udW5zdWJzY3JpYmUoKSxuPW51bGw7dmFyIHA9aTtpPW51bGwsby5uZXh0KHApfX07ZnVuY3Rpb24gYygpe3ZhciBwPXMrZSxsPXQubm93KCk7aWYobDxwKXtuPXRoaXMuc2NoZWR1bGUodm9pZCAwLHAtbCksby5hZGQobik7cmV0dXJufWEoKX1yLnN1YnNjcmliZSh5KG8sZnVuY3Rpb24ocCl7aT1wLHM9dC5ub3coKSxufHwobj10LnNjaGVkdWxlKGMsZSksby5hZGQobikpfSxmdW5jdGlvbigpe2EoKSxvLmNvbXBsZXRlKCl9LHZvaWQgMCxmdW5jdGlvbigpe2k9bj1udWxsfSkpfSl9ZnVuY3Rpb24gSGUoZSl7cmV0dXJuIGcoZnVuY3Rpb24odCxyKXt2YXIgbz0hMTt0LnN1YnNjcmliZSh5KHIsZnVuY3Rpb24obil7bz0hMCxyLm5leHQobil9LGZ1bmN0aW9uKCl7b3x8ci5uZXh0KGUpLHIuY29tcGxldGUoKX0pKX0pfWZ1bmN0aW9uIHhlKGUpe3JldHVybiBlPD0wP2Z1bmN0aW9uKCl7cmV0dXJuIEx9OmcoZnVuY3Rpb24odCxyKXt2YXIgbz0wO3Quc3Vic2NyaWJlKHkocixmdW5jdGlvbihuKXsrK288PWUmJihyLm5leHQobiksZTw9byYmci5jb21wbGV0ZSgpKX0pKX0pfWZ1bmN0aW9uIFooKXtyZXR1cm4gZyhmdW5jdGlvbihlLHQpe2Uuc3Vic2NyaWJlKHkodCxmZSkpfSl9ZnVuY3Rpb24gSW8oZSl7cmV0dXJuIG0oZnVuY3Rpb24oKXtyZXR1cm4gZX0pfWZ1bmN0aW9uIENyKGUsdCl7cmV0dXJuIHQ/ZnVuY3Rpb24ocil7cmV0dXJuIEZlKHQucGlwZSh4ZSgxKSxaKCkpLHIucGlwZShDcihlKSkpfTpzZShmdW5jdGlvbihyLG8pe3JldHVybiBJKGUocixvKSkucGlwZSh4ZSgxKSxJbyhyKSl9KX1mdW5jdGlvbiB6ZShlLHQpe3Q9PT12b2lkIDAmJih0PWFlKTt2YXIgcj1CZShlLHQpO3JldHVybiBDcihmdW5jdGlvbigpe3JldHVybiByfSl9ZnVuY3Rpb24gWChlLHQpe3JldHVybiB0PT09dm9pZCAwJiYodD11ZSksZT1lIT1udWxsP2U6cmEsZyhmdW5jdGlvbihyLG8pe3ZhciBuLGk9ITA7ci5zdWJzY3JpYmUoeShvLGZ1bmN0aW9uKHMpe3ZhciBhPXQocyk7KGl8fCFlKG4sYSkpJiYoaT0hMSxuPWEsby5uZXh0KHMpKX0pKX0pfWZ1bmN0aW9uIHJhKGUsdCl7cmV0dXJuIGU9PT10fWZ1bmN0aW9uIGVlKGUsdCl7cmV0dXJuIFgoZnVuY3Rpb24ocixvKXtyZXR1cm4gdD90KHJbZV0sb1tlXSk6cltlXT09PW9bZV19KX1mdW5jdGlvbiBGbyhlKXtyZXR1cm4gZT09PXZvaWQgMCYmKGU9b2EpLGcoZnVuY3Rpb24odCxyKXt2YXIgbz0hMTt0LnN1YnNjcmliZSh5KHIsZnVuY3Rpb24obil7bz0hMCxyLm5leHQobil9LGZ1bmN0aW9uKCl7cmV0dXJuIG8/ci5jb21wbGV0ZSgpOnIuZXJyb3IoZSgpKX0pKX0pfWZ1bmN0aW9uIG9hKCl7cmV0dXJuIG5ldyBKdH1mdW5jdGlvbiByZSgpe2Zvcih2YXIgZT1bXSx0PTA7dDxhcmd1bWVudHMubGVuZ3RoO3QrKyllW3RdPWFyZ3VtZW50c1t0XTtyZXR1cm4gZnVuY3Rpb24ocil7cmV0dXJuIEZlKHIsai5hcHBseSh2b2lkIDAsRChbXSxOKGUpKSkpfX1mdW5jdGlvbiBBKGUpe3JldHVybiBnKGZ1bmN0aW9uKHQscil7dHJ5e3Quc3Vic2NyaWJlKHIpfWZpbmFsbHl7ci5hZGQoZSl9fSl9ZnVuY3Rpb24gJGUoZSx0KXt2YXIgcj1hcmd1bWVudHMubGVuZ3RoPj0yO3JldHVybiBmdW5jdGlvbihvKXtyZXR1cm4gby5waXBlKGU/TShmdW5jdGlvbihuLGkpe3JldHVybiBlKG4saSxvKX0pOnVlLHhlKDEpLHI/SGUodCk6Rm8oZnVuY3Rpb24oKXtyZXR1cm4gbmV3IEp0fSkpfX1mdW5jdGlvbiBqbygpe2Zvcih2YXIgZT1bXSx0PTA7dDxhcmd1bWVudHMubGVuZ3RoO3QrKyllW3RdPWFyZ3VtZW50c1t0XTt2YXIgcj1NZShlKSxvPU50KGUsMS8wKTtyZXR1cm4gZT11dChlKSxnKGZ1bmN0aW9uKG4saSl7ZnQobykoZ2UoRChbbl0sTihlKSkscikpLnN1YnNjcmliZShpKX0pfWZ1bmN0aW9uIHFlKCl7Zm9yKHZhciBlPVtdLHQ9MDt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKWVbdF09YXJndW1lbnRzW3RdO3JldHVybiBqby5hcHBseSh2b2lkIDAsRChbXSxOKGUpKSl9ZnVuY3Rpb24gVHQoZSl7dmFyIHQscj0xLzAsbztyZXR1cm4gZSE9bnVsbCYmKHR5cGVvZiBlPT0ib2JqZWN0Ij8odD1lLmNvdW50LHI9dD09PXZvaWQgMD8xLzA6dCxvPWUuZGVsYXkpOnI9ZSkscjw9MD9mdW5jdGlvbigpe3JldHVybiBMfTpnKGZ1bmN0aW9uKG4saSl7dmFyIHM9MCxhLGM9ZnVuY3Rpb24oKXtpZihhPT1udWxsfHxhLnVuc3Vic2NyaWJlKCksYT1udWxsLG8hPW51bGwpe3ZhciBsPXR5cGVvZiBvPT0ibnVtYmVyIj9CZShvKTpJKG8ocykpLGY9eShpLGZ1bmN0aW9uKCl7Zi51bnN1YnNjcmliZSgpLHAoKX0pO2wuc3Vic2NyaWJlKGYpfWVsc2UgcCgpfSxwPWZ1bmN0aW9uKCl7dmFyIGw9ITE7YT1uLnN1YnNjcmliZSh5KGksdm9pZCAwLGZ1bmN0aW9uKCl7KytzPHI/YT9jKCk6bD0hMDppLmNvbXBsZXRlKCl9KSksbCYmYygpfTtwKCl9KX1mdW5jdGlvbiBrcihlKXtyZXR1cm4gZyhmdW5jdGlvbih0LHIpe3ZhciBvPSExLG49bnVsbDt0LnN1YnNjcmliZSh5KHIsZnVuY3Rpb24oaSl7bz0hMCxuPWl9KSksSShlKS5zdWJzY3JpYmUoeShyLGZ1bmN0aW9uKCl7aWYobyl7bz0hMTt2YXIgaT1uO249bnVsbCxyLm5leHQoaSl9fSxmZSkpfSl9ZnVuY3Rpb24gSHIoZSx0KXtyZXR1cm4gZyhQbyhlLHQsYXJndW1lbnRzLmxlbmd0aD49MiwhMCkpfWZ1bmN0aW9uIGxlKGUpe2U9PT12b2lkIDAmJihlPXt9KTt2YXIgdD1lLmNvbm5lY3RvcixyPXQ9PT12b2lkIDA/ZnVuY3Rpb24oKXtyZXR1cm4gbmV3IHh9OnQsbz1lLnJlc2V0T25FcnJvcixuPW89PT12b2lkIDA/ITA6byxpPWUucmVzZXRPbkNvbXBsZXRlLHM9aT09PXZvaWQgMD8hMDppLGE9ZS5yZXNldE9uUmVmQ291bnRaZXJvLGM9YT09PXZvaWQgMD8hMDphO3JldHVybiBmdW5jdGlvbihwKXt2YXIgbCxmLHUsZD0wLHY9ITEsYj0hMSx6PWZ1bmN0aW9uKCl7Zj09bnVsbHx8Zi51bnN1YnNjcmliZSgpLGY9dm9pZCAwfSxLPWZ1bmN0aW9uKCl7eigpLGw9dT12b2lkIDAsdj1iPSExfSxHPWZ1bmN0aW9uKCl7dmFyIEM9bDtLKCksQz09bnVsbHx8Qy51bnN1YnNjcmliZSgpfTtyZXR1cm4gZyhmdW5jdGlvbihDLGl0KXtkKyssIWImJiF2JiZ6KCk7dmFyIE5lPXU9dSE9bnVsbD91OnIoKTtpdC5hZGQoZnVuY3Rpb24oKXtkLS0sZD09PTAmJiFiJiYhdiYmKGY9JHIoRyxjKSl9KSxOZS5zdWJzY3JpYmUoaXQpLCFsJiZkPjAmJihsPW5ldyB0dCh7bmV4dDpmdW5jdGlvbihQZSl7cmV0dXJuIE5lLm5leHQoUGUpfSxlcnJvcjpmdW5jdGlvbihQZSl7Yj0hMCx6KCksZj0kcihLLG4sUGUpLE5lLmVycm9yKFBlKX0sY29tcGxldGU6ZnVuY3Rpb24oKXt2PSEwLHooKSxmPSRyKEsscyksTmUuY29tcGxldGUoKX19KSxJKEMpLnN1YnNjcmliZShsKSl9KShwKX19ZnVuY3Rpb24gJHIoZSx0KXtmb3IodmFyIHI9W10sbz0yO288YXJndW1lbnRzLmxlbmd0aDtvKyspcltvLTJdPWFyZ3VtZW50c1tvXTtpZih0PT09ITApe2UoKTtyZXR1cm59aWYodCE9PSExKXt2YXIgbj1uZXcgdHQoe25leHQ6ZnVuY3Rpb24oKXtuLnVuc3Vic2NyaWJlKCksZSgpfX0pO3JldHVybiBJKHQuYXBwbHkodm9pZCAwLEQoW10sTihyKSkpKS5zdWJzY3JpYmUobil9fWZ1bmN0aW9uIEooZSx0LHIpe3ZhciBvLG4saSxzLGE9ITE7cmV0dXJuIGUmJnR5cGVvZiBlPT0ib2JqZWN0Ij8obz1lLmJ1ZmZlclNpemUscz1vPT09dm9pZCAwPzEvMDpvLG49ZS53aW5kb3dUaW1lLHQ9bj09PXZvaWQgMD8xLzA6bixpPWUucmVmQ291bnQsYT1pPT09dm9pZCAwPyExOmkscj1lLnNjaGVkdWxlcik6cz1lIT1udWxsP2U6MS8wLGxlKHtjb25uZWN0b3I6ZnVuY3Rpb24oKXtyZXR1cm4gbmV3IEV0KHMsdCxyKX0scmVzZXRPbkVycm9yOiEwLHJlc2V0T25Db21wbGV0ZTohMSxyZXNldE9uUmVmQ291bnRaZXJvOmF9KX1mdW5jdGlvbiBqZShlKXtyZXR1cm4gTShmdW5jdGlvbih0LHIpe3JldHVybiBlPD1yfSl9ZnVuY3Rpb24gUnIoZSl7cmV0dXJuIGcoZnVuY3Rpb24odCxyKXt2YXIgbz0hMSxuPXkocixmdW5jdGlvbigpe249PW51bGx8fG4udW5zdWJzY3JpYmUoKSxvPSEwfSxmZSk7SShlKS5zdWJzY3JpYmUobiksdC5zdWJzY3JpYmUoeShyLGZ1bmN0aW9uKGkpe3JldHVybiBvJiZyLm5leHQoaSl9KSl9KX1mdW5jdGlvbiBWKCl7Zm9yKHZhciBlPVtdLHQ9MDt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKWVbdF09YXJndW1lbnRzW3RdO3ZhciByPU1lKGUpO3JldHVybiBnKGZ1bmN0aW9uKG8sbil7KHI/RmUoZSxvLHIpOkZlKGUsbykpLnN1YnNjcmliZShuKX0pfWZ1bmN0aW9uIEUoZSx0KXtyZXR1cm4gZyhmdW5jdGlvbihyLG8pe3ZhciBuPW51bGwsaT0wLHM9ITEsYT1mdW5jdGlvbigpe3JldHVybiBzJiYhbiYmby5jb21wbGV0ZSgpfTtyLnN1YnNjcmliZSh5KG8sZnVuY3Rpb24oYyl7bj09bnVsbHx8bi51bnN1YnNjcmliZSgpO3ZhciBwPTAsbD1pKys7SShlKGMsbCkpLnN1YnNjcmliZShuPXkobyxmdW5jdGlvbihmKXtyZXR1cm4gby5uZXh0KHQ/dChjLGYsbCxwKyspOmYpfSxmdW5jdGlvbigpe249bnVsbCxhKCl9KSl9LGZ1bmN0aW9uKCl7cz0hMCxhKCl9KSl9KX1mdW5jdGlvbiBZKGUpe3JldHVybiBnKGZ1bmN0aW9uKHQscil7SShlKS5zdWJzY3JpYmUoeShyLGZ1bmN0aW9uKCl7cmV0dXJuIHIuY29tcGxldGUoKX0sZmUpKSwhci5jbG9zZWQmJnQuc3Vic2NyaWJlKHIpfSl9ZnVuY3Rpb24gUHIoZSx0KXtyZXR1cm4gdD09PXZvaWQgMCYmKHQ9ITEpLGcoZnVuY3Rpb24ocixvKXt2YXIgbj0wO3Iuc3Vic2NyaWJlKHkobyxmdW5jdGlvbihpKXt2YXIgcz1lKGksbisrKTsoc3x8dCkmJm8ubmV4dChpKSwhcyYmby5jb21wbGV0ZSgpfSkpfSl9ZnVuY3Rpb24gdyhlLHQscil7dmFyIG89ayhlKXx8dHx8cj97bmV4dDplLGVycm9yOnQsY29tcGxldGU6cn06ZTtyZXR1cm4gbz9nKGZ1bmN0aW9uKG4saSl7dmFyIHM7KHM9by5zdWJzY3JpYmUpPT09bnVsbHx8cz09PXZvaWQgMHx8cy5jYWxsKG8pO3ZhciBhPSEwO24uc3Vic2NyaWJlKHkoaSxmdW5jdGlvbihjKXt2YXIgcDsocD1vLm5leHQpPT09bnVsbHx8cD09PXZvaWQgMHx8cC5jYWxsKG8sYyksaS5uZXh0KGMpfSxmdW5jdGlvbigpe3ZhciBjO2E9ITEsKGM9by5jb21wbGV0ZSk9PT1udWxsfHxjPT09dm9pZCAwfHxjLmNhbGwobyksaS5jb21wbGV0ZSgpfSxmdW5jdGlvbihjKXt2YXIgcDthPSExLChwPW8uZXJyb3IpPT09bnVsbHx8cD09PXZvaWQgMHx8cC5jYWxsKG8sYyksaS5lcnJvcihjKX0sZnVuY3Rpb24oKXt2YXIgYyxwO2EmJigoYz1vLnVuc3Vic2NyaWJlKT09PW51bGx8fGM9PT12b2lkIDB8fGMuY2FsbChvKSksKHA9by5maW5hbGl6ZSk9PT1udWxsfHxwPT09dm9pZCAwfHxwLmNhbGwobyl9KSl9KTp1ZX1mdW5jdGlvbiBXbyhlLHQpe3JldHVybiBnKGZ1bmN0aW9uKHIsbyl7dmFyIG49dCE9bnVsbD90Ont9LGk9bi5sZWFkaW5nLHM9aT09PXZvaWQgMD8hMDppLGE9bi50cmFpbGluZyxjPWE9PT12b2lkIDA/ITE6YSxwPSExLGw9bnVsbCxmPW51bGwsdT0hMSxkPWZ1bmN0aW9uKCl7Zj09bnVsbHx8Zi51bnN1YnNjcmliZSgpLGY9bnVsbCxjJiYoeigpLHUmJm8uY29tcGxldGUoKSl9LHY9ZnVuY3Rpb24oKXtmPW51bGwsdSYmby5jb21wbGV0ZSgpfSxiPWZ1bmN0aW9uKEspe3JldHVybiBmPUkoZShLKSkuc3Vic2NyaWJlKHkobyxkLHYpKX0sej1mdW5jdGlvbigpe2lmKHApe3A9ITE7dmFyIEs9bDtsPW51bGwsby5uZXh0KEspLCF1JiZiKEspfX07ci5zdWJzY3JpYmUoeShvLGZ1bmN0aW9uKEspe3A9ITAsbD1LLCEoZiYmIWYuY2xvc2VkKSYmKHM/eigpOmIoSykpfSxmdW5jdGlvbigpe3U9ITAsIShjJiZwJiZmJiYhZi5jbG9zZWQpJiZvLmNvbXBsZXRlKCl9KSl9KX1mdW5jdGlvbiBJcihlLHQscil7dD09PXZvaWQgMCYmKHQ9YWUpO3ZhciBvPUJlKGUsdCk7cmV0dXJuIFdvKGZ1bmN0aW9uKCl7cmV0dXJuIG99LHIpfWZ1bmN0aW9uIG5lKCl7Zm9yKHZhciBlPVtdLHQ9MDt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKWVbdF09YXJndW1lbnRzW3RdO3ZhciByPVFlKGUpO3JldHVybiBnKGZ1bmN0aW9uKG8sbil7Zm9yKHZhciBpPWUubGVuZ3RoLHM9bmV3IEFycmF5KGkpLGE9ZS5tYXAoZnVuY3Rpb24oKXtyZXR1cm4hMX0pLGM9ITEscD1mdW5jdGlvbihmKXtJKGVbZl0pLnN1YnNjcmliZSh5KG4sZnVuY3Rpb24odSl7c1tmXT11LCFjJiYhYVtmXSYmKGFbZl09ITAsKGM9YS5ldmVyeSh1ZSkpJiYoYT1udWxsKSl9LGZlKSl9LGw9MDtsPGk7bCsrKXAobCk7by5zdWJzY3JpYmUoeShuLGZ1bmN0aW9uKGYpe2lmKGMpe3ZhciB1PUQoW2ZdLE4ocykpO24ubmV4dChyP3IuYXBwbHkodm9pZCAwLEQoW10sTih1KSkpOnUpfX0pKX0pfWZ1bmN0aW9uIFVvKCl7Zm9yKHZhciBlPVtdLHQ9MDt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKWVbdF09YXJndW1lbnRzW3RdO3JldHVybiBnKGZ1bmN0aW9uKHIsbyl7U3QuYXBwbHkodm9pZCAwLEQoW3JdLE4oZSkpKS5zdWJzY3JpYmUobyl9KX1mdW5jdGlvbiBGcigpe2Zvcih2YXIgZT1bXSx0PTA7dDxhcmd1bWVudHMubGVuZ3RoO3QrKyllW3RdPWFyZ3VtZW50c1t0XTtyZXR1cm4gVW8uYXBwbHkodm9pZCAwLEQoW10sTihlKSkpfWZ1bmN0aW9uIE5vKCl7bGV0IGU9bmV3IEV0KDEpO3JldHVybiBoKGRvY3VtZW50LCJET01Db250ZW50TG9hZGVkIix7b25jZTohMH0pLnN1YnNjcmliZSgoKT0+ZS5uZXh0KGRvY3VtZW50KSksZX1mdW5jdGlvbiBxKGUsdD1kb2N1bWVudCl7cmV0dXJuIEFycmF5LmZyb20odC5xdWVyeVNlbGVjdG9yQWxsKGUpKX1mdW5jdGlvbiBXKGUsdD1kb2N1bWVudCl7bGV0IHI9Y2UoZSx0KTtpZih0eXBlb2Ygcj09InVuZGVmaW5lZCIpdGhyb3cgbmV3IFJlZmVyZW5jZUVycm9yKGBNaXNzaW5nIGVsZW1lbnQ6IGV4cGVjdGVkICIke2V9IiB0byBiZSBwcmVzZW50YCk7cmV0dXJuIHJ9ZnVuY3Rpb24gY2UoZSx0PWRvY3VtZW50KXtyZXR1cm4gdC5xdWVyeVNlbGVjdG9yKGUpfHx2b2lkIDB9ZnVuY3Rpb24gUmUoKXtyZXR1cm4gZG9jdW1lbnQuYWN0aXZlRWxlbWVudCBpbnN0YW5jZW9mIEhUTUxFbGVtZW50JiZkb2N1bWVudC5hY3RpdmVFbGVtZW50fHx2b2lkIDB9dmFyIG5hPV8oaChkb2N1bWVudC5ib2R5LCJmb2N1c2luIiksaChkb2N1bWVudC5ib2R5LCJmb2N1c291dCIpKS5waXBlKGtlKDEpLFYodm9pZCAwKSxtKCgpPT5SZSgpfHxkb2N1bWVudC5ib2R5KSxKKDEpKTtmdW5jdGlvbiBadChlKXtyZXR1cm4gbmEucGlwZShtKHQ9PmUuY29udGFpbnModCkpLFgoKSl9ZnVuY3Rpb24gSmUoZSl7cmV0dXJue3g6ZS5vZmZzZXRMZWZ0LHk6ZS5vZmZzZXRUb3B9fWZ1bmN0aW9uIERvKGUpe3JldHVybiBfKGgod2luZG93LCJsb2FkIiksaCh3aW5kb3csInJlc2l6ZSIpKS5waXBlKENlKDAsT2UpLG0oKCk9PkplKGUpKSxWKEplKGUpKSl9ZnVuY3Rpb24gZXIoZSl7cmV0dXJue3g6ZS5zY3JvbGxMZWZ0LHk6ZS5zY3JvbGxUb3B9fWZ1bmN0aW9uIGR0KGUpe3JldHVybiBfKGgoZSwic2Nyb2xsIiksaCh3aW5kb3csInJlc2l6ZSIpKS5waXBlKENlKDAsT2UpLG0oKCk9PmVyKGUpKSxWKGVyKGUpKSl9ZnVuY3Rpb24gVm8oZSx0KXtpZih0eXBlb2YgdD09InN0cmluZyJ8fHR5cGVvZiB0PT0ibnVtYmVyIillLmlubmVySFRNTCs9dC50b1N0cmluZygpO2Vsc2UgaWYodCBpbnN0YW5jZW9mIE5vZGUpZS5hcHBlbmRDaGlsZCh0KTtlbHNlIGlmKEFycmF5LmlzQXJyYXkodCkpZm9yKGxldCByIG9mIHQpVm8oZSxyKX1mdW5jdGlvbiBUKGUsdCwuLi5yKXtsZXQgbz1kb2N1bWVudC5jcmVhdGVFbGVtZW50KGUpO2lmKHQpZm9yKGxldCBuIG9mIE9iamVjdC5rZXlzKHQpKXR5cGVvZiB0W25dIT0idW5kZWZpbmVkIiYmKHR5cGVvZiB0W25dIT0iYm9vbGVhbiI/by5zZXRBdHRyaWJ1dGUobix0W25dKTpvLnNldEF0dHJpYnV0ZShuLCIiKSk7Zm9yKGxldCBuIG9mIHIpVm8obyxuKTtyZXR1cm4gb31mdW5jdGlvbiB0cihlKXtpZihlPjk5OSl7bGV0IHQ9KygoZS05NTApJTFlMz45OSk7cmV0dXJuYCR7KChlKzFlLTYpLzFlMykudG9GaXhlZCh0KX1rYH1lbHNlIHJldHVybiBlLnRvU3RyaW5nKCl9ZnVuY3Rpb24gaHQoZSl7bGV0IHQ9VCgic2NyaXB0Iix7c3JjOmV9KTtyZXR1cm4gSCgoKT0+KGRvY3VtZW50LmhlYWQuYXBwZW5kQ2hpbGQodCksXyhoKHQsImxvYWQiKSxoKHQsImVycm9yIikucGlwZShFKCgpPT5McigoKT0+bmV3IFJlZmVyZW5jZUVycm9yKGBJbnZhbGlkIHNjcmlwdDogJHtlfWApKSkpKS5waXBlKG0oKCk9Pnt9KSxBKCgpPT5kb2N1bWVudC5oZWFkLnJlbW92ZUNoaWxkKHQpKSx4ZSgxKSkpKX12YXIgem89bmV3IHgsaWE9SCgoKT0+dHlwZW9mIFJlc2l6ZU9ic2VydmVyPT0idW5kZWZpbmVkIj9odCgiaHR0cHM6Ly91bnBrZy5jb20vcmVzaXplLW9ic2VydmVyLXBvbHlmaWxsIik6aih2b2lkIDApKS5waXBlKG0oKCk9Pm5ldyBSZXNpemVPYnNlcnZlcihlPT57Zm9yKGxldCB0IG9mIGUpem8ubmV4dCh0KX0pKSxFKGU9Pl8oVmUsaihlKSkucGlwZShBKCgpPT5lLmRpc2Nvbm5lY3QoKSkpKSxKKDEpKTtmdW5jdGlvbiBoZShlKXtyZXR1cm57d2lkdGg6ZS5vZmZzZXRXaWR0aCxoZWlnaHQ6ZS5vZmZzZXRIZWlnaHR9fWZ1bmN0aW9uIHllKGUpe3JldHVybiBpYS5waXBlKHcodD0+dC5vYnNlcnZlKGUpKSxFKHQ9PnpvLnBpcGUoTSgoe3RhcmdldDpyfSk9PnI9PT1lKSxBKCgpPT50LnVub2JzZXJ2ZShlKSksbSgoKT0+aGUoZSkpKSksVihoZShlKSkpfWZ1bmN0aW9uIGJ0KGUpe3JldHVybnt3aWR0aDplLnNjcm9sbFdpZHRoLGhlaWdodDplLnNjcm9sbEhlaWdodH19ZnVuY3Rpb24gcnIoZSl7bGV0IHQ9ZS5wYXJlbnRFbGVtZW50O2Zvcig7dCYmKGUuc2Nyb2xsV2lkdGg8PXQuc2Nyb2xsV2lkdGgmJmUuc2Nyb2xsSGVpZ2h0PD10LnNjcm9sbEhlaWdodCk7KXQ9KGU9dCkucGFyZW50RWxlbWVudDtyZXR1cm4gdD9lOnZvaWQgMH12YXIgcW89bmV3IHgsYWE9SCgoKT0+aihuZXcgSW50ZXJzZWN0aW9uT2JzZXJ2ZXIoZT0+e2ZvcihsZXQgdCBvZiBlKXFvLm5leHQodCl9LHt0aHJlc2hvbGQ6MH0pKSkucGlwZShFKGU9Pl8oVmUsaihlKSkucGlwZShBKCgpPT5lLmRpc2Nvbm5lY3QoKSkpKSxKKDEpKTtmdW5jdGlvbiBvcihlKXtyZXR1cm4gYWEucGlwZSh3KHQ9PnQub2JzZXJ2ZShlKSksRSh0PT5xby5waXBlKE0oKHt0YXJnZXQ6cn0pPT5yPT09ZSksQSgoKT0+dC51bm9ic2VydmUoZSkpLG0oKHtpc0ludGVyc2VjdGluZzpyfSk9PnIpKSkpfWZ1bmN0aW9uIEtvKGUsdD0xNil7cmV0dXJuIGR0KGUpLnBpcGUobSgoe3k6cn0pPT57bGV0IG89aGUoZSksbj1idChlKTtyZXR1cm4gcj49bi5oZWlnaHQtby5oZWlnaHQtdH0pLFgoKSl9dmFyIG5yPXtkcmF3ZXI6VygiW2RhdGEtbWQtdG9nZ2xlPWRyYXdlcl0iKSxzZWFyY2g6VygiW2RhdGEtbWQtdG9nZ2xlPXNlYXJjaF0iKX07ZnVuY3Rpb24gUW8oZSl7cmV0dXJuIG5yW2VdLmNoZWNrZWR9ZnVuY3Rpb24gS2UoZSx0KXtucltlXS5jaGVja2VkIT09dCYmbnJbZV0uY2xpY2soKX1mdW5jdGlvbiBXZShlKXtsZXQgdD1ucltlXTtyZXR1cm4gaCh0LCJjaGFuZ2UiKS5waXBlKG0oKCk9PnQuY2hlY2tlZCksVih0LmNoZWNrZWQpKX1mdW5jdGlvbiBzYShlLHQpe3N3aXRjaChlLmNvbnN0cnVjdG9yKXtjYXNlIEhUTUxJbnB1dEVsZW1lbnQ6cmV0dXJuIGUudHlwZT09PSJyYWRpbyI/L15BcnJvdy8udGVzdCh0KTohMDtjYXNlIEhUTUxTZWxlY3RFbGVtZW50OmNhc2UgSFRNTFRleHRBcmVhRWxlbWVudDpyZXR1cm4hMDtkZWZhdWx0OnJldHVybiBlLmlzQ29udGVudEVkaXRhYmxlfX1mdW5jdGlvbiBjYSgpe3JldHVybiBfKGgod2luZG93LCJjb21wb3NpdGlvbnN0YXJ0IikucGlwZShtKCgpPT4hMCkpLGgod2luZG93LCJjb21wb3NpdGlvbmVuZCIpLnBpcGUobSgoKT0+ITEpKSkucGlwZShWKCExKSl9ZnVuY3Rpb24gWW8oKXtsZXQgZT1oKHdpbmRvdywia2V5ZG93biIpLnBpcGUoTSh0PT4hKHQubWV0YUtleXx8dC5jdHJsS2V5KSksbSh0PT4oe21vZGU6UW8oInNlYXJjaCIpPyJzZWFyY2giOiJnbG9iYWwiLHR5cGU6dC5rZXksY2xhaW0oKXt0LnByZXZlbnREZWZhdWx0KCksdC5zdG9wUHJvcGFnYXRpb24oKX19KSksTSgoe21vZGU6dCx0eXBlOnJ9KT0+e2lmKHQ9PT0iZ2xvYmFsIil7bGV0IG89UmUoKTtpZih0eXBlb2YgbyE9InVuZGVmaW5lZCIpcmV0dXJuIXNhKG8scil9cmV0dXJuITB9KSxsZSgpKTtyZXR1cm4gY2EoKS5waXBlKEUodD0+dD9MOmUpKX1mdW5jdGlvbiBwZSgpe3JldHVybiBuZXcgVVJMKGxvY2F0aW9uLmhyZWYpfWZ1bmN0aW9uIG90KGUsdD0hMSl7aWYodGUoIm5hdmlnYXRpb24uaW5zdGFudCIpJiYhdCl7bGV0IHI9VCgiYSIse2hyZWY6ZS5ocmVmfSk7ZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChyKSxyLmNsaWNrKCksci5yZW1vdmUoKX1lbHNlIGxvY2F0aW9uLmhyZWY9ZS5ocmVmfWZ1bmN0aW9uIEJvKCl7cmV0dXJuIG5ldyB4fWZ1bmN0aW9uIEdvKCl7cmV0dXJuIGxvY2F0aW9uLmhhc2guc2xpY2UoMSl9ZnVuY3Rpb24gaXIoZSl7bGV0IHQ9VCgiYSIse2hyZWY6ZX0pO3QuYWRkRXZlbnRMaXN0ZW5lcigiY2xpY2siLHI9PnIuc3RvcFByb3BhZ2F0aW9uKCkpLHQuY2xpY2soKX1mdW5jdGlvbiBwYShlKXtyZXR1cm4gXyhoKHdpbmRvdywiaGFzaGNoYW5nZSIpLGUpLnBpcGUobShHbyksVihHbygpKSxNKHQ9PnQubGVuZ3RoPjApLEooMSkpfWZ1bmN0aW9uIEpvKGUpe3JldHVybiBwYShlKS5waXBlKG0odD0+Y2UoYFtpZD0iJHt0fSJdYCkpLE0odD0+dHlwZW9mIHQhPSJ1bmRlZmluZWQiKSl9ZnVuY3Rpb24ganIoZSl7bGV0IHQ9bWF0Y2hNZWRpYShlKTtyZXR1cm4gWHQocj0+dC5hZGRMaXN0ZW5lcigoKT0+cih0Lm1hdGNoZXMpKSkucGlwZShWKHQubWF0Y2hlcykpfWZ1bmN0aW9uIFhvKCl7bGV0IGU9bWF0Y2hNZWRpYSgicHJpbnQiKTtyZXR1cm4gXyhoKHdpbmRvdywiYmVmb3JlcHJpbnQiKS5waXBlKG0oKCk9PiEwKSksaCh3aW5kb3csImFmdGVycHJpbnQiKS5waXBlKG0oKCk9PiExKSkpLnBpcGUoVihlLm1hdGNoZXMpKX1mdW5jdGlvbiBXcihlLHQpe3JldHVybiBlLnBpcGUoRShyPT5yP3QoKTpMKSl9ZnVuY3Rpb24gYXIoZSx0KXtyZXR1cm4gbmV3IFAocj0+e2xldCBvPW5ldyBYTUxIdHRwUmVxdWVzdDtvLm9wZW4oIkdFVCIsYCR7ZX1gKSxvLnJlc3BvbnNlVHlwZT0iYmxvYiIsby5hZGRFdmVudExpc3RlbmVyKCJsb2FkIiwoKT0+e28uc3RhdHVzPj0yMDAmJm8uc3RhdHVzPDMwMD8oci5uZXh0KG8ucmVzcG9uc2UpLHIuY29tcGxldGUoKSk6ci5lcnJvcihuZXcgRXJyb3Ioby5zdGF0dXNUZXh0KSl9KSxvLmFkZEV2ZW50TGlzdGVuZXIoImVycm9yIiwoKT0+e3IuZXJyb3IobmV3IEVycm9yKCJOZXR3b3JrIEVycm9yIikpfSksby5hZGRFdmVudExpc3RlbmVyKCJhYm9ydCIsKCk9PntyLmVycm9yKG5ldyBFcnJvcigiUmVxdWVzdCBhYm9ydGVkIikpfSksdHlwZW9mKHQ9PW51bGw/dm9pZCAwOnQucHJvZ3Jlc3MkKSE9InVuZGVmaW5lZCImJihvLmFkZEV2ZW50TGlzdGVuZXIoInByb2dyZXNzIixuPT57dC5wcm9ncmVzcyQubmV4dChuLmxvYWRlZC9uLnRvdGFsKjEwMCl9KSx0LnByb2dyZXNzJC5uZXh0KDUpKSxvLnNlbmQoKX0pfWZ1bmN0aW9uIFVlKGUsdCl7cmV0dXJuIGFyKGUsdCkucGlwZShFKHI9PnIudGV4dCgpKSxtKHI9PkpTT04ucGFyc2UocikpLEooMSkpfWZ1bmN0aW9uIFpvKGUsdCl7bGV0IHI9bmV3IERPTVBhcnNlcjtyZXR1cm4gYXIoZSx0KS5waXBlKEUobz0+by50ZXh0KCkpLG0obz0+ci5wYXJzZUZyb21TdHJpbmcobywidGV4dC94bWwiKSksSigxKSl9ZnVuY3Rpb24gZW4oKXtyZXR1cm57eDpNYXRoLm1heCgwLHNjcm9sbFgpLHk6TWF0aC5tYXgoMCxzY3JvbGxZKX19ZnVuY3Rpb24gdG4oKXtyZXR1cm4gXyhoKHdpbmRvdywic2Nyb2xsIix7cGFzc2l2ZTohMH0pLGgod2luZG93LCJyZXNpemUiLHtwYXNzaXZlOiEwfSkpLnBpcGUobShlbiksVihlbigpKSl9ZnVuY3Rpb24gcm4oKXtyZXR1cm57d2lkdGg6aW5uZXJXaWR0aCxoZWlnaHQ6aW5uZXJIZWlnaHR9fWZ1bmN0aW9uIG9uKCl7cmV0dXJuIGgod2luZG93LCJyZXNpemUiLHtwYXNzaXZlOiEwfSkucGlwZShtKHJuKSxWKHJuKCkpKX1mdW5jdGlvbiBubigpe3JldHVybiBCKFt0bigpLG9uKCldKS5waXBlKG0oKFtlLHRdKT0+KHtvZmZzZXQ6ZSxzaXplOnR9KSksSigxKSl9ZnVuY3Rpb24gc3IoZSx7dmlld3BvcnQkOnQsaGVhZGVyJDpyfSl7bGV0IG89dC5waXBlKGVlKCJzaXplIikpLG49QihbbyxyXSkucGlwZShtKCgpPT5KZShlKSkpO3JldHVybiBCKFtyLHQsbl0pLnBpcGUobSgoW3toZWlnaHQ6aX0se29mZnNldDpzLHNpemU6YX0se3g6Yyx5OnB9XSk9Pih7b2Zmc2V0Ont4OnMueC1jLHk6cy55LXAraX0sc2l6ZTphfSkpKX1mdW5jdGlvbiBsYShlKXtyZXR1cm4gaChlLCJtZXNzYWdlIix0PT50LmRhdGEpfWZ1bmN0aW9uIG1hKGUpe2xldCB0PW5ldyB4O3JldHVybiB0LnN1YnNjcmliZShyPT5lLnBvc3RNZXNzYWdlKHIpKSx0fWZ1bmN0aW9uIGFuKGUsdD1uZXcgV29ya2VyKGUpKXtsZXQgcj1sYSh0KSxvPW1hKHQpLG49bmV3IHg7bi5zdWJzY3JpYmUobyk7bGV0IGk9by5waXBlKFooKSxyZSghMCkpO3JldHVybiBuLnBpcGUoWigpLHFlKHIucGlwZShZKGkpKSksbGUoKSl9dmFyIGZhPVcoIiNfX2NvbmZpZyIpLHZ0PUpTT04ucGFyc2UoZmEudGV4dENvbnRlbnQpO3Z0LmJhc2U9YCR7bmV3IFVSTCh2dC5iYXNlLHBlKCkpfWA7ZnVuY3Rpb24gbWUoKXtyZXR1cm4gdnR9ZnVuY3Rpb24gdGUoZSl7cmV0dXJuIHZ0LmZlYXR1cmVzLmluY2x1ZGVzKGUpfWZ1bmN0aW9uIGJlKGUsdCl7cmV0dXJuIHR5cGVvZiB0IT0idW5kZWZpbmVkIj92dC50cmFuc2xhdGlvbnNbZV0ucmVwbGFjZSgiIyIsdC50b1N0cmluZygpKTp2dC50cmFuc2xhdGlvbnNbZV19ZnVuY3Rpb24gRWUoZSx0PWRvY3VtZW50KXtyZXR1cm4gVyhgW2RhdGEtbWQtY29tcG9uZW50PSR7ZX1dYCx0KX1mdW5jdGlvbiBvZShlLHQ9ZG9jdW1lbnQpe3JldHVybiBxKGBbZGF0YS1tZC1jb21wb25lbnQ9JHtlfV1gLHQpfWZ1bmN0aW9uIHVhKGUpe2xldCB0PVcoIi5tZC10eXBlc2V0ID4gOmZpcnN0LWNoaWxkIixlKTtyZXR1cm4gaCh0LCJjbGljayIse29uY2U6ITB9KS5waXBlKG0oKCk9PlcoIi5tZC10eXBlc2V0IixlKSksbShyPT4oe2hhc2g6X19tZF9oYXNoKHIuaW5uZXJIVE1MKX0pKSl9ZnVuY3Rpb24gc24oZSl7aWYoIXRlKCJhbm5vdW5jZS5kaXNtaXNzIil8fCFlLmNoaWxkRWxlbWVudENvdW50KXJldHVybiBMO2lmKCFlLmhpZGRlbil7bGV0IHQ9VygiLm1kLXR5cGVzZXQiLGUpO19fbWRfaGFzaCh0LmlubmVySFRNTCk9PT1fX21kX2dldCgiX19hbm5vdW5jZSIpJiYoZS5oaWRkZW49ITApfXJldHVybiBIKCgpPT57bGV0IHQ9bmV3IHg7cmV0dXJuIHQuc3Vic2NyaWJlKCh7aGFzaDpyfSk9PntlLmhpZGRlbj0hMCxfX21kX3NldCgiX19hbm5vdW5jZSIscil9KSx1YShlKS5waXBlKHcocj0+dC5uZXh0KHIpKSxBKCgpPT50LmNvbXBsZXRlKCkpLG0ocj0+Uih7cmVmOmV9LHIpKSl9KX1mdW5jdGlvbiBkYShlLHt0YXJnZXQkOnR9KXtyZXR1cm4gdC5waXBlKG0ocj0+KHtoaWRkZW46ciE9PWV9KSkpfWZ1bmN0aW9uIGNuKGUsdCl7bGV0IHI9bmV3IHg7cmV0dXJuIHIuc3Vic2NyaWJlKCh7aGlkZGVuOm99KT0+e2UuaGlkZGVuPW99KSxkYShlLHQpLnBpcGUodyhvPT5yLm5leHQobykpLEEoKCk9PnIuY29tcGxldGUoKSksbShvPT5SKHtyZWY6ZX0sbykpKX1mdW5jdGlvbiBoYShlLHQpe2xldCByPUgoKCk9PkIoW0RvKGUpLGR0KHQpXSkpLnBpcGUobSgoW3t4Om8seTpufSxpXSk9PntsZXR7d2lkdGg6cyxoZWlnaHQ6YX09aGUoZSk7cmV0dXJue3g6by1pLngrcy8yLHk6bi1pLnkrYS8yfX0pKTtyZXR1cm4gWnQoZSkucGlwZShFKG89PnIucGlwZShtKG49Pih7YWN0aXZlOm8sb2Zmc2V0Om59KSkseGUoKyFvfHwxLzApKSkpfWZ1bmN0aW9uIHBuKGUsdCx7dGFyZ2V0JDpyfSl7bGV0W28sbl09QXJyYXkuZnJvbShlLmNoaWxkcmVuKTtyZXR1cm4gSCgoKT0+e2xldCBpPW5ldyB4LHM9aS5waXBlKFooKSxyZSghMCkpO3JldHVybiBpLnN1YnNjcmliZSh7bmV4dCh7b2Zmc2V0OmF9KXtlLnN0eWxlLnNldFByb3BlcnR5KCItLW1kLXRvb2x0aXAteCIsYCR7YS54fXB4YCksZS5zdHlsZS5zZXRQcm9wZXJ0eSgiLS1tZC10b29sdGlwLXkiLGAke2EueX1weGApfSxjb21wbGV0ZSgpe2Uuc3R5bGUucmVtb3ZlUHJvcGVydHkoIi0tbWQtdG9vbHRpcC14IiksZS5zdHlsZS5yZW1vdmVQcm9wZXJ0eSgiLS1tZC10b29sdGlwLXkiKX19KSxvcihlKS5waXBlKFkocykpLnN1YnNjcmliZShhPT57ZS50b2dnbGVBdHRyaWJ1dGUoImRhdGEtbWQtdmlzaWJsZSIsYSl9KSxfKGkucGlwZShNKCh7YWN0aXZlOmF9KT0+YSkpLGkucGlwZShrZSgyNTApLE0oKHthY3RpdmU6YX0pPT4hYSkpKS5zdWJzY3JpYmUoe25leHQoe2FjdGl2ZTphfSl7YT9lLnByZXBlbmQobyk6by5yZW1vdmUoKX0sY29tcGxldGUoKXtlLnByZXBlbmQobyl9fSksaS5waXBlKENlKDE2LE9lKSkuc3Vic2NyaWJlKCh7YWN0aXZlOmF9KT0+e28uY2xhc3NMaXN0LnRvZ2dsZSgibWQtdG9vbHRpcC0tYWN0aXZlIixhKX0pLGkucGlwZShJcigxMjUsT2UpLE0oKCk9PiEhZS5vZmZzZXRQYXJlbnQpLG0oKCk9PmUub2Zmc2V0UGFyZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpKSxtKCh7eDphfSk9PmEpKS5zdWJzY3JpYmUoe25leHQoYSl7YT9lLnN0eWxlLnNldFByb3BlcnR5KCItLW1kLXRvb2x0aXAtMCIsYCR7LWF9cHhgKTplLnN0eWxlLnJlbW92ZVByb3BlcnR5KCItLW1kLXRvb2x0aXAtMCIpfSxjb21wbGV0ZSgpe2Uuc3R5bGUucmVtb3ZlUHJvcGVydHkoIi0tbWQtdG9vbHRpcC0wIil9fSksaChuLCJjbGljayIpLnBpcGUoWShzKSxNKGE9PiEoYS5tZXRhS2V5fHxhLmN0cmxLZXkpKSkuc3Vic2NyaWJlKGE9PnthLnN0b3BQcm9wYWdhdGlvbigpLGEucHJldmVudERlZmF1bHQoKX0pLGgobiwibW91c2Vkb3duIikucGlwZShZKHMpLG5lKGkpKS5zdWJzY3JpYmUoKFthLHthY3RpdmU6Y31dKT0+e3ZhciBwO2lmKGEuYnV0dG9uIT09MHx8YS5tZXRhS2V5fHxhLmN0cmxLZXkpYS5wcmV2ZW50RGVmYXVsdCgpO2Vsc2UgaWYoYyl7YS5wcmV2ZW50RGVmYXVsdCgpO2xldCBsPWUucGFyZW50RWxlbWVudC5jbG9zZXN0KCIubWQtYW5ub3RhdGlvbiIpO2wgaW5zdGFuY2VvZiBIVE1MRWxlbWVudD9sLmZvY3VzKCk6KHA9UmUoKSk9PW51bGx8fHAuYmx1cigpfX0pLHIucGlwZShZKHMpLE0oYT0+YT09PW8pLHplKDEyNSkpLnN1YnNjcmliZSgoKT0+ZS5mb2N1cygpKSxoYShlLHQpLnBpcGUodyhhPT5pLm5leHQoYSkpLEEoKCk9PmkuY29tcGxldGUoKSksbShhPT5SKHtyZWY6ZX0sYSkpKX0pfWZ1bmN0aW9uIFVyKGUpe3JldHVybiBUKCJkaXYiLHtjbGFzczoibWQtdG9vbHRpcCIsaWQ6ZX0sVCgiZGl2Iix7Y2xhc3M6Im1kLXRvb2x0aXBfX2lubmVyIG1kLXR5cGVzZXQifSkpfWZ1bmN0aW9uIGxuKGUsdCl7aWYodD10P2Ake3R9X2Fubm90YXRpb25fJHtlfWA6dm9pZCAwLHQpe2xldCByPXQ/YCMke3R9YDp2b2lkIDA7cmV0dXJuIFQoImFzaWRlIix7Y2xhc3M6Im1kLWFubm90YXRpb24iLHRhYkluZGV4OjB9LFVyKHQpLFQoImEiLHtocmVmOnIsY2xhc3M6Im1kLWFubm90YXRpb25fX2luZGV4Iix0YWJJbmRleDotMX0sVCgic3BhbiIseyJkYXRhLW1kLWFubm90YXRpb24taWQiOmV9KSkpfWVsc2UgcmV0dXJuIFQoImFzaWRlIix7Y2xhc3M6Im1kLWFubm90YXRpb24iLHRhYkluZGV4OjB9LFVyKHQpLFQoInNwYW4iLHtjbGFzczoibWQtYW5ub3RhdGlvbl9faW5kZXgiLHRhYkluZGV4Oi0xfSxUKCJzcGFuIix7ImRhdGEtbWQtYW5ub3RhdGlvbi1pZCI6ZX0pKSl9ZnVuY3Rpb24gbW4oZSl7cmV0dXJuIFQoImJ1dHRvbiIse2NsYXNzOiJtZC1jbGlwYm9hcmQgbWQtaWNvbiIsdGl0bGU6YmUoImNsaXBib2FyZC5jb3B5IiksImRhdGEtY2xpcGJvYXJkLXRhcmdldCI6YCMke2V9ID4gY29kZWB9KX1mdW5jdGlvbiBOcihlLHQpe2xldCByPXQmMixvPXQmMSxuPU9iamVjdC5rZXlzKGUudGVybXMpLmZpbHRlcihjPT4hZS50ZXJtc1tjXSkucmVkdWNlKChjLHApPT5bLi4uYyxUKCJkZWwiLG51bGwscCksIiAiXSxbXSkuc2xpY2UoMCwtMSksaT1tZSgpLHM9bmV3IFVSTChlLmxvY2F0aW9uLGkuYmFzZSk7dGUoInNlYXJjaC5oaWdobGlnaHQiKSYmcy5zZWFyY2hQYXJhbXMuc2V0KCJoIixPYmplY3QuZW50cmllcyhlLnRlcm1zKS5maWx0ZXIoKFssY10pPT5jKS5yZWR1Y2UoKGMsW3BdKT0+YCR7Y30gJHtwfWAudHJpbSgpLCIiKSk7bGV0e3RhZ3M6YX09bWUoKTtyZXR1cm4gVCgiYSIse2hyZWY6YCR7c31gLGNsYXNzOiJtZC1zZWFyY2gtcmVzdWx0X19saW5rIix0YWJJbmRleDotMX0sVCgiYXJ0aWNsZSIse2NsYXNzOiJtZC1zZWFyY2gtcmVzdWx0X19hcnRpY2xlIG1kLXR5cGVzZXQiLCJkYXRhLW1kLXNjb3JlIjplLnNjb3JlLnRvRml4ZWQoMil9LHI+MCYmVCgiZGl2Iix7Y2xhc3M6Im1kLXNlYXJjaC1yZXN1bHRfX2ljb24gbWQtaWNvbiJ9KSxyPjAmJlQoImgxIixudWxsLGUudGl0bGUpLHI8PTAmJlQoImgyIixudWxsLGUudGl0bGUpLG8+MCYmZS50ZXh0Lmxlbmd0aD4wJiZlLnRleHQsZS50YWdzJiZlLnRhZ3MubWFwKGM9PntsZXQgcD1hP2MgaW4gYT9gbWQtdGFnLWljb24gbWQtdGFnLS0ke2FbY119YDoibWQtdGFnLWljb24iOiIiO3JldHVybiBUKCJzcGFuIix7Y2xhc3M6YG1kLXRhZyAke3B9YH0sYyl9KSxvPjAmJm4ubGVuZ3RoPjAmJlQoInAiLHtjbGFzczoibWQtc2VhcmNoLXJlc3VsdF9fdGVybXMifSxiZSgic2VhcmNoLnJlc3VsdC50ZXJtLm1pc3NpbmciKSwiOiAiLC4uLm4pKSl9ZnVuY3Rpb24gZm4oZSl7bGV0IHQ9ZVswXS5zY29yZSxyPVsuLi5lXSxvPW1lKCksbj1yLmZpbmRJbmRleChsPT4hYCR7bmV3IFVSTChsLmxvY2F0aW9uLG8uYmFzZSl9YC5pbmNsdWRlcygiIyIpKSxbaV09ci5zcGxpY2UobiwxKSxzPXIuZmluZEluZGV4KGw9Pmwuc2NvcmU8dCk7cz09PS0xJiYocz1yLmxlbmd0aCk7bGV0IGE9ci5zbGljZSgwLHMpLGM9ci5zbGljZShzKSxwPVtOcihpLDJ8KyghbiYmcz09PTApKSwuLi5hLm1hcChsPT5OcihsLDEpKSwuLi5jLmxlbmd0aD9bVCgiZGV0YWlscyIse2NsYXNzOiJtZC1zZWFyY2gtcmVzdWx0X19tb3JlIn0sVCgic3VtbWFyeSIse3RhYkluZGV4Oi0xfSxUKCJkaXYiLG51bGwsYy5sZW5ndGg+MCYmYy5sZW5ndGg9PT0xP2JlKCJzZWFyY2gucmVzdWx0Lm1vcmUub25lIik6YmUoInNlYXJjaC5yZXN1bHQubW9yZS5vdGhlciIsYy5sZW5ndGgpKSksLi4uYy5tYXAobD0+TnIobCwxKSkpXTpbXV07cmV0dXJuIFQoImxpIix7Y2xhc3M6Im1kLXNlYXJjaC1yZXN1bHRfX2l0ZW0ifSxwKX1mdW5jdGlvbiB1bihlKXtyZXR1cm4gVCgidWwiLHtjbGFzczoibWQtc291cmNlX19mYWN0cyJ9LE9iamVjdC5lbnRyaWVzKGUpLm1hcCgoW3Qscl0pPT5UKCJsaSIse2NsYXNzOmBtZC1zb3VyY2VfX2ZhY3QgbWQtc291cmNlX19mYWN0LS0ke3R9YH0sdHlwZW9mIHI9PSJudW1iZXIiP3RyKHIpOnIpKSl9ZnVuY3Rpb24gRHIoZSl7bGV0IHQ9YHRhYmJlZC1jb250cm9sIHRhYmJlZC1jb250cm9sLS0ke2V9YDtyZXR1cm4gVCgiZGl2Iix7Y2xhc3M6dCxoaWRkZW46ITB9LFQoImJ1dHRvbiIse2NsYXNzOiJ0YWJiZWQtYnV0dG9uIix0YWJJbmRleDotMSwiYXJpYS1oaWRkZW4iOiJ0cnVlIn0pKX1mdW5jdGlvbiBkbihlKXtyZXR1cm4gVCgiZGl2Iix7Y2xhc3M6Im1kLXR5cGVzZXRfX3Njcm9sbHdyYXAifSxUKCJkaXYiLHtjbGFzczoibWQtdHlwZXNldF9fdGFibGUifSxlKSl9ZnVuY3Rpb24gYmEoZSl7bGV0IHQ9bWUoKSxyPW5ldyBVUkwoYC4uLyR7ZS52ZXJzaW9ufS9gLHQuYmFzZSk7cmV0dXJuIFQoImxpIix7Y2xhc3M6Im1kLXZlcnNpb25fX2l0ZW0ifSxUKCJhIix7aHJlZjpgJHtyfWAsY2xhc3M6Im1kLXZlcnNpb25fX2xpbmsifSxlLnRpdGxlKSl9ZnVuY3Rpb24gaG4oZSx0KXtyZXR1cm4gVCgiZGl2Iix7Y2xhc3M6Im1kLXZlcnNpb24ifSxUKCJidXR0b24iLHtjbGFzczoibWQtdmVyc2lvbl9fY3VycmVudCIsImFyaWEtbGFiZWwiOmJlKCJzZWxlY3QudmVyc2lvbiIpfSx0LnRpdGxlKSxUKCJ1bCIse2NsYXNzOiJtZC12ZXJzaW9uX19saXN0In0sZS5tYXAoYmEpKSl9ZnVuY3Rpb24gdmEoZSl7cmV0dXJuIGUudGFnTmFtZT09PSJDT0RFIj9xKCIuYywgLmMxLCAuY20iLGUpOltlXX1mdW5jdGlvbiBnYShlKXtsZXQgdD1bXTtmb3IobGV0IHIgb2YgdmEoZSkpe2xldCBvPVtdLG49ZG9jdW1lbnQuY3JlYXRlTm9kZUl0ZXJhdG9yKHIsTm9kZUZpbHRlci5TSE9XX1RFWFQpO2ZvcihsZXQgaT1uLm5leHROb2RlKCk7aTtpPW4ubmV4dE5vZGUoKSlvLnB1c2goaSk7Zm9yKGxldCBpIG9mIG8pe2xldCBzO2Zvcig7cz0vKFwoXGQrXCkpKCEpPy8uZXhlYyhpLnRleHRDb250ZW50KTspe2xldFssYSxjXT1zO2lmKHR5cGVvZiBjPT0idW5kZWZpbmVkIil7bGV0IHA9aS5zcGxpdFRleHQocy5pbmRleCk7aT1wLnNwbGl0VGV4dChhLmxlbmd0aCksdC5wdXNoKHApfWVsc2V7aS50ZXh0Q29udGVudD1hLHQucHVzaChpKTticmVha319fX1yZXR1cm4gdH1mdW5jdGlvbiBibihlLHQpe3QuYXBwZW5kKC4uLkFycmF5LmZyb20oZS5jaGlsZE5vZGVzKSl9ZnVuY3Rpb24gY3IoZSx0LHt0YXJnZXQkOnIscHJpbnQkOm99KXtsZXQgbj10LmNsb3Nlc3QoIltpZF0iKSxpPW49PW51bGw/dm9pZCAwOm4uaWQscz1uZXcgTWFwO2ZvcihsZXQgYSBvZiBnYSh0KSl7bGV0WyxjXT1hLnRleHRDb250ZW50Lm1hdGNoKC9cKChcZCspXCkvKTtjZShgOnNjb3BlID4gbGk6bnRoLWNoaWxkKCR7Y30pYCxlKSYmKHMuc2V0KGMsbG4oYyxpKSksYS5yZXBsYWNlV2l0aChzLmdldChjKSkpfXJldHVybiBzLnNpemU9PT0wP0w6SCgoKT0+e2xldCBhPW5ldyB4LGM9YS5waXBlKFooKSxyZSghMCkpLHA9W107Zm9yKGxldFtsLGZdb2YgcylwLnB1c2goW1coIi5tZC10eXBlc2V0IixmKSxXKGA6c2NvcGUgPiBsaTpudGgtY2hpbGQoJHtsfSlgLGUpXSk7cmV0dXJuIG8ucGlwZShZKGMpKS5zdWJzY3JpYmUobD0+e2UuaGlkZGVuPSFsLGUuY2xhc3NMaXN0LnRvZ2dsZSgibWQtYW5ub3RhdGlvbi1saXN0IixsKTtmb3IobGV0W2YsdV1vZiBwKWw/Ym4oZix1KTpibih1LGYpfSksXyguLi5bLi4uc10ubWFwKChbLGxdKT0+cG4obCx0LHt0YXJnZXQkOnJ9KSkpLnBpcGUoQSgoKT0+YS5jb21wbGV0ZSgpKSxsZSgpKX0pfWZ1bmN0aW9uIHZuKGUpe2lmKGUubmV4dEVsZW1lbnRTaWJsaW5nKXtsZXQgdD1lLm5leHRFbGVtZW50U2libGluZztpZih0LnRhZ05hbWU9PT0iT0wiKXJldHVybiB0O2lmKHQudGFnTmFtZT09PSJQIiYmIXQuY2hpbGRyZW4ubGVuZ3RoKXJldHVybiB2bih0KX19ZnVuY3Rpb24gZ24oZSx0KXtyZXR1cm4gSCgoKT0+e2xldCByPXZuKGUpO3JldHVybiB0eXBlb2YgciE9InVuZGVmaW5lZCI/Y3IocixlLHQpOkx9KX12YXIgeW49SHQoenIoKSk7dmFyIHhhPTA7ZnVuY3Rpb24gRW4oZSl7aWYoZS5uZXh0RWxlbWVudFNpYmxpbmcpe2xldCB0PWUubmV4dEVsZW1lbnRTaWJsaW5nO2lmKHQudGFnTmFtZT09PSJPTCIpcmV0dXJuIHQ7aWYodC50YWdOYW1lPT09IlAiJiYhdC5jaGlsZHJlbi5sZW5ndGgpcmV0dXJuIEVuKHQpfX1mdW5jdGlvbiB4bihlKXtyZXR1cm4geWUoZSkucGlwZShtKCh7d2lkdGg6dH0pPT4oe3Njcm9sbGFibGU6YnQoZSkud2lkdGg+dH0pKSxlZSgic2Nyb2xsYWJsZSIpKX1mdW5jdGlvbiB3bihlLHQpe2xldHttYXRjaGVzOnJ9PW1hdGNoTWVkaWEoIihob3ZlcikiKSxvPUgoKCk9PntsZXQgbj1uZXcgeDtpZihuLnN1YnNjcmliZSgoe3Njcm9sbGFibGU6c30pPT57cyYmcj9lLnNldEF0dHJpYnV0ZSgidGFiaW5kZXgiLCIwIik6ZS5yZW1vdmVBdHRyaWJ1dGUoInRhYmluZGV4Iil9KSx5bi5kZWZhdWx0LmlzU3VwcG9ydGVkKCkmJihlLmNsb3Nlc3QoIi5jb3B5Iil8fHRlKCJjb250ZW50LmNvZGUuY29weSIpJiYhZS5jbG9zZXN0KCIubm8tY29weSIpKSl7bGV0IHM9ZS5jbG9zZXN0KCJwcmUiKTtzLmlkPWBfX2NvZGVfJHt4YSsrfWAscy5pbnNlcnRCZWZvcmUobW4ocy5pZCksZSl9bGV0IGk9ZS5jbG9zZXN0KCIuaGlnaGxpZ2h0Iik7aWYoaSBpbnN0YW5jZW9mIEhUTUxFbGVtZW50KXtsZXQgcz1FbihpKTtpZih0eXBlb2YgcyE9InVuZGVmaW5lZCImJihpLmNsYXNzTGlzdC5jb250YWlucygiYW5ub3RhdGUiKXx8dGUoImNvbnRlbnQuY29kZS5hbm5vdGF0ZSIpKSl7bGV0IGE9Y3IocyxlLHQpO3JldHVybiB4bihlKS5waXBlKHcoYz0+bi5uZXh0KGMpKSxBKCgpPT5uLmNvbXBsZXRlKCkpLG0oYz0+Uih7cmVmOmV9LGMpKSxxZSh5ZShpKS5waXBlKG0oKHt3aWR0aDpjLGhlaWdodDpwfSk9PmMmJnApLFgoKSxFKGM9PmM/YTpMKSkpKX19cmV0dXJuIHhuKGUpLnBpcGUodyhzPT5uLm5leHQocykpLEEoKCk9Pm4uY29tcGxldGUoKSksbShzPT5SKHtyZWY6ZX0scykpKX0pO3JldHVybiB0ZSgiY29udGVudC5sYXp5Iik/b3IoZSkucGlwZShNKG49Pm4pLHhlKDEpLEUoKCk9Pm8pKTpvfWZ1bmN0aW9uIHlhKGUse3RhcmdldCQ6dCxwcmludCQ6cn0pe2xldCBvPSEwO3JldHVybiBfKHQucGlwZShtKG49Pm4uY2xvc2VzdCgiZGV0YWlsczpub3QoW29wZW5dKSIpKSxNKG49PmU9PT1uKSxtKCgpPT4oe2FjdGlvbjoib3BlbiIscmV2ZWFsOiEwfSkpKSxyLnBpcGUoTShuPT5ufHwhbyksdygoKT0+bz1lLm9wZW4pLG0obj0+KHthY3Rpb246bj8ib3BlbiI6ImNsb3NlIn0pKSkpfWZ1bmN0aW9uIFNuKGUsdCl7cmV0dXJuIEgoKCk9PntsZXQgcj1uZXcgeDtyZXR1cm4gci5zdWJzY3JpYmUoKHthY3Rpb246byxyZXZlYWw6bn0pPT57ZS50b2dnbGVBdHRyaWJ1dGUoIm9wZW4iLG89PT0ib3BlbiIpLG4mJmUuc2Nyb2xsSW50b1ZpZXcoKX0pLHlhKGUsdCkucGlwZSh3KG89PnIubmV4dChvKSksQSgoKT0+ci5jb21wbGV0ZSgpKSxtKG89PlIoe3JlZjplfSxvKSkpfSl9dmFyIFRuPSIubm9kZSBjaXJjbGUsLm5vZGUgZWxsaXBzZSwubm9kZSBwYXRoLC5ub2RlIHBvbHlnb24sLm5vZGUgcmVjdHtmaWxsOnZhcigtLW1kLW1lcm1haWQtbm9kZS1iZy1jb2xvcik7c3Ryb2tlOnZhcigtLW1kLW1lcm1haWQtbm9kZS1mZy1jb2xvcil9bWFya2Vye2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1lZGdlLWNvbG9yKSFpbXBvcnRhbnR9LmVkZ2VMYWJlbCAubGFiZWwgcmVjdHtmaWxsOiMwMDAwfS5sYWJlbHtjb2xvcjp2YXIoLS1tZC1tZXJtYWlkLWxhYmVsLWZnLWNvbG9yKTtmb250LWZhbWlseTp2YXIoLS1tZC1tZXJtYWlkLWZvbnQtZmFtaWx5KX0ubGFiZWwgZm9yZWlnbk9iamVjdHtsaW5lLWhlaWdodDpub3JtYWw7b3ZlcmZsb3c6dmlzaWJsZX0ubGFiZWwgZGl2IC5lZGdlTGFiZWx7Y29sb3I6dmFyKC0tbWQtbWVybWFpZC1sYWJlbC1mZy1jb2xvcil9LmVkZ2VMYWJlbCwuZWRnZUxhYmVsIHJlY3QsLmxhYmVsIGRpdiAuZWRnZUxhYmVse2JhY2tncm91bmQtY29sb3I6dmFyKC0tbWQtbWVybWFpZC1sYWJlbC1iZy1jb2xvcil9LmVkZ2VMYWJlbCwuZWRnZUxhYmVsIHJlY3R7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLWxhYmVsLWJnLWNvbG9yKTtjb2xvcjp2YXIoLS1tZC1tZXJtYWlkLWVkZ2UtY29sb3IpfS5lZGdlUGF0aCAucGF0aCwuZmxvd2NoYXJ0LWxpbmt7c3Ryb2tlOnZhcigtLW1kLW1lcm1haWQtZWRnZS1jb2xvcik7c3Ryb2tlLXdpZHRoOi4wNXJlbX0uZWRnZVBhdGggLmFycm93aGVhZFBhdGh7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLWVkZ2UtY29sb3IpO3N0cm9rZTpub25lfS5jbHVzdGVyIHJlY3R7ZmlsbDp2YXIoLS1tZC1kZWZhdWx0LWZnLWNvbG9yLS1saWdodGVzdCk7c3Ryb2tlOnZhcigtLW1kLWRlZmF1bHQtZmctY29sb3ItLWxpZ2h0ZXIpfS5jbHVzdGVyIHNwYW57Y29sb3I6dmFyKC0tbWQtbWVybWFpZC1sYWJlbC1mZy1jb2xvcik7Zm9udC1mYW1pbHk6dmFyKC0tbWQtbWVybWFpZC1mb250LWZhbWlseSl9ZyAjZmxvd2NoYXJ0LWNpcmNsZUVuZCxnICNmbG93Y2hhcnQtY2lyY2xlU3RhcnQsZyAjZmxvd2NoYXJ0LWNyb3NzRW5kLGcgI2Zsb3djaGFydC1jcm9zc1N0YXJ0LGcgI2Zsb3djaGFydC1wb2ludEVuZCxnICNmbG93Y2hhcnQtcG9pbnRTdGFydHtzdHJva2U6bm9uZX1nLmNsYXNzR3JvdXAgbGluZSxnLmNsYXNzR3JvdXAgcmVjdHtmaWxsOnZhcigtLW1kLW1lcm1haWQtbm9kZS1iZy1jb2xvcik7c3Ryb2tlOnZhcigtLW1kLW1lcm1haWQtbm9kZS1mZy1jb2xvcil9Zy5jbGFzc0dyb3VwIHRleHR7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLWxhYmVsLWZnLWNvbG9yKTtmb250LWZhbWlseTp2YXIoLS1tZC1tZXJtYWlkLWZvbnQtZmFtaWx5KX0uY2xhc3NMYWJlbCAuYm94e2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1sYWJlbC1iZy1jb2xvcik7YmFja2dyb3VuZC1jb2xvcjp2YXIoLS1tZC1tZXJtYWlkLWxhYmVsLWJnLWNvbG9yKTtvcGFjaXR5OjF9LmNsYXNzTGFiZWwgLmxhYmVse2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1sYWJlbC1mZy1jb2xvcik7Zm9udC1mYW1pbHk6dmFyKC0tbWQtbWVybWFpZC1mb250LWZhbWlseSl9Lm5vZGUgLmRpdmlkZXJ7c3Ryb2tlOnZhcigtLW1kLW1lcm1haWQtbm9kZS1mZy1jb2xvcil9LnJlbGF0aW9ue3N0cm9rZTp2YXIoLS1tZC1tZXJtYWlkLWVkZ2UtY29sb3IpfS5jYXJkaW5hbGl0eXtmaWxsOnZhcigtLW1kLW1lcm1haWQtbGFiZWwtZmctY29sb3IpO2ZvbnQtZmFtaWx5OnZhcigtLW1kLW1lcm1haWQtZm9udC1mYW1pbHkpfS5jYXJkaW5hbGl0eSB0ZXh0e2ZpbGw6aW5oZXJpdCFpbXBvcnRhbnR9ZGVmcyAjY2xhc3NEaWFncmFtLWNvbXBvc2l0aW9uRW5kLGRlZnMgI2NsYXNzRGlhZ3JhbS1jb21wb3NpdGlvblN0YXJ0LGRlZnMgI2NsYXNzRGlhZ3JhbS1kZXBlbmRlbmN5RW5kLGRlZnMgI2NsYXNzRGlhZ3JhbS1kZXBlbmRlbmN5U3RhcnQsZGVmcyAjY2xhc3NEaWFncmFtLWV4dGVuc2lvbkVuZCxkZWZzICNjbGFzc0RpYWdyYW0tZXh0ZW5zaW9uU3RhcnR7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLWVkZ2UtY29sb3IpIWltcG9ydGFudDtzdHJva2U6dmFyKC0tbWQtbWVybWFpZC1lZGdlLWNvbG9yKSFpbXBvcnRhbnR9ZGVmcyAjY2xhc3NEaWFncmFtLWFnZ3JlZ2F0aW9uRW5kLGRlZnMgI2NsYXNzRGlhZ3JhbS1hZ2dyZWdhdGlvblN0YXJ0e2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1sYWJlbC1iZy1jb2xvcikhaW1wb3J0YW50O3N0cm9rZTp2YXIoLS1tZC1tZXJtYWlkLWVkZ2UtY29sb3IpIWltcG9ydGFudH1nLnN0YXRlR3JvdXAgcmVjdHtmaWxsOnZhcigtLW1kLW1lcm1haWQtbm9kZS1iZy1jb2xvcik7c3Ryb2tlOnZhcigtLW1kLW1lcm1haWQtbm9kZS1mZy1jb2xvcil9Zy5zdGF0ZUdyb3VwIC5zdGF0ZS10aXRsZXtmaWxsOnZhcigtLW1kLW1lcm1haWQtbGFiZWwtZmctY29sb3IpIWltcG9ydGFudDtmb250LWZhbWlseTp2YXIoLS1tZC1tZXJtYWlkLWZvbnQtZmFtaWx5KX1nLnN0YXRlR3JvdXAgLmNvbXBvc2l0e2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1sYWJlbC1iZy1jb2xvcil9Lm5vZGVMYWJlbHtjb2xvcjp2YXIoLS1tZC1tZXJtYWlkLWxhYmVsLWZnLWNvbG9yKTtmb250LWZhbWlseTp2YXIoLS1tZC1tZXJtYWlkLWZvbnQtZmFtaWx5KX0ubm9kZSBjaXJjbGUuc3RhdGUtZW5kLC5ub2RlIGNpcmNsZS5zdGF0ZS1zdGFydCwuc3RhcnQtc3RhdGV7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLWVkZ2UtY29sb3IpO3N0cm9rZTpub25lfS5lbmQtc3RhdGUtaW5uZXIsLmVuZC1zdGF0ZS1vdXRlcntmaWxsOnZhcigtLW1kLW1lcm1haWQtZWRnZS1jb2xvcil9LmVuZC1zdGF0ZS1pbm5lciwubm9kZSBjaXJjbGUuc3RhdGUtZW5ke3N0cm9rZTp2YXIoLS1tZC1tZXJtYWlkLWxhYmVsLWJnLWNvbG9yKX0udHJhbnNpdGlvbntzdHJva2U6dmFyKC0tbWQtbWVybWFpZC1lZGdlLWNvbG9yKX1baWRePXN0YXRlLWZvcmtdIHJlY3QsW2lkXj1zdGF0ZS1qb2luXSByZWN0e2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1lZGdlLWNvbG9yKSFpbXBvcnRhbnQ7c3Ryb2tlOm5vbmUhaW1wb3J0YW50fS5zdGF0ZWRpYWdyYW0tY2x1c3Rlci5zdGF0ZWRpYWdyYW0tY2x1c3RlciAuaW5uZXJ7ZmlsbDp2YXIoLS1tZC1kZWZhdWx0LWJnLWNvbG9yKX0uc3RhdGVkaWFncmFtLWNsdXN0ZXIgcmVjdHtmaWxsOnZhcigtLW1kLW1lcm1haWQtbm9kZS1iZy1jb2xvcik7c3Ryb2tlOnZhcigtLW1kLW1lcm1haWQtbm9kZS1mZy1jb2xvcil9LnN0YXRlZGlhZ3JhbS1zdGF0ZSByZWN0LmRpdmlkZXJ7ZmlsbDp2YXIoLS1tZC1kZWZhdWx0LWZnLWNvbG9yLS1saWdodGVzdCk7c3Ryb2tlOnZhcigtLW1kLWRlZmF1bHQtZmctY29sb3ItLWxpZ2h0ZXIpfWRlZnMgI3N0YXRlZGlhZ3JhbS1iYXJiRW5ke3N0cm9rZTp2YXIoLS1tZC1tZXJtYWlkLWVkZ2UtY29sb3IpfS5hdHRyaWJ1dGVCb3hFdmVuLC5hdHRyaWJ1dGVCb3hPZGR7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLW5vZGUtYmctY29sb3IpO3N0cm9rZTp2YXIoLS1tZC1tZXJtYWlkLW5vZGUtZmctY29sb3IpfS5lbnRpdHlCb3h7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLWxhYmVsLWJnLWNvbG9yKTtzdHJva2U6dmFyKC0tbWQtbWVybWFpZC1ub2RlLWZnLWNvbG9yKX0uZW50aXR5TGFiZWx7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLWxhYmVsLWZnLWNvbG9yKTtmb250LWZhbWlseTp2YXIoLS1tZC1tZXJtYWlkLWZvbnQtZmFtaWx5KX0ucmVsYXRpb25zaGlwTGFiZWxCb3h7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLWxhYmVsLWJnLWNvbG9yKTtmaWxsLW9wYWNpdHk6MTtiYWNrZ3JvdW5kLWNvbG9yOnZhcigtLW1kLW1lcm1haWQtbGFiZWwtYmctY29sb3IpO29wYWNpdHk6MX0ucmVsYXRpb25zaGlwTGFiZWx7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLWxhYmVsLWZnLWNvbG9yKX0ucmVsYXRpb25zaGlwTGluZXtzdHJva2U6dmFyKC0tbWQtbWVybWFpZC1lZGdlLWNvbG9yKX1kZWZzICNPTkVfT1JfTU9SRV9FTkQgKixkZWZzICNPTkVfT1JfTU9SRV9TVEFSVCAqLGRlZnMgI09OTFlfT05FX0VORCAqLGRlZnMgI09OTFlfT05FX1NUQVJUICosZGVmcyAjWkVST19PUl9NT1JFX0VORCAqLGRlZnMgI1pFUk9fT1JfTU9SRV9TVEFSVCAqLGRlZnMgI1pFUk9fT1JfT05FX0VORCAqLGRlZnMgI1pFUk9fT1JfT05FX1NUQVJUICp7c3Ryb2tlOnZhcigtLW1kLW1lcm1haWQtZWRnZS1jb2xvcikhaW1wb3J0YW50fWRlZnMgI1pFUk9fT1JfTU9SRV9FTkQgY2lyY2xlLGRlZnMgI1pFUk9fT1JfTU9SRV9TVEFSVCBjaXJjbGV7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLWxhYmVsLWJnLWNvbG9yKX0uYWN0b3J7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLXNlcXVlbmNlLWFjdG9yLWJnLWNvbG9yKTtzdHJva2U6dmFyKC0tbWQtbWVybWFpZC1zZXF1ZW5jZS1hY3Rvci1ib3JkZXItY29sb3IpfXRleHQuYWN0b3I+dHNwYW57ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLXNlcXVlbmNlLWFjdG9yLWZnLWNvbG9yKTtmb250LWZhbWlseTp2YXIoLS1tZC1tZXJtYWlkLWZvbnQtZmFtaWx5KX1saW5le3N0cm9rZTp2YXIoLS1tZC1tZXJtYWlkLXNlcXVlbmNlLWFjdG9yLWxpbmUtY29sb3IpfS5hY3Rvci1tYW4gY2lyY2xlLC5hY3Rvci1tYW4gbGluZXtmaWxsOnZhcigtLW1kLW1lcm1haWQtc2VxdWVuY2UtYWN0b3JtYW4tYmctY29sb3IpO3N0cm9rZTp2YXIoLS1tZC1tZXJtYWlkLXNlcXVlbmNlLWFjdG9ybWFuLWxpbmUtY29sb3IpfS5tZXNzYWdlTGluZTAsLm1lc3NhZ2VMaW5lMXtzdHJva2U6dmFyKC0tbWQtbWVybWFpZC1zZXF1ZW5jZS1tZXNzYWdlLWxpbmUtY29sb3IpfS5ub3Rle2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1zZXF1ZW5jZS1ub3RlLWJnLWNvbG9yKTtzdHJva2U6dmFyKC0tbWQtbWVybWFpZC1zZXF1ZW5jZS1ub3RlLWJvcmRlci1jb2xvcil9Lmxvb3BUZXh0LC5sb29wVGV4dD50c3BhbiwubWVzc2FnZVRleHQsLm5vdGVUZXh0PnRzcGFue3N0cm9rZTpub25lO2ZvbnQtZmFtaWx5OnZhcigtLW1kLW1lcm1haWQtZm9udC1mYW1pbHkpIWltcG9ydGFudH0ubWVzc2FnZVRleHR7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLXNlcXVlbmNlLW1lc3NhZ2UtZmctY29sb3IpfS5sb29wVGV4dCwubG9vcFRleHQ+dHNwYW57ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLXNlcXVlbmNlLWxvb3AtZmctY29sb3IpfS5ub3RlVGV4dD50c3BhbntmaWxsOnZhcigtLW1kLW1lcm1haWQtc2VxdWVuY2Utbm90ZS1mZy1jb2xvcil9I2Fycm93aGVhZCBwYXRoe2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1zZXF1ZW5jZS1tZXNzYWdlLWxpbmUtY29sb3IpO3N0cm9rZTpub25lfS5sb29wTGluZXtmaWxsOnZhcigtLW1kLW1lcm1haWQtc2VxdWVuY2UtbG9vcC1iZy1jb2xvcik7c3Ryb2tlOnZhcigtLW1kLW1lcm1haWQtc2VxdWVuY2UtbG9vcC1ib3JkZXItY29sb3IpfS5sYWJlbEJveHtmaWxsOnZhcigtLW1kLW1lcm1haWQtc2VxdWVuY2UtbGFiZWwtYmctY29sb3IpO3N0cm9rZTpub25lfS5sYWJlbFRleHQsLmxhYmVsVGV4dD5zcGFue2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1zZXF1ZW5jZS1sYWJlbC1mZy1jb2xvcik7Zm9udC1mYW1pbHk6dmFyKC0tbWQtbWVybWFpZC1mb250LWZhbWlseSl9LnNlcXVlbmNlTnVtYmVye2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1zZXF1ZW5jZS1udW1iZXItZmctY29sb3IpfXJlY3QucmVjdHtmaWxsOnZhcigtLW1kLW1lcm1haWQtc2VxdWVuY2UtYm94LWJnLWNvbG9yKTtzdHJva2U6bm9uZX1yZWN0LnJlY3QrdGV4dC50ZXh0e2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1zZXF1ZW5jZS1ib3gtZmctY29sb3IpfWRlZnMgI3NlcXVlbmNlbnVtYmVye2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1zZXF1ZW5jZS1udW1iZXItYmctY29sb3IpIWltcG9ydGFudH0iO3ZhciBxcix3YT0wO2Z1bmN0aW9uIFNhKCl7cmV0dXJuIHR5cGVvZiBtZXJtYWlkPT0idW5kZWZpbmVkInx8bWVybWFpZCBpbnN0YW5jZW9mIEVsZW1lbnQ/aHQoImh0dHBzOi8vdW5wa2cuY29tL21lcm1haWRAOS40LjMvZGlzdC9tZXJtYWlkLm1pbi5qcyIpOmoodm9pZCAwKX1mdW5jdGlvbiBPbihlKXtyZXR1cm4gZS5jbGFzc0xpc3QucmVtb3ZlKCJtZXJtYWlkIikscXJ8fChxcj1TYSgpLnBpcGUodygoKT0+bWVybWFpZC5pbml0aWFsaXplKHtzdGFydE9uTG9hZDohMSx0aGVtZUNTUzpUbixzZXF1ZW5jZTp7YWN0b3JGb250U2l6ZToiMTZweCIsbWVzc2FnZUZvbnRTaXplOiIxNnB4Iixub3RlRm9udFNpemU6IjE2cHgifX0pKSxtKCgpPT57fSksSigxKSkpLHFyLnN1YnNjcmliZSgoKT0+e2UuY2xhc3NMaXN0LmFkZCgibWVybWFpZCIpO2xldCB0PWBfX21lcm1haWRfJHt3YSsrfWAscj1UKCJkaXYiLHtjbGFzczoibWVybWFpZCJ9KSxvPWUudGV4dENvbnRlbnQ7bWVybWFpZC5tZXJtYWlkQVBJLnJlbmRlcih0LG8sKG4saSk9PntsZXQgcz1yLmF0dGFjaFNoYWRvdyh7bW9kZToiY2xvc2VkIn0pO3MuaW5uZXJIVE1MPW4sZS5yZXBsYWNlV2l0aChyKSxpPT1udWxsfHxpKHMpfSl9KSxxci5waXBlKG0oKCk9Pih7cmVmOmV9KSkpfXZhciBNbj1UKCJ0YWJsZSIpO2Z1bmN0aW9uIExuKGUpe3JldHVybiBlLnJlcGxhY2VXaXRoKE1uKSxNbi5yZXBsYWNlV2l0aChkbihlKSksaih7cmVmOmV9KX1mdW5jdGlvbiBUYShlKXtsZXQgdD1xKCI6c2NvcGUgPiBpbnB1dCIsZSkscj10LmZpbmQobz0+by5jaGVja2VkKXx8dFswXTtyZXR1cm4gXyguLi50Lm1hcChvPT5oKG8sImNoYW5nZSIpLnBpcGUobSgoKT0+VyhgbGFiZWxbZm9yPSIke28uaWR9Il1gKSkpKSkucGlwZShWKFcoYGxhYmVsW2Zvcj0iJHtyLmlkfSJdYCkpLG0obz0+KHthY3RpdmU6b30pKSl9ZnVuY3Rpb24gX24oZSx7dmlld3BvcnQkOnR9KXtsZXQgcj1EcigicHJldiIpO2UuYXBwZW5kKHIpO2xldCBvPURyKCJuZXh0Iik7ZS5hcHBlbmQobyk7bGV0IG49VygiLnRhYmJlZC1sYWJlbHMiLGUpO3JldHVybiBIKCgpPT57bGV0IGk9bmV3IHgscz1pLnBpcGUoWigpLHJlKCEwKSk7cmV0dXJuIEIoW2kseWUoZSldKS5waXBlKENlKDEsT2UpLFkocykpLnN1YnNjcmliZSh7bmV4dChbe2FjdGl2ZTphfSxjXSl7bGV0IHA9SmUoYSkse3dpZHRoOmx9PWhlKGEpO2Uuc3R5bGUuc2V0UHJvcGVydHkoIi0tbWQtaW5kaWNhdG9yLXgiLGAke3AueH1weGApLGUuc3R5bGUuc2V0UHJvcGVydHkoIi0tbWQtaW5kaWNhdG9yLXdpZHRoIixgJHtsfXB4YCk7bGV0IGY9ZXIobik7KHAueDxmLnh8fHAueCtsPmYueCtjLndpZHRoKSYmbi5zY3JvbGxUbyh7bGVmdDpNYXRoLm1heCgwLHAueC0xNiksYmVoYXZpb3I6InNtb290aCJ9KX0sY29tcGxldGUoKXtlLnN0eWxlLnJlbW92ZVByb3BlcnR5KCItLW1kLWluZGljYXRvci14IiksZS5zdHlsZS5yZW1vdmVQcm9wZXJ0eSgiLS1tZC1pbmRpY2F0b3Itd2lkdGgiKX19KSxCKFtkdChuKSx5ZShuKV0pLnBpcGUoWShzKSkuc3Vic2NyaWJlKChbYSxjXSk9PntsZXQgcD1idChuKTtyLmhpZGRlbj1hLng8MTYsby5oaWRkZW49YS54PnAud2lkdGgtYy53aWR0aC0xNn0pLF8oaChyLCJjbGljayIpLnBpcGUobSgoKT0+LTEpKSxoKG8sImNsaWNrIikucGlwZShtKCgpPT4xKSkpLnBpcGUoWShzKSkuc3Vic2NyaWJlKGE9PntsZXR7d2lkdGg6Y309aGUobik7bi5zY3JvbGxCeSh7bGVmdDpjKmEsYmVoYXZpb3I6InNtb290aCJ9KX0pLHRlKCJjb250ZW50LnRhYnMubGluayIpJiZpLnBpcGUoamUoMSksbmUodCkpLnN1YnNjcmliZSgoW3thY3RpdmU6YX0se29mZnNldDpjfV0pPT57bGV0IHA9YS5pbm5lclRleHQudHJpbSgpO2lmKGEuaGFzQXR0cmlidXRlKCJkYXRhLW1kLXN3aXRjaGluZyIpKWEucmVtb3ZlQXR0cmlidXRlKCJkYXRhLW1kLXN3aXRjaGluZyIpO2Vsc2V7bGV0IGw9ZS5vZmZzZXRUb3AtYy55O2ZvcihsZXQgdSBvZiBxKCJbZGF0YS10YWJzXSIpKWZvcihsZXQgZCBvZiBxKCI6c2NvcGUgPiBpbnB1dCIsdSkpe2xldCB2PVcoYGxhYmVsW2Zvcj0iJHtkLmlkfSJdYCk7aWYodiE9PWEmJnYuaW5uZXJUZXh0LnRyaW0oKT09PXApe3Yuc2V0QXR0cmlidXRlKCJkYXRhLW1kLXN3aXRjaGluZyIsIiIpLGQuY2xpY2soKTticmVha319d2luZG93LnNjcm9sbFRvKHt0b3A6ZS5vZmZzZXRUb3AtbH0pO2xldCBmPV9fbWRfZ2V0KCJfX3RhYnMiKXx8W107X19tZF9zZXQoIl9fdGFicyIsWy4uLm5ldyBTZXQoW3AsLi4uZl0pXSl9fSksaS5waXBlKFkocykpLnN1YnNjcmliZSgoKT0+e2ZvcihsZXQgYSBvZiBxKCJhdWRpbywgdmlkZW8iLGUpKWEucGF1c2UoKX0pLFRhKGUpLnBpcGUodyhhPT5pLm5leHQoYSkpLEEoKCk9PmkuY29tcGxldGUoKSksbShhPT5SKHtyZWY6ZX0sYSkpKX0pLnBpcGUocnQoYWUpKX1mdW5jdGlvbiBBbihlLHt2aWV3cG9ydCQ6dCx0YXJnZXQkOnIscHJpbnQkOm99KXtyZXR1cm4gXyguLi5xKCIuYW5ub3RhdGU6bm90KC5oaWdobGlnaHQpIixlKS5tYXAobj0+Z24obix7dGFyZ2V0JDpyLHByaW50JDpvfSkpLC4uLnEoInByZTpub3QoLm1lcm1haWQpID4gY29kZSIsZSkubWFwKG49PnduKG4se3RhcmdldCQ6cixwcmludCQ6b30pKSwuLi5xKCJwcmUubWVybWFpZCIsZSkubWFwKG49Pk9uKG4pKSwuLi5xKCJ0YWJsZTpub3QoW2NsYXNzXSkiLGUpLm1hcChuPT5MbihuKSksLi4ucSgiZGV0YWlscyIsZSkubWFwKG49PlNuKG4se3RhcmdldCQ6cixwcmludCQ6b30pKSwuLi5xKCJbZGF0YS10YWJzXSIsZSkubWFwKG49Pl9uKG4se3ZpZXdwb3J0JDp0fSkpKX1mdW5jdGlvbiBPYShlLHthbGVydCQ6dH0pe3JldHVybiB0LnBpcGUoRShyPT5fKGooITApLGooITEpLnBpcGUoemUoMmUzKSkpLnBpcGUobShvPT4oe21lc3NhZ2U6cixhY3RpdmU6b30pKSkpKX1mdW5jdGlvbiBDbihlLHQpe2xldCByPVcoIi5tZC10eXBlc2V0IixlKTtyZXR1cm4gSCgoKT0+e2xldCBvPW5ldyB4O3JldHVybiBvLnN1YnNjcmliZSgoe21lc3NhZ2U6bixhY3RpdmU6aX0pPT57ZS5jbGFzc0xpc3QudG9nZ2xlKCJtZC1kaWFsb2ctLWFjdGl2ZSIsaSksci50ZXh0Q29udGVudD1ufSksT2EoZSx0KS5waXBlKHcobj0+by5uZXh0KG4pKSxBKCgpPT5vLmNvbXBsZXRlKCkpLG0obj0+Uih7cmVmOmV9LG4pKSl9KX1mdW5jdGlvbiBNYSh7dmlld3BvcnQkOmV9KXtpZighdGUoImhlYWRlci5hdXRvaGlkZSIpKXJldHVybiBqKCExKTtsZXQgdD1lLnBpcGUobSgoe29mZnNldDp7eTpufX0pPT5uKSxMZSgyLDEpLG0oKFtuLGldKT0+W248aSxpXSksZWUoMCkpLHI9QihbZSx0XSkucGlwZShNKChbe29mZnNldDpufSxbLGldXSk9Pk1hdGguYWJzKGktbi55KT4xMDApLG0oKFssW25dXSk9Pm4pLFgoKSksbz1XZSgic2VhcmNoIik7cmV0dXJuIEIoW2Usb10pLnBpcGUobSgoW3tvZmZzZXQ6bn0saV0pPT5uLnk+NDAwJiYhaSksWCgpLEUobj0+bj9yOmooITEpKSxWKCExKSl9ZnVuY3Rpb24ga24oZSx0KXtyZXR1cm4gSCgoKT0+QihbeWUoZSksTWEodCldKSkucGlwZShtKChbe2hlaWdodDpyfSxvXSk9Pih7aGVpZ2h0OnIsaGlkZGVuOm99KSksWCgocixvKT0+ci5oZWlnaHQ9PT1vLmhlaWdodCYmci5oaWRkZW49PT1vLmhpZGRlbiksSigxKSl9ZnVuY3Rpb24gSG4oZSx7aGVhZGVyJDp0LG1haW4kOnJ9KXtyZXR1cm4gSCgoKT0+e2xldCBvPW5ldyB4LG49by5waXBlKFooKSxyZSghMCkpO3JldHVybiBvLnBpcGUoZWUoImFjdGl2ZSIpLEdlKHQpKS5zdWJzY3JpYmUoKFt7YWN0aXZlOml9LHtoaWRkZW46c31dKT0+e2UuY2xhc3NMaXN0LnRvZ2dsZSgibWQtaGVhZGVyLS1zaGFkb3ciLGkmJiFzKSxlLmhpZGRlbj1zfSksci5zdWJzY3JpYmUobyksdC5waXBlKFkobiksbShpPT5SKHtyZWY6ZX0saSkpKX0pfWZ1bmN0aW9uIExhKGUse3ZpZXdwb3J0JDp0LGhlYWRlciQ6cn0pe3JldHVybiBzcihlLHt2aWV3cG9ydCQ6dCxoZWFkZXIkOnJ9KS5waXBlKG0oKHtvZmZzZXQ6e3k6b319KT0+e2xldHtoZWlnaHQ6bn09aGUoZSk7cmV0dXJue2FjdGl2ZTpvPj1ufX0pLGVlKCJhY3RpdmUiKSl9ZnVuY3Rpb24gJG4oZSx0KXtyZXR1cm4gSCgoKT0+e2xldCByPW5ldyB4O3Iuc3Vic2NyaWJlKHtuZXh0KHthY3RpdmU6bn0pe2UuY2xhc3NMaXN0LnRvZ2dsZSgibWQtaGVhZGVyX190aXRsZS0tYWN0aXZlIixuKX0sY29tcGxldGUoKXtlLmNsYXNzTGlzdC5yZW1vdmUoIm1kLWhlYWRlcl9fdGl0bGUtLWFjdGl2ZSIpfX0pO2xldCBvPWNlKCIubWQtY29udGVudCBoMSIpO3JldHVybiB0eXBlb2Ygbz09InVuZGVmaW5lZCI/TDpMYShvLHQpLnBpcGUodyhuPT5yLm5leHQobikpLEEoKCk9PnIuY29tcGxldGUoKSksbShuPT5SKHtyZWY6ZX0sbikpKX0pfWZ1bmN0aW9uIFJuKGUse3ZpZXdwb3J0JDp0LGhlYWRlciQ6cn0pe2xldCBvPXIucGlwZShtKCh7aGVpZ2h0Oml9KT0+aSksWCgpKSxuPW8ucGlwZShFKCgpPT55ZShlKS5waXBlKG0oKHtoZWlnaHQ6aX0pPT4oe3RvcDplLm9mZnNldFRvcCxib3R0b206ZS5vZmZzZXRUb3AraX0pKSxlZSgiYm90dG9tIikpKSk7cmV0dXJuIEIoW28sbix0XSkucGlwZShtKChbaSx7dG9wOnMsYm90dG9tOmF9LHtvZmZzZXQ6e3k6Y30sc2l6ZTp7aGVpZ2h0OnB9fV0pPT4ocD1NYXRoLm1heCgwLHAtTWF0aC5tYXgoMCxzLWMsaSktTWF0aC5tYXgoMCxwK2MtYSkpLHtvZmZzZXQ6cy1pLGhlaWdodDpwLGFjdGl2ZTpzLWk8PWN9KSksWCgoaSxzKT0+aS5vZmZzZXQ9PT1zLm9mZnNldCYmaS5oZWlnaHQ9PT1zLmhlaWdodCYmaS5hY3RpdmU9PT1zLmFjdGl2ZSkpfWZ1bmN0aW9uIF9hKGUpe2xldCB0PV9fbWRfZ2V0KCJfX3BhbGV0dGUiKXx8e2luZGV4OmUuZmluZEluZGV4KHI9Pm1hdGNoTWVkaWEoci5nZXRBdHRyaWJ1dGUoImRhdGEtbWQtY29sb3ItbWVkaWEiKSkubWF0Y2hlcyl9O3JldHVybiBqKC4uLmUpLnBpcGUoc2Uocj0+aChyLCJjaGFuZ2UiKS5waXBlKG0oKCk9PnIpKSksVihlW01hdGgubWF4KDAsdC5pbmRleCldKSxtKHI9Pih7aW5kZXg6ZS5pbmRleE9mKHIpLGNvbG9yOntzY2hlbWU6ci5nZXRBdHRyaWJ1dGUoImRhdGEtbWQtY29sb3Itc2NoZW1lIikscHJpbWFyeTpyLmdldEF0dHJpYnV0ZSgiZGF0YS1tZC1jb2xvci1wcmltYXJ5IiksYWNjZW50OnIuZ2V0QXR0cmlidXRlKCJkYXRhLW1kLWNvbG9yLWFjY2VudCIpfX0pKSxKKDEpKX1mdW5jdGlvbiBQbihlKXtsZXQgdD1UKCJtZXRhIix7bmFtZToidGhlbWUtY29sb3IifSk7ZG9jdW1lbnQuaGVhZC5hcHBlbmRDaGlsZCh0KTtsZXQgcj1UKCJtZXRhIix7bmFtZToiY29sb3Itc2NoZW1lIn0pO3JldHVybiBkb2N1bWVudC5oZWFkLmFwcGVuZENoaWxkKHIpLEgoKCk9PntsZXQgbz1uZXcgeDtvLnN1YnNjcmliZShpPT57ZG9jdW1lbnQuYm9keS5zZXRBdHRyaWJ1dGUoImRhdGEtbWQtY29sb3Itc3dpdGNoaW5nIiwiIik7Zm9yKGxldFtzLGFdb2YgT2JqZWN0LmVudHJpZXMoaS5jb2xvcikpZG9jdW1lbnQuYm9keS5zZXRBdHRyaWJ1dGUoYGRhdGEtbWQtY29sb3ItJHtzfWAsYSk7Zm9yKGxldCBzPTA7czxuLmxlbmd0aDtzKyspe2xldCBhPW5bc10ubmV4dEVsZW1lbnRTaWJsaW5nO2EgaW5zdGFuY2VvZiBIVE1MRWxlbWVudCYmKGEuaGlkZGVuPWkuaW5kZXghPT1zKX1fX21kX3NldCgiX19wYWxldHRlIixpKX0pLG8ucGlwZShtKCgpPT57bGV0IGk9RWUoImhlYWRlciIpLHM9d2luZG93LmdldENvbXB1dGVkU3R5bGUoaSk7cmV0dXJuIHIuY29udGVudD1zLmNvbG9yU2NoZW1lLHMuYmFja2dyb3VuZENvbG9yLm1hdGNoKC9cZCsvZykubWFwKGE9PigrYSkudG9TdHJpbmcoMTYpLnBhZFN0YXJ0KDIsIjAiKSkuam9pbigiIil9KSkuc3Vic2NyaWJlKGk9PnQuY29udGVudD1gIyR7aX1gKSxvLnBpcGUoU2UoYWUpKS5zdWJzY3JpYmUoKCk9Pntkb2N1bWVudC5ib2R5LnJlbW92ZUF0dHJpYnV0ZSgiZGF0YS1tZC1jb2xvci1zd2l0Y2hpbmciKX0pO2xldCBuPXEoImlucHV0IixlKTtyZXR1cm4gX2EobikucGlwZSh3KGk9Pm8ubmV4dChpKSksQSgoKT0+by5jb21wbGV0ZSgpKSxtKGk9PlIoe3JlZjplfSxpKSkpfSl9ZnVuY3Rpb24gSW4oZSx7cHJvZ3Jlc3MkOnR9KXtyZXR1cm4gSCgoKT0+e2xldCByPW5ldyB4O3JldHVybiByLnN1YnNjcmliZSgoe3ZhbHVlOm99KT0+e2Uuc3R5bGUuc2V0UHJvcGVydHkoIi0tbWQtcHJvZ3Jlc3MtdmFsdWUiLGAke299YCl9KSx0LnBpcGUodyhvPT5yLm5leHQoe3ZhbHVlOm99KSksQSgoKT0+ci5jb21wbGV0ZSgpKSxtKG89Pih7cmVmOmUsdmFsdWU6b30pKSl9KX12YXIgS3I9SHQoenIoKSk7ZnVuY3Rpb24gQWEoZSl7ZS5zZXRBdHRyaWJ1dGUoImRhdGEtbWQtY29weWluZyIsIiIpO2xldCB0PWUuY2xvc2VzdCgiW2RhdGEtY29weV0iKSxyPXQ/dC5nZXRBdHRyaWJ1dGUoImRhdGEtY29weSIpOmUuaW5uZXJUZXh0O3JldHVybiBlLnJlbW92ZUF0dHJpYnV0ZSgiZGF0YS1tZC1jb3B5aW5nIikscn1mdW5jdGlvbiBGbih7YWxlcnQkOmV9KXtLci5kZWZhdWx0LmlzU3VwcG9ydGVkKCkmJm5ldyBQKHQ9PntuZXcgS3IuZGVmYXVsdCgiW2RhdGEtY2xpcGJvYXJkLXRhcmdldF0sIFtkYXRhLWNsaXBib2FyZC10ZXh0XSIse3RleHQ6cj0+ci5nZXRBdHRyaWJ1dGUoImRhdGEtY2xpcGJvYXJkLXRleHQiKXx8QWEoVyhyLmdldEF0dHJpYnV0ZSgiZGF0YS1jbGlwYm9hcmQtdGFyZ2V0IikpKX0pLm9uKCJzdWNjZXNzIixyPT50Lm5leHQocikpfSkucGlwZSh3KHQ9Pnt0LnRyaWdnZXIuZm9jdXMoKX0pLG0oKCk9PmJlKCJjbGlwYm9hcmQuY29waWVkIikpKS5zdWJzY3JpYmUoZSl9ZnVuY3Rpb24gQ2EoZSl7aWYoZS5sZW5ndGg8MilyZXR1cm5bIiJdO2xldFt0LHJdPVsuLi5lXS5zb3J0KChuLGkpPT5uLmxlbmd0aC1pLmxlbmd0aCkubWFwKG49Pm4ucmVwbGFjZSgvW14vXSskLywiIikpLG89MDtpZih0PT09cilvPXQubGVuZ3RoO2Vsc2UgZm9yKDt0LmNoYXJDb2RlQXQobyk9PT1yLmNoYXJDb2RlQXQobyk7KW8rKztyZXR1cm4gZS5tYXAobj0+bi5yZXBsYWNlKHQuc2xpY2UoMCxvKSwiIikpfWZ1bmN0aW9uIHByKGUpe2xldCB0PV9fbWRfZ2V0KCJfX3NpdGVtYXAiLHNlc3Npb25TdG9yYWdlLGUpO2lmKHQpcmV0dXJuIGoodCk7e2xldCByPW1lKCk7cmV0dXJuIFpvKG5ldyBVUkwoInNpdGVtYXAueG1sIixlfHxyLmJhc2UpKS5waXBlKG0obz0+Q2EocSgibG9jIixvKS5tYXAobj0+bi50ZXh0Q29udGVudCkpKSxkZSgoKT0+TCksSGUoW10pLHcobz0+X19tZF9zZXQoIl9fc2l0ZW1hcCIsbyxzZXNzaW9uU3RvcmFnZSxlKSkpfX1mdW5jdGlvbiBqbihlKXtsZXQgdD1XKCJbcmVsPWNhbm9uaWNhbF0iLGUpO3QuaHJlZj10LmhyZWYucmVwbGFjZSgiLy9sb2NhbGhvc3Q6IiwiLy8xMjcuMC4wLjEiKTtsZXQgcj1uZXcgTWFwO2ZvcihsZXQgbyBvZiBxKCI6c2NvcGUgPiAqIixlKSl7bGV0IG49by5vdXRlckhUTUw7Zm9yKGxldCBpIG9mWyJocmVmIiwic3JjIl0pe2xldCBzPW8uZ2V0QXR0cmlidXRlKGkpO2lmKHM9PT1udWxsKWNvbnRpbnVlO2xldCBhPW5ldyBVUkwocyx0LmhyZWYpLGM9by5jbG9uZU5vZGUoKTtjLnNldEF0dHJpYnV0ZShpLGAke2F9YCksbj1jLm91dGVySFRNTDticmVha31yLnNldChuLG8pfXJldHVybiByfWZ1bmN0aW9uIFduKHtsb2NhdGlvbiQ6ZSx2aWV3cG9ydCQ6dCxwcm9ncmVzcyQ6cn0pe2xldCBvPW1lKCk7aWYobG9jYXRpb24ucHJvdG9jb2w9PT0iZmlsZToiKXJldHVybiBMO2xldCBuPXByKCkucGlwZShtKGw9PmwubWFwKGY9PmAke25ldyBVUkwoZixvLmJhc2UpfWApKSksaT1oKGRvY3VtZW50LmJvZHksImNsaWNrIikucGlwZShuZShuKSxFKChbbCxmXSk9PntpZighKGwudGFyZ2V0IGluc3RhbmNlb2YgRWxlbWVudCkpcmV0dXJuIEw7bGV0IHU9bC50YXJnZXQuY2xvc2VzdCgiYSIpO2lmKHU9PT1udWxsKXJldHVybiBMO2lmKHUudGFyZ2V0fHxsLm1ldGFLZXl8fGwuY3RybEtleSlyZXR1cm4gTDtsZXQgZD1uZXcgVVJMKHUuaHJlZik7cmV0dXJuIGQuc2VhcmNoPWQuaGFzaD0iIixmLmluY2x1ZGVzKGAke2R9YCk/KGwucHJldmVudERlZmF1bHQoKSxqKG5ldyBVUkwodS5ocmVmKSkpOkx9KSxsZSgpKTtpLnBpcGUoeGUoMSkpLnN1YnNjcmliZSgoKT0+e2xldCBsPWNlKCJsaW5rW3JlbD1pY29uXSIpO3R5cGVvZiBsIT0idW5kZWZpbmVkIiYmKGwuaHJlZj1sLmhyZWYpfSksaCh3aW5kb3csImJlZm9yZXVubG9hZCIpLnN1YnNjcmliZSgoKT0+e2hpc3Rvcnkuc2Nyb2xsUmVzdG9yYXRpb249ImF1dG8ifSksaS5waXBlKG5lKHQpKS5zdWJzY3JpYmUoKFtsLHtvZmZzZXQ6Zn1dKT0+e2hpc3Rvcnkuc2Nyb2xsUmVzdG9yYXRpb249Im1hbnVhbCIsaGlzdG9yeS5yZXBsYWNlU3RhdGUoZiwiIiksaGlzdG9yeS5wdXNoU3RhdGUobnVsbCwiIixsKX0pLGkuc3Vic2NyaWJlKGUpO2xldCBzPWUucGlwZShWKHBlKCkpLGVlKCJwYXRobmFtZSIpLGplKDEpLEUobD0+YXIobCx7cHJvZ3Jlc3MkOnJ9KS5waXBlKGRlKCgpPT4ob3QobCwhMCksTCkpKSkpLGE9bmV3IERPTVBhcnNlcixjPXMucGlwZShFKGw9PmwudGV4dCgpKSxFKGw9PntsZXQgZj1hLnBhcnNlRnJvbVN0cmluZyhsLCJ0ZXh0L2h0bWwiKTtmb3IobGV0IGIgb2ZbIltkYXRhLW1kLWNvbXBvbmVudD1hbm5vdW5jZV0iLCJbZGF0YS1tZC1jb21wb25lbnQ9Y29udGFpbmVyXSIsIltkYXRhLW1kLWNvbXBvbmVudD1oZWFkZXItdG9waWNdIiwiW2RhdGEtbWQtY29tcG9uZW50PW91dGRhdGVkXSIsIltkYXRhLW1kLWNvbXBvbmVudD1sb2dvXSIsIltkYXRhLW1kLWNvbXBvbmVudD1za2lwXSIsLi4udGUoIm5hdmlnYXRpb24udGFicy5zdGlja3kiKT9bIltkYXRhLW1kLWNvbXBvbmVudD10YWJzXSJdOltdXSl7bGV0IHo9Y2UoYiksSz1jZShiLGYpO3R5cGVvZiB6IT0idW5kZWZpbmVkIiYmdHlwZW9mIEshPSJ1bmRlZmluZWQiJiZ6LnJlcGxhY2VXaXRoKEspfWxldCB1PWpuKGRvY3VtZW50LmhlYWQpLGQ9am4oZi5oZWFkKTtmb3IobGV0W2Isel1vZiBkKXouZ2V0QXR0cmlidXRlKCJyZWwiKT09PSJzdHlsZXNoZWV0Inx8ei5oYXNBdHRyaWJ1dGUoInNyYyIpfHwodS5oYXMoYik/dS5kZWxldGUoYik6ZG9jdW1lbnQuaGVhZC5hcHBlbmRDaGlsZCh6KSk7Zm9yKGxldCBiIG9mIHUudmFsdWVzKCkpYi5nZXRBdHRyaWJ1dGUoInJlbCIpPT09InN0eWxlc2hlZXQifHxiLmhhc0F0dHJpYnV0ZSgic3JjIil8fGIucmVtb3ZlKCk7bGV0IHY9RWUoImNvbnRhaW5lciIpO3JldHVybiBGZShxKCJzY3JpcHQiLHYpKS5waXBlKEUoYj0+e2xldCB6PWYuY3JlYXRlRWxlbWVudCgic2NyaXB0Iik7aWYoYi5zcmMpe2ZvcihsZXQgSyBvZiBiLmdldEF0dHJpYnV0ZU5hbWVzKCkpei5zZXRBdHRyaWJ1dGUoSyxiLmdldEF0dHJpYnV0ZShLKSk7cmV0dXJuIGIucmVwbGFjZVdpdGgoeiksbmV3IFAoSz0+e3oub25sb2FkPSgpPT5LLmNvbXBsZXRlKCl9KX1lbHNlIHJldHVybiB6LnRleHRDb250ZW50PWIudGV4dENvbnRlbnQsYi5yZXBsYWNlV2l0aCh6KSxMfSksWigpLHJlKGYpKX0pLGxlKCkpO3JldHVybiBoKHdpbmRvdywicG9wc3RhdGUiKS5waXBlKG0ocGUpKS5zdWJzY3JpYmUoZSksZS5waXBlKFYocGUoKSksTGUoMiwxKSxNKChbbCxmXSk9PmwucGF0aG5hbWU9PT1mLnBhdGhuYW1lJiZsLmhhc2ghPT1mLmhhc2gpLG0oKFssbF0pPT5sKSkuc3Vic2NyaWJlKGw9Pnt2YXIgZix1O2hpc3Rvcnkuc3RhdGUhPT1udWxsfHwhbC5oYXNoP3dpbmRvdy5zY3JvbGxUbygwLCh1PShmPWhpc3Rvcnkuc3RhdGUpPT1udWxsP3ZvaWQgMDpmLnkpIT1udWxsP3U6MCk6KGhpc3Rvcnkuc2Nyb2xsUmVzdG9yYXRpb249ImF1dG8iLGlyKGwuaGFzaCksaGlzdG9yeS5zY3JvbGxSZXN0b3JhdGlvbj0ibWFudWFsIil9KSxlLnBpcGUoa3IoaSksVihwZSgpKSxMZSgyLDEpLE0oKFtsLGZdKT0+bC5wYXRobmFtZT09PWYucGF0aG5hbWUmJmwuaGFzaD09PWYuaGFzaCksbSgoWyxsXSk9PmwpKS5zdWJzY3JpYmUobD0+e2hpc3Rvcnkuc2Nyb2xsUmVzdG9yYXRpb249ImF1dG8iLGlyKGwuaGFzaCksaGlzdG9yeS5zY3JvbGxSZXN0b3JhdGlvbj0ibWFudWFsIixoaXN0b3J5LmJhY2soKX0pLGMucGlwZShuZShlKSkuc3Vic2NyaWJlKChbLGxdKT0+e3ZhciBmLHU7aGlzdG9yeS5zdGF0ZSE9PW51bGx8fCFsLmhhc2g/d2luZG93LnNjcm9sbFRvKDAsKHU9KGY9aGlzdG9yeS5zdGF0ZSk9PW51bGw/dm9pZCAwOmYueSkhPW51bGw/dTowKTppcihsLmhhc2gpfSksdC5waXBlKGVlKCJvZmZzZXQiKSxrZSgxMDApKS5zdWJzY3JpYmUoKHtvZmZzZXQ6bH0pPT57aGlzdG9yeS5yZXBsYWNlU3RhdGUobCwiIil9KSxjfXZhciBEbj1IdChObigpKTtmdW5jdGlvbiBWbihlKXtsZXQgdD1lLnNlcGFyYXRvci5zcGxpdCgifCIpLm1hcChuPT5uLnJlcGxhY2UoLyhcKFw/WyE9PF1bXildK1wpKS9nLCIiKS5sZW5ndGg9PT0wPyJcdUZGRkQiOm4pLmpvaW4oInwiKSxyPW5ldyBSZWdFeHAodCwiaW1nIiksbz0obixpLHMpPT5gJHtpfTxtYXJrIGRhdGEtbWQtaGlnaGxpZ2h0PiR7c308L21hcms+YDtyZXR1cm4gbj0+e249bi5yZXBsYWNlKC9bXHMqK1wtOn5eXSsvZywiICIpLnRyaW0oKTtsZXQgaT1uZXcgUmVnRXhwKGAoXnwke2Uuc2VwYXJhdG9yfXwpKCR7bi5yZXBsYWNlKC9bfFxce30oKVtcXV4kKyo/Li1dL2csIlxcJCYiKS5yZXBsYWNlKHIsInwiKX0pYCwiaW1nIik7cmV0dXJuIHM9PigwLERuLmRlZmF1bHQpKHMpLnJlcGxhY2UoaSxvKS5yZXBsYWNlKC88XC9tYXJrPihccyspPG1hcmtbXj5dKj4vaW1nLCIkMSIpfX1mdW5jdGlvbiBNdChlKXtyZXR1cm4gZS50eXBlPT09MX1mdW5jdGlvbiBscihlKXtyZXR1cm4gZS50eXBlPT09M31mdW5jdGlvbiB6bihlLHQpe2xldCByPWFuKGUpO3JldHVybiBfKGoobG9jYXRpb24ucHJvdG9jb2whPT0iZmlsZToiKSxXZSgic2VhcmNoIikpLnBpcGUoJGUobz0+byksRSgoKT0+dCkpLnN1YnNjcmliZSgoe2NvbmZpZzpvLGRvY3M6bn0pPT5yLm5leHQoe3R5cGU6MCxkYXRhOntjb25maWc6byxkb2NzOm4sb3B0aW9uczp7c3VnZ2VzdDp0ZSgic2VhcmNoLnN1Z2dlc3QiKX19fSkpLHJ9ZnVuY3Rpb24gcW4oe2RvY3VtZW50JDplfSl7bGV0IHQ9bWUoKSxyPVVlKG5ldyBVUkwoIi4uL3ZlcnNpb25zLmpzb24iLHQuYmFzZSkpLnBpcGUoZGUoKCk9PkwpKSxvPXIucGlwZShtKG49PntsZXRbLGldPXQuYmFzZS5tYXRjaCgvKFteL10rKVwvPyQvKTtyZXR1cm4gbi5maW5kKCh7dmVyc2lvbjpzLGFsaWFzZXM6YX0pPT5zPT09aXx8YS5pbmNsdWRlcyhpKSl8fG5bMF19KSk7ci5waXBlKG0obj0+bmV3IE1hcChuLm1hcChpPT5bYCR7bmV3IFVSTChgLi4vJHtpLnZlcnNpb259L2AsdC5iYXNlKX1gLGldKSkpLEUobj0+aChkb2N1bWVudC5ib2R5LCJjbGljayIpLnBpcGUoTShpPT4haS5tZXRhS2V5JiYhaS5jdHJsS2V5KSxuZShvKSxFKChbaSxzXSk9PntpZihpLnRhcmdldCBpbnN0YW5jZW9mIEVsZW1lbnQpe2xldCBhPWkudGFyZ2V0LmNsb3Nlc3QoImEiKTtpZihhJiYhYS50YXJnZXQmJm4uaGFzKGEuaHJlZikpe2xldCBjPWEuaHJlZjtyZXR1cm4haS50YXJnZXQuY2xvc2VzdCgiLm1kLXZlcnNpb24iKSYmbi5nZXQoYyk9PT1zP0w6KGkucHJldmVudERlZmF1bHQoKSxqKGMpKX19cmV0dXJuIEx9KSxFKGk9PntsZXR7dmVyc2lvbjpzfT1uLmdldChpKTtyZXR1cm4gcHIobmV3IFVSTChpKSkucGlwZShtKGE9PntsZXQgcD1wZSgpLmhyZWYucmVwbGFjZSh0LmJhc2UsIiIpO3JldHVybiBhLmluY2x1ZGVzKHAuc3BsaXQoIiMiKVswXSk/bmV3IFVSTChgLi4vJHtzfS8ke3B9YCx0LmJhc2UpOm5ldyBVUkwoaSl9KSl9KSkpKS5zdWJzY3JpYmUobj0+b3QobiwhMCkpLEIoW3Isb10pLnN1YnNjcmliZSgoW24saV0pPT57VygiLm1kLWhlYWRlcl9fdG9waWMiKS5hcHBlbmRDaGlsZChobihuLGkpKX0pLGUucGlwZShFKCgpPT5vKSkuc3Vic2NyaWJlKG49Pnt2YXIgcztsZXQgaT1fX21kX2dldCgiX19vdXRkYXRlZCIsc2Vzc2lvblN0b3JhZ2UpO2lmKGk9PT1udWxsKXtpPSEwO2xldCBhPSgocz10LnZlcnNpb24pPT1udWxsP3ZvaWQgMDpzLmRlZmF1bHQpfHwibGF0ZXN0IjtBcnJheS5pc0FycmF5KGEpfHwoYT1bYV0pO2U6Zm9yKGxldCBjIG9mIGEpZm9yKGxldCBwIG9mIG4uYWxpYXNlcylpZihuZXcgUmVnRXhwKGMsImkiKS50ZXN0KHApKXtpPSExO2JyZWFrIGV9X19tZF9zZXQoIl9fb3V0ZGF0ZWQiLGksc2Vzc2lvblN0b3JhZ2UpfWlmKGkpZm9yKGxldCBhIG9mIG9lKCJvdXRkYXRlZCIpKWEuaGlkZGVuPSExfSl9ZnVuY3Rpb24gUGEoZSx7d29ya2VyJDp0fSl7bGV0e3NlYXJjaFBhcmFtczpyfT1wZSgpO3IuaGFzKCJxIikmJihLZSgic2VhcmNoIiwhMCksZS52YWx1ZT1yLmdldCgicSIpLGUuZm9jdXMoKSxXZSgic2VhcmNoIikucGlwZSgkZShpPT4haSkpLnN1YnNjcmliZSgoKT0+e2xldCBpPXBlKCk7aS5zZWFyY2hQYXJhbXMuZGVsZXRlKCJxIiksaGlzdG9yeS5yZXBsYWNlU3RhdGUoe30sIiIsYCR7aX1gKX0pKTtsZXQgbz1adChlKSxuPV8odC5waXBlKCRlKE10KSksaChlLCJrZXl1cCIpLG8pLnBpcGUobSgoKT0+ZS52YWx1ZSksWCgpKTtyZXR1cm4gQihbbixvXSkucGlwZShtKChbaSxzXSk9Pih7dmFsdWU6aSxmb2N1czpzfSkpLEooMSkpfWZ1bmN0aW9uIEtuKGUse3dvcmtlciQ6dH0pe2xldCByPW5ldyB4LG89ci5waXBlKFooKSxyZSghMCkpO0IoW3QucGlwZSgkZShNdCkpLHJdLChpLHMpPT5zKS5waXBlKGVlKCJ2YWx1ZSIpKS5zdWJzY3JpYmUoKHt2YWx1ZTppfSk9PnQubmV4dCh7dHlwZToyLGRhdGE6aX0pKSxyLnBpcGUoZWUoImZvY3VzIikpLnN1YnNjcmliZSgoe2ZvY3VzOml9KT0+e2kmJktlKCJzZWFyY2giLGkpfSksaChlLmZvcm0sInJlc2V0IikucGlwZShZKG8pKS5zdWJzY3JpYmUoKCk9PmUuZm9jdXMoKSk7bGV0IG49VygiaGVhZGVyIFtmb3I9X19zZWFyY2hdIik7cmV0dXJuIGgobiwiY2xpY2siKS5zdWJzY3JpYmUoKCk9PmUuZm9jdXMoKSksUGEoZSx7d29ya2VyJDp0fSkucGlwZSh3KGk9PnIubmV4dChpKSksQSgoKT0+ci5jb21wbGV0ZSgpKSxtKGk9PlIoe3JlZjplfSxpKSksSigxKSl9ZnVuY3Rpb24gUW4oZSx7d29ya2VyJDp0LHF1ZXJ5JDpyfSl7bGV0IG89bmV3IHgsbj1LbyhlLnBhcmVudEVsZW1lbnQpLnBpcGUoTShCb29sZWFuKSksaT1lLnBhcmVudEVsZW1lbnQscz1XKCI6c2NvcGUgPiA6Zmlyc3QtY2hpbGQiLGUpLGE9VygiOnNjb3BlID4gOmxhc3QtY2hpbGQiLGUpO1dlKCJzZWFyY2giKS5zdWJzY3JpYmUobD0+YS5zZXRBdHRyaWJ1dGUoInJvbGUiLGw/Imxpc3QiOiJwcmVzZW50YXRpb24iKSksby5waXBlKG5lKHIpLFJyKHQucGlwZSgkZShNdCkpKSkuc3Vic2NyaWJlKChbe2l0ZW1zOmx9LHt2YWx1ZTpmfV0pPT57c3dpdGNoKGwubGVuZ3RoKXtjYXNlIDA6cy50ZXh0Q29udGVudD1mLmxlbmd0aD9iZSgic2VhcmNoLnJlc3VsdC5ub25lIik6YmUoInNlYXJjaC5yZXN1bHQucGxhY2Vob2xkZXIiKTticmVhaztjYXNlIDE6cy50ZXh0Q29udGVudD1iZSgic2VhcmNoLnJlc3VsdC5vbmUiKTticmVhaztkZWZhdWx0OmxldCB1PXRyKGwubGVuZ3RoKTtzLnRleHRDb250ZW50PWJlKCJzZWFyY2gucmVzdWx0Lm90aGVyIix1KX19KTtsZXQgYz1vLnBpcGUodygoKT0+YS5pbm5lckhUTUw9IiIpLEUoKHtpdGVtczpsfSk9Pl8oaiguLi5sLnNsaWNlKDAsMTApKSxqKC4uLmwuc2xpY2UoMTApKS5waXBlKExlKDQpLEZyKG4pLEUoKFtmXSk9PmYpKSkpLG0oZm4pLGxlKCkpO3JldHVybiBjLnN1YnNjcmliZShsPT5hLmFwcGVuZENoaWxkKGwpKSxjLnBpcGUoc2UobD0+e2xldCBmPWNlKCJkZXRhaWxzIixsKTtyZXR1cm4gdHlwZW9mIGY9PSJ1bmRlZmluZWQiP0w6aChmLCJ0b2dnbGUiKS5waXBlKFkobyksbSgoKT0+ZikpfSkpLnN1YnNjcmliZShsPT57bC5vcGVuPT09ITEmJmwub2Zmc2V0VG9wPD1pLnNjcm9sbFRvcCYmaS5zY3JvbGxUbyh7dG9wOmwub2Zmc2V0VG9wfSl9KSx0LnBpcGUoTShsciksbSgoe2RhdGE6bH0pPT5sKSkucGlwZSh3KGw9Pm8ubmV4dChsKSksQSgoKT0+by5jb21wbGV0ZSgpKSxtKGw9PlIoe3JlZjplfSxsKSkpfWZ1bmN0aW9uIElhKGUse3F1ZXJ5JDp0fSl7cmV0dXJuIHQucGlwZShtKCh7dmFsdWU6cn0pPT57bGV0IG89cGUoKTtyZXR1cm4gby5oYXNoPSIiLHI9ci5yZXBsYWNlKC9ccysvZywiKyIpLnJlcGxhY2UoLyYvZywiJTI2IikucmVwbGFjZSgvPS9nLCIlM0QiKSxvLnNlYXJjaD1gcT0ke3J9YCx7dXJsOm99fSkpfWZ1bmN0aW9uIFluKGUsdCl7bGV0IHI9bmV3IHgsbz1yLnBpcGUoWigpLHJlKCEwKSk7cmV0dXJuIHIuc3Vic2NyaWJlKCh7dXJsOm59KT0+e2Uuc2V0QXR0cmlidXRlKCJkYXRhLWNsaXBib2FyZC10ZXh0IixlLmhyZWYpLGUuaHJlZj1gJHtufWB9KSxoKGUsImNsaWNrIikucGlwZShZKG8pKS5zdWJzY3JpYmUobj0+bi5wcmV2ZW50RGVmYXVsdCgpKSxJYShlLHQpLnBpcGUodyhuPT5yLm5leHQobikpLEEoKCk9PnIuY29tcGxldGUoKSksbShuPT5SKHtyZWY6ZX0sbikpKX1mdW5jdGlvbiBCbihlLHt3b3JrZXIkOnQsa2V5Ym9hcmQkOnJ9KXtsZXQgbz1uZXcgeCxuPUVlKCJzZWFyY2gtcXVlcnkiKSxpPV8oaChuLCJrZXlkb3duIiksaChuLCJmb2N1cyIpKS5waXBlKFNlKGFlKSxtKCgpPT5uLnZhbHVlKSxYKCkpO3JldHVybiBvLnBpcGUoR2UoaSksbSgoW3tzdWdnZXN0OmF9LGNdKT0+e2xldCBwPWMuc3BsaXQoLyhbXHMtXSspLyk7aWYoYSE9bnVsbCYmYS5sZW5ndGgmJnBbcC5sZW5ndGgtMV0pe2xldCBsPWFbYS5sZW5ndGgtMV07bC5zdGFydHNXaXRoKHBbcC5sZW5ndGgtMV0pJiYocFtwLmxlbmd0aC0xXT1sKX1lbHNlIHAubGVuZ3RoPTA7cmV0dXJuIHB9KSkuc3Vic2NyaWJlKGE9PmUuaW5uZXJIVE1MPWEuam9pbigiIikucmVwbGFjZSgvXHMvZywiJm5ic3A7IikpLHIucGlwZShNKCh7bW9kZTphfSk9PmE9PT0ic2VhcmNoIikpLnN1YnNjcmliZShhPT57c3dpdGNoKGEudHlwZSl7Y2FzZSJBcnJvd1JpZ2h0IjplLmlubmVyVGV4dC5sZW5ndGgmJm4uc2VsZWN0aW9uU3RhcnQ9PT1uLnZhbHVlLmxlbmd0aCYmKG4udmFsdWU9ZS5pbm5lclRleHQpO2JyZWFrfX0pLHQucGlwZShNKGxyKSxtKCh7ZGF0YTphfSk9PmEpKS5waXBlKHcoYT0+by5uZXh0KGEpKSxBKCgpPT5vLmNvbXBsZXRlKCkpLG0oKCk9Pih7cmVmOmV9KSkpfWZ1bmN0aW9uIEduKGUse2luZGV4JDp0LGtleWJvYXJkJDpyfSl7bGV0IG89bWUoKTt0cnl7bGV0IG49em4oby5zZWFyY2gsdCksaT1FZSgic2VhcmNoLXF1ZXJ5IixlKSxzPUVlKCJzZWFyY2gtcmVzdWx0IixlKTtoKGUsImNsaWNrIikucGlwZShNKCh7dGFyZ2V0OmN9KT0+YyBpbnN0YW5jZW9mIEVsZW1lbnQmJiEhYy5jbG9zZXN0KCJhIikpKS5zdWJzY3JpYmUoKCk9PktlKCJzZWFyY2giLCExKSksci5waXBlKE0oKHttb2RlOmN9KT0+Yz09PSJzZWFyY2giKSkuc3Vic2NyaWJlKGM9PntsZXQgcD1SZSgpO3N3aXRjaChjLnR5cGUpe2Nhc2UiRW50ZXIiOmlmKHA9PT1pKXtsZXQgbD1uZXcgTWFwO2ZvcihsZXQgZiBvZiBxKCI6Zmlyc3QtY2hpbGQgW2hyZWZdIixzKSl7bGV0IHU9Zi5maXJzdEVsZW1lbnRDaGlsZDtsLnNldChmLHBhcnNlRmxvYXQodS5nZXRBdHRyaWJ1dGUoImRhdGEtbWQtc2NvcmUiKSkpfWlmKGwuc2l6ZSl7bGV0W1tmXV09Wy4uLmxdLnNvcnQoKFssdV0sWyxkXSk9PmQtdSk7Zi5jbGljaygpfWMuY2xhaW0oKX1icmVhaztjYXNlIkVzY2FwZSI6Y2FzZSJUYWIiOktlKCJzZWFyY2giLCExKSxpLmJsdXIoKTticmVhaztjYXNlIkFycm93VXAiOmNhc2UiQXJyb3dEb3duIjppZih0eXBlb2YgcD09InVuZGVmaW5lZCIpaS5mb2N1cygpO2Vsc2V7bGV0IGw9W2ksLi4ucSgiOm5vdChkZXRhaWxzKSA+IFtocmVmXSwgc3VtbWFyeSwgZGV0YWlsc1tvcGVuXSBbaHJlZl0iLHMpXSxmPU1hdGgubWF4KDAsKE1hdGgubWF4KDAsbC5pbmRleE9mKHApKStsLmxlbmd0aCsoYy50eXBlPT09IkFycm93VXAiPy0xOjEpKSVsLmxlbmd0aCk7bFtmXS5mb2N1cygpfWMuY2xhaW0oKTticmVhaztkZWZhdWx0OmkhPT1SZSgpJiZpLmZvY3VzKCl9fSksci5waXBlKE0oKHttb2RlOmN9KT0+Yz09PSJnbG9iYWwiKSkuc3Vic2NyaWJlKGM9Pntzd2l0Y2goYy50eXBlKXtjYXNlImYiOmNhc2UicyI6Y2FzZSIvIjppLmZvY3VzKCksaS5zZWxlY3QoKSxjLmNsYWltKCk7YnJlYWt9fSk7bGV0IGE9S24oaSx7d29ya2VyJDpufSk7cmV0dXJuIF8oYSxRbihzLHt3b3JrZXIkOm4scXVlcnkkOmF9KSkucGlwZShxZSguLi5vZSgic2VhcmNoLXNoYXJlIixlKS5tYXAoYz0+WW4oYyx7cXVlcnkkOmF9KSksLi4ub2UoInNlYXJjaC1zdWdnZXN0IixlKS5tYXAoYz0+Qm4oYyx7d29ya2VyJDpuLGtleWJvYXJkJDpyfSkpKSl9Y2F0Y2gobil7cmV0dXJuIGUuaGlkZGVuPSEwLFZlfX1mdW5jdGlvbiBKbihlLHtpbmRleCQ6dCxsb2NhdGlvbiQ6cn0pe3JldHVybiBCKFt0LHIucGlwZShWKHBlKCkpLE0obz0+ISFvLnNlYXJjaFBhcmFtcy5nZXQoImgiKSkpXSkucGlwZShtKChbbyxuXSk9PlZuKG8uY29uZmlnKShuLnNlYXJjaFBhcmFtcy5nZXQoImgiKSkpLG0obz0+e3ZhciBzO2xldCBuPW5ldyBNYXAsaT1kb2N1bWVudC5jcmVhdGVOb2RlSXRlcmF0b3IoZSxOb2RlRmlsdGVyLlNIT1dfVEVYVCk7Zm9yKGxldCBhPWkubmV4dE5vZGUoKTthO2E9aS5uZXh0Tm9kZSgpKWlmKChzPWEucGFyZW50RWxlbWVudCkhPW51bGwmJnMub2Zmc2V0SGVpZ2h0KXtsZXQgYz1hLnRleHRDb250ZW50LHA9byhjKTtwLmxlbmd0aD5jLmxlbmd0aCYmbi5zZXQoYSxwKX1mb3IobGV0W2EsY11vZiBuKXtsZXR7Y2hpbGROb2RlczpwfT1UKCJzcGFuIixudWxsLGMpO2EucmVwbGFjZVdpdGgoLi4uQXJyYXkuZnJvbShwKSl9cmV0dXJue3JlZjplLG5vZGVzOm59fSkpfWZ1bmN0aW9uIEZhKGUse3ZpZXdwb3J0JDp0LG1haW4kOnJ9KXtsZXQgbz1lLmNsb3Nlc3QoIi5tZC1ncmlkIiksbj1vLm9mZnNldFRvcC1vLnBhcmVudEVsZW1lbnQub2Zmc2V0VG9wO3JldHVybiBCKFtyLHRdKS5waXBlKG0oKFt7b2Zmc2V0OmksaGVpZ2h0OnN9LHtvZmZzZXQ6e3k6YX19XSk9PihzPXMrTWF0aC5taW4obixNYXRoLm1heCgwLGEtaSkpLW4se2hlaWdodDpzLGxvY2tlZDphPj1pK259KSksWCgoaSxzKT0+aS5oZWlnaHQ9PT1zLmhlaWdodCYmaS5sb2NrZWQ9PT1zLmxvY2tlZCkpfWZ1bmN0aW9uIFFyKGUsbyl7dmFyIG49byx7aGVhZGVyJDp0fT1uLHI9dG8obixbImhlYWRlciQiXSk7bGV0IGk9VygiLm1kLXNpZGViYXJfX3Njcm9sbHdyYXAiLGUpLHt5OnN9PUplKGkpO3JldHVybiBIKCgpPT57bGV0IGE9bmV3IHgsYz1hLnBpcGUoWigpLHJlKCEwKSkscD1hLnBpcGUoQ2UoMCxPZSkpO3JldHVybiBwLnBpcGUobmUodCkpLnN1YnNjcmliZSh7bmV4dChbe2hlaWdodDpsfSx7aGVpZ2h0OmZ9XSl7aS5zdHlsZS5oZWlnaHQ9YCR7bC0yKnN9cHhgLGUuc3R5bGUudG9wPWAke2Z9cHhgfSxjb21wbGV0ZSgpe2kuc3R5bGUuaGVpZ2h0PSIiLGUuc3R5bGUudG9wPSIifX0pLHAucGlwZSgkZSgpKS5zdWJzY3JpYmUoKCk9Pntmb3IobGV0IGwgb2YgcSgiLm1kLW5hdl9fbGluay0tYWN0aXZlW2hyZWZdIixlKSl7bGV0IGY9cnIobCk7aWYodHlwZW9mIGYhPSJ1bmRlZmluZWQiKXtsZXQgdT1sLm9mZnNldFRvcC1mLm9mZnNldFRvcCx7aGVpZ2h0OmR9PWhlKGYpO2Yuc2Nyb2xsVG8oe3RvcDp1LWQvMn0pfX19KSxnZShxKCJsYWJlbFt0YWJpbmRleF0iLGUpKS5waXBlKHNlKGw9PmgobCwiY2xpY2siKS5waXBlKFNlKGFlKSxtKCgpPT5sKSxZKGMpKSkpLnN1YnNjcmliZShsPT57bGV0IGY9VyhgW2lkPSIke2wuaHRtbEZvcn0iXWApO1coYFthcmlhLWxhYmVsbGVkYnk9IiR7bC5pZH0iXWApLnNldEF0dHJpYnV0ZSgiYXJpYS1leHBhbmRlZCIsYCR7Zi5jaGVja2VkfWApfSksRmEoZSxyKS5waXBlKHcobD0+YS5uZXh0KGwpKSxBKCgpPT5hLmNvbXBsZXRlKCkpLG0obD0+Uih7cmVmOmV9LGwpKSl9KX1mdW5jdGlvbiBYbihlLHQpe2lmKHR5cGVvZiB0IT0idW5kZWZpbmVkIil7bGV0IHI9YGh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvJHtlfS8ke3R9YDtyZXR1cm4gU3QoVWUoYCR7cn0vcmVsZWFzZXMvbGF0ZXN0YCkucGlwZShkZSgoKT0+TCksbShvPT4oe3ZlcnNpb246by50YWdfbmFtZX0pKSxIZSh7fSkpLFVlKHIpLnBpcGUoZGUoKCk9PkwpLG0obz0+KHtzdGFyczpvLnN0YXJnYXplcnNfY291bnQsZm9ya3M6by5mb3Jrc19jb3VudH0pKSxIZSh7fSkpKS5waXBlKG0oKFtvLG5dKT0+UihSKHt9LG8pLG4pKSl9ZWxzZXtsZXQgcj1gaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy8ke2V9YDtyZXR1cm4gVWUocikucGlwZShtKG89Pih7cmVwb3NpdG9yaWVzOm8ucHVibGljX3JlcG9zfSkpLEhlKHt9KSl9fWZ1bmN0aW9uIFpuKGUsdCl7bGV0IHI9YGh0dHBzOi8vJHtlfS9hcGkvdjQvcHJvamVjdHMvJHtlbmNvZGVVUklDb21wb25lbnQodCl9YDtyZXR1cm4gVWUocikucGlwZShkZSgoKT0+TCksbSgoe3N0YXJfY291bnQ6byxmb3Jrc19jb3VudDpufSk9Pih7c3RhcnM6byxmb3JrczpufSkpLEhlKHt9KSl9ZnVuY3Rpb24gZWkoZSl7bGV0IHQ9ZS5tYXRjaCgvXi4rZ2l0aHViXC5jb21cLyhbXi9dKylcLz8oW14vXSspPy9pKTtpZih0KXtsZXRbLHIsb109dDtyZXR1cm4gWG4ocixvKX1pZih0PWUubWF0Y2goL14uKz8oW14vXSpnaXRsYWJbXi9dKylcLyguKz8pXC8/JC9pKSx0KXtsZXRbLHIsb109dDtyZXR1cm4gWm4ocixvKX1yZXR1cm4gTH12YXIgamE7ZnVuY3Rpb24gV2EoZSl7cmV0dXJuIGphfHwoamE9SCgoKT0+e2xldCB0PV9fbWRfZ2V0KCJfX3NvdXJjZSIsc2Vzc2lvblN0b3JhZ2UpO2lmKHQpcmV0dXJuIGoodCk7aWYob2UoImNvbnNlbnQiKS5sZW5ndGgpe2xldCBvPV9fbWRfZ2V0KCJfX2NvbnNlbnQiKTtpZighKG8mJm8uZ2l0aHViKSlyZXR1cm4gTH1yZXR1cm4gZWkoZS5ocmVmKS5waXBlKHcobz0+X19tZF9zZXQoIl9fc291cmNlIixvLHNlc3Npb25TdG9yYWdlKSkpfSkucGlwZShkZSgoKT0+TCksTSh0PT5PYmplY3Qua2V5cyh0KS5sZW5ndGg+MCksbSh0PT4oe2ZhY3RzOnR9KSksSigxKSkpfWZ1bmN0aW9uIHRpKGUpe2xldCB0PVcoIjpzY29wZSA+IDpsYXN0LWNoaWxkIixlKTtyZXR1cm4gSCgoKT0+e2xldCByPW5ldyB4O3JldHVybiByLnN1YnNjcmliZSgoe2ZhY3RzOm99KT0+e3QuYXBwZW5kQ2hpbGQodW4obykpLHQuY2xhc3NMaXN0LmFkZCgibWQtc291cmNlX19yZXBvc2l0b3J5LS1hY3RpdmUiKX0pLFdhKGUpLnBpcGUodyhvPT5yLm5leHQobykpLEEoKCk9PnIuY29tcGxldGUoKSksbShvPT5SKHtyZWY6ZX0sbykpKX0pfWZ1bmN0aW9uIFVhKGUse3ZpZXdwb3J0JDp0LGhlYWRlciQ6cn0pe3JldHVybiB5ZShkb2N1bWVudC5ib2R5KS5waXBlKEUoKCk9PnNyKGUse2hlYWRlciQ6cix2aWV3cG9ydCQ6dH0pKSxtKCh7b2Zmc2V0Ont5Om99fSk9Pih7aGlkZGVuOm8+PTEwfSkpLGVlKCJoaWRkZW4iKSl9ZnVuY3Rpb24gcmkoZSx0KXtyZXR1cm4gSCgoKT0+e2xldCByPW5ldyB4O3JldHVybiByLnN1YnNjcmliZSh7bmV4dCh7aGlkZGVuOm99KXtlLmhpZGRlbj1vfSxjb21wbGV0ZSgpe2UuaGlkZGVuPSExfX0pLCh0ZSgibmF2aWdhdGlvbi50YWJzLnN0aWNreSIpP2ooe2hpZGRlbjohMX0pOlVhKGUsdCkpLnBpcGUodyhvPT5yLm5leHQobykpLEEoKCk9PnIuY29tcGxldGUoKSksbShvPT5SKHtyZWY6ZX0sbykpKX0pfWZ1bmN0aW9uIE5hKGUse3ZpZXdwb3J0JDp0LGhlYWRlciQ6cn0pe2xldCBvPW5ldyBNYXAsbj1xKCJbaHJlZl49XFwjXSIsZSk7Zm9yKGxldCBhIG9mIG4pe2xldCBjPWRlY29kZVVSSUNvbXBvbmVudChhLmhhc2guc3Vic3RyaW5nKDEpKSxwPWNlKGBbaWQ9IiR7Y30iXWApO3R5cGVvZiBwIT0idW5kZWZpbmVkIiYmby5zZXQoYSxwKX1sZXQgaT1yLnBpcGUoZWUoImhlaWdodCIpLG0oKHtoZWlnaHQ6YX0pPT57bGV0IGM9RWUoIm1haW4iKSxwPVcoIjpzY29wZSA+IDpmaXJzdC1jaGlsZCIsYyk7cmV0dXJuIGErLjgqKHAub2Zmc2V0VG9wLWMub2Zmc2V0VG9wKX0pLGxlKCkpO3JldHVybiB5ZShkb2N1bWVudC5ib2R5KS5waXBlKGVlKCJoZWlnaHQiKSxFKGE9PkgoKCk9PntsZXQgYz1bXTtyZXR1cm4gaihbLi4ub10ucmVkdWNlKChwLFtsLGZdKT0+e2Zvcig7Yy5sZW5ndGgmJm8uZ2V0KGNbYy5sZW5ndGgtMV0pLnRhZ05hbWU+PWYudGFnTmFtZTspYy5wb3AoKTtsZXQgdT1mLm9mZnNldFRvcDtmb3IoOyF1JiZmLnBhcmVudEVsZW1lbnQ7KWY9Zi5wYXJlbnRFbGVtZW50LHU9Zi5vZmZzZXRUb3A7bGV0IGQ9Zi5vZmZzZXRQYXJlbnQ7Zm9yKDtkO2Q9ZC5vZmZzZXRQYXJlbnQpdSs9ZC5vZmZzZXRUb3A7cmV0dXJuIHAuc2V0KFsuLi5jPVsuLi5jLGxdXS5yZXZlcnNlKCksdSl9LG5ldyBNYXApKX0pLnBpcGUobShjPT5uZXcgTWFwKFsuLi5jXS5zb3J0KChbLHBdLFssbF0pPT5wLWwpKSksR2UoaSksRSgoW2MscF0pPT50LnBpcGUoSHIoKFtsLGZdLHtvZmZzZXQ6e3k6dX0sc2l6ZTpkfSk9PntsZXQgdj11K2QuaGVpZ2h0Pj1NYXRoLmZsb29yKGEuaGVpZ2h0KTtmb3IoO2YubGVuZ3RoOyl7bGV0WyxiXT1mWzBdO2lmKGItcDx1fHx2KWw9Wy4uLmwsZi5zaGlmdCgpXTtlbHNlIGJyZWFrfWZvcig7bC5sZW5ndGg7KXtsZXRbLGJdPWxbbC5sZW5ndGgtMV07aWYoYi1wPj11JiYhdilmPVtsLnBvcCgpLC4uLmZdO2Vsc2UgYnJlYWt9cmV0dXJuW2wsZl19LFtbXSxbLi4uY11dKSxYKChsLGYpPT5sWzBdPT09ZlswXSYmbFsxXT09PWZbMV0pKSkpKSkucGlwZShtKChbYSxjXSk9Pih7cHJldjphLm1hcCgoW3BdKT0+cCksbmV4dDpjLm1hcCgoW3BdKT0+cCl9KSksVih7cHJldjpbXSxuZXh0OltdfSksTGUoMiwxKSxtKChbYSxjXSk9PmEucHJldi5sZW5ndGg8Yy5wcmV2Lmxlbmd0aD97cHJldjpjLnByZXYuc2xpY2UoTWF0aC5tYXgoMCxhLnByZXYubGVuZ3RoLTEpLGMucHJldi5sZW5ndGgpLG5leHQ6W119OntwcmV2OmMucHJldi5zbGljZSgtMSksbmV4dDpjLm5leHQuc2xpY2UoMCxjLm5leHQubGVuZ3RoLWEubmV4dC5sZW5ndGgpfSkpfWZ1bmN0aW9uIG9pKGUse3ZpZXdwb3J0JDp0LGhlYWRlciQ6cixtYWluJDpvLHRhcmdldCQ6bn0pe3JldHVybiBIKCgpPT57bGV0IGk9bmV3IHgscz1pLnBpcGUoWigpLHJlKCEwKSk7aWYoaS5zdWJzY3JpYmUoKHtwcmV2OmEsbmV4dDpjfSk9Pntmb3IobGV0W3Bdb2YgYylwLmNsYXNzTGlzdC5yZW1vdmUoIm1kLW5hdl9fbGluay0tcGFzc2VkIikscC5jbGFzc0xpc3QucmVtb3ZlKCJtZC1uYXZfX2xpbmstLWFjdGl2ZSIpO2ZvcihsZXRbcCxbbF1db2YgYS5lbnRyaWVzKCkpbC5jbGFzc0xpc3QuYWRkKCJtZC1uYXZfX2xpbmstLXBhc3NlZCIpLGwuY2xhc3NMaXN0LnRvZ2dsZSgibWQtbmF2X19saW5rLS1hY3RpdmUiLHA9PT1hLmxlbmd0aC0xKX0pLHRlKCJ0b2MuZm9sbG93Iikpe2xldCBhPV8odC5waXBlKGtlKDEpLG0oKCk9Pnt9KSksdC5waXBlKGtlKDI1MCksbSgoKT0+InNtb290aCIpKSk7aS5waXBlKE0oKHtwcmV2OmN9KT0+Yy5sZW5ndGg+MCksR2Uoby5waXBlKFNlKGFlKSkpLG5lKGEpKS5zdWJzY3JpYmUoKFtbe3ByZXY6Y31dLHBdKT0+e2xldFtsXT1jW2MubGVuZ3RoLTFdO2lmKGwub2Zmc2V0SGVpZ2h0KXtsZXQgZj1ycihsKTtpZih0eXBlb2YgZiE9InVuZGVmaW5lZCIpe2xldCB1PWwub2Zmc2V0VG9wLWYub2Zmc2V0VG9wLHtoZWlnaHQ6ZH09aGUoZik7Zi5zY3JvbGxUbyh7dG9wOnUtZC8yLGJlaGF2aW9yOnB9KX19fSl9cmV0dXJuIHRlKCJuYXZpZ2F0aW9uLnRyYWNraW5nIikmJnQucGlwZShZKHMpLGVlKCJvZmZzZXQiKSxrZSgyNTApLGplKDEpLFkobi5waXBlKGplKDEpKSksVHQoe2RlbGF5OjI1MH0pLG5lKGkpKS5zdWJzY3JpYmUoKFsse3ByZXY6YX1dKT0+e2xldCBjPXBlKCkscD1hW2EubGVuZ3RoLTFdO2lmKHAmJnAubGVuZ3RoKXtsZXRbbF09cCx7aGFzaDpmfT1uZXcgVVJMKGwuaHJlZik7Yy5oYXNoIT09ZiYmKGMuaGFzaD1mLGhpc3RvcnkucmVwbGFjZVN0YXRlKHt9LCIiLGAke2N9YCkpfWVsc2UgYy5oYXNoPSIiLGhpc3RvcnkucmVwbGFjZVN0YXRlKHt9LCIiLGAke2N9YCl9KSxOYShlLHt2aWV3cG9ydCQ6dCxoZWFkZXIkOnJ9KS5waXBlKHcoYT0+aS5uZXh0KGEpKSxBKCgpPT5pLmNvbXBsZXRlKCkpLG0oYT0+Uih7cmVmOmV9LGEpKSl9KX1mdW5jdGlvbiBEYShlLHt2aWV3cG9ydCQ6dCxtYWluJDpyLHRhcmdldCQ6b30pe2xldCBuPXQucGlwZShtKCh7b2Zmc2V0Ont5OnN9fSk9PnMpLExlKDIsMSksbSgoW3MsYV0pPT5zPmEmJmE+MCksWCgpKSxpPXIucGlwZShtKCh7YWN0aXZlOnN9KT0+cykpO3JldHVybiBCKFtpLG5dKS5waXBlKG0oKFtzLGFdKT0+IShzJiZhKSksWCgpLFkoby5waXBlKGplKDEpKSkscmUoITApLFR0KHtkZWxheToyNTB9KSxtKHM9Pih7aGlkZGVuOnN9KSkpfWZ1bmN0aW9uIG5pKGUse3ZpZXdwb3J0JDp0LGhlYWRlciQ6cixtYWluJDpvLHRhcmdldCQ6bn0pe2xldCBpPW5ldyB4LHM9aS5waXBlKFooKSxyZSghMCkpO3JldHVybiBpLnN1YnNjcmliZSh7bmV4dCh7aGlkZGVuOmF9KXtlLmhpZGRlbj1hLGE/KGUuc2V0QXR0cmlidXRlKCJ0YWJpbmRleCIsIi0xIiksZS5ibHVyKCkpOmUucmVtb3ZlQXR0cmlidXRlKCJ0YWJpbmRleCIpfSxjb21wbGV0ZSgpe2Uuc3R5bGUudG9wPSIiLGUuaGlkZGVuPSEwLGUucmVtb3ZlQXR0cmlidXRlKCJ0YWJpbmRleCIpfX0pLHIucGlwZShZKHMpLGVlKCJoZWlnaHQiKSkuc3Vic2NyaWJlKCh7aGVpZ2h0OmF9KT0+e2Uuc3R5bGUudG9wPWAke2ErMTZ9cHhgfSksaChlLCJjbGljayIpLnN1YnNjcmliZShhPT57YS5wcmV2ZW50RGVmYXVsdCgpLHdpbmRvdy5zY3JvbGxUbyh7dG9wOjB9KX0pLERhKGUse3ZpZXdwb3J0JDp0LG1haW4kOm8sdGFyZ2V0JDpufSkucGlwZSh3KGE9PmkubmV4dChhKSksQSgoKT0+aS5jb21wbGV0ZSgpKSxtKGE9PlIoe3JlZjplfSxhKSkpfWZ1bmN0aW9uIGlpKHtkb2N1bWVudCQ6ZSx0YWJsZXQkOnR9KXtlLnBpcGUoRSgoKT0+cSgiLm1kLXRvZ2dsZS0taW5kZXRlcm1pbmF0ZSIpKSx3KHI9PntyLmluZGV0ZXJtaW5hdGU9ITAsci5jaGVja2VkPSExfSksc2Uocj0+aChyLCJjaGFuZ2UiKS5waXBlKFByKCgpPT5yLmNsYXNzTGlzdC5jb250YWlucygibWQtdG9nZ2xlLS1pbmRldGVybWluYXRlIikpLG0oKCk9PnIpKSksbmUodCkpLnN1YnNjcmliZSgoW3Isb10pPT57ci5jbGFzc0xpc3QucmVtb3ZlKCJtZC10b2dnbGUtLWluZGV0ZXJtaW5hdGUiKSxvJiYoci5jaGVja2VkPSExKX0pfWZ1bmN0aW9uIFZhKCl7cmV0dXJuLyhpUGFkfGlQaG9uZXxpUG9kKS8udGVzdChuYXZpZ2F0b3IudXNlckFnZW50KX1mdW5jdGlvbiBhaSh7ZG9jdW1lbnQkOmV9KXtlLnBpcGUoRSgoKT0+cSgiW2RhdGEtbWQtc2Nyb2xsZml4XSIpKSx3KHQ9PnQucmVtb3ZlQXR0cmlidXRlKCJkYXRhLW1kLXNjcm9sbGZpeCIpKSxNKFZhKSxzZSh0PT5oKHQsInRvdWNoc3RhcnQiKS5waXBlKG0oKCk9PnQpKSkpLnN1YnNjcmliZSh0PT57bGV0IHI9dC5zY3JvbGxUb3A7cj09PTA/dC5zY3JvbGxUb3A9MTpyK3Qub2Zmc2V0SGVpZ2h0PT09dC5zY3JvbGxIZWlnaHQmJih0LnNjcm9sbFRvcD1yLTEpfSl9ZnVuY3Rpb24gc2koe3ZpZXdwb3J0JDplLHRhYmxldCQ6dH0pe0IoW1dlKCJzZWFyY2giKSx0XSkucGlwZShtKChbcixvXSk9PnImJiFvKSxFKHI9PmoocikucGlwZSh6ZShyPzQwMDoxMDApKSksbmUoZSkpLnN1YnNjcmliZSgoW3Ise29mZnNldDp7eTpvfX1dKT0+e2lmKHIpZG9jdW1lbnQuYm9keS5zZXRBdHRyaWJ1dGUoImRhdGEtbWQtc2Nyb2xsbG9jayIsIiIpLGRvY3VtZW50LmJvZHkuc3R5bGUudG9wPWAtJHtvfXB4YDtlbHNle2xldCBuPS0xKnBhcnNlSW50KGRvY3VtZW50LmJvZHkuc3R5bGUudG9wLDEwKTtkb2N1bWVudC5ib2R5LnJlbW92ZUF0dHJpYnV0ZSgiZGF0YS1tZC1zY3JvbGxsb2NrIiksZG9jdW1lbnQuYm9keS5zdHlsZS50b3A9IiIsbiYmd2luZG93LnNjcm9sbFRvKDAsbil9fSl9T2JqZWN0LmVudHJpZXN8fChPYmplY3QuZW50cmllcz1mdW5jdGlvbihlKXtsZXQgdD1bXTtmb3IobGV0IHIgb2YgT2JqZWN0LmtleXMoZSkpdC5wdXNoKFtyLGVbcl1dKTtyZXR1cm4gdH0pO09iamVjdC52YWx1ZXN8fChPYmplY3QudmFsdWVzPWZ1bmN0aW9uKGUpe2xldCB0PVtdO2ZvcihsZXQgciBvZiBPYmplY3Qua2V5cyhlKSl0LnB1c2goZVtyXSk7cmV0dXJuIHR9KTt0eXBlb2YgRWxlbWVudCE9InVuZGVmaW5lZCImJihFbGVtZW50LnByb3RvdHlwZS5zY3JvbGxUb3x8KEVsZW1lbnQucHJvdG90eXBlLnNjcm9sbFRvPWZ1bmN0aW9uKGUsdCl7dHlwZW9mIGU9PSJvYmplY3QiPyh0aGlzLnNjcm9sbExlZnQ9ZS5sZWZ0LHRoaXMuc2Nyb2xsVG9wPWUudG9wKToodGhpcy5zY3JvbGxMZWZ0PWUsdGhpcy5zY3JvbGxUb3A9dCl9KSxFbGVtZW50LnByb3RvdHlwZS5yZXBsYWNlV2l0aHx8KEVsZW1lbnQucHJvdG90eXBlLnJlcGxhY2VXaXRoPWZ1bmN0aW9uKC4uLmUpe2xldCB0PXRoaXMucGFyZW50Tm9kZTtpZih0KXtlLmxlbmd0aD09PTAmJnQucmVtb3ZlQ2hpbGQodGhpcyk7Zm9yKGxldCByPWUubGVuZ3RoLTE7cj49MDtyLS0pe2xldCBvPWVbcl07dHlwZW9mIG89PSJzdHJpbmciP289ZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUobyk6by5wYXJlbnROb2RlJiZvLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQobykscj90Lmluc2VydEJlZm9yZSh0aGlzLnByZXZpb3VzU2libGluZyxvKTp0LnJlcGxhY2VDaGlsZChvLHRoaXMpfX19KSk7ZnVuY3Rpb24gemEoKXtyZXR1cm4gbG9jYXRpb24ucHJvdG9jb2w9PT0iZmlsZToiP2h0KGAke25ldyBVUkwoInNlYXJjaC9zZWFyY2hfaW5kZXguanMiLFlyLmJhc2UpfWApLnBpcGUobSgoKT0+X19pbmRleCksSigxKSk6VWUobmV3IFVSTCgic2VhcmNoL3NlYXJjaF9pbmRleC5qc29uIixZci5iYXNlKSl9ZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsYXNzTGlzdC5yZW1vdmUoIm5vLWpzIik7ZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsYXNzTGlzdC5hZGQoImpzIik7dmFyIG50PU5vKCksX3Q9Qm8oKSxndD1KbyhfdCksQnI9WW8oKSxUZT1ubigpLG1yPWpyKCIobWluLXdpZHRoOiA5NjBweCkiKSxwaT1qcigiKG1pbi13aWR0aDogMTIyMHB4KSIpLGxpPVhvKCksWXI9bWUoKSxtaT1kb2N1bWVudC5mb3Jtcy5uYW1lZEl0ZW0oInNlYXJjaCIpP3phKCk6VmUsR3I9bmV3IHg7Rm4oe2FsZXJ0JDpHcn0pO3ZhciBKcj1uZXcgeDt0ZSgibmF2aWdhdGlvbi5pbnN0YW50IikmJlduKHtsb2NhdGlvbiQ6X3Qsdmlld3BvcnQkOlRlLHByb2dyZXNzJDpKcn0pLnN1YnNjcmliZShudCk7dmFyIGNpOygoY2k9WXIudmVyc2lvbik9PW51bGw/dm9pZCAwOmNpLnByb3ZpZGVyKT09PSJtaWtlIiYmcW4oe2RvY3VtZW50JDpudH0pO18oX3QsZ3QpLnBpcGUoemUoMTI1KSkuc3Vic2NyaWJlKCgpPT57S2UoImRyYXdlciIsITEpLEtlKCJzZWFyY2giLCExKX0pO0JyLnBpcGUoTSgoe21vZGU6ZX0pPT5lPT09Imdsb2JhbCIpKS5zdWJzY3JpYmUoZT0+e3N3aXRjaChlLnR5cGUpe2Nhc2UicCI6Y2FzZSIsIjpsZXQgdD1jZSgibGlua1tyZWw9cHJldl0iKTt0eXBlb2YgdCE9InVuZGVmaW5lZCImJm90KHQpO2JyZWFrO2Nhc2UibiI6Y2FzZSIuIjpsZXQgcj1jZSgibGlua1tyZWw9bmV4dF0iKTt0eXBlb2YgciE9InVuZGVmaW5lZCImJm90KHIpO2JyZWFrO2Nhc2UiRW50ZXIiOmxldCBvPVJlKCk7byBpbnN0YW5jZW9mIEhUTUxMYWJlbEVsZW1lbnQmJm8uY2xpY2soKX19KTtpaSh7ZG9jdW1lbnQkOm50LHRhYmxldCQ6bXJ9KTthaSh7ZG9jdW1lbnQkOm50fSk7c2koe3ZpZXdwb3J0JDpUZSx0YWJsZXQkOm1yfSk7dmFyIFhlPWtuKEVlKCJoZWFkZXIiKSx7dmlld3BvcnQkOlRlfSksTHQ9bnQucGlwZShtKCgpPT5FZSgibWFpbiIpKSxFKGU9PlJuKGUse3ZpZXdwb3J0JDpUZSxoZWFkZXIkOlhlfSkpLEooMSkpLHFhPV8oLi4ub2UoImNvbnNlbnQiKS5tYXAoZT0+Y24oZSx7dGFyZ2V0JDpndH0pKSwuLi5vZSgiZGlhbG9nIikubWFwKGU9PkNuKGUse2FsZXJ0JDpHcn0pKSwuLi5vZSgiaGVhZGVyIikubWFwKGU9PkhuKGUse3ZpZXdwb3J0JDpUZSxoZWFkZXIkOlhlLG1haW4kOkx0fSkpLC4uLm9lKCJwYWxldHRlIikubWFwKGU9PlBuKGUpKSwuLi5vZSgicHJvZ3Jlc3MiKS5tYXAoZT0+SW4oZSx7cHJvZ3Jlc3MkOkpyfSkpLC4uLm9lKCJzZWFyY2giKS5tYXAoZT0+R24oZSx7aW5kZXgkOm1pLGtleWJvYXJkJDpCcn0pKSwuLi5vZSgic291cmNlIikubWFwKGU9PnRpKGUpKSksS2E9SCgoKT0+XyguLi5vZSgiYW5ub3VuY2UiKS5tYXAoZT0+c24oZSkpLC4uLm9lKCJjb250ZW50IikubWFwKGU9PkFuKGUse3ZpZXdwb3J0JDpUZSx0YXJnZXQkOmd0LHByaW50JDpsaX0pKSwuLi5vZSgiY29udGVudCIpLm1hcChlPT50ZSgic2VhcmNoLmhpZ2hsaWdodCIpP0puKGUse2luZGV4JDptaSxsb2NhdGlvbiQ6X3R9KTpMKSwuLi5vZSgiaGVhZGVyLXRpdGxlIikubWFwKGU9PiRuKGUse3ZpZXdwb3J0JDpUZSxoZWFkZXIkOlhlfSkpLC4uLm9lKCJzaWRlYmFyIikubWFwKGU9PmUuZ2V0QXR0cmlidXRlKCJkYXRhLW1kLXR5cGUiKT09PSJuYXZpZ2F0aW9uIj9XcihwaSwoKT0+UXIoZSx7dmlld3BvcnQkOlRlLGhlYWRlciQ6WGUsbWFpbiQ6THR9KSk6V3IobXIsKCk9PlFyKGUse3ZpZXdwb3J0JDpUZSxoZWFkZXIkOlhlLG1haW4kOkx0fSkpKSwuLi5vZSgidGFicyIpLm1hcChlPT5yaShlLHt2aWV3cG9ydCQ6VGUsaGVhZGVyJDpYZX0pKSwuLi5vZSgidG9jIikubWFwKGU9Pm9pKGUse3ZpZXdwb3J0JDpUZSxoZWFkZXIkOlhlLG1haW4kOkx0LHRhcmdldCQ6Z3R9KSksLi4ub2UoInRvcCIpLm1hcChlPT5uaShlLHt2aWV3cG9ydCQ6VGUsaGVhZGVyJDpYZSxtYWluJDpMdCx0YXJnZXQkOmd0fSkpKSksZmk9bnQucGlwZShFKCgpPT5LYSkscWUocWEpLEooMSkpO2ZpLnN1YnNjcmliZSgpO3dpbmRvdy5kb2N1bWVudCQ9bnQ7d2luZG93LmxvY2F0aW9uJD1fdDt3aW5kb3cudGFyZ2V0JD1ndDt3aW5kb3cua2V5Ym9hcmQkPUJyO3dpbmRvdy52aWV3cG9ydCQ9VGU7d2luZG93LnRhYmxldCQ9bXI7d2luZG93LnNjcmVlbiQ9cGk7d2luZG93LnByaW50JD1saTt3aW5kb3cuYWxlcnQkPUdyO3dpbmRvdy5wcm9ncmVzcyQ9SnI7d2luZG93LmNvbXBvbmVudCQ9Zmk7fSkoKTsKLy8jIHNvdXJjZU1hcHBpbmdVUkw9YnVuZGxlLjk0YzQ0NTQxLm1pbi5qcy5tYXAKCg=="></script><!--URL:../assets/javascripts/bundle.94c44541.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 2023-10-08 21:55:41.955384. Original URL public_html/print_page/index.html--> |