mirror of
https://gitlab.easter-eggs.com/ee/ldapsaisie.git
synced 2024-11-25 03:19:08 +01:00
8503 lines
No EOL
962 KiB
HTML
8503 lines
No EOL
962 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.5.12" 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.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%3Bmargin%3A0%20auto%7D.md-typeset%20figcaption%7Bfont-style%3Aitalic%3Bmargin%3A1em%20auto%3Bmax-width%3A24rem%7D.md-typeset%20iframe%7Bmax-width%3A100%25%7D.md-typeset%20table%3Anot%28%5Bclass%5D%29%7Bbackground-color%3Avar%28--md-default-bg-color%29%3Bborder%3A.05rem%20solid%20var%28--md-typeset-table-color%29%3Bborder-radius%3A.1rem%3Bdisplay%3Ainline-block%3Bfont-size%3A.64rem%3Bmax-width%3A100%25%3Boverflow%3Aauto%3Btouch-action%3Aauto%7D%40media%20print%7B.md-typeset%20table%3Anot%28%5Bclass%5D%29%7Bdisplay%3Atable%7D%7D.md-typeset%20table%3Anot%28%5Bclass%5D%29%2B%2A%7Bmargin-top%3A1.5em%7D.md-typeset%20table%3Anot%28%5Bclass%5D%29%20td%3E%3Afirst-child%2C.md-typeset%20table%3Anot%28%5Bclass%5D%29%20th%3E%3Afirst-child%7Bmargin-top%3A0%7D.md-typeset%20table%3Anot%28%5Bclass%5D%29%20td%3E%3Alast-child%2C.md-typeset%20table%3Anot%28%5Bclass%5D%29%20th%3E%3Alast-child%7Bmargin-bottom%3A0%7D.md-typeset%20table%3Anot%28%5Bclass%5D%29%20td%3Anot%28%5Balign%5D%29%2C.md-typeset%20table%3Anot%28%5Bclass%5D%29%20th%3Anot%28%5Balign%5D%29%7Btext-align%3Aleft%7D%5Bdir%3Drtl%5D%20.md-typeset%20table%3Anot%28%5Bclass%5D%29%20td%3Anot%28%5Balign%5D%29%2C%5Bdir%3Drtl%5D%20.md-typeset%20table%3Anot%28%5Bclass%5D%29%20th%3Anot%28%5Balign%5D%29%7Btext-align%3Aright%7D.md-typeset%20table%3Anot%28%5Bclass%5D%29%20th%7Bfont-weight%3A700%3Bmin-width%3A5rem%3Bpadding%3A.9375em%201.25em%3Bvertical-align%3Atop%7D.md-typeset%20table%3Anot%28%5Bclass%5D%29%20td%7Bborder-top%3A.05rem%20solid%20var%28--md-typeset-table-color%29%3Bpadding%3A.9375em%201.25em%3Bvertical-align%3Atop%7D.md-typeset%20table%3Anot%28%5Bclass%5D%29%20tbody%20tr%7Btransition%3Abackground-color%20125ms%7D.md-typeset%20table%3Anot%28%5Bclass%5D%29%20tbody%20tr%3Ahover%7Bbackground-color%3Avar%28--md-typeset-table-color--light%29%3Bbox-shadow%3A0%20.05rem%200%20var%28--md-default-bg-color%29%20inset%7D.md-typeset%20table%3Anot%28%5Bclass%5D%29%20a%7Bword-break%3Anormal%7D.md-typeset%20table%20th%5Brole%3Dcolumnheader%5D%7Bcursor%3Apointer%7D%5Bdir%3Dltr%5D%20.md-typeset%20table%20th%5Brole%3Dcolumnheader%5D%3Aafter%7Bmargin-left%3A.5em%7D%5Bdir%3Drtl%5D%20.md-typeset%20table%20th%5Brole%3Dcolumnheader%5D%3Aafter%7Bmargin-right%3A.5em%7D.md-typeset%20table%20th%5Brole%3Dcolumnheader%5D%3Aafter%7Bcontent%3A%22%22%3Bdisplay%3Ainline-block%3Bheight%3A1.2em%3B-webkit-mask-image%3Avar%28--md-typeset-table-sort-icon%29%3Bmask-image%3Avar%28--md-typeset-table-sort-icon%29%3B-webkit-mask-repeat%3Ano-repeat%3Bmask-repeat%3Ano-repeat%3B-webkit-mask-size%3Acontain%3Bmask-size%3Acontain%3Btransition%3Abackground-color%20125ms%3Bvertical-align%3Atext-bottom%3Bwidth%3A1.2em%7D.md-typeset%20table%20th%5Brole%3Dcolumnheader%5D%3Ahover%3Aafter%7Bbackground-color%3Avar%28--md-default-fg-color--lighter%29%7D.md-typeset%20table%20th%5Brole%3Dcolumnheader%5D%5Baria-sort%3Dascending%5D%3Aafter%7Bbackground-color%3Avar%28--md-default-fg-color--light%29%3B-webkit-mask-image%3Avar%28--md-typeset-table-sort-icon--asc%29%3Bmask-image%3Avar%28--md-typeset-table-sort-icon--asc%29%7D.md-typeset%20table%20th%5Brole%3Dcolumnheader%5D%5Baria-sort%3Ddescending%5D%3Aafter%7Bbackground-color%3Avar%28--md-default-fg-color--light%29%3B-webkit-mask-image%3Avar%28--md-typeset-table-sort-icon--desc%29%3Bmask-image%3Avar%28--md-typeset-table-sort-icon--desc%29%7D.md-typeset__scrollwrap%7Bmargin%3A1em%20-.8rem%3Boverflow-x%3Aauto%3Btouch-action%3Aauto%7D.md-typeset__table%7Bdisplay%3Ainline-block%3Bmargin-bottom%3A.5em%3Bpadding%3A0%20.8rem%7D%40media%20print%7B.md-typeset__table%7Bdisplay%3Ablock%7D%7Dhtml%20.md-typeset__table%20table%7Bdisplay%3Atable%3Bmargin%3A0%3Boverflow%3Ahidden%3Bwidth%3A100%25%7D%40media%20screen%20and%20%28max-width%3A44.984375em%29%7B.md-content__inner%3Epre%7Bmargin%3A1em%20-.8rem%7D.md-content__inner%3Epre%20code%7Bborder-radius%3A0%7D%7D.md-typeset%20.md-author%7Bborder-radius%3A100%25%3Bdisplay%3Ablock%3Bflex-shrink%3A0%3Bheight%3A1.6rem%3Boverflow%3Ahidden%3Bposition%3Arelative%3Btransition%3Acolor%20125ms%2Ctransform%20125ms%3Bwidth%3A1.6rem%7D.md-typeset%20.md-author%20img%7Bdisplay%3Ablock%7D.md-typeset%20.md-author--more%7Bbackground%3Avar%28--md-default-fg-color--lightest%29%3Bcolor%3Avar%28--md-default-fg-color--lighter%29%3Bfont-size%3A.6rem%3Bfont-weight%3A700%3Bline-height%3A1.6rem%3Btext-align%3Acenter%7D.md-typeset%20.md-author--long%7Bheight%3A2.4rem%3Bwidth%3A2.4rem%7D.md-typeset%20a.md-author%7Btransform%3Ascale%281%29%7D.md-typeset%20a.md-author%20img%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%7Bdisplay%3Aflex%3Bflex-wrap%3Awrap%3Bplace-content%3Abaseline%20center%3Bposition%3Arelative%7D.md-feedback__list%3Ahover%20.md-icon%3Anot%28%3Adisabled%29%7Bcolor%3Avar%28--md-default-fg-color--lighter%29%7D%3Adisabled%20.md-feedback__list%7Bmin-height%3A1.8rem%7D.md-feedback__icon%7Bcolor%3Avar%28--md-default-fg-color--light%29%3Bcursor%3Apointer%3Bflex-shrink%3A0%3Bmargin%3A0%20.1rem%3Btransition%3Acolor%20125ms%7D.md-feedback__icon%3Anot%28%3Adisabled%29.md-icon%3Ahover%7Bcolor%3Avar%28--md-accent-fg-color%29%7D.md-feedback__icon%3Adisabled%7Bcolor%3Avar%28--md-default-fg-color--lightest%29%3Bpointer-events%3Anone%7D.md-feedback__note%7Bopacity%3A0%3Bposition%3Arelative%3Btransform%3AtranslateY%28.4rem%29%3Btransition%3Atransform%20.4s%20cubic-bezier%28.1%2C.7%2C.1%2C1%29%2Copacity%20.15s%7D.md-feedback__note%3E%2A%7Bmargin%3A0%20auto%3Bmax-width%3A16rem%7D%3Adisabled%20.md-feedback__note%7Bopacity%3A1%3Btransform%3AtranslateY%280%29%7D.md-footer%7Bbackground-color%3Avar%28--md-footer-bg-color%29%3Bcolor%3Avar%28--md-footer-fg-color%29%7D%40media%20print%7B.md-footer%7Bdisplay%3Anone%7D%7D.md-footer__inner%7Bjustify-content%3Aspace-between%3Boverflow%3Aauto%3Bpadding%3A.2rem%7D.md-footer__inner%3Anot%28%5Bhidden%5D%29%7Bdisplay%3Aflex%7D.md-footer__link%7Balign-items%3Aend%3Bdisplay%3Aflex%3Bflex-grow%3A0.01%3Bmargin-bottom%3A.4rem%3Bmargin-top%3A1rem%3Bmax-width%3A100%25%3Boutline-color%3Avar%28--md-accent-fg-color%29%3Boverflow%3Ahidden%3Btransition%3Aopacity%20.25s%7D.md-footer__link%3Afocus%2C.md-footer__link%3Ahover%7Bopacity%3A.7%7D%5Bdir%3Drtl%5D%20.md-footer__link%20svg%7Btransform%3AscaleX%28-1%29%7D%40media%20screen%20and%20%28max-width%3A44.984375em%29%7B.md-footer__link--prev%7Bflex-shrink%3A0%7D.md-footer__link--prev%20.md-footer__title%7Bdisplay%3Anone%7D%7D%5Bdir%3Dltr%5D%20.md-footer__link--next%7Bmargin-left%3Aauto%7D%5Bdir%3Drtl%5D%20.md-footer__link--next%7Bmargin-right%3Aauto%7D.md-footer__link--next%7Btext-align%3Aright%7D%5Bdir%3Drtl%5D%20.md-footer__link--next%7Btext-align%3Aleft%7D.md-footer__title%7Bflex-grow%3A1%3Bfont-size%3A.9rem%3Bmargin-bottom%3A.7rem%3Bmax-width%3Acalc%28100%25%20-%202.4rem%29%3Bpadding%3A0%201rem%3Bwhite-space%3Anowrap%7D.md-footer__button%7Bmargin%3A.2rem%3Bpadding%3A.4rem%7D.md-footer__direction%7Bfont-size%3A.64rem%3Bopacity%3A.7%7D.md-footer-meta%7Bbackground-color%3Avar%28--md-footer-bg-color--dark%29%7D.md-footer-meta__inner%7Bdisplay%3Aflex%3Bflex-wrap%3Awrap%3Bjustify-content%3Aspace-between%3Bpadding%3A.2rem%7Dhtml%20.md-footer-meta.md-typeset%20a%7Bcolor%3Avar%28--md-footer-fg-color--light%29%7Dhtml%20.md-footer-meta.md-typeset%20a%3Afocus%2Chtml%20.md-footer-meta.md-typeset%20a%3Ahover%7Bcolor%3Avar%28--md-footer-fg-color%29%7D.md-copyright%7Bcolor%3Avar%28--md-footer-fg-color--lighter%29%3Bfont-size%3A.64rem%3Bmargin%3Aauto%20.6rem%3Bpadding%3A.4rem%200%3Bwidth%3A100%25%7D%40media%20screen%20and%20%28min-width%3A45em%29%7B.md-copyright%7Bwidth%3Aauto%7D%7D.md-copyright__highlight%7Bcolor%3Avar%28--md-footer-fg-color--light%29%7D.md-social%7Bdisplay%3Ainline-flex%3Bgap%3A.2rem%3Bmargin%3A0%20.4rem%3Bpadding%3A.2rem%200%20.6rem%7D%40media%20screen%20and%20%28min-width%3A45em%29%7B.md-social%7Bpadding%3A.6rem%200%7D%7D.md-social__link%7Bdisplay%3Ainline-block%3Bheight%3A1.6rem%3Btext-align%3Acenter%3Bwidth%3A1.6rem%7D.md-social__link%3Abefore%7Bline-height%3A1.9%7D.md-social__link%20svg%7Bfill%3Acurrentcolor%3Bmax-height%3A.8rem%3Bvertical-align%3A-25%25%7D.md-typeset%20.md-button%7Bborder%3A.1rem%20solid%3Bborder-radius%3A.1rem%3Bcolor%3Avar%28--md-primary-fg-color%29%3Bcursor%3Apointer%3Bdisplay%3Ainline-block%3Bfont-weight%3A700%3Bpadding%3A.625em%202em%3Btransition%3Acolor%20125ms%2Cbackground-color%20125ms%2Cborder-color%20125ms%7D.md-typeset%20.md-button--primary%7Bbackground-color%3Avar%28--md-primary-fg-color%29%3Bborder-color%3Avar%28--md-primary-fg-color%29%3Bcolor%3Avar%28--md-primary-bg-color%29%7D.md-typeset%20.md-button%3Afocus%2C.md-typeset%20.md-button%3Ahover%7Bbackground-color%3Avar%28--md-accent-fg-color%29%3Bborder-color%3Avar%28--md-accent-fg-color%29%3Bcolor%3Avar%28--md-accent-bg-color%29%7D%5Bdir%3Dltr%5D%20.md-typeset%20.md-input%7Bborder-top-left-radius%3A.1rem%7D%5Bdir%3Dltr%5D%20.md-typeset%20.md-input%2C%5Bdir%3Drtl%5D%20.md-typeset%20.md-input%7Bborder-top-right-radius%3A.1rem%7D%5Bdir%3Drtl%5D%20.md-typeset%20.md-input%7Bborder-top-left-radius%3A.1rem%7D.md-typeset%20.md-input%7Bborder-bottom%3A.1rem%20solid%20var%28--md-default-fg-color--lighter%29%3Bbox-shadow%3Avar%28--md-shadow-z1%29%3Bfont-size%3A.8rem%3Bheight%3A1.8rem%3Bpadding%3A0%20.6rem%3Btransition%3Aborder%20.25s%2Cbox-shadow%20.25s%7D.md-typeset%20.md-input%3Afocus%2C.md-typeset%20.md-input%3Ahover%7Bborder-bottom-color%3Avar%28--md-accent-fg-color%29%3Bbox-shadow%3Avar%28--md-shadow-z2%29%7D.md-typeset%20.md-input--stretch%7Bwidth%3A100%25%7D.md-header%7Bbackground-color%3Avar%28--md-primary-fg-color%29%3Bbox-shadow%3A0%200%20.2rem%20%230000%2C0%20.2rem%20.4rem%20%230000%3Bcolor%3Avar%28--md-primary-bg-color%29%3Bdisplay%3Ablock%3Bleft%3A0%3Bposition%3Asticky%3Bright%3A0%3Btop%3A0%3Bz-index%3A4%7D%40media%20print%7B.md-header%7Bdisplay%3Anone%7D%7D.md-header%5Bhidden%5D%7Btransform%3AtranslateY%28-100%25%29%3Btransition%3Atransform%20.25s%20cubic-bezier%28.8%2C0%2C.6%2C1%29%2Cbox-shadow%20.25s%7D.md-header--shadow%7Bbox-shadow%3A0%200%20.2rem%20%230000001a%2C0%20.2rem%20.4rem%20%230003%3Btransition%3Atransform%20.25s%20cubic-bezier%28.1%2C.7%2C.1%2C1%29%2Cbox-shadow%20.25s%7D.md-header__inner%7Balign-items%3Acenter%3Bdisplay%3Aflex%3Bpadding%3A0%20.2rem%7D.md-header__button%7Bcolor%3Acurrentcolor%3Bcursor%3Apointer%3Bmargin%3A.2rem%3Boutline-color%3Avar%28--md-accent-fg-color%29%3Bpadding%3A.4rem%3Bposition%3Arelative%3Btransition%3Aopacity%20.25s%3Bvertical-align%3Amiddle%3Bz-index%3A1%7D.md-header__button%3Ahover%7Bopacity%3A.7%7D.md-header__button%3Anot%28%5Bhidden%5D%29%7Bdisplay%3Ainline-block%7D.md-header__button%3Anot%28.focus-visible%29%7B-webkit-tap-highlight-color%3Atransparent%3Boutline%3Anone%7D.md-header__button.md-logo%7Bmargin%3A.2rem%3Bpadding%3A.4rem%7D%40media%20screen%20and%20%28max-width%3A76.234375em%29%7B.md-header__button.md-logo%7Bdisplay%3Anone%7D%7D.md-header__button.md-logo%20img%2C.md-header__button.md-logo%20svg%7Bfill%3Acurrentcolor%3Bdisplay%3Ablock%3Bheight%3A1.2rem%3Bwidth%3Aauto%7D%40media%20screen%20and%20%28min-width%3A60em%29%7B.md-header__button%5Bfor%3D__search%5D%7Bdisplay%3Anone%7D%7D.no-js%20.md-header__button%5Bfor%3D__search%5D%7Bdisplay%3Anone%7D%5Bdir%3Drtl%5D%20.md-header__button%5Bfor%3D__search%5D%20svg%7Btransform%3AscaleX%28-1%29%7D%40media%20screen%20and%20%28min-width%3A76.25em%29%7B.md-header__button%5Bfor%3D__drawer%5D%7Bdisplay%3Anone%7D%7D.md-header__topic%7Bdisplay%3Aflex%3Bmax-width%3A100%25%3Bposition%3Aabsolute%3Btransition%3Atransform%20.4s%20cubic-bezier%28.1%2C.7%2C.1%2C1%29%2Copacity%20.15s%3Bwhite-space%3Anowrap%7D.md-header__topic%2B.md-header__topic%7Bopacity%3A0%3Bpointer-events%3Anone%3Btransform%3AtranslateX%281.25rem%29%3Btransition%3Atransform%20.4s%20cubic-bezier%281%2C.7%2C.1%2C.1%29%2Copacity%20.15s%3Bz-index%3A-1%7D%5Bdir%3Drtl%5D%20.md-header__topic%2B.md-header__topic%7Btransform%3AtranslateX%28-1.25rem%29%7D.md-header__topic%3Afirst-child%7Bfont-weight%3A700%7D%5Bdir%3Dltr%5D%20.md-header__title%7Bmargin-left%3A1rem%3Bmargin-right%3A.4rem%7D%5Bdir%3Drtl%5D%20.md-header__title%7Bmargin-left%3A.4rem%3Bmargin-right%3A1rem%7D.md-header__title%7Bflex-grow%3A1%3Bfont-size%3A.9rem%3Bheight%3A2.4rem%3Bline-height%3A2.4rem%7D.md-header__title--active%20.md-header__topic%7Bopacity%3A0%3Bpointer-events%3Anone%3Btransform%3AtranslateX%28-1.25rem%29%3Btransition%3Atransform%20.4s%20cubic-bezier%281%2C.7%2C.1%2C.1%29%2Copacity%20.15s%3Bz-index%3A-1%7D%5Bdir%3Drtl%5D%20.md-header__title--active%20.md-header__topic%7Btransform%3AtranslateX%281.25rem%29%7D.md-header__title--active%20.md-header__topic%2B.md-header__topic%7Bopacity%3A1%3Bpointer-events%3Aauto%3Btransform%3AtranslateX%280%29%3Btransition%3Atransform%20.4s%20cubic-bezier%28.1%2C.7%2C.1%2C1%29%2Copacity%20.15s%3Bz-index%3A0%7D.md-header__title%3E.md-header__ellipsis%7Bheight%3A100%25%3Bposition%3Arelative%3Bwidth%3A100%25%7D.md-header__option%7Bdisplay%3Aflex%3Bflex-shrink%3A0%3Bmax-width%3A100%25%3Btransition%3Amax-width%200ms%20.25s%2Copacity%20.25s%20.25s%3Bwhite-space%3Anowrap%7D%5Bdata-md-toggle%3Dsearch%5D%3Achecked~.md-header%20.md-header__option%7Bmax-width%3A0%3Bopacity%3A0%3Btransition%3Amax-width%200ms%2Copacity%200ms%7D.md-header__option%3Einput%7Bbottom%3A0%7D.md-header__source%7Bdisplay%3Anone%7D%40media%20screen%20and%20%28min-width%3A60em%29%7B%5Bdir%3Dltr%5D%20.md-header__source%7Bmargin-left%3A1rem%7D%5Bdir%3Drtl%5D%20.md-header__source%7Bmargin-right%3A1rem%7D.md-header__source%7Bdisplay%3Ablock%3Bmax-width%3A11.7rem%3Bwidth%3A11.7rem%7D%7D%40media%20screen%20and%20%28min-width%3A76.25em%29%7B%5Bdir%3Dltr%5D%20.md-header__source%7Bmargin-left%3A1.4rem%7D%5Bdir%3Drtl%5D%20.md-header__source%7Bmargin-right%3A1.4rem%7D%7D.md-meta%7Bcolor%3Avar%28--md-default-fg-color--light%29%3Bfont-size%3A.7rem%3Bline-height%3A1.3%7D.md-meta__list%7Bdisplay%3Ainline-flex%3Bflex-wrap%3Awrap%3Blist-style%3Anone%3Bmargin%3A0%3Bpadding%3A0%7D.md-meta__item%3Anot%28%3Alast-child%29%3Aafter%7Bcontent%3A%22%C2%B7%22%3Bmargin-left%3A.2rem%3Bmargin-right%3A.2rem%7D.md-meta__link%7Bcolor%3Avar%28--md-typeset-a-color%29%7D.md-meta__link%3Afocus%2C.md-meta__link%3Ahover%7Bcolor%3Avar%28--md-accent-fg-color%29%7D.md-draft%7Bbackground-color%3A%23ff1744%3Bborder-radius%3A.125em%3Bcolor%3A%23fff%3Bdisplay%3Ainline-block%3Bfont-weight%3A700%3Bpadding-left%3A.5714285714em%3Bpadding-right%3A.5714285714em%7D%3Aroot%7B--md-nav-icon--prev%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M20%2011v2H8l5.5%205.5-1.42%201.42L4.16%2012l7.92-7.92L13.5%205.5%208%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.md-toggle--indeterminate~.md-nav%2C.md-nav__toggle%3Achecked~.md-nav%7Bgrid-template-rows%3A1fr%3Bopacity%3A1%3Btransition%3Agrid-template-rows%20.25s%20cubic-bezier%28.86%2C0%2C.07%2C1%29%2Copacity%20.15s%20.1s%2Cvisibility%200ms%3Bvisibility%3Avisible%7D.md-nav__toggle.md-toggle--indeterminate~.md-nav%7Btransition%3Anone%7D.md-nav__item--nested%3E.md-nav%3E.md-nav__title%7Bdisplay%3Anone%7D.md-nav__item--section%7Bdisplay%3Ablock%3Bmargin%3A1.25em%200%7D.md-nav__item--section%3Alast-child%7Bmargin-bottom%3A0%7D.md-nav__item--section%3E.md-nav__link%7Bfont-weight%3A700%7D.md-nav__item--section%3E.md-nav__link%5Bfor%5D%7Bcolor%3Avar%28--md-default-fg-color--light%29%7D.md-nav__item--section%3E.md-nav__link%3Anot%28.md-nav__container%29%7Bpointer-events%3Anone%7D.md-nav__item--section%3E.md-nav__link%20.md-icon%2C.md-nav__item--section%3E.md-nav__link%3E%5Bfor%5D%7Bdisplay%3Anone%7D%5Bdir%3Dltr%5D%20.md-nav__item--section%3E.md-nav%7Bmargin-left%3A-.6rem%7D%5Bdir%3Drtl%5D%20.md-nav__item--section%3E.md-nav%7Bmargin-right%3A-.6rem%7D.md-nav__item--section%3E.md-nav%7Bdisplay%3Ablock%3Bopacity%3A1%3Bvisibility%3Avisible%7D.md-nav__item--section%3E.md-nav%3E.md-nav__list%3E.md-nav__item%7Bpadding%3A0%7D.md-nav__icon%7Bborder-radius%3A100%25%3Bheight%3A.9rem%3Btransition%3Abackground-color%20.25s%3Bwidth%3A.9rem%7D.md-nav__icon%3Ahover%7Bbackground-color%3Avar%28--md-accent-fg-color--transparent%29%7D.md-nav__icon%3Aafter%7Bbackground-color%3Acurrentcolor%3Bborder-radius%3A100%25%3Bcontent%3A%22%22%3Bdisplay%3Ainline-block%3Bheight%3A100%25%3B-webkit-mask-image%3Avar%28--md-nav-icon--next%29%3Bmask-image%3Avar%28--md-nav-icon--next%29%3B-webkit-mask-position%3Acenter%3Bmask-position%3Acenter%3B-webkit-mask-repeat%3Ano-repeat%3Bmask-repeat%3Ano-repeat%3B-webkit-mask-size%3Acontain%3Bmask-size%3Acontain%3Btransition%3Atransform%20.25s%3Bvertical-align%3A-.1rem%3Bwidth%3A100%25%7D%5Bdir%3Drtl%5D%20.md-nav__icon%3Aafter%7Btransform%3Arotate%28180deg%29%7D.md-nav__item--nested%20.md-nav__toggle%3Achecked~.md-nav__link%20.md-nav__icon%3Aafter%2C.md-nav__item--nested%20.md-toggle--indeterminate~.md-nav__link%20.md-nav__icon%3Aafter%7Btransform%3Arotate%2890deg%29%7D.md-nav--lifted%3E.md-nav__list%3E.md-nav__item%2C.md-nav--lifted%3E.md-nav__title%7Bdisplay%3Anone%7D.md-nav--lifted%3E.md-nav__list%3E.md-nav__item--active%7Bdisplay%3Ablock%7D.md-nav--lifted%3E.md-nav__list%3E.md-nav__item--active%3E.md-nav__link%7Bbackground%3Avar%28--md-default-bg-color%29%3Bbox-shadow%3A0%200%20.4rem%20.4rem%20var%28--md-default-bg-color%29%3Bmargin-top%3A0%3Bposition%3Asticky%3Btop%3A0%3Bz-index%3A1%7D.md-nav--lifted%3E.md-nav__list%3E.md-nav__item--active%3E.md-nav__link%3Anot%28.md-nav__container%29%7Bpointer-events%3Anone%7D.md-nav--lifted%3E.md-nav__list%3E.md-nav__item--active.md-nav__item--section%7Bmargin%3A0%7D%5Bdir%3Dltr%5D%20.md-nav--lifted%3E.md-nav__list%3E.md-nav__item%3E.md-nav%3Anot%28.md-nav--secondary%29%7Bmargin-left%3A-.6rem%7D%5Bdir%3Drtl%5D%20.md-nav--lifted%3E.md-nav__list%3E.md-nav__item%3E.md-nav%3Anot%28.md-nav--secondary%29%7Bmargin-right%3A-.6rem%7D.md-nav--lifted%3E.md-nav__list%3E.md-nav__item%3E%5Bfor%5D%7Bcolor%3Avar%28--md-default-fg-color--light%29%7D.md-nav--lifted%20.md-nav%5Bdata-md-level%3D%221%22%5D%7Bgrid-template-rows%3A1fr%3Bopacity%3A1%3Bvisibility%3Avisible%7D%5Bdir%3Dltr%5D%20.md-nav--integrated%3E.md-nav__list%3E.md-nav__item--active%20.md-nav--secondary%7Bborder-left%3A.05rem%20solid%20var%28--md-primary-fg-color%29%7D%5Bdir%3Drtl%5D%20.md-nav--integrated%3E.md-nav__list%3E.md-nav__item--active%20.md-nav--secondary%7Bborder-right%3A.05rem%20solid%20var%28--md-primary-fg-color%29%7D.md-nav--integrated%3E.md-nav__list%3E.md-nav__item--active%20.md-nav--secondary%7Bdisplay%3Ablock%3Bmargin-bottom%3A1.25em%3Bopacity%3A1%3Bvisibility%3Avisible%7D.md-nav--integrated%3E.md-nav__list%3E.md-nav__item--active%20.md-nav--secondary%3E.md-nav__list%7Boverflow%3Avisible%3Bpadding-bottom%3A0%7D.md-nav--integrated%3E.md-nav__list%3E.md-nav__item--active%20.md-nav--secondary%3E.md-nav__title%7Bdisplay%3Anone%7D%7D.md-pagination%7Bfont-size%3A.8rem%3Bfont-weight%3A700%3Bgap%3A.4rem%7D.md-pagination%2C.md-pagination%3E%2A%7Balign-items%3Acenter%3Bdisplay%3Aflex%3Bjustify-content%3Acenter%7D.md-pagination%3E%2A%7Bborder-radius%3A.2rem%3Bheight%3A1.8rem%3Bmin-width%3A1.8rem%3Btext-align%3Acenter%7D.md-pagination__current%7Bbackground-color%3Avar%28--md-default-fg-color--lightest%29%3Bcolor%3Avar%28--md-default-fg-color--light%29%7D.md-pagination__link%7Btransition%3Acolor%20125ms%2Cbackground-color%20125ms%7D.md-pagination__link%3Afocus%2C.md-pagination__link%3Ahover%7Bbackground-color%3Avar%28--md-accent-fg-color--transparent%29%3Bcolor%3Avar%28--md-accent-fg-color%29%7D.md-pagination__link%3Afocus%20svg%2C.md-pagination__link%3Ahover%20svg%7Bcolor%3Avar%28--md-accent-fg-color%29%7D.md-pagination__link.focus-visible%7Boutline-color%3Avar%28--md-accent-fg-color%29%3Boutline-offset%3A.2rem%7D.md-pagination__link%20svg%7Bfill%3Acurrentcolor%3Bcolor%3Avar%28--md-default-fg-color--lighter%29%3Bdisplay%3Ablock%3Bmax-height%3A100%25%3Bwidth%3A1.2rem%7D.md-post__back%7Bborder-bottom%3A.05rem%20solid%20var%28--md-default-fg-color--lightest%29%3Bmargin-bottom%3A1.2rem%3Bpadding-bottom%3A1.2rem%7D%40media%20screen%20and%20%28max-width%3A76.234375em%29%7B.md-post__back%7Bdisplay%3Anone%7D%7D%5Bdir%3Drtl%5D%20.md-post__back%20svg%7Btransform%3AscaleX%28-1%29%7D.md-post__authors%7Bdisplay%3Aflex%3Bflex-direction%3Acolumn%3Bgap%3A.6rem%3Bmargin%3A0%20.6rem%201.2rem%7D.md-post%20.md-post__meta%20a%7Btransition%3Acolor%20125ms%7D.md-post%20.md-post__meta%20a%3Afocus%2C.md-post%20.md-post__meta%20a%3Ahover%7Bcolor%3Avar%28--md-accent-fg-color%29%7D.md-post__title%7Bcolor%3Avar%28--md-default-fg-color--light%29%3Bfont-weight%3A700%7D.md-post--excerpt%7Bmargin-bottom%3A3.2rem%7D.md-post--excerpt%20.md-post__header%7Balign-items%3Acenter%3Bdisplay%3Aflex%3Bgap%3A.6rem%3Bmin-height%3A1.6rem%7D.md-post--excerpt%20.md-post__authors%7Balign-items%3Acenter%3Bdisplay%3Ainline-flex%3Bflex-direction%3Arow%3Bgap%3A.2rem%3Bmargin%3A0%3Bmin-height%3A2.4rem%7D%5Bdir%3Dltr%5D%20.md-post--excerpt%20.md-post__meta%20.md-meta__list%7Bmargin-right%3A.4rem%7D%5Bdir%3Drtl%5D%20.md-post--excerpt%20.md-post__meta%20.md-meta__list%7Bmargin-left%3A.4rem%7D.md-post--excerpt%20.md-post__content%3E%3Afirst-child%7B--md-scroll-margin%3A6rem%3Bmargin-top%3A0%7D.md-post%3E.md-nav--secondary%7Bmargin%3A1em%200%7D.md-profile%7Balign-items%3Acenter%3Bdisplay%3Aflex%3Bfont-size%3A.7rem%3Bgap%3A.6rem%3Bline-height%3A1.4%3Bwidth%3A100%25%7D.md-profile__description%7Bflex-grow%3A1%7D.md-content--post%7Bdisplay%3Aflex%7D%40media%20screen%20and%20%28max-width%3A76.234375em%29%7B.md-content--post%7Bflex-flow%3Acolumn-reverse%7D%7D.md-content--post%3E.md-content__inner%7Bmin-width%3A0%7D%40media%20screen%20and%20%28min-width%3A76.25em%29%7B%5Bdir%3Dltr%5D%20.md-content--post%3E.md-content__inner%7Bmargin-left%3A1.2rem%7D%5Bdir%3Drtl%5D%20.md-content--post%3E.md-content__inner%7Bmargin-right%3A1.2rem%7D%7D%40media%20screen%20and%20%28max-width%3A76.234375em%29%7B.md-sidebar.md-sidebar--post%7Bpadding%3A0%3Bposition%3Astatic%3Bwidth%3A100%25%7D.md-sidebar.md-sidebar--post%20.md-sidebar__scrollwrap%7Boverflow%3Avisible%7D.md-sidebar.md-sidebar--post%20.md-sidebar__inner%7Bpadding%3A0%7D.md-sidebar.md-sidebar--post%20.md-post__meta%7Bmargin-left%3A.6rem%3Bmargin-right%3A.6rem%7D.md-sidebar.md-sidebar--post%20.md-nav__item%7Bborder%3Anone%3Bdisplay%3Ainline%7D.md-sidebar.md-sidebar--post%20.md-nav__list%7Bdisplay%3Ainline-flex%3Bflex-wrap%3Awrap%3Bgap%3A.6rem%3Bpadding-bottom%3A.6rem%3Bpadding-top%3A.6rem%7D.md-sidebar.md-sidebar--post%20.md-nav__link%7Bpadding%3A0%7D.md-sidebar.md-sidebar--post%20.md-nav%7Bheight%3Aauto%3Bmargin-bottom%3A0%3Bposition%3Astatic%7D%7D%3Aroot%7B--md-progress-value%3A0%3B--md-progress-delay%3A400ms%7D.md-progress%7Bbackground%3Avar%28--md-primary-bg-color%29%3Bheight%3A.075rem%3Bopacity%3Amin%28clamp%280%2Cvar%28--md-progress-value%29%2C1%29%2Cclamp%280%2C100%20-%20var%28--md-progress-value%29%2C1%29%29%3Bposition%3Afixed%3Btop%3A0%3Btransform%3AscaleX%28calc%28var%28--md-progress-value%29%2A1%25%29%29%3Btransform-origin%3Aleft%3Btransition%3Atransform%20.5s%20cubic-bezier%28.19%2C1%2C.22%2C1%29%2Copacity%20.25s%20var%28--md-progress-delay%29%3Bwidth%3A100%25%3Bz-index%3A4%7D%3Aroot%7B--md-search-result-icon%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M14%202H6a2%202%200%200%200-2%202v16a2%202%200%200%200%202%202h7c-.41-.25-.8-.56-1.14-.9-.33-.33-.61-.7-.86-1.1H6V4h7v5h5v1.18c.71.16%201.39.43%202%20.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.md-source-file%7Bmargin%3A1em%200%7D%5Bdir%3Dltr%5D%20.md-source-file__fact%7Bmargin-right%3A.6rem%7D%5Bdir%3Drtl%5D%20.md-source-file__fact%7Bmargin-left%3A.6rem%7D.md-source-file__fact%7Balign-items%3Acenter%3Bcolor%3Avar%28--md-default-fg-color--light%29%3Bdisplay%3Ainline-flex%3Bfont-size%3A.68rem%3Bgap%3A.3rem%7D.md-source-file__fact%20.md-icon%7Bflex-shrink%3A0%3Bmargin-bottom%3A.05rem%7D%5Bdir%3Dltr%5D%20.md-source-file__fact%20.md-author%7Bfloat%3Aleft%7D%5Bdir%3Drtl%5D%20.md-source-file__fact%20.md-author%7Bfloat%3Aright%7D.md-source-file__fact%20.md-author%7Bmargin-right%3A.2rem%7D.md-source-file__fact%20svg%7Bwidth%3A.9rem%7D%3Aroot%7B--md-status%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M11%209h2V7h-2m1%2013c-4.41%200-8-3.59-8-8s3.59-8%208-8%208%203.59%208%208-3.59%208-8%208m0-18A10%2010%200%200%200%202%2012a10%2010%200%200%200%2010%2010%2010%2010%200%200%200%2010-10A10%2010%200%200%200%2012%202m-1%2015h2v-6h-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%3Anot%28%5Bhidden%5D%29%7Bdisplay%3Ainline-flex%3Bflex-wrap%3Awrap%3Bgap%3A.5em%3Bmargin-bottom%3A.75em%3Bmargin-top%3A-.125em%7D.md-typeset%20.md-tag%7Balign-items%3Acenter%3Bbackground%3Avar%28--md-default-fg-color--lightest%29%3Bborder-radius%3A2.4rem%3Bdisplay%3Ainline-flex%3Bfont-size%3A.64rem%3Bfont-size%3Amin%28.8em%2C.64rem%29%3Bfont-weight%3A700%3Bgap%3A.5em%3Bletter-spacing%3Anormal%3Bline-height%3A1.6%3Bpadding%3A.3125em%20.78125em%7D.md-typeset%20.md-tag%5Bhref%5D%7B-webkit-tap-highlight-color%3Atransparent%3Bcolor%3Ainherit%3Boutline%3Anone%3Btransition%3Acolor%20125ms%2Cbackground-color%20125ms%7D.md-typeset%20.md-tag%5Bhref%5D%3Afocus%2C.md-typeset%20.md-tag%5Bhref%5D%3Ahover%7Bbackground-color%3Avar%28--md-accent-fg-color%29%3Bcolor%3Avar%28--md-accent-bg-color%29%7D%5Bid%5D%3E.md-typeset%20.md-tag%7Bvertical-align%3Atext-top%7D.md-typeset%20.md-tag-icon%3Abefore%7Bbackground-color%3Avar%28--md-default-fg-color--lighter%29%3Bcontent%3A%22%22%3Bdisplay%3Ainline-block%3Bheight%3A1.2em%3B-webkit-mask-image%3Avar%28--md-tag-icon%29%3Bmask-image%3Avar%28--md-tag-icon%29%3B-webkit-mask-position%3Acenter%3Bmask-position%3Acenter%3B-webkit-mask-repeat%3Ano-repeat%3Bmask-repeat%3Ano-repeat%3B-webkit-mask-size%3Acontain%3Bmask-size%3Acontain%3Btransition%3Abackground-color%20125ms%3Bvertical-align%3Atext-bottom%3Bwidth%3A1.2em%7D.md-typeset%20.md-tag-icon%5Bhref%5D%3Afocus%3Abefore%2C.md-typeset%20.md-tag-icon%5Bhref%5D%3Ahover%3Abefore%7Bbackground-color%3Avar%28--md-accent-bg-color%29%7D%40keyframes%20pulse%7B0%25%7Btransform%3Ascale%28.95%29%7D75%25%7Btransform%3Ascale%281%29%7Dto%7Btransform%3Ascale%28.95%29%7D%7D%3Aroot%7B--md-annotation-bg-icon%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M12%202A10%2010%200%200%200%202%2012a10%2010%200%200%200%2010%2010%2010%2010%200%200%200%2010-10A10%2010%200%200%200%2012%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.md-tooltip--inline%7Bfont-weight%3A700%3B-webkit-user-select%3Anone%3Buser-select%3Anone%3Bwidth%3Aauto%7D.md-tooltip--inline%3Anot%28.md-tooltip--active%29%7Btransform%3AtranslateY%28.2rem%29%20scale%28.9%29%7D.md-tooltip--inline%20.md-tooltip__inner%7Bfont-size%3A.5rem%3Bpadding%3A.2rem%20.4rem%7D%5Bhidden%5D%2B.md-tooltip--inline%7Bdisplay%3Anone%7D.focus-visible%3E.md-tooltip%2C.md-tooltip%3Atarget%7Boutline%3Avar%28--md-accent-fg-color%29%20auto%7D.md-tooltip__inner%7Bfont-size%3A.64rem%3Bpadding%3A.8rem%7D.md-tooltip__inner.md-typeset%3E%3Afirst-child%7Bmargin-top%3A0%7D.md-tooltip__inner.md-typeset%3E%3Alast-child%7Bmargin-bottom%3A0%7D.md-annotation%7Bfont-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.5.1%20by%20%40fontawesome%20-%20https%3A//fontawesome.com%20License%20-%20https%3A//fontawesome.com/license/free%20%28Icons%3A%20CC%20BY%204.0%2C%20Fonts%3A%20SIL%20OFL%201.1%2C%20Code%3A%20MIT%20License%29%20Copyright%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.md-typeset%20div.arithmatex%3E%2A%7Bwidth%3A-webkit-min-content%3Bwidth%3Amin-content%7D%7D.md-typeset%20div.arithmatex%3E%2A%7Bmargin-left%3Aauto%21important%3Bmargin-right%3Aauto%21important%3Bpadding%3A0%20.8rem%3Btouch-action%3Aauto%7D.md-typeset%20div.arithmatex%3E%2A%20mjx-container%7Bmargin%3A0%21important%7D.md-typeset%20div.arithmatex%20mjx-assistive-mml%7Bheight%3A0%7D.md-typeset%20del.critic%7Bbackground-color%3Avar%28--md-typeset-del-color%29%7D.md-typeset%20del.critic%2C.md-typeset%20ins.critic%7B-webkit-box-decoration-break%3Aclone%3Bbox-decoration-break%3Aclone%7D.md-typeset%20ins.critic%7Bbackground-color%3Avar%28--md-typeset-ins-color%29%7D.md-typeset%20.critic.comment%7B-webkit-box-decoration-break%3Aclone%3Bbox-decoration-break%3Aclone%3Bcolor%3Avar%28--md-code-hl-comment-color%29%7D.md-typeset%20.critic.comment%3Abefore%7Bcontent%3A%22/%2A%20%22%7D.md-typeset%20.critic.comment%3Aafter%7Bcontent%3A%22%20%2A/%22%7D.md-typeset%20.critic.block%7Bbox-shadow%3Anone%3Bdisplay%3Ablock%3Bmargin%3A1em%200%3Boverflow%3Aauto%3Bpadding-left%3A.8rem%3Bpadding-right%3A.8rem%7D.md-typeset%20.critic.block%3E%3Afirst-child%7Bmargin-top%3A.5em%7D.md-typeset%20.critic.block%3E%3Alast-child%7Bmargin-bottom%3A.5em%7D%3Aroot%7B--md-details-icon%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M8.59%2016.58%2013.17%2012%208.59%207.41%2010%206l6%206-6%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%3Boverflow%3Ahidden%7D.md-typeset%20summary.focus-visible%7Boutline-color%3Avar%28--md-accent-fg-color%29%3Boutline-offset%3A.2rem%7D.md-typeset%20summary%3Anot%28.focus-visible%29%7B-webkit-tap-highlight-color%3Atransparent%3Boutline%3Anone%7D%5Bdir%3Dltr%5D%20.md-typeset%20summary%3Aafter%7Bright%3A.4rem%7D%5Bdir%3Drtl%5D%20.md-typeset%20summary%3Aafter%7Bleft%3A.4rem%7D.md-typeset%20summary%3Aafter%7Bbackground-color%3Acurrentcolor%3Bcontent%3A%22%22%3Bheight%3A1rem%3B-webkit-mask-image%3Avar%28--md-details-icon%29%3Bmask-image%3Avar%28--md-details-icon%29%3B-webkit-mask-position%3Acenter%3Bmask-position%3Acenter%3B-webkit-mask-repeat%3Ano-repeat%3Bmask-repeat%3Ano-repeat%3B-webkit-mask-size%3Acontain%3Bmask-size%3Acontain%3Bposition%3Aabsolute%3Btop%3A.625em%3Btransform%3Arotate%280deg%29%3Btransition%3Atransform%20.25s%3Bwidth%3A1rem%7D%5Bdir%3Drtl%5D%20.md-typeset%20summary%3Aafter%7Btransform%3Arotate%28180deg%29%7D.md-typeset%20summary%3A%3Amarker%7Bdisplay%3Anone%7D.md-typeset%20summary%3A%3A-webkit-details-marker%7Bdisplay%3Anone%7D.md-typeset%20.emojione%2C.md-typeset%20.gemoji%2C.md-typeset%20.twemoji%7B--md-icon-size%3A1.125em%3Bdisplay%3Ainline-flex%3Bheight%3Avar%28--md-icon-size%29%3Bvertical-align%3Atext-top%7D.md-typeset%20.emojione%20svg%2C.md-typeset%20.gemoji%20svg%2C.md-typeset%20.twemoji%20svg%7Bfill%3Acurrentcolor%3Bmax-height%3A100%25%3Bwidth%3Avar%28--md-icon-size%29%7D.md-typeset%20.lg%2C.md-typeset%20.xl%2C.md-typeset%20.xxl%2C.md-typeset%20.xxxl%7Bvertical-align%3Atext-bottom%7D.md-typeset%20.middle%7Bvertical-align%3Amiddle%7D.md-typeset%20.lg%7B--md-icon-size%3A1.5em%7D.md-typeset%20.xl%7B--md-icon-size%3A2.25em%7D.md-typeset%20.xxl%7B--md-icon-size%3A3em%7D.md-typeset%20.xxxl%7B--md-icon-size%3A4em%7D.highlight%20.o%2C.highlight%20.ow%7Bcolor%3Avar%28--md-code-hl-operator-color%29%7D.highlight%20.p%7Bcolor%3Avar%28--md-code-hl-punctuation-color%29%7D.highlight%20.cpf%2C.highlight%20.l%2C.highlight%20.s%2C.highlight%20.s1%2C.highlight%20.s2%2C.highlight%20.sb%2C.highlight%20.sc%2C.highlight%20.si%2C.highlight%20.ss%7Bcolor%3Avar%28--md-code-hl-string-color%29%7D.highlight%20.cp%2C.highlight%20.se%2C.highlight%20.sh%2C.highlight%20.sr%2C.highlight%20.sx%7Bcolor%3Avar%28--md-code-hl-special-color%29%7D.highlight%20.il%2C.highlight%20.m%2C.highlight%20.mb%2C.highlight%20.mf%2C.highlight%20.mh%2C.highlight%20.mi%2C.highlight%20.mo%7Bcolor%3Avar%28--md-code-hl-number-color%29%7D.highlight%20.k%2C.highlight%20.kd%2C.highlight%20.kn%2C.highlight%20.kp%2C.highlight%20.kr%2C.highlight%20.kt%7Bcolor%3Avar%28--md-code-hl-keyword-color%29%7D.highlight%20.kc%2C.highlight%20.n%7Bcolor%3Avar%28--md-code-hl-name-color%29%7D.highlight%20.bp%2C.highlight%20.nb%2C.highlight%20.no%7Bcolor%3Avar%28--md-code-hl-constant-color%29%7D.highlight%20.nc%2C.highlight%20.ne%2C.highlight%20.nf%2C.highlight%20.nn%7Bcolor%3Avar%28--md-code-hl-function-color%29%7D.highlight%20.nd%2C.highlight%20.ni%2C.highlight%20.nl%2C.highlight%20.nt%7Bcolor%3Avar%28--md-code-hl-keyword-color%29%7D.highlight%20.c%2C.highlight%20.c1%2C.highlight%20.ch%2C.highlight%20.cm%2C.highlight%20.cs%2C.highlight%20.sd%7Bcolor%3Avar%28--md-code-hl-comment-color%29%7D.highlight%20.na%2C.highlight%20.nv%2C.highlight%20.vc%2C.highlight%20.vg%2C.highlight%20.vi%7Bcolor%3Avar%28--md-code-hl-variable-color%29%7D.highlight%20.ge%2C.highlight%20.gh%2C.highlight%20.go%2C.highlight%20.gp%2C.highlight%20.gr%2C.highlight%20.gs%2C.highlight%20.gt%2C.highlight%20.gu%7Bcolor%3Avar%28--md-code-hl-generic-color%29%7D.highlight%20.gd%2C.highlight%20.gi%7Bborder-radius%3A.1rem%3Bmargin%3A0%20-.125em%3Bpadding%3A0%20.125em%7D.highlight%20.gd%7Bbackground-color%3Avar%28--md-typeset-del-color%29%7D.highlight%20.gi%7Bbackground-color%3Avar%28--md-typeset-ins-color%29%7D.highlight%20.hll%7Bbackground-color%3Avar%28--md-code-hl-color--light%29%3Bbox-shadow%3A2px%200%200%200%20var%28--md-code-hl-color%29%20inset%3Bdisplay%3Ablock%3Bmargin%3A0%20-1.1764705882em%3Bpadding%3A0%201.1764705882em%7D.highlight%20span.filename%7Bbackground-color%3Avar%28--md-code-bg-color%29%3Bborder-bottom%3A.05rem%20solid%20var%28--md-default-fg-color--lightest%29%3Bborder-top-left-radius%3A.1rem%3Bborder-top-right-radius%3A.1rem%3Bdisplay%3Aflow-root%3Bfont-size%3A.85em%3Bfont-weight%3A700%3Bmargin-top%3A1em%3Bpadding%3A.6617647059em%201.1764705882em%3Bposition%3Arelative%7D.highlight%20span.filename%2Bpre%7Bmargin-top%3A0%7D.highlight%20span.filename%2Bpre%3Ecode%7Bborder-top-left-radius%3A0%3Bborder-top-right-radius%3A0%7D.highlight%20%5Bdata-linenos%5D%3Abefore%7Bbackground-color%3Avar%28--md-code-bg-color%29%3Bbox-shadow%3A-.05rem%200%20var%28--md-default-fg-color--lightest%29%20inset%3Bcolor%3Avar%28--md-default-fg-color--light%29%3Bcontent%3Aattr%28data-linenos%29%3Bfloat%3Aleft%3Bleft%3A-1.1764705882em%3Bmargin-left%3A-1.1764705882em%3Bmargin-right%3A1.1764705882em%3Bpadding-left%3A1.1764705882em%3Bposition%3Asticky%3B-webkit-user-select%3Anone%3Buser-select%3Anone%3Bz-index%3A3%7D.highlight%20code%20a%5Bid%5D%7Bposition%3Aabsolute%3Bvisibility%3Ahidden%7D.highlight%20code%5Bdata-md-copying%5D%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-labels%3Elabel%3E%5Bhref%5D%3Afirst-child%7Bcolor%3Ainherit%7D.md-typeset%20.tabbed-labels--linked%3Elabel%7Bpadding%3A0%7D.md-typeset%20.tabbed-labels--linked%3Elabel%3Ea%7Bdisplay%3Ablock%3Bpadding%3A.78125em%201.25em%20.625em%7D.md-typeset%20.tabbed-content%7Bwidth%3A100%25%7D%40media%20print%7B.md-typeset%20.tabbed-content%7Bdisplay%3Acontents%7D%7D.md-typeset%20.tabbed-block%7Bdisplay%3Anone%7D%40media%20print%7B.md-typeset%20.tabbed-block%7Bdisplay%3Ablock%7D.md-typeset%20.tabbed-block%3Afirst-child%7Border%3A1%7D.md-typeset%20.tabbed-block%3Anth-child%282%29%7Border%3A2%7D.md-typeset%20.tabbed-block%3Anth-child%283%29%7Border%3A3%7D.md-typeset%20.tabbed-block%3Anth-child%284%29%7Border%3A4%7D.md-typeset%20.tabbed-block%3Anth-child%285%29%7Border%3A5%7D.md-typeset%20.tabbed-block%3Anth-child%286%29%7Border%3A6%7D.md-typeset%20.tabbed-block%3Anth-child%287%29%7Border%3A7%7D.md-typeset%20.tabbed-block%3Anth-child%288%29%7Border%3A8%7D.md-typeset%20.tabbed-block%3Anth-child%289%29%7Border%3A9%7D.md-typeset%20.tabbed-block%3Anth-child%2810%29%7Border%3A10%7D.md-typeset%20.tabbed-block%3Anth-child%2811%29%7Border%3A11%7D.md-typeset%20.tabbed-block%3Anth-child%2812%29%7Border%3A12%7D.md-typeset%20.tabbed-block%3Anth-child%2813%29%7Border%3A13%7D.md-typeset%20.tabbed-block%3Anth-child%2814%29%7Border%3A14%7D.md-typeset%20.tabbed-block%3Anth-child%2815%29%7Border%3A15%7D.md-typeset%20.tabbed-block%3Anth-child%2816%29%7Border%3A16%7D.md-typeset%20.tabbed-block%3Anth-child%2817%29%7Border%3A17%7D.md-typeset%20.tabbed-block%3Anth-child%2818%29%7Border%3A18%7D.md-typeset%20.tabbed-block%3Anth-child%2819%29%7Border%3A19%7D.md-typeset%20.tabbed-block%3Anth-child%2820%29%7Border%3A20%7D%7D.md-typeset%20.tabbed-block%3E.highlight%3Afirst-child%3Epre%2C.md-typeset%20.tabbed-block%3Epre%3Afirst-child%7Bmargin%3A0%7D.md-typeset%20.tabbed-block%3E.highlight%3Afirst-child%3Epre%3Ecode%2C.md-typeset%20.tabbed-block%3Epre%3Afirst-child%3Ecode%7Bborder-top-left-radius%3A0%3Bborder-top-right-radius%3A0%7D.md-typeset%20.tabbed-block%3E.highlight%3Afirst-child%3E.filename%7Bborder-top-left-radius%3A0%3Bborder-top-right-radius%3A0%3Bmargin%3A0%7D.md-typeset%20.tabbed-block%3E.highlight%3Afirst-child%3E.highlighttable%7Bmargin%3A0%7D.md-typeset%20.tabbed-block%3E.highlight%3Afirst-child%3E.highlighttable%3Etbody%3Etr%3E.filename%20span.filename%2C.md-typeset%20.tabbed-block%3E.highlight%3Afirst-child%3E.highlighttable%3Etbody%3Etr%3E.linenos%7Bborder-top-left-radius%3A0%3Bborder-top-right-radius%3A0%3Bmargin%3A0%7D.md-typeset%20.tabbed-block%3E.highlight%3Afirst-child%3E.highlighttable%3Etbody%3Etr%3E.code%3Ediv%3Epre%3Ecode%7Bborder-top-left-radius%3A0%3Bborder-top-right-radius%3A0%7D.md-typeset%20.tabbed-block%3E.highlight%3Afirst-child%2B.result%7Bmargin-top%3A-.125em%7D.md-typeset%20.tabbed-block%3E.tabbed-set%7Bmargin%3A0%7D.md-typeset%20.tabbed-button%7Balign-self%3Acenter%3Bborder-radius%3A100%25%3Bcolor%3Avar%28--md-default-fg-color--light%29%3Bcursor%3Apointer%3Bdisplay%3Ablock%3Bheight%3A.9rem%3Bmargin-top%3A.1rem%3Bpointer-events%3Aauto%3Btransition%3Abackground-color%20.25s%3Bwidth%3A.9rem%7D.md-typeset%20.tabbed-button%3Ahover%7Bbackground-color%3Avar%28--md-accent-fg-color--transparent%29%3Bcolor%3Avar%28--md-accent-fg-color%29%7D.md-typeset%20.tabbed-button%3Aafter%7Bbackground-color%3Acurrentcolor%3Bcontent%3A%22%22%3Bdisplay%3Ablock%3Bheight%3A100%25%3B-webkit-mask-image%3Avar%28--md-tabbed-icon--prev%29%3Bmask-image%3Avar%28--md-tabbed-icon--prev%29%3B-webkit-mask-position%3Acenter%3Bmask-position%3Acenter%3B-webkit-mask-repeat%3Ano-repeat%3Bmask-repeat%3Ano-repeat%3B-webkit-mask-size%3Acontain%3Bmask-size%3Acontain%3Btransition%3Abackground-color%20.25s%2Ctransform%20.25s%3Bwidth%3A100%25%7D.md-typeset%20.tabbed-control%7Bbackground%3Alinear-gradient%28to%20right%2Cvar%28--md-default-bg-color%29%2060%25%2C%230000%29%3Bdisplay%3Aflex%3Bheight%3A1.9rem%3Bjustify-content%3Astart%3Bpointer-events%3Anone%3Bposition%3Aabsolute%3Btransition%3Aopacity%20125ms%3Bwidth%3A1.2rem%7D%5Bdir%3Drtl%5D%20.md-typeset%20.tabbed-control%7Btransform%3Arotate%28180deg%29%7D.md-typeset%20.tabbed-control%5Bhidden%5D%7Bopacity%3A0%7D.md-typeset%20.tabbed-control--next%7Bbackground%3Alinear-gradient%28to%20left%2Cvar%28--md-default-bg-color%29%2060%25%2C%230000%29%3Bjustify-content%3Aend%3Bright%3A0%7D.md-typeset%20.tabbed-control--next%20.tabbed-button%3Aafter%7B-webkit-mask-image%3Avar%28--md-tabbed-icon--next%29%3Bmask-image%3Avar%28--md-tabbed-icon--next%29%7D%40media%20screen%20and%20%28max-width%3A44.984375em%29%7B%5Bdir%3Dltr%5D%20.md-content__inner%3E.tabbed-set%20.tabbed-labels%7Bpadding-left%3A.8rem%7D%5Bdir%3Drtl%5D%20.md-content__inner%3E.tabbed-set%20.tabbed-labels%7Bpadding-right%3A.8rem%7D.md-content__inner%3E.tabbed-set%20.tabbed-labels%7Bmargin%3A0%20-.8rem%3Bmax-width%3A100vw%3Bscroll-padding-inline-start%3A.8rem%7D%5Bdir%3Dltr%5D%20.md-content__inner%3E.tabbed-set%20.tabbed-labels%3Aafter%7Bpadding-right%3A.8rem%7D%5Bdir%3Drtl%5D%20.md-content__inner%3E.tabbed-set%20.tabbed-labels%3Aafter%7Bpadding-left%3A.8rem%7D.md-content__inner%3E.tabbed-set%20.tabbed-labels%3Aafter%7Bcontent%3A%22%22%7D%5Bdir%3Dltr%5D%20.md-content__inner%3E.tabbed-set%20.tabbed-labels~.tabbed-control--prev%7Bpadding-left%3A.8rem%7D%5Bdir%3Drtl%5D%20.md-content__inner%3E.tabbed-set%20.tabbed-labels~.tabbed-control--prev%7Bpadding-right%3A.8rem%7D%5Bdir%3Dltr%5D%20.md-content__inner%3E.tabbed-set%20.tabbed-labels~.tabbed-control--prev%7Bmargin-left%3A-.8rem%7D%5Bdir%3Drtl%5D%20.md-content__inner%3E.tabbed-set%20.tabbed-labels~.tabbed-control--prev%7Bmargin-right%3A-.8rem%7D.md-content__inner%3E.tabbed-set%20.tabbed-labels~.tabbed-control--prev%7Bwidth%3A2rem%7D%5Bdir%3Dltr%5D%20.md-content__inner%3E.tabbed-set%20.tabbed-labels~.tabbed-control--next%7Bpadding-right%3A.8rem%7D%5Bdir%3Drtl%5D%20.md-content__inner%3E.tabbed-set%20.tabbed-labels~.tabbed-control--next%7Bpadding-left%3A.8rem%7D%5Bdir%3Dltr%5D%20.md-content__inner%3E.tabbed-set%20.tabbed-labels~.tabbed-control--next%7Bmargin-right%3A-.8rem%7D%5Bdir%3Drtl%5D%20.md-content__inner%3E.tabbed-set%20.tabbed-labels~.tabbed-control--next%7Bmargin-left%3A-.8rem%7D.md-content__inner%3E.tabbed-set%20.tabbed-labels~.tabbed-control--next%7Bwidth%3A2rem%7D%7D%40media%20screen%7B.md-typeset%20.tabbed-set%3Einput%3Afirst-child%3Achecked~.tabbed-labels%3E%3Afirst-child%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2810%29%3Achecked~.tabbed-labels%3E%3Anth-child%2810%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2811%29%3Achecked~.tabbed-labels%3E%3Anth-child%2811%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2812%29%3Achecked~.tabbed-labels%3E%3Anth-child%2812%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2813%29%3Achecked~.tabbed-labels%3E%3Anth-child%2813%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2814%29%3Achecked~.tabbed-labels%3E%3Anth-child%2814%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2815%29%3Achecked~.tabbed-labels%3E%3Anth-child%2815%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2816%29%3Achecked~.tabbed-labels%3E%3Anth-child%2816%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2817%29%3Achecked~.tabbed-labels%3E%3Anth-child%2817%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2818%29%3Achecked~.tabbed-labels%3E%3Anth-child%2818%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2819%29%3Achecked~.tabbed-labels%3E%3Anth-child%2819%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%282%29%3Achecked~.tabbed-labels%3E%3Anth-child%282%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2820%29%3Achecked~.tabbed-labels%3E%3Anth-child%2820%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%283%29%3Achecked~.tabbed-labels%3E%3Anth-child%283%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%284%29%3Achecked~.tabbed-labels%3E%3Anth-child%284%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%285%29%3Achecked~.tabbed-labels%3E%3Anth-child%285%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%286%29%3Achecked~.tabbed-labels%3E%3Anth-child%286%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%287%29%3Achecked~.tabbed-labels%3E%3Anth-child%287%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%288%29%3Achecked~.tabbed-labels%3E%3Anth-child%288%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%289%29%3Achecked~.tabbed-labels%3E%3Anth-child%289%29%7Bcolor%3Avar%28--md-default-fg-color%29%7D.md-typeset%20.no-js%20.tabbed-set%3Einput%3Afirst-child%3Achecked~.tabbed-labels%3E%3Afirst-child%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%2810%29%3Achecked~.tabbed-labels%3E%3Anth-child%2810%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%2811%29%3Achecked~.tabbed-labels%3E%3Anth-child%2811%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%2812%29%3Achecked~.tabbed-labels%3E%3Anth-child%2812%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%2813%29%3Achecked~.tabbed-labels%3E%3Anth-child%2813%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%2814%29%3Achecked~.tabbed-labels%3E%3Anth-child%2814%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%2815%29%3Achecked~.tabbed-labels%3E%3Anth-child%2815%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%2816%29%3Achecked~.tabbed-labels%3E%3Anth-child%2816%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%2817%29%3Achecked~.tabbed-labels%3E%3Anth-child%2817%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%2818%29%3Achecked~.tabbed-labels%3E%3Anth-child%2818%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%2819%29%3Achecked~.tabbed-labels%3E%3Anth-child%2819%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%282%29%3Achecked~.tabbed-labels%3E%3Anth-child%282%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%2820%29%3Achecked~.tabbed-labels%3E%3Anth-child%2820%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%283%29%3Achecked~.tabbed-labels%3E%3Anth-child%283%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%284%29%3Achecked~.tabbed-labels%3E%3Anth-child%284%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%285%29%3Achecked~.tabbed-labels%3E%3Anth-child%285%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%286%29%3Achecked~.tabbed-labels%3E%3Anth-child%286%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%287%29%3Achecked~.tabbed-labels%3E%3Anth-child%287%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%288%29%3Achecked~.tabbed-labels%3E%3Anth-child%288%29%2C.md-typeset%20.no-js%20.tabbed-set%3Einput%3Anth-child%289%29%3Achecked~.tabbed-labels%3E%3Anth-child%289%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Afirst-child%3Achecked~.tabbed-labels%3E%3Afirst-child%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%2810%29%3Achecked~.tabbed-labels%3E%3Anth-child%2810%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%2811%29%3Achecked~.tabbed-labels%3E%3Anth-child%2811%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%2812%29%3Achecked~.tabbed-labels%3E%3Anth-child%2812%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%2813%29%3Achecked~.tabbed-labels%3E%3Anth-child%2813%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%2814%29%3Achecked~.tabbed-labels%3E%3Anth-child%2814%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%2815%29%3Achecked~.tabbed-labels%3E%3Anth-child%2815%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%2816%29%3Achecked~.tabbed-labels%3E%3Anth-child%2816%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%2817%29%3Achecked~.tabbed-labels%3E%3Anth-child%2817%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%2818%29%3Achecked~.tabbed-labels%3E%3Anth-child%2818%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%2819%29%3Achecked~.tabbed-labels%3E%3Anth-child%2819%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%282%29%3Achecked~.tabbed-labels%3E%3Anth-child%282%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%2820%29%3Achecked~.tabbed-labels%3E%3Anth-child%2820%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%283%29%3Achecked~.tabbed-labels%3E%3Anth-child%283%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%284%29%3Achecked~.tabbed-labels%3E%3Anth-child%284%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%285%29%3Achecked~.tabbed-labels%3E%3Anth-child%285%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%286%29%3Achecked~.tabbed-labels%3E%3Anth-child%286%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%287%29%3Achecked~.tabbed-labels%3E%3Anth-child%287%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%288%29%3Achecked~.tabbed-labels%3E%3Anth-child%288%29%2C.no-js%20.md-typeset%20.tabbed-set%3Einput%3Anth-child%289%29%3Achecked~.tabbed-labels%3E%3Anth-child%289%29%7Bborder-color%3Avar%28--md-default-fg-color%29%7D%7D.md-typeset%20.tabbed-set%3Einput%3Afirst-child.focus-visible~.tabbed-labels%3E%3Afirst-child%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2810%29.focus-visible~.tabbed-labels%3E%3Anth-child%2810%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2811%29.focus-visible~.tabbed-labels%3E%3Anth-child%2811%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2812%29.focus-visible~.tabbed-labels%3E%3Anth-child%2812%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2813%29.focus-visible~.tabbed-labels%3E%3Anth-child%2813%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2814%29.focus-visible~.tabbed-labels%3E%3Anth-child%2814%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2815%29.focus-visible~.tabbed-labels%3E%3Anth-child%2815%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2816%29.focus-visible~.tabbed-labels%3E%3Anth-child%2816%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2817%29.focus-visible~.tabbed-labels%3E%3Anth-child%2817%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2818%29.focus-visible~.tabbed-labels%3E%3Anth-child%2818%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2819%29.focus-visible~.tabbed-labels%3E%3Anth-child%2819%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%282%29.focus-visible~.tabbed-labels%3E%3Anth-child%282%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2820%29.focus-visible~.tabbed-labels%3E%3Anth-child%2820%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%283%29.focus-visible~.tabbed-labels%3E%3Anth-child%283%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%284%29.focus-visible~.tabbed-labels%3E%3Anth-child%284%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%285%29.focus-visible~.tabbed-labels%3E%3Anth-child%285%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%286%29.focus-visible~.tabbed-labels%3E%3Anth-child%286%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%287%29.focus-visible~.tabbed-labels%3E%3Anth-child%287%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%288%29.focus-visible~.tabbed-labels%3E%3Anth-child%288%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%289%29.focus-visible~.tabbed-labels%3E%3Anth-child%289%29%7Bcolor%3Avar%28--md-accent-fg-color%29%7D.md-typeset%20.tabbed-set%3Einput%3Afirst-child%3Achecked~.tabbed-content%3E%3Afirst-child%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2810%29%3Achecked~.tabbed-content%3E%3Anth-child%2810%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2811%29%3Achecked~.tabbed-content%3E%3Anth-child%2811%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2812%29%3Achecked~.tabbed-content%3E%3Anth-child%2812%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2813%29%3Achecked~.tabbed-content%3E%3Anth-child%2813%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2814%29%3Achecked~.tabbed-content%3E%3Anth-child%2814%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2815%29%3Achecked~.tabbed-content%3E%3Anth-child%2815%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2816%29%3Achecked~.tabbed-content%3E%3Anth-child%2816%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2817%29%3Achecked~.tabbed-content%3E%3Anth-child%2817%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2818%29%3Achecked~.tabbed-content%3E%3Anth-child%2818%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2819%29%3Achecked~.tabbed-content%3E%3Anth-child%2819%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%282%29%3Achecked~.tabbed-content%3E%3Anth-child%282%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%2820%29%3Achecked~.tabbed-content%3E%3Anth-child%2820%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%283%29%3Achecked~.tabbed-content%3E%3Anth-child%283%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%284%29%3Achecked~.tabbed-content%3E%3Anth-child%284%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%285%29%3Achecked~.tabbed-content%3E%3Anth-child%285%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%286%29%3Achecked~.tabbed-content%3E%3Anth-child%286%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%287%29%3Achecked~.tabbed-content%3E%3Anth-child%287%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%288%29%3Achecked~.tabbed-content%3E%3Anth-child%288%29%2C.md-typeset%20.tabbed-set%3Einput%3Anth-child%289%29%3Achecked~.tabbed-content%3E%3Anth-child%289%29%7Bdisplay%3Ablock%7D%3Aroot%7B--md-tasklist-icon%3Aurl%28%27data%3Aimage/svg%2Bxml%3Bcharset%3Dutf-8%2C%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M1%2012C1%205.925%205.925%201%2012%201s11%204.925%2011%2011-4.925%2011-11%2011S1%2018.075%201%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.md-typeset%20.grid%7Bgrid-gap%3A.4rem%3Bdisplay%3Agrid%3Bgrid-template-columns%3Arepeat%28auto-fit%2Cminmax%28min%28100%25%2C16rem%29%2C1fr%29%29%3Bmargin%3A1em%200%7D.md-typeset%20.grid.cards%3Eol%2C.md-typeset%20.grid.cards%3Eul%7Bdisplay%3Acontents%7D.md-typeset%20.grid.cards%3Eol%3Eli%2C.md-typeset%20.grid.cards%3Eul%3Eli%2C.md-typeset%20.grid%3E.card%7Bborder%3A.05rem%20solid%20var%28--md-default-fg-color--lightest%29%3Bborder-radius%3A.1rem%3Bdisplay%3Ablock%3Bmargin%3A0%3Bpadding%3A.8rem%3Btransition%3Aborder%20.25s%2Cbox-shadow%20.25s%7D.md-typeset%20.grid.cards%3Eol%3Eli%3Afocus-within%2C.md-typeset%20.grid.cards%3Eol%3Eli%3Ahover%2C.md-typeset%20.grid.cards%3Eul%3Eli%3Afocus-within%2C.md-typeset%20.grid.cards%3Eul%3Eli%3Ahover%2C.md-typeset%20.grid%3E.card%3Afocus-within%2C.md-typeset%20.grid%3E.card%3Ahover%7Bborder-color%3A%230000%3Bbox-shadow%3Avar%28--md-shadow-z2%29%7D.md-typeset%20.grid.cards%3Eol%3Eli%3Ehr%2C.md-typeset%20.grid.cards%3Eul%3Eli%3Ehr%2C.md-typeset%20.grid%3E.card%3Ehr%7Bmargin-bottom%3A1em%3Bmargin-top%3A1em%7D.md-typeset%20.grid.cards%3Eol%3Eli%3E%3Afirst-child%2C.md-typeset%20.grid.cards%3Eul%3Eli%3E%3Afirst-child%2C.md-typeset%20.grid%3E.card%3E%3Afirst-child%7Bmargin-top%3A0%7D.md-typeset%20.grid.cards%3Eol%3Eli%3E%3Alast-child%2C.md-typeset%20.grid.cards%3Eul%3Eli%3E%3Alast-child%2C.md-typeset%20.grid%3E.card%3E%3Alast-child%7Bmargin-bottom%3A0%7D.md-typeset%20.grid%3E%2A%2C.md-typeset%20.grid%3E.admonition%2C.md-typeset%20.grid%3E.highlight%3E%2A%2C.md-typeset%20.grid%3E.highlighttable%2C.md-typeset%20.grid%3E.md-typeset%20details%2C.md-typeset%20.grid%3Edetails%2C.md-typeset%20.grid%3Epre%7Bmargin-bottom%3A0%3Bmargin-top%3A0%7D.md-typeset%20.grid%3E.highlight%3Epre%3Aonly-child%2C.md-typeset%20.grid%3E.highlight%3Epre%3Ecode%2C.md-typeset%20.grid%3E.highlighttable%2C.md-typeset%20.grid%3E.highlighttable%3Etbody%2C.md-typeset%20.grid%3E.highlighttable%3Etbody%3Etr%2C.md-typeset%20.grid%3E.highlighttable%3Etbody%3Etr%3E.code%2C.md-typeset%20.grid%3E.highlighttable%3Etbody%3Etr%3E.code%3E.highlight%2C.md-typeset%20.grid%3E.highlighttable%3Etbody%3Etr%3E.code%3E.highlight%3Epre%2C.md-typeset%20.grid%3E.highlighttable%3Etbody%3Etr%3E.code%3E.highlight%3Epre%3Ecode%7Bheight%3A100%25%7D.md-typeset%20.grid%3E.tabbed-set%7Bmargin-bottom%3A0%3Bmargin-top%3A0%7D%40media%20screen%20and%20%28min-width%3A45em%29%7B%5Bdir%3Dltr%5D%20.md-typeset%20.inline%7Bfloat%3Aleft%7D%5Bdir%3Drtl%5D%20.md-typeset%20.inline%7Bfloat%3Aright%7D%5Bdir%3Dltr%5D%20.md-typeset%20.inline%7Bmargin-right%3A.8rem%7D%5Bdir%3Drtl%5D%20.md-typeset%20.inline%7Bmargin-left%3A.8rem%7D.md-typeset%20.inline%7Bmargin-bottom%3A.8rem%3Bmargin-top%3A0%3Bwidth%3A11.7rem%7D%5Bdir%3Dltr%5D%20.md-typeset%20.inline.end%7Bfloat%3Aright%7D%5Bdir%3Drtl%5D%20.md-typeset%20.inline.end%7Bfloat%3Aleft%7D%5Bdir%3Dltr%5D%20.md-typeset%20.inline.end%7Bmargin-left%3A.8rem%3Bmargin-right%3A0%7D%5Bdir%3Drtl%5D%20.md-typeset%20.inline.end%7Bmargin-left%3A0%3Bmargin-right%3A.8rem%7D%7D" rel="stylesheet"/><!--URL:../assets/stylesheets/main.7e359304.min.css-->
|
||
<link href="data:text/css,%40media%20screen%7B%5Bdata-md-color-scheme%3Dslate%5D%7B--md-default-fg-color%3Ahsla%28var%28--md-hue%29%2C15%25%2C90%25%2C0.82%29%3B--md-default-fg-color--light%3Ahsla%28var%28--md-hue%29%2C15%25%2C90%25%2C0.56%29%3B--md-default-fg-color--lighter%3Ahsla%28var%28--md-hue%29%2C15%25%2C90%25%2C0.32%29%3B--md-default-fg-color--lightest%3Ahsla%28var%28--md-hue%29%2C15%25%2C90%25%2C0.12%29%3B--md-default-bg-color%3Ahsla%28var%28--md-hue%29%2C15%25%2C14%25%2C1%29%3B--md-default-bg-color--light%3Ahsla%28var%28--md-hue%29%2C15%25%2C14%25%2C0.54%29%3B--md-default-bg-color--lighter%3Ahsla%28var%28--md-hue%29%2C15%25%2C14%25%2C0.26%29%3B--md-default-bg-color--lightest%3Ahsla%28var%28--md-hue%29%2C15%25%2C14%25%2C0.07%29%3B--md-code-fg-color%3Ahsla%28var%28--md-hue%29%2C18%25%2C86%25%2C0.82%29%3B--md-code-bg-color%3Ahsla%28var%28--md-hue%29%2C15%25%2C18%25%2C1%29%3B--md-code-hl-color%3A%232977ff%3B--md-code-hl-color--light%3A%232977ff1a%3B--md-code-hl-number-color%3A%23e6695b%3B--md-code-hl-special-color%3A%23f06090%3B--md-code-hl-function-color%3A%23c973d9%3B--md-code-hl-constant-color%3A%239383e2%3B--md-code-hl-keyword-color%3A%236791e0%3B--md-code-hl-string-color%3A%232fb170%3B--md-code-hl-name-color%3Avar%28--md-code-fg-color%29%3B--md-code-hl-operator-color%3Avar%28--md-default-fg-color--light%29%3B--md-code-hl-punctuation-color%3Avar%28--md-default-fg-color--light%29%3B--md-code-hl-comment-color%3Avar%28--md-default-fg-color--light%29%3B--md-code-hl-generic-color%3Avar%28--md-default-fg-color--light%29%3B--md-code-hl-variable-color%3Avar%28--md-default-fg-color--light%29%3B--md-typeset-color%3Avar%28--md-default-fg-color%29%3B--md-typeset-a-color%3Avar%28--md-primary-fg-color%29%3B--md-typeset-kbd-color%3Ahsla%28var%28--md-hue%29%2C15%25%2C90%25%2C0.12%29%3B--md-typeset-kbd-accent-color%3Ahsla%28var%28--md-hue%29%2C15%25%2C90%25%2C0.2%29%3B--md-typeset-kbd-border-color%3Ahsla%28var%28--md-hue%29%2C15%25%2C14%25%2C1%29%3B--md-typeset-mark-color%3A%234287ff4d%3B--md-typeset-table-color%3Ahsla%28var%28--md-hue%29%2C15%25%2C95%25%2C0.12%29%3B--md-typeset-table-color--light%3Ahsla%28var%28--md-hue%29%2C15%25%2C95%25%2C0.035%29%3B--md-admonition-fg-color%3Avar%28--md-default-fg-color%29%3B--md-admonition-bg-color%3Avar%28--md-default-bg-color%29%3B--md-footer-bg-color%3Ahsla%28var%28--md-hue%29%2C15%25%2C10%25%2C0.87%29%3B--md-footer-bg-color--dark%3Ahsla%28var%28--md-hue%29%2C15%25%2C8%25%2C1%29%3B--md-shadow-z1%3A0%200.2rem%200.5rem%20%230000000d%2C0%200%200.05rem%20%230000001a%3B--md-shadow-z2%3A0%200.2rem%200.5rem%20%2300000040%2C0%200%200.05rem%20%2300000040%3B--md-shadow-z3%3A0%200.2rem%200.5rem%20%230006%2C0%200%200.05rem%20%2300000059%3Bcolor-scheme%3Adark%7D%5Bdata-md-color-scheme%3Dslate%5D%20img%5Bsrc%24%3D%22%23gh-light-mode-only%22%5D%2C%5Bdata-md-color-scheme%3Dslate%5D%20img%5Bsrc%24%3D%22%23only-light%22%5D%7Bdisplay%3Anone%7D%5Bdata-md-color-scheme%3Dslate%5D%5Bdata-md-color-primary%3Dpink%5D%7B--md-typeset-a-color%3A%23ed5487%7D%5Bdata-md-color-scheme%3Dslate%5D%5Bdata-md-color-primary%3Dpurple%5D%7B--md-typeset-a-color%3A%23c46fd3%7D%5Bdata-md-color-scheme%3Dslate%5D%5Bdata-md-color-primary%3Ddeep-purple%5D%7B--md-typeset-a-color%3A%23a47bea%7D%5Bdata-md-color-scheme%3Dslate%5D%5Bdata-md-color-primary%3Dindigo%5D%7B--md-typeset-a-color%3A%235488e8%7D%5Bdata-md-color-scheme%3Dslate%5D%5Bdata-md-color-primary%3Dteal%5D%7B--md-typeset-a-color%3A%2300ccb8%7D%5Bdata-md-color-scheme%3Dslate%5D%5Bdata-md-color-primary%3Dgreen%5D%7B--md-typeset-a-color%3A%2371c174%7D%5Bdata-md-color-scheme%3Dslate%5D%5Bdata-md-color-primary%3Ddeep-orange%5D%7B--md-typeset-a-color%3A%23ff764d%7D%5Bdata-md-color-scheme%3Dslate%5D%5Bdata-md-color-primary%3Dbrown%5D%7B--md-typeset-a-color%3A%23c1775c%7D%5Bdata-md-color-scheme%3Dslate%5D%5Bdata-md-color-primary%3Dblack%5D%2C%5Bdata-md-color-scheme%3Dslate%5D%5Bdata-md-color-primary%3Dblue-grey%5D%2C%5Bdata-md-color-scheme%3Dslate%5D%5Bdata-md-color-primary%3Dgrey%5D%2C%5Bdata-md-color-scheme%3Dslate%5D%5Bdata-md-color-primary%3Dwhite%5D%7B--md-typeset-a-color%3A%235e8bde%7D%5Bdata-md-color-switching%5D%20%2A%2C%5Bdata-md-color-switching%5D%20%3Aafter%2C%5Bdata-md-color-switching%5D%20%3Abefore%7Btransition-duration%3A0ms%21important%7D%7D%5Bdata-md-color-accent%3Dred%5D%7B--md-accent-fg-color%3A%23ff1947%3B--md-accent-fg-color--transparent%3A%23ff19471a%3B--md-accent-bg-color%3A%23fff%3B--md-accent-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-accent%3Dpink%5D%7B--md-accent-fg-color%3A%23f50056%3B--md-accent-fg-color--transparent%3A%23f500561a%3B--md-accent-bg-color%3A%23fff%3B--md-accent-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-accent%3Dpurple%5D%7B--md-accent-fg-color%3A%23df41fb%3B--md-accent-fg-color--transparent%3A%23df41fb1a%3B--md-accent-bg-color%3A%23fff%3B--md-accent-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-accent%3Ddeep-purple%5D%7B--md-accent-fg-color%3A%237c4dff%3B--md-accent-fg-color--transparent%3A%237c4dff1a%3B--md-accent-bg-color%3A%23fff%3B--md-accent-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-accent%3Dindigo%5D%7B--md-accent-fg-color%3A%23526cfe%3B--md-accent-fg-color--transparent%3A%23526cfe1a%3B--md-accent-bg-color%3A%23fff%3B--md-accent-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-accent%3Dblue%5D%7B--md-accent-fg-color%3A%234287ff%3B--md-accent-fg-color--transparent%3A%234287ff1a%3B--md-accent-bg-color%3A%23fff%3B--md-accent-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-accent%3Dlight-blue%5D%7B--md-accent-fg-color%3A%230091eb%3B--md-accent-fg-color--transparent%3A%230091eb1a%3B--md-accent-bg-color%3A%23fff%3B--md-accent-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-accent%3Dcyan%5D%7B--md-accent-fg-color%3A%2300bad6%3B--md-accent-fg-color--transparent%3A%2300bad61a%3B--md-accent-bg-color%3A%23fff%3B--md-accent-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-accent%3Dteal%5D%7B--md-accent-fg-color%3A%2300bda4%3B--md-accent-fg-color--transparent%3A%2300bda41a%3B--md-accent-bg-color%3A%23fff%3B--md-accent-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-accent%3Dgreen%5D%7B--md-accent-fg-color%3A%2300c753%3B--md-accent-fg-color--transparent%3A%2300c7531a%3B--md-accent-bg-color%3A%23fff%3B--md-accent-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-accent%3Dlight-green%5D%7B--md-accent-fg-color%3A%2363de17%3B--md-accent-fg-color--transparent%3A%2363de171a%3B--md-accent-bg-color%3A%23fff%3B--md-accent-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-accent%3Dlime%5D%7B--md-accent-fg-color%3A%23b0eb00%3B--md-accent-fg-color--transparent%3A%23b0eb001a%3B--md-accent-bg-color%3A%23000000de%3B--md-accent-bg-color--light%3A%230000008a%7D%5Bdata-md-color-accent%3Dyellow%5D%7B--md-accent-fg-color%3A%23ffd500%3B--md-accent-fg-color--transparent%3A%23ffd5001a%3B--md-accent-bg-color%3A%23000000de%3B--md-accent-bg-color--light%3A%230000008a%7D%5Bdata-md-color-accent%3Damber%5D%7B--md-accent-fg-color%3A%23fa0%3B--md-accent-fg-color--transparent%3A%23ffaa001a%3B--md-accent-bg-color%3A%23000000de%3B--md-accent-bg-color--light%3A%230000008a%7D%5Bdata-md-color-accent%3Dorange%5D%7B--md-accent-fg-color%3A%23ff9100%3B--md-accent-fg-color--transparent%3A%23ff91001a%3B--md-accent-bg-color%3A%23000000de%3B--md-accent-bg-color--light%3A%230000008a%7D%5Bdata-md-color-accent%3Ddeep-orange%5D%7B--md-accent-fg-color%3A%23ff6e42%3B--md-accent-fg-color--transparent%3A%23ff6e421a%3B--md-accent-bg-color%3A%23fff%3B--md-accent-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-primary%3Dred%5D%7B--md-primary-fg-color%3A%23ef5552%3B--md-primary-fg-color--light%3A%23e57171%3B--md-primary-fg-color--dark%3A%23e53734%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-primary%3Dpink%5D%7B--md-primary-fg-color%3A%23e92063%3B--md-primary-fg-color--light%3A%23ec417a%3B--md-primary-fg-color--dark%3A%23c3185d%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-primary%3Dpurple%5D%7B--md-primary-fg-color%3A%23ab47bd%3B--md-primary-fg-color--light%3A%23bb69c9%3B--md-primary-fg-color--dark%3A%238c24a8%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-primary%3Ddeep-purple%5D%7B--md-primary-fg-color%3A%237e56c2%3B--md-primary-fg-color--light%3A%239574cd%3B--md-primary-fg-color--dark%3A%23673ab6%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-primary%3Dindigo%5D%7B--md-primary-fg-color%3A%234051b5%3B--md-primary-fg-color--light%3A%235d6cc0%3B--md-primary-fg-color--dark%3A%23303fa1%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-primary%3Dblue%5D%7B--md-primary-fg-color%3A%232094f3%3B--md-primary-fg-color--light%3A%2342a5f5%3B--md-primary-fg-color--dark%3A%231975d2%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-primary%3Dlight-blue%5D%7B--md-primary-fg-color%3A%2302a6f2%3B--md-primary-fg-color--light%3A%2328b5f6%3B--md-primary-fg-color--dark%3A%230287cf%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-primary%3Dcyan%5D%7B--md-primary-fg-color%3A%2300bdd6%3B--md-primary-fg-color--light%3A%2325c5da%3B--md-primary-fg-color--dark%3A%230097a8%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-primary%3Dteal%5D%7B--md-primary-fg-color%3A%23009485%3B--md-primary-fg-color--light%3A%2326a699%3B--md-primary-fg-color--dark%3A%23007a6c%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-primary%3Dgreen%5D%7B--md-primary-fg-color%3A%234cae4f%3B--md-primary-fg-color--light%3A%2368bb6c%3B--md-primary-fg-color--dark%3A%23398e3d%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-primary%3Dlight-green%5D%7B--md-primary-fg-color%3A%238bc34b%3B--md-primary-fg-color--light%3A%239ccc66%3B--md-primary-fg-color--dark%3A%23689f38%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-primary%3Dlime%5D%7B--md-primary-fg-color%3A%23cbdc38%3B--md-primary-fg-color--light%3A%23d3e156%3B--md-primary-fg-color--dark%3A%23b0b52c%3B--md-primary-bg-color%3A%23000000de%3B--md-primary-bg-color--light%3A%230000008a%7D%5Bdata-md-color-primary%3Dyellow%5D%7B--md-primary-fg-color%3A%23ffec3d%3B--md-primary-fg-color--light%3A%23ffee57%3B--md-primary-fg-color--dark%3A%23fbc02d%3B--md-primary-bg-color%3A%23000000de%3B--md-primary-bg-color--light%3A%230000008a%7D%5Bdata-md-color-primary%3Damber%5D%7B--md-primary-fg-color%3A%23ffc105%3B--md-primary-fg-color--light%3A%23ffc929%3B--md-primary-fg-color--dark%3A%23ffa200%3B--md-primary-bg-color%3A%23000000de%3B--md-primary-bg-color--light%3A%230000008a%7D%5Bdata-md-color-primary%3Dorange%5D%7B--md-primary-fg-color%3A%23ffa724%3B--md-primary-fg-color--light%3A%23ffa724%3B--md-primary-fg-color--dark%3A%23fa8900%3B--md-primary-bg-color%3A%23000000de%3B--md-primary-bg-color--light%3A%230000008a%7D%5Bdata-md-color-primary%3Ddeep-orange%5D%7B--md-primary-fg-color%3A%23ff6e42%3B--md-primary-fg-color--light%3A%23ff8a66%3B--md-primary-fg-color--dark%3A%23f4511f%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-primary%3Dbrown%5D%7B--md-primary-fg-color%3A%23795649%3B--md-primary-fg-color--light%3A%238d6e62%3B--md-primary-fg-color--dark%3A%235d4037%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%7D%5Bdata-md-color-primary%3Dgrey%5D%7B--md-primary-fg-color%3A%23757575%3B--md-primary-fg-color--light%3A%239e9e9e%3B--md-primary-fg-color--dark%3A%23616161%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%3B--md-typeset-a-color%3A%234051b5%7D%5Bdata-md-color-primary%3Dblue-grey%5D%7B--md-primary-fg-color%3A%23546d78%3B--md-primary-fg-color--light%3A%23607c8a%3B--md-primary-fg-color--dark%3A%23455a63%3B--md-primary-bg-color%3A%23fff%3B--md-primary-bg-color--light%3A%23ffffffb3%3B--md-typeset-a-color%3A%234051b5%7D%5Bdata-md-color-primary%3Dlight-green%5D%3Anot%28%5Bdata-md-color-scheme%3Dslate%5D%29%7B--md-typeset-a-color%3A%2372ad2e%7D%5Bdata-md-color-primary%3Dlime%5D%3Anot%28%5Bdata-md-color-scheme%3Dslate%5D%29%7B--md-typeset-a-color%3A%238b990a%7D%5Bdata-md-color-primary%3Dyellow%5D%3Anot%28%5Bdata-md-color-scheme%3Dslate%5D%29%7B--md-typeset-a-color%3A%23b8a500%7D%5Bdata-md-color-primary%3Damber%5D%3Anot%28%5Bdata-md-color-scheme%3Dslate%5D%29%7B--md-typeset-a-color%3A%23d19d00%7D%5Bdata-md-color-primary%3Dorange%5D%3Anot%28%5Bdata-md-color-scheme%3Dslate%5D%29%7B--md-typeset-a-color%3A%23e68a00%7D%5Bdata-md-color-primary%3Dwhite%5D%7B--md-primary-fg-color%3Ahsla%28var%28--md-hue%29%2C0%25%2C100%25%2C1%29%3B--md-primary-fg-color--light%3Ahsla%28var%28--md-hue%29%2C0%25%2C100%25%2C0.7%29%3B--md-primary-fg-color--dark%3Ahsla%28var%28--md-hue%29%2C0%25%2C0%25%2C0.07%29%3B--md-primary-bg-color%3Ahsla%28var%28--md-hue%29%2C0%25%2C0%25%2C0.87%29%3B--md-primary-bg-color--light%3Ahsla%28var%28--md-hue%29%2C0%25%2C0%25%2C0.54%29%3B--md-typeset-a-color%3A%234051b5%7D%5Bdata-md-color-primary%3Dwhite%5D%20.md-button%7Bcolor%3Avar%28--md-typeset-a-color%29%7D%5Bdata-md-color-primary%3Dwhite%5D%20.md-button--primary%7Bbackground-color%3Avar%28--md-typeset-a-color%29%3Bborder-color%3Avar%28--md-typeset-a-color%29%3Bcolor%3Ahsla%28var%28--md-hue%29%2C0%25%2C100%25%2C1%29%7D%40media%20screen%20and%20%28min-width%3A60em%29%7B%5Bdata-md-color-primary%3Dwhite%5D%20.md-search__form%7Bbackground-color%3Ahsla%28var%28--md-hue%29%2C0%25%2C0%25%2C.07%29%7D%5Bdata-md-color-primary%3Dwhite%5D%20.md-search__form%3Ahover%7Bbackground-color%3Ahsla%28var%28--md-hue%29%2C0%25%2C0%25%2C.32%29%7D%5Bdata-md-color-primary%3Dwhite%5D%20.md-search__input%2B.md-search__icon%7Bcolor%3Ahsla%28var%28--md-hue%29%2C0%25%2C0%25%2C.87%29%7D%7D%40media%20screen%20and%20%28min-width%3A76.25em%29%7B%5Bdata-md-color-primary%3Dwhite%5D%20.md-tabs%7Bborder-bottom%3A.05rem%20solid%20%2300000012%7D%7D%5Bdata-md-color-primary%3Dblack%5D%7B--md-primary-fg-color%3Ahsla%28var%28--md-hue%29%2C15%25%2C9%25%2C1%29%3B--md-primary-fg-color--light%3Ahsla%28var%28--md-hue%29%2C15%25%2C9%25%2C0.54%29%3B--md-primary-fg-color--dark%3Ahsla%28var%28--md-hue%29%2C15%25%2C9%25%2C1%29%3B--md-primary-bg-color%3Ahsla%28var%28--md-hue%29%2C15%25%2C100%25%2C1%29%3B--md-primary-bg-color--light%3Ahsla%28var%28--md-hue%29%2C15%25%2C100%25%2C0.7%29%3B--md-typeset-a-color%3A%234051b5%7D%5Bdata-md-color-primary%3Dblack%5D%20.md-button%7Bcolor%3Avar%28--md-typeset-a-color%29%7D%5Bdata-md-color-primary%3Dblack%5D%20.md-button--primary%7Bbackground-color%3Avar%28--md-typeset-a-color%29%3Bborder-color%3Avar%28--md-typeset-a-color%29%3Bcolor%3Ahsla%28var%28--md-hue%29%2C0%25%2C100%25%2C1%29%7D%5Bdata-md-color-primary%3Dblack%5D%20.md-header%7Bbackground-color%3Ahsla%28var%28--md-hue%29%2C15%25%2C9%25%2C1%29%7D%40media%20screen%20and%20%28max-width%3A59.984375em%29%7B%5Bdata-md-color-primary%3Dblack%5D%20.md-nav__source%7Bbackground-color%3Ahsla%28var%28--md-hue%29%2C15%25%2C11%25%2C.87%29%7D%7D%40media%20screen%20and%20%28max-width%3A76.234375em%29%7Bhtml%20%5Bdata-md-color-primary%3Dblack%5D%20.md-nav--primary%20.md-nav__title%5Bfor%3D__drawer%5D%7Bbackground-color%3Ahsla%28var%28--md-hue%29%2C15%25%2C9%25%2C1%29%7D%7D%40media%20screen%20and%20%28min-width%3A76.25em%29%7B%5Bdata-md-color-primary%3Dblack%5D%20.md-tabs%7Bbackground-color%3Ahsla%28var%28--md-hue%29%2C15%25%2C9%25%2C1%29%7D%7D" rel="stylesheet"/><!--URL:../assets/stylesheets/palette.06af60db.min.css-->
|
||
<link crossorigin="" href="https://fonts.gstatic.com" rel="preconnect"/>
|
||
<link href="data:text/css; charset=utf-8;base64,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>L'<a href="https://www.php.net/manual/fr/intro.ftp.php">extension PHP <code>ftp</code></a> (nécessaire pour le
|
||
fonctionnement du <a href="#conf-configuration-des-lsaddons">LSaddon</a> FTP, paquet <code>php-ftp</code>
|
||
dans Debian)</li>
|
||
</ul>
|
||
<ul>
|
||
<li>La librairie <a href="https://github.com/phpseclib/phpseclib">PhpSecLib</a> (nécessaire pour le
|
||
fonctionnement du <a href="#conf-configuration-des-lsaddons">LSaddon</a> SSH, paquet
|
||
<code>php-phpseclib</code> dans Debian)</li>
|
||
</ul>
|
||
<div class="admonition warning">
|
||
<p class="admonition-title">Warning</p>
|
||
<p>La librairie <a href="http://pear.php.net/package/Net_LDAP2">Net_LDAP2</a> oblige le fait que la racine DSE
|
||
de l'annuaire soit lisible en anonyme sinon la connexion à l'annuaire échouera systématiquement.</p>
|
||
</div>
|
||
<div class="admonition note">
|
||
<p class="admonition-title">Note</p>
|
||
<p>Cette documentation est écrite à l'aide du langage Markdown et est mis en forme pour une
|
||
consultation en ligne à l'aide de <a href="https://www.mkdocs.org/">mkdocs</a> et son thème
|
||
<a href="https://squidfunk.github.io/mkdocs-material/">mkdocs-material</a>. Le dépendances pour construire
|
||
cette documentation sont listées dans le fichier <code>doc/requirements.txt</code> et sont installables à
|
||
l'aide de la commande <code>pip install -r doc/requirements.txt</code>.</p>
|
||
</div></section><section class="print-page" id="install-download"><h1 id="install-download-telechargement">Téléchargement</h1>
|
||
<h2 id="install-download-a-partir-du-paquet-debian">À partir du paquet Debian</h2>
|
||
<p>L'installation à partir du paquet Debian peut être réalisée soit en téléchargeant manuellement le
|
||
paquet, soit en déclarant le dépôt APT suivant dans votre fichier <code>/etc/apt/sources.list</code> :</p>
|
||
<div class="highlight"><pre><span></span><code><a href="#install-download-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>deb http://ldapsaisie.org/debian stable main
|
||
</code></pre></div>
|
||
<p>Il ne vous restera ensuite plus qu'a installer le paquet <code>ldapsaisie</code> avec la commande suivante :</p>
|
||
<div class="highlight"><pre><span></span><code><a href="#install-download-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a>apt-get install ldapsaisie
|
||
</code></pre></div>
|
||
<p>Le fichier <code>/etc/ldapsaisie/apache.conf</code> est un example de configuration du serveur web Apache. La
|
||
configuration du logiciel ce fera ensuite dans le dossier <code>/etc/ldapsaisie/local/</code>.</p>
|
||
<h2 id="install-download-a-partir-de-git">À partir de Git</h2>
|
||
<p>Le dépôt Git peut être récupéré anonymement en utilisant la commande suivante :</p>
|
||
<div class="highlight"><pre><span></span><code><a href="#install-download-__codelineno-2-1" id="__codelineno-2-1" name="__codelineno-2-1"></a>git clone https://gitlab.easter-eggs.com/ee/ldapsaisie.git
|
||
</code></pre></div>
|
||
<p>La racine web de l'application se trouvera alors dans le dossier <code>/ldapsaisie/src/public_html/</code>.</p>
|
||
<h2 id="install-download-a-partir-des-snapshot">À partir des snapshot</h2>
|
||
<p>Toutes les nuits, un snapshot de l'arbre Git est réalisé et est téléchargeable au format <em>tar.gz</em> à
|
||
l'adresse suivante :</p>
|
||
<p><a href="http://ldapsaisie.org/download/ldapsaisie-snapshoot.tar.gz">http://ldapsaisie.org/download/ldapsaisie-snapshoot.tar.gz</a></p></section><section class="print-page" id="install-arbo"><h1 id="install-arbo-arborescence-du-projet">Arborescence du projet</h1>
|
||
<ul>
|
||
<li>
|
||
<p><code>doc/</code></p>
|
||
<p>Les fichiers sources de la documentation (Markdown & 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> 'set_default_value_on_creation_if_empty' => [booleen],
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-23" id="__codelineno-0-23" name="__codelineno-0-23"></a> 'force_generation_if_empty' => [booleen],
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-24" id="__codelineno-0-24" name="__codelineno-0-24"></a> 'check_data' => array (
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-25" id="__codelineno-0-25" name="__codelineno-0-25"></a> // Régle de vérification syntaxique des données saisies
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-26" id="__codelineno-0-26" name="__codelineno-0-26"></a> ),
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-27" id="__codelineno-0-27" name="__codelineno-0-27"></a> 'validation' => array (
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-28" id="__codelineno-0-28" name="__codelineno-0-28"></a> // Règle de vérification d'intégrité des données saisies
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-29" id="__codelineno-0-29" name="__codelineno-0-29"></a> ),
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-30" id="__codelineno-0-30" name="__codelineno-0-30"></a> 'rights' => array(
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-31" id="__codelineno-0-31" name="__codelineno-0-31"></a> 'LSprofile1' => 'droit1',
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-32" id="__codelineno-0-32" name="__codelineno-0-32"></a> 'LSprofile2' => 'droit2',
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-33" id="__codelineno-0-33" name="__codelineno-0-33"></a> ...
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-34" id="__codelineno-0-34" name="__codelineno-0-34"></a> ),
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-35" id="__codelineno-0-35" name="__codelineno-0-35"></a> 'view' => 1,
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-36" id="__codelineno-0-36" name="__codelineno-0-36"></a> 'form' => array (
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-37" id="__codelineno-0-37" name="__codelineno-0-37"></a> 'create' => 1,
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-38" id="__codelineno-0-38" name="__codelineno-0-38"></a> 'modify' => 0,
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-39" id="__codelineno-0-39" name="__codelineno-0-39"></a> ...
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-40" id="__codelineno-0-40" name="__codelineno-0-40"></a> ),
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-41" id="__codelineno-0-41" name="__codelineno-0-41"></a> 'dependAttrs' => array(
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-42" id="__codelineno-0-42" name="__codelineno-0-42"></a> // Attributs en dépendance
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-43" id="__codelineno-0-43" name="__codelineno-0-43"></a> ),
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-44" id="__codelineno-0-44" name="__codelineno-0-44"></a> 'onDisplay' => 'fonction2'
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-45" id="__codelineno-0-45" name="__codelineno-0-45"></a>
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-46" id="__codelineno-0-46" name="__codelineno-0-46"></a> 'before_modify' => 'function1',
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-47" id="__codelineno-0-47" name="__codelineno-0-47"></a> 'after_modify' => 'function2'
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-48" id="__codelineno-0-48" name="__codelineno-0-48"></a> ),
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-49" id="__codelineno-0-49" name="__codelineno-0-49"></a> /* ----------- end -----------*/
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-50" id="__codelineno-0-50" name="__codelineno-0-50"></a> ...
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-51" id="__codelineno-0-51" name="__codelineno-0-51"></a>);
|
||
<a href="#conf-lsobject-lsattribute-__codelineno-0-52" id="__codelineno-0-52" name="__codelineno-0-52"></a>...
|
||
</code></pre></div>
|
||
<ul>
|
||
<li>
|
||
<p><code>label</code></p>
|
||
<p>Le label de l'attribut.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>displayAttrName</code></p>
|
||
<p>Booléen définissant si le nom de l'attribut doit être affiché en préfixe du message d'aide
|
||
(paramètre <code>help_info</code>).</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>help_info</code></p>
|
||
<p>Message d'aide qui sera affiché dans une bulle d'aide à côté du nom de l'attribut dans les
|
||
formulaires.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>help_info_in_view</code></p>
|
||
<p>Booléen définissant si le message d'aide doit être affiché sur la vue de visualisation de l'objet.</p>
|
||
<p>Valeurs possibles : <em>0</em> ou <em>1</em></p>
|
||
<p>Valeur par défaut : <em>0</em></p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>ldap_type</code></p>
|
||
<p>Le type LDAP de l'attribut (facultatif, par défaut:
|
||
<a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_ascii-lsattr_ldap_ascii">LSattr_ldap_ascii</a>).
|
||
<a href="#conf-lsobject-lsattribute-lsattr_ldap-configuration-des-attributs-ldap">Voir la section concernée.</a></p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>ldap_options</code></p>
|
||
<p>Tableau associatif contenant les paramètres de configuration du type LDAP de l'attribut.
|
||
<a href="#conf-lsobject-lsattribute-lsattr_ldap-configuration-des-attributs-ldap">Voir la section concernée.</a></p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>html_type</code></p>
|
||
<p>Le type HTML de l'attribut (facultatif, par défaut:
|
||
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_text-lsattr_html_text">LSattr_html_text</a>).
|
||
<a href="#conf-lsobject-lsattribute-lsattr_html-configuration-des-attributs-html">Voir la section concernée.</a></p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>html_options</code></p>
|
||
<p>Tableau associatif contenant les paramètres de configuration du type HTML de l'attribut.
|
||
<a href="#conf-lsobject-lsattribute-lsattr_html-configuration-des-attributs-html">Voir la section concernée.</a></p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>no_value_label</code></p>
|
||
<p>Label affiché lorsque l'attribut n'a pas de valeur (facultatif).</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>multiple</code></p>
|
||
<p>Booléen définissant si cet attribut peut stocker plusieurs valeurs.</p>
|
||
<p>Valeurs possibles : <em>0</em> ou <em>1</em></p>
|
||
<p>Valeur par défaut : <em>0</em></p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>required</code></p>
|
||
<p>Booléen définissant si cet attribut doit obligatoirement être défini.</p>
|
||
<p>Valeurs possibles : <em>0</em> ou <em>1</em></p>
|
||
<p>Valeur par défaut : <em>0</em></p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>generate_function</code></p>
|
||
<p>Nom de la fonction permettant de générer la valeur de l'attribut. Cette fonction sera éxecutée, en
|
||
passant en premier paramètre, l'objet <a href="#conf-lsobject-configuration-lsobject">LSobject</a> courant.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>generate_value_format</code></p>
|
||
<p><a href="#conf-global-lsformat-format-parametrable">LSformat</a> permettant la génération de l'attribut.</p>
|
||
<div class="admonition note">
|
||
<p class="admonition-title">Note</p>
|
||
<p>Cette méthode de génération est utilisée uniquement si aucune fonction de génération de la
|
||
valeur n'est définie (paramètre <code>generate_function</code>).</p>
|
||
</div>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>default_value</code></p>
|
||
<p>Valeur par défaut de l'attribut.</p>
|
||
<div class="admonition warning">
|
||
<p class="admonition-title">Warning</p>
|
||
<p>Il doit s'agir de la valeur telque retournée par le formulaire web. Ainsi, par exemple dans le
|
||
cas d'un attribut booléen, les valeurs possibles sont <code>yes</code> ou <code>no</code>.</p>
|
||
</div>
|
||
<div class="admonition note">
|
||
<p class="admonition-title">Note</p>
|
||
<p>Cette valeur est également utilisée dans le cadre de la génération automatique de la valeur de
|
||
l'attribut si aucune autre méthode n'est disponible (via une fonction ou un
|
||
<a href="#conf-global-lsformat-format-parametrable">LSformat</a>).</p>
|
||
</div>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>set_default_value_on_creation_if_empty</code></p>
|
||
<p>Booléen permettant de définir si la valeur de l'attribut doit être initialisée avec sa valeur par
|
||
défaut à la création de l'objet si aucune autre valeur n'as été fournie dans le contexte de
|
||
création (par défaut : <em>1</em>).</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>force_generation_if_empty</code></p>
|
||
<p>Booléen permettant de définir si la valeur de l'attribut doit être générée si elle est vide, que
|
||
ce soit à la création ou la modification de l'objet (par défaut : <em>0</em>).</p>
|
||
<div class="admonition warning">
|
||
<p class="admonition-title">Warning</p>
|
||
<p>Si la génération échoue, cela bloquera l'action. Par ailleurs, cette génération est
|
||
prioritaire sur l'utilisation de la valeur par défaut de l'attribut induit par le paramètre
|
||
<code>set_default_value_on_creation_if_empty</code>.</p>
|
||
</div>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>check_data</code></p>
|
||
<p>Tableau associatif contenant les règles de vérification syntaxique des données de l'attribut.
|
||
<a href="#conf-lsobject-lsattribute-check_data-configuration-des-regles-de-verification-syntaxique">Voir la section concernée.</a></p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>validation</code></p>
|
||
<p>Tableau associatif contenant les règles de vérification d'intégrité des données de l'attribut.
|
||
<a href="#conf-lsobject-lsattribute-validation-configuration-des-regles-de-verification-dintegrite">Voir la section concernée.</a></p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>rights</code></p>
|
||
<p>Tableau associatif dont les clés sont les noms des
|
||
<a href="#conf-global-ldap-lsprofile-profils-dutilisateurs">LSprofiles</a> ayant des droits sur cet
|
||
attribut et les valeurs associées sont les droits correspondants. La valeur des droits d'un
|
||
<a href="#conf-global-ldap-lsprofile-profils-dutilisateurs">LSprofile</a> peut être <code>r</code> pour le droit de
|
||
lecture ou <code>w</code> pour le droit de lecture-écriture. Par défaut, un
|
||
<a href="#conf-global-ldap-lsprofile-profils-dutilisateurs">LSprofile</a> n'a aucun droit.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>view</code></p>
|
||
<p>Booléen définissant si l'attribut est, ou non, affiché lors de la visualisation des objets du type
|
||
courant.</p>
|
||
<p>Valeurs possibles : <em>0</em> ou <em>1</em></p>
|
||
<p>Valeur par défaut : <em>0</em></p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>form</code></p>
|
||
<p>Tableau associatif dont les clés sont les noms des <a href="#conf-lsobject-lsform-lsform">LSforms</a> et les valeurs
|
||
associées la définition de l'affichage dans ce <a href="#conf-lsobject-lsform-lsform">LSform</a>. Si cette valeur vaut
|
||
<code>0</code>, alors l'attribut sera lecture-seule et si cette valeur vaut <code>1</code>, cet attribut sera affiché
|
||
en lecture-écriture.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>dependAttrs</code></p>
|
||
<p>Tableau associatif listant les attributs dépendants de celui-ci. Les attributs listés ici seront
|
||
regénérés lors de chaque modification de l'attribut courant. Cette génération sera effectuée avec
|
||
la fonction définie dans le paramètre <code>generate_function</code> de l'attribut.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>onDisplay</code></p>
|
||
<p>Nom ou liste de nom des fonctions retournant les valeurs d'affichages de l'attribut. Si c'est une
|
||
liste, chacune des fonctions seront executée les unes après les autres. Ces fonctions seront
|
||
éxecutées, en passant en premier paramètre, le tableau des valeurs de l'objet.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>before_modify</code></p>
|
||
<p>Chaîne de caractères (ou tableau de chaine de caractères) correspondant au nom d'une ou plusieurs
|
||
fonctions qui seront exécutées avant toutes modifications de la valeur de l'attribut.
|
||
<a href="#conf-lsobject-lsattribute-triggers-declencheurs">Voir la section concernée</a></p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>after_modify</code></p>
|
||
<p>Chaîne de caractères (ou tableau de chaine de caractères) correspondant au nom d'une ou plusieurs
|
||
fonctions qui seront exécutées après toutes modifications de la valeur de l'attribut.
|
||
<a href="#conf-lsobject-lsattribute-triggers-declencheurs">Voir la section concernée</a></p>
|
||
</li>
|
||
</ul></section><h4 class="nav-section-title">Types d'attribut LDAP (LSattr_ldap)</h4><section class="print-page" id="conf-lsobject-lsattribute-lsattr_ldap"><h1 id="conf-lsobject-lsattribute-lsattr_ldap-configuration-des-attributs-ldap-lsattr_ldap">Configuration des attributs LDAP (LSattr_ldap)</h1>
|
||
<p>Cette section décrit les options propres à chacun des types d'attributs LDAP supportés par
|
||
LdapSaisie.</p></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_ascii"><h1 id="conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_ascii-lsattr_ldap_ascii">LSattr_ldap_ascii</h1>
|
||
<p>Ce type est utilisé pour la gestion des attributs dont la valeur est une chaine de caractère. Ce
|
||
type est le type par défaut.</p></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_boolean"><h1 id="conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_boolean-lsattr_ldap_boolean">LSattr_ldap_boolean</h1>
|
||
<p>Ce type est utilisé pour la gestion des attributs dont la valeur est une booléen. On attend ici par
|
||
booléen, tout attribut ne pouvant prendre que deux valeurs pré-définies correspond pour l'un à <em>Oui</em>
|
||
et l'autre à <em>Non</em></p>
|
||
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-lsattr_ldap-lsattr_ldap_boolean-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a>'ldap_options' => 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_gpg_pub_key"><h1 id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_gpg_pub_key-lsattr_html_gpg_pub_key">LSattr_html_gpg_pub_key</h1>
|
||
<p>Ce type est utilisé pour la gestion des attributs dont la valeur est une clef publique GPG. Il
|
||
permet dans l'interface, d'avoir un affichage adapté à ce type de donnée.</p></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_image"><h1 id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_image-lsattr_html_image">LSattr_html_image</h1>
|
||
<p>Ce type est utilisé pour la gestion des attributs dont la valeur est une image. Pour le moment, les
|
||
attributs à valeurs multiples ne sont pas gérés.</p></section><section class="print-page" id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute"><h1 id="conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-lsattr_html_jsoncompositeattribute">LSattr_html_jsonCompositeAttribute</h1>
|
||
<p>Ce type est utilisé pour la gestion des attributs dont les valeurs sont des dictionnaires de valeurs
|
||
encodées aux formats <em>JSON</em>.</p>
|
||
<p>Exemple de valeur gérée :</p>
|
||
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="p">{</span><span class="nt">"component1"</span><span class="p">:</span><span class="w"> </span><span class="s2">"value1"</span><span class="p">,</span><span class="w"> </span><span class="nt">"component2"</span><span class="p">:</span><span class="w"> </span><span class="s2">"value2"</span><span class="p">,</span><span class="w"> </span><span class="nt">"component3"</span><span class="p">:</span><span class="w"> </span><span class="s2">"value3"</span><span class="p">}</span>
|
||
</code></pre></div>
|
||
<p>Le principe est que ces dictionnaires contienent plusieurs composants référencés par leur clé et
|
||
stockant une valeur dont le type peut être un texte libre ou bien être issue d'une liste déroulante
|
||
configurable selon le même principe que le type d'attribut
|
||
<a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_select_list-lsattr_html_select_list">LSattr_html_select_list</a>.</p>
|
||
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lsattribute-lsattr_html-lsattr_html_jsoncompositeattribute-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a>'html_options' => 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-gpg_pub_key"><h1 id="conf-lsobject-lsattribute-check_data-gpg_pub_key-gpg_pub_key">gpg_pub_key</h1>
|
||
<p>Cette règle vérifie que la valeur est une clé publique GPG. Pour cela, la clé est importée dans un
|
||
<em>keyring</em> GnuPG.</p></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-imagefile"><h1 id="conf-lsobject-lsattribute-check_data-imagefile-imagefile">imagefile</h1>
|
||
<p>Cette règle vérifie que la valeur est bien un fichier et que le type mime de celui-ci est bien une
|
||
image. Cette règle utilise la règle mimetype en spécifiant si l'utilisateur ne le fait pas que le
|
||
type mime doit respecter la regex suivante : <code>/image\/.*/</code></p>
|
||
<div class="admonition important">
|
||
<p class="admonition-title">Important</p>
|
||
<p>Cette règle est une simple interface à la règle mimetype, il est donc possible de passer
|
||
d'autres paramètres propres à ce type.</p>
|
||
</div></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-imagesize"><h1 id="conf-lsobject-lsattribute-check_data-imagesize-imagesize">imagesize</h1>
|
||
<p>Cette règle vérifie que la valeur est une image dont la taille en pixels respecte les limites
|
||
passées en paramètre.</p>
|
||
<ul>
|
||
<li>
|
||
<p><code>minWidth</code></p>
|
||
<p>Largeur minimum.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>maxWitdh</code></p>
|
||
<p>Largeur maximum.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>minHeight</code></p>
|
||
<p>Hauteur minimum.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>maxHeight</code></p>
|
||
<p>Hauteur maximum.</p>
|
||
</li>
|
||
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-inarray"><h1 id="conf-lsobject-lsattribute-check_data-inarray-inarray">inarray</h1>
|
||
<p>Cette règle vérifie que la valeur saisie fait partie d'une liste de valeurs autorisées
|
||
(ou interdites).</p>
|
||
<ul>
|
||
<li>
|
||
<p><code>possible_values</code></p>
|
||
<p>Tableau listant les valeurs autorisées.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>reverse</code></p>
|
||
<p>Booléen permettant d'inverser la logique de validation : si <code>reverse</code> est vrai, la valeur testée
|
||
sera acceptée si elle ne fait pas partie des valeurs possibles (Paramètre facultatif, par défaut :
|
||
<code>False</code>).</p>
|
||
</li>
|
||
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-integer"><h1 id="conf-lsobject-lsattribute-check_data-integer-integer">integer</h1>
|
||
<p>Cette règle vérifie que la valeur saisie est un entier. Les paramètres permettent de spécifier
|
||
éventuellement si la valeur doit être positive ou négative et également de borner les valeurs
|
||
valides.</p>
|
||
<ul>
|
||
<li>
|
||
<p><code>positive</code></p>
|
||
<p>Booléen définissant si la valeur doit être positive.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>negative</code></p>
|
||
<p>Booléen définissant si la valeur doit être negative.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>min</code></p>
|
||
<p>Valeur minimale (supérieur ou égale).</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>max</code></p>
|
||
<p>Valeur maximale (inférieur ou égale).</p>
|
||
</li>
|
||
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-ldapsearchuri"><h1 id="conf-lsobject-lsattribute-check_data-ldapsearchuri-ldapsearchuri">ldapSearchURI</h1>
|
||
<p>Cette règle vérifie que la valeur est une URI de recherche LDAP valide, c'est à dire, par exemple,
|
||
<code>ldaps://ldap.example.com:636/o=example?attr1,attr2?one?(gidNumber=100)</code></p>
|
||
<p>Cette vérification commence par découper la valeur à l'aide du sépérateur <code>?</code> et elle s'assure
|
||
ensuite :</p>
|
||
<ul>
|
||
<li>Que la première partie est bien une URI LDAP valide. Si l'hôte LDAP est spécifié, elle s'assure
|
||
qu'il soit une adresse IP ou un nom de domaine valide. Si le port LDAP est spécifié, elle s'assure
|
||
également qu'il soit correct et que l'hôte est également bien spécifié.</li>
|
||
</ul>
|
||
<ul>
|
||
<li>Si la base de recherche est spécifiée, elle s'assure qu'elle soit compatible avec la racine de
|
||
l'annuaire connecté.</li>
|
||
</ul>
|
||
<ul>
|
||
<li>Si un ou plusieurs attributs sont spécifiés, elle les vérifie un à un afin de vérifier qu'il
|
||
s'agit de nom d'attribut valide.</li>
|
||
</ul>
|
||
<ul>
|
||
<li>Que le scope de recherche soit bien spécifié et valide.</li>
|
||
</ul>
|
||
<ul>
|
||
<li>Si le filtre de recherche est spécifié, elle vérifie qu'il soit valide.</li>
|
||
</ul>
|
||
<p><strong>Paramêtres de configuration :</strong></p>
|
||
<ul>
|
||
<li>
|
||
<p><code>check_resolving_ldap_host</code></p>
|
||
<p>Si l'hôte du serveur LDAP est spécifié et qu'il s'agit d'un nom de domaine valide, un tentative de
|
||
résolution DNS sera également faite (optionnel, par défaut : <code>True</code>).</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>host_required</code></p>
|
||
<p>Booléen détermintant si une erreur est relevée en cas d'absence de l'hôte LDAP. (optionnel,
|
||
par défaut : <code>False</code>)</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>basedn_required</code></p>
|
||
<p>Booléen détermintant si une erreur est relevée en cas d'absence de base de recherche. (optionnel,
|
||
par défaut : <code>False</code>)</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>scope_required</code></p>
|
||
<p>Booléen détermintant si une erreur est relevée en cas d'absence de portée de recherche.
|
||
(optionnel, par défaut : <code>True</code>)</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>attr_required</code></p>
|
||
<p>Booléen détermintant si une erreur est relevée en cas d'absence d'attribut recherché. (optionnel,
|
||
par défaut : <code>False</code>)</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>max_attrs_count</code></p>
|
||
<p>Nombre maximum d'attribut recherchés. (optionnel, par défaut : pas de limite)</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>filter_required</code></p>
|
||
<p>Booléen détermintant si une erreur est relevée en cas d'absence de filtre de recherche.
|
||
(optionnel, par défaut : <code>False</code>)</p>
|
||
</li>
|
||
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-lettersonly"><h1 id="conf-lsobject-lsattribute-check_data-lettersonly-lettersonly">lettersonly</h1>
|
||
<p>Cette règle vérifie que la valeur est une chaîne de caractères composée uniquement de lettres
|
||
non-accuentées, en minuscule ou en majuscule.</p></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-maxlength"><h1 id="conf-lsobject-lsattribute-check_data-maxlength-maxlength">maxlength</h1>
|
||
<p>Cette règle vérifie que la valeur saisie est une chaine de caractères dont la longueur est inférieur
|
||
ou égale à la valeur passées en paramètre.</p>
|
||
<ul>
|
||
<li>
|
||
<p><code>limit</code></p>
|
||
<p>Limite supérieur (ou égale) de la longueur de la chaîne de caratères.</p>
|
||
</li>
|
||
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-mimetype"><h1 id="conf-lsobject-lsattribute-check_data-mimetype-mimetype">mimetype</h1>
|
||
<p>Cette règle vérifie que la valeur est bien un fichier et que le type mime de celui-ci est correct.
|
||
Il est possible de vérifier si le type mime fait partie d'une liste ou encore s'il valide une
|
||
expression régulière.</p>
|
||
<ul>
|
||
<li>
|
||
<p><code>mimeType</code></p>
|
||
<p>Type mime obligatoire. Ce paramètre peut être une simple chaine correspondant au type mime ou un
|
||
tableau listant plusieurs possibilités.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>mimeTypeRegEx</code></p>
|
||
<p>Expression régulière que doit respecter le type mime.</p>
|
||
</li>
|
||
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-minlength"><h1 id="conf-lsobject-lsattribute-check_data-minlength-minlength">minlength</h1>
|
||
<p>Cette règle vérifie que la valeur saisie est une chaine de caractères dont la longueur est supérieur
|
||
ou égale à la valeur passée en paramètre.</p>
|
||
<ul>
|
||
<li>
|
||
<p><code>limit</code></p>
|
||
<p>Limite inférieure (ou égale) de la longueur de la chaîne de caratères.</p>
|
||
</li>
|
||
</ul></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-nonzero"><h1 id="conf-lsobject-lsattribute-check_data-nonzero-nonzero">nonzero</h1>
|
||
<p>Cette régle vérifie que la valeur est une valeur numérique non nulle.</p></section><section class="print-page" id="conf-lsobject-lsattribute-check_data-nopunctuation"><h1 id="conf-lsobject-lsattribute-check_data-nopunctuation-nopunctuation">nopunctuation</h1>
|
||
<p>Cette régle vérifie que la valeur est une chaîne de caractères ne contenant pas de signe de
|
||
ponctuation. Les caractères suivants sont actuellement exclus :
|
||
<code>( ) . \ / \ * \ ^ \ ? # ! @ $ % + = , " ' > < ~ [ ] { }</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"> 'showSelectionBoxes' => [boolean],</span>
|
||
<a href="#conf-lsobject-lssearch-__codelineno-0-65" id="__codelineno-0-65" name="__codelineno-0-65"></a><span class="x">);</span>
|
||
</code></pre></div>
|
||
<ul>
|
||
<li>
|
||
<p><code>attrs</code></p>
|
||
<p>Tableau listant les attributs pouvant être utilisés dans les filtres de recherche LDAP employés
|
||
par LdapSaisie. Lorsqu'un motif de recherche est passé par l'utilisateur, LdapSaisie composera un
|
||
filtre LDAP à partir de cette liste.</p>
|
||
<p>Lors d'une recherche non-approximative, le filtre de recherche sera composé (par défaut) de la
|
||
manière suivante :</p>
|
||
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lssearch-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a>(|(attr1=*motif*)(attr2=*motif*)...)
|
||
</code></pre></div>
|
||
<p>Lors d'une recherche approximative, le filtre de recherche sera composé (par défaut) de la manière
|
||
suivante :</p>
|
||
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lssearch-__codelineno-2-1" id="__codelineno-2-1" name="__codelineno-2-1"></a>(|(attr1=~motif)(attr2~=motif)...)
|
||
</code></pre></div>
|
||
<p>Il est également possible de paramétrer la manière dont sera composé le filtre de recherche
|
||
attribut par attribut à l'aide des paramètres <code>searchLSformat</code> et <code>approxLSformat</code>.</p>
|
||
<div class="admonition important">
|
||
<p class="admonition-title">Important</p>
|
||
<p>Ces filtres, une fois composés, sont insérés dans un autre, filtrant en plus sur les
|
||
<em>ObjectClass</em> du type d'<a href="#conf-lsobject-configuration-lsobject">LSobject</a> de la manière suivante :</p>
|
||
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lssearch-__codelineno-3-1" id="__codelineno-3-1" name="__codelineno-3-1"></a>(& (&(objectclass=oc1)(objectclass=oc2)) (filtre) )
|
||
</code></pre></div>
|
||
</div>
|
||
<ul>
|
||
<li>
|
||
<p><code>searchLSformat</code></p>
|
||
<p>Ce paramètre est un <a href="#conf-global-lsformat-format-parametrable">LSformat</a> permettant de définir,
|
||
attribut par attribut, comment le filtre de recherche LDAP est composé à partir d'un motif de
|
||
recherche et en cas de recherche non-approximative.</p>
|
||
<p>Ce <a href="#conf-global-lsformat-format-parametrable">LSformat</a> est composé à l'aide des éléments
|
||
<code>name</code>, le nom de l'attribut et <code>pattern</code>, le motif de recherche.</p>
|
||
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lssearch-__codelineno-4-1" id="__codelineno-4-1" name="__codelineno-4-1"></a>(%{name}=%{pattern})
|
||
</code></pre></div>
|
||
<div class="admonition important">
|
||
<p class="admonition-title">Important</p>
|
||
<p>Le filtre déduit doit obligatoirement commencer par <code>(</code> et se terminer par <code>)</code>.</p>
|
||
</div>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>approxLSformat</code></p>
|
||
<p>Ce paramètre est un <a href="#conf-global-lsformat-format-parametrable">LSformat</a> permettant de définir,
|
||
attribut par attribut, comment le filtre de recherche LDAP est composé à partir d'un motif de
|
||
recherche et en cas de recherche approximative.</p>
|
||
<p>Ce <a href="#conf-global-lsformat-format-parametrable">LSformat</a> est composé à l'aide des éléments
|
||
<code>name</code>, le nom de l'attribut et <code>pattern</code>, le motif de recherche.</p>
|
||
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lssearch-__codelineno-5-1" id="__codelineno-5-1" name="__codelineno-5-1"></a>(%{name}=~%{pattern})
|
||
</code></pre></div>
|
||
<div class="admonition important">
|
||
<p class="admonition-title">Important</p>
|
||
<p>Le filtre déduit doit obligatoirement commencer par <code>(</code> et se terminer par <code>)</code>.</p>
|
||
</div>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>params</code></p>
|
||
<p>Tableau des paramètres par défaut d'une recherche. Ce tableau contient les paramètres qui seront
|
||
utilisés pour initialisé une recherche. Ces paramètres pourront être redéfini par l'utilisateur
|
||
ou par l'application en fonction du contexte dans lequel cette recherche est effectuée.</p>
|
||
<ul>
|
||
<li>
|
||
<p><code>pattern</code></p>
|
||
<p>Mot clé de la recherche.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>sizelimit</code></p>
|
||
<p>Entier determinant le nombre maximum d'objet pouvant être retournés dans une recherche.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>recursive</code></p>
|
||
<p>Booléen déterminant si la recherche récursive est activée.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>approx</code></p>
|
||
<p>Booléen déterminant si la recherche approximative est activée.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>withoutCache</code></p>
|
||
<p>Booléen déterminant si le cache de recherche doit être utilisé.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>onlyAccessible</code></p>
|
||
<p>Booléen déterminant si seul les objets accessibles à l'utilisateur connecté doivent être
|
||
retournés par la recherche.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>sortBy</code></p>
|
||
<p>Mot clé déterminant sur quel valeur/colonne le résultat de recherche sera trié.</p>
|
||
<p>Valeurs possibles : <code>displayName</code>, <code>subDn</code> ou <code>NULL</code>.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>sortDirection</code></p>
|
||
<p>Mot clé déterminant le sens du trie du résultat de la recherche.</p>
|
||
<p>Valeurs possibles : <code>ASC</code>, <code>DESC</code> ou <code>NULL</code>.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>sortlimit</code></p>
|
||
<p>Entier determinant le nombre maximum d'objet pouvant être triés dans le résultat d'une
|
||
recherche.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>displayFormat</code></p>
|
||
<p><a href="#conf-global-lsformat-format-parametrable">LSformat</a> d'affichage du nom de l'objet dans le
|
||
résultat de la recherche.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>nbObjectsByPage</code></p>
|
||
<p>Entier déterminant le nombre d'objet maximum affichés dans une page de résultat de la recherche.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>nbObjectsByPageChoices</code></p>
|
||
<p>Tableau des choix proposés à l'utilisateur pour le nombre d'objets maximum affichés dans une
|
||
page de résultat de la recherche.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>validPatternRegex</code></p>
|
||
<p>Expression régulière de validation des mots clés de recherche pour ce type
|
||
d'<a href="#conf-lsobject-configuration-lsobject">LSobject</a>.</p>
|
||
<p>(Par défaut : <code>/^[\w\-_\\\'\"^[]\(\){}\=\+\£\%\$\€\.\:\;\,\?\/\@]+$/iu</code>)</p>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>predefinedFilters</code></p>
|
||
<p>Tableau associatif contenant des filtres prédéfinis pour la recherche. Les clés sont les filtres
|
||
au format LDAP et les valeurs sont les labels associés.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>extraDisplayedColumns</code></p>
|
||
<p>Tableau associatif contenant des colonnes supplémentaires à afficher dans les résultats de
|
||
recherche. Les clés sont les identifiants des colonnes supplémentaires et les valeurs sont leur
|
||
configuration définie à partir des paramètres suivant :</p>
|
||
<ul>
|
||
<li>
|
||
<p><code>label</code></p>
|
||
<p>Le label de la colonne.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>LSformat</code></p>
|
||
<p>Le <a href="#conf-global-lsformat-format-parametrable">LSformat</a> d'affichage de la colonne. Ce format
|
||
est composé à partir des attributs des objets LDAP dans leur format brut.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>alternativeLSformats</code></p>
|
||
<p>Tableau des <a href="#conf-global-lsformat-format-parametrable">LSformats</a> alternatifs à utiliser si le
|
||
résultat du format principal est vide. Les formats définis dans cette liste sont essayés les uns
|
||
après les autres et le premier <a href="#conf-global-lsformat-format-parametrable">LSformat</a> retournant
|
||
une valeur non-vide est utilisé.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>formaterLSformat</code></p>
|
||
<p><a href="#conf-global-lsformat-format-parametrable">LSformat</a> optionnel permettant de mettre en forme le
|
||
résultat obtenu des <a href="#conf-global-lsformat-format-parametrable">LSformats</a> précédents. Ce
|
||
<a href="#conf-global-lsformat-format-parametrable">LSformat</a> ne sera utilisé que si le résultat obtenu
|
||
précédement n'est pas vide. Il est ainsi possible d'utiliser les paramètres <code>LSformat</code> et
|
||
<code>alternativeLSformats</code> afin de récupérer la valeur à afficher, puis de la mettre en forme grâce
|
||
à ce <a href="#conf-global-lsformat-format-parametrable">LSformat</a>. Ce format est composé à partir des
|
||
attributs des objets LDAP dans leur format brut et de la valeur retournés précedement accessible
|
||
via la variable <code>val</code>.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>formaterFunction</code></p>
|
||
<p>Le nom d'une fonction optionnelle à exécuter pour mettre en forme le résultat obtenu des
|
||
<a href="#conf-global-lsformat-format-parametrable">LSformats</a> précédents. Cette fonction ne sera
|
||
appelée que si le résultat obtenu précédement n'est pas vide. La fonction prendra en paramètre
|
||
la valeur à mettre en forme et retournera la valeur mise en forme.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>generateFunction</code></p>
|
||
<p>Le nom d'une fonction qui sera utilisée pour générer la valeur d'affichage de cette colonne. La
|
||
fonction prendra en paramètre une référence de l'objet <code>LSsearchEntry</code> et retournera la valeur
|
||
de la colonne.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>additionalAttrs</code></p>
|
||
<p>Un tableau de nom d'attributs à inclure dans le resultat de la recherche LDAP. Ce tableau permet
|
||
notamment d'inclure les attributs nécessaires au bon fonctionnement de la fonction
|
||
<code>generateFunction</code>.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>escape</code></p>
|
||
<p>Ce paramètre booléen permet de définir si, lors de l'affichage, le contenu de la colonne doit
|
||
être transformé pour protéger les caractères éligibles en entités HTML. Par défaut, ce paramètre
|
||
est <code>True</code>.</p>
|
||
<div class="admonition warning">
|
||
<p class="admonition-title">Warning</p>
|
||
<p>Cette fonctionnalité existe pour des raisons de sécurité et notamment en protection des
|
||
failles <code>XSS</code>. Si vous désactivez cette fonctionnalité, il est important de gérer la
|
||
problématique de sécurité par ailleurs.</p>
|
||
</div>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>cssStyle</code></p>
|
||
<p>Ce paramètre permet de définir un style CSS personnalisé pour la colonne. S'il est défini, le
|
||
contenu de ce paramètre sera ajouté en tant qu'attribut <code>style</code> des balises <code>th</code> et <code>td</code> de la
|
||
colone.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>visibleTo</code></p>
|
||
<p>Ce paramètre permet de restreindre la visibilité de cette colonne aux seuls
|
||
<a href="#conf-global-ldap-lsprofile-profils-dutilisateurs">LSprofiles</a> spécifiés. S'il est omis, la
|
||
colonne sera visible pour tous.</p>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>customActions</code></p>
|
||
<p>Tableau associatif contenant les paramètres de configuration des
|
||
<a href="#conf-lsobject-lssearch-customactions">customActions</a>. <a href="#conf-lsobject-lssearch-customactions">Voir la section concernée</a>.</p>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>
|
||
<p><code>showSelectionBoxes</code></p>
|
||
<p>Booléen permettant de définir si les cases à cocher de sélections des objets doivent être
|
||
affichées. Lorsqu'elles sont affichées, l'utilisateur pourra sélectionner un ou plusieurs objets
|
||
dans la liste avant de déclencher une <a href="#conf-lsobject-lssearch-customsactions">customAction</a>. Dans ce cas, les DNs de ces
|
||
objets seront passés à la page d'exécution de la <a href="#conf-lsobject-lssearch-customsactions">customAction</a> via le paramètre
|
||
<code>selected</code>.</p>
|
||
</li>
|
||
</ul>
|
||
<h2 id="conf-lsobject-lssearch-les-actions-personnalisees-customactions">Les actions personnalisées (customActions)</h2>
|
||
<p>Cette section décrit la manière de configurer les actions personnalisées exécutables sur les
|
||
recherches d'<a href="#conf-lsobject-configuration-lsobject">LSobjects</a> appelées <a href="#conf-lsobject-lssearch-customactions">customActions</a>.</p>
|
||
<div class="highlight"><pre><span></span><code><a href="#conf-lsobject-lssearch-__codelineno-6-1" id="__codelineno-6-1" name="__codelineno-6-1"></a>$GLOBALS['LSobjects']['[nom du type d'LSobject]']['LSsearch']['customActions'] = array (
|
||
<a href="#conf-lsobject-lssearch-__codelineno-6-2" id="__codelineno-6-2" name="__codelineno-6-2"></a> 'action1' => 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'envoi de courriels. Il
|
||
utilise pour cela les librairies <a href="http://pear.php.net/">PEAR</a> <em>Mail</em> et <em>Mail_Mime</em> qui doivent être
|
||
installés.</p>
|
||
<p>Cet <a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a> offre aussi la possibilité d'envoyer des
|
||
courriels dont le contenu est construit à partir de modèles. Ces modèles sont enregistrés dans des
|
||
fichiers textes stockés (voir <code>$GLOBALS['MAIL_TEMPLATES_DIRECTORIES']</code>). Pour chaque modèle, vous
|
||
devez fournir trois fichiers portant le même nom mais avec des extensions différentes :</p>
|
||
<ul>
|
||
<li><code>template.subject</code> : le sujet du courriel. Note : seule la première ligne du fichier est utilisé
|
||
(et passée dans la fonction <code>trim()</code>)</li>
|
||
<li><code>template.html</code> : le contenu HTML du courriel</li>
|
||
<li><code>template.txt</code>: le contenu texte du courriel</li>
|
||
</ul>
|
||
<p>Ces trois fichiers sont utilisés en tant que modèle <a href="http://www.smarty.net/">Smarty</a> et seront
|
||
construit en utilisant les variables fournies dans le contexte d'envoi des courriels. À noter que le
|
||
moteur Smarty utilisé pour la génération du contenu de ces courriels n'est pas le même que celui
|
||
utilisé par LdapSaisie pour l'affichage des pages.</p>
|
||
<p>Par ailleurs, cet <a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a> fourni une vue de gestion des
|
||
modèles de courriels existants (voir <code>$GLOBALS['MAIL_TEMPLATES_EDITOR_VIEW_ACCESS']</code> pour la
|
||
configuration des accès).</p>
|
||
<div class="admonition warning">
|
||
<p class="admonition-title">Warning</p>
|
||
<p>Cette vue n'est pas conçues pour être mise entre toutes les mains. La sécurisation de modèles de
|
||
courriels étant très complexe, il est fortement recommandé de n'ouvrir l'accès à cette vue
|
||
qu'aux utilisateurs avertis et de confiances.</p>
|
||
</div>
|
||
<p>Cet <a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a> doit être configuré en éditant son
|
||
fichier de configuration <code>config.LSaddons.mail.php</code>.</p>
|
||
<div class="highlight"><pre><span></span><code><a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="x"> ***********************************************</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a><span class="x"> * Configuration du support de l'envoi de mail *</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a><span class="x"> ***********************************************</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a><span class="x"> */</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a><span class="x">// Pear :: Mail</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a><span class="x">define('PEAR_MAIL','/usr/share/php/Mail.php');</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a><span class="x">// Pear :: Mail_mime</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a><span class="x">define('PEAR_MAIL_MIME','/usr/share/php/Mail/mime.php');</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a><span class="x">/*</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a><span class="x"> * Méthode d'envoie :</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a><span class="x"> * - mail : envoie avec la méthode PHP mail()</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a><span class="x"> * - sendmail : envoie la commande sendmail du système</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-16" id="__codelineno-0-16" name="__codelineno-0-16"></a><span class="x"> * - smtp : envoie en utilisant un serveur SMTP</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-17" id="__codelineno-0-17" name="__codelineno-0-17"></a><span class="x"> */</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-18" id="__codelineno-0-18" name="__codelineno-0-18"></a><span class="x">define('MAIL_SEND_METHOD','smtp');</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-19" id="__codelineno-0-19" name="__codelineno-0-19"></a>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-20" id="__codelineno-0-20" name="__codelineno-0-20"></a><span class="x">/*</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-21" id="__codelineno-0-21" name="__codelineno-0-21"></a><span class="x"> * Paramètres d'envoie :</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-22" id="__codelineno-0-22" name="__codelineno-0-22"></a><span class="x"> * Ces paramètres dépende de la méthode utilisé. Repporté vous à la documentation</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-23" id="__codelineno-0-23" name="__codelineno-0-23"></a><span class="x"> * de PEAR :: Mail pour plus d'information.</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-24" id="__codelineno-0-24" name="__codelineno-0-24"></a><span class="x"> * Lien : http://pear.php.net/manual/en/package.mail.mail.factory.php</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-25" id="__codelineno-0-25" name="__codelineno-0-25"></a><span class="x"> * Infos :</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-26" id="__codelineno-0-26" name="__codelineno-0-26"></a><span class="x"> * List of parameter for the backends</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-27" id="__codelineno-0-27" name="__codelineno-0-27"></a><span class="x"> * mail</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-28" id="__codelineno-0-28" name="__codelineno-0-28"></a><span class="x"> * o If safe mode is disabled, $params will be passed as the fifth</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-29" id="__codelineno-0-29" name="__codelineno-0-29"></a><span class="x"> * argument to the PHP mail() function. If $params is an array,</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-30" id="__codelineno-0-30" name="__codelineno-0-30"></a><span class="x"> * its elements will be joined as a space-delimited string.</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-31" id="__codelineno-0-31" name="__codelineno-0-31"></a><span class="x"> * sendmail</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-32" id="__codelineno-0-32" name="__codelineno-0-32"></a><span class="x"> * o $params["sendmail_path"] - The location of the sendmail program</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-33" id="__codelineno-0-33" name="__codelineno-0-33"></a><span class="x"> * on the filesystem. Default is /usr/bin/sendmail.</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-34" id="__codelineno-0-34" name="__codelineno-0-34"></a><span class="x"> * o $params["sendmail_args"] - Additional parameters to pass to the</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-35" id="__codelineno-0-35" name="__codelineno-0-35"></a><span class="x"> * sendmail. Default is -i.</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-36" id="__codelineno-0-36" name="__codelineno-0-36"></a><span class="x"> * smtp</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-37" id="__codelineno-0-37" name="__codelineno-0-37"></a><span class="x"> * o $params["host"] - The server to connect. Default is localhost.</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-38" id="__codelineno-0-38" name="__codelineno-0-38"></a><span class="x"> * o $params["port"] - The port to connect. Default is 25.</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-39" id="__codelineno-0-39" name="__codelineno-0-39"></a><span class="x"> * o $params["auth"] - Whether or not to use SMTP authentication.</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-40" id="__codelineno-0-40" name="__codelineno-0-40"></a><span class="x"> * Default is FALSE.</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-41" id="__codelineno-0-41" name="__codelineno-0-41"></a><span class="x"> * o $params["username"] - The username to use for SMTP authentication.</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-42" id="__codelineno-0-42" name="__codelineno-0-42"></a><span class="x"> * o $params["password"] - The password to use for SMTP authentication.</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-43" id="__codelineno-0-43" name="__codelineno-0-43"></a><span class="x"> * o $params["localhost"] - The value to give when sending EHLO or HELO.</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-44" id="__codelineno-0-44" name="__codelineno-0-44"></a><span class="x"> * Default is localhost</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-45" id="__codelineno-0-45" name="__codelineno-0-45"></a><span class="x"> * o $params["timeout"] - The SMTP connection timeout.</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-46" id="__codelineno-0-46" name="__codelineno-0-46"></a><span class="x"> * Default is NULL (no timeout).</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-47" id="__codelineno-0-47" name="__codelineno-0-47"></a><span class="x"> * o $params["verp"] - Whether to use VERP or not. Default is FALSE.</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-48" id="__codelineno-0-48" name="__codelineno-0-48"></a><span class="x"> * o $params["debug"] - Whether to enable SMTP debug mode or not.</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-49" id="__codelineno-0-49" name="__codelineno-0-49"></a><span class="x"> * Default is FALSE.</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-50" id="__codelineno-0-50" name="__codelineno-0-50"></a><span class="x"> * o $params["persist"] - Indicates whether or not the SMTP connection</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-51" id="__codelineno-0-51" name="__codelineno-0-51"></a><span class="x"> * should persist over multiple calls to the send() method.</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-52" id="__codelineno-0-52" name="__codelineno-0-52"></a><span class="x"> */</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-53" id="__codelineno-0-53" name="__codelineno-0-53"></a><span class="x">$GLOBALS['MAIL_SEND_PARAMS'] = NULL;</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-54" id="__codelineno-0-54" name="__codelineno-0-54"></a>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-55" id="__codelineno-0-55" name="__codelineno-0-55"></a><span class="x">/*</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-56" id="__codelineno-0-56" name="__codelineno-0-56"></a><span class="x"> * Headers :</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-57" id="__codelineno-0-57" name="__codelineno-0-57"></a><span class="x"> */</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-58" id="__codelineno-0-58" name="__codelineno-0-58"></a><span class="x">$GLOBALS['MAIL_HEARDERS = array();</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-59" id="__codelineno-0-59" name="__codelineno-0-59"></a>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-60" id="__codelineno-0-60" name="__codelineno-0-60"></a><span class="x">// Catch all sent emails</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-61" id="__codelineno-0-61" name="__codelineno-0-61"></a><span class="x">$GLOBALS['MAIL_CATCH_ALL'] = array();</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-62" id="__codelineno-0-62" name="__codelineno-0-62"></a>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-63" id="__codelineno-0-63" name="__codelineno-0-63"></a><span class="x">/**</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-64" id="__codelineno-0-64" name="__codelineno-0-64"></a><span class="x"> * Email templates</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-65" id="__codelineno-0-65" name="__codelineno-0-65"></a><span class="x"> *</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-66" id="__codelineno-0-66" name="__codelineno-0-66"></a><span class="x"> * This addon offer ability to send email by using templates. Email templates are stored in</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-67" id="__codelineno-0-67" name="__codelineno-0-67"></a><span class="x"> * full-text files in configured directories (see $GLOBALS['MAIL_TEMPLATES_DIRECTORIES']). For each</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-68" id="__codelineno-0-68" name="__codelineno-0-68"></a><span class="x"> * template, you have to provide three files with the same name but with different extensions:</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-69" id="__codelineno-0-69" name="__codelineno-0-69"></a><span class="x"> * - template.subject: the email subject. Note: only the first line is used (and stripped)</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-70" id="__codelineno-0-70" name="__codelineno-0-70"></a><span class="x"> * - template.html: the HTML content of the email</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-71" id="__codelineno-0-71" name="__codelineno-0-71"></a><span class="x"> * - template.txt: the text content of the email</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-72" id="__codelineno-0-72" name="__codelineno-0-72"></a><span class="x"> * All these files will be used as Smarty templates and will be computed using variables provided</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-73" id="__codelineno-0-73" name="__codelineno-0-73"></a><span class="x"> * in the sending context. Note that the Smarty object used to compute the template is not the same</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-74" id="__codelineno-0-74" name="__codelineno-0-74"></a><span class="x"> * as the one used by LdapSaisie to display pages.</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-75" id="__codelineno-0-75" name="__codelineno-0-75"></a><span class="x"> *</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-76" id="__codelineno-0-76" name="__codelineno-0-76"></a><span class="x"> * Futhermore, this addon offer a view to list and edit existing template (see</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-77" id="__codelineno-0-77" name="__codelineno-0-77"></a><span class="x"> * $GLOBALS['MAIL_TEMPLATES_EDITOR_VIEW_ACCESS'] to configured access).</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-78" id="__codelineno-0-78" name="__codelineno-0-78"></a><span class="x"> */</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-79" id="__codelineno-0-79" name="__codelineno-0-79"></a>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-80" id="__codelineno-0-80" name="__codelineno-0-80"></a><span class="x">// List of directory paths where as stored mail templates</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-81" id="__codelineno-0-81" name="__codelineno-0-81"></a><span class="x">// Notes:</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-82" id="__codelineno-0-82" name="__codelineno-0-82"></a><span class="x">// - provided path could be absolute or relative. Relative path are relative to the root base</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-83" id="__codelineno-0-83" name="__codelineno-0-83"></a><span class="x">// sources LdapSaisie directory (commonly /usr/share/ldapsaisie or the src directory if you</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-84" id="__codelineno-0-84" name="__codelineno-0-84"></a><span class="x">// installed it from sources). On Debian installation, you can specify 'local/email_templates' to</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-85" id="__codelineno-0-85" name="__codelineno-0-85"></a><span class="x">// refer to /etc/ldapsaisie/local/email_templates directory/</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-86" id="__codelineno-0-86" name="__codelineno-0-86"></a><span class="x">// - Multiple directories could be specified, sorted so that the first ones take priority over</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-87" id="__codelineno-0-87" name="__codelineno-0-87"></a><span class="x">// the last one.</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-88" id="__codelineno-0-88" name="__codelineno-0-88"></a><span class="x">// - To allow users to edit them using the editor view, these directories must be</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-89" id="__codelineno-0-89" name="__codelineno-0-89"></a><span class="x">// writable by PHP process (commonly runed as www-data).</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-90" id="__codelineno-0-90" name="__codelineno-0-90"></a><span class="x">$GLOBALS['MAIL_TEMPLATES_DIRECTORIES'] = array('local/email_templates');</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-91" id="__codelineno-0-91" name="__codelineno-0-91"></a>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-92" id="__codelineno-0-92" name="__codelineno-0-92"></a><span class="x">// List of granted LSprofiles to access mail templates editor view</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-93" id="__codelineno-0-93" name="__codelineno-0-93"></a><span class="x">// WARNING: Sanitizing mail templates is hell... EXPOSE THIS VIEW ONLY TO TRUSTED USERS!</span>
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-0-94" id="__codelineno-0-94" name="__codelineno-0-94"></a><span class="x">$GLOBALS['MAIL_TEMPLATES_EDITOR_VIEW_ACCESS'] = array('admin');</span>
|
||
</code></pre></div>
|
||
<p>Cet <a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a> offre avant tout la possibilité d'envoyer des
|
||
courriels en utilisant la fonction PHP <code>sendMail()</code> :</p>
|
||
<div class="highlight"><pre><span></span><code><a href="#conf-lsaddon-lsaddon_mail-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a>bool sendMail(
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-1-2" id="__codelineno-1-2" name="__codelineno-1-2"></a> <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>
|
||
<p>Pour l'envoi de courriels en utilisant un modèle, il faut utiliser la fonction PHP
|
||
<code>sendMailFromTemplate()</code> :</p>
|
||
<div class="highlight"><pre><span></span><code><a href="#conf-lsaddon-lsaddon_mail-__codelineno-2-1" id="__codelineno-2-1" name="__codelineno-2-1"></a>bool sendMailFromTemplate(
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-2-2" id="__codelineno-2-2" name="__codelineno-2-2"></a> <string> $tplname,
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-2-3" id="__codelineno-2-3" name="__codelineno-2-3"></a> <string> $to,
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-2-4" id="__codelineno-2-4" name="__codelineno-2-4"></a> <array> $variables,
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-2-5" id="__codelineno-2-5" name="__codelineno-2-5"></a> <array(string)> $headers,
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-2-6" id="__codelineno-2-6" name="__codelineno-2-6"></a> <array> $attachments
|
||
<a href="#conf-lsaddon-lsaddon_mail-__codelineno-2-7" id="__codelineno-2-7" name="__codelineno-2-7"></a>);
|
||
</code></pre></div></section><section class="print-page" id="conf-lsaddon-lsaddon_maildir"><h1 id="conf-lsaddon-lsaddon_maildir-lsaddon_maildir">LSaddon_maildir</h1>
|
||
<p>Cet <a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a> est utilisé pour gérer la manipulation distante
|
||
de maildir.</p>
|
||
<p><strong>FIXME</strong></p></section><section class="print-page" id="conf-lsaddon-lsaddon_mailquota"><h1 id="conf-lsaddon-lsaddon_mailquota-lsaddon_mailquota">LSaddon_mailquota</h1>
|
||
<p>Cet <a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a> fournie une fonction <code>mailquota_get_usage</code>
|
||
pouvant être utilisée pour récupérer l'utilisation du quota d'une boîte mail IMAP. Pour cela,
|
||
LdapSaisie se connecte au serveur IMAP en utilisant un compte maître.</p>
|
||
<p>Cet <a href="#conf-lsaddon-configuration-des-lsaddons">LSaddon</a> fournie une également une fonction
|
||
<code>mailquota_show_usage</code> pouvant être utilisée comme
|
||
<a href="#conf-lsobject-customactions-customactions">customActions</a> et permettant d'afficher l'utilisation
|
||
du quota de la boîte mail correspondante via une message dynamique (<code>LSinfo</code>).</p>
|
||
<p>Des paramètres de configuration sont disponibles dans le fichier de configuration
|
||
<code>config.LSaddons.mailquota.php</code>.</p>
|
||
<div class="highlight"><pre><span></span><code><a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-1" id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="x">// IMAP Mailbox connection string LSformat (composed with LSldapObject attributes)</span>
|
||
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-2" id="__codelineno-0-2" name="__codelineno-0-2"></a><span class="x">// See : https://php.net/imap_open (parameter $mailbox)</span>
|
||
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-3" id="__codelineno-0-3" name="__codelineno-0-3"></a><span class="x">define('MAILQUOTA_IMAP_MAILBOX','{localhost}');</span>
|
||
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-4" id="__codelineno-0-4" name="__codelineno-0-4"></a>
|
||
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-5" id="__codelineno-0-5" name="__codelineno-0-5"></a><span class="x">// IMAP Master user</span>
|
||
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-6" id="__codelineno-0-6" name="__codelineno-0-6"></a><span class="x">define('MAILQUOTA_IMAP_MASTER_USER', 'ldapsaisie');</span>
|
||
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-7" id="__codelineno-0-7" name="__codelineno-0-7"></a>
|
||
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-8" id="__codelineno-0-8" name="__codelineno-0-8"></a><span class="x">// IMAP Master user's password</span>
|
||
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-9" id="__codelineno-0-9" name="__codelineno-0-9"></a><span class="x">define('MAILQUOTA_IMAP_MASTER_USER_PWD', 'secret');</span>
|
||
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-10" id="__codelineno-0-10" name="__codelineno-0-10"></a>
|
||
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-11" id="__codelineno-0-11" name="__codelineno-0-11"></a><span class="x">// IMAP Master user LSformat composed with :</span>
|
||
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-12" id="__codelineno-0-12" name="__codelineno-0-12"></a><span class="x">// * masteruser = master username (MAILQUOTA_IMAP_MASTER_USER)</span>
|
||
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-13" id="__codelineno-0-13" name="__codelineno-0-13"></a><span class="x">// * LSldapObject attributes</span>
|
||
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-14" id="__codelineno-0-14" name="__codelineno-0-14"></a><span class="x">define('MAILQUOTA_IMAP_MASTER_USER_FORMAT', '%{mail}*%{masteruser}');</span>
|
||
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-15" id="__codelineno-0-15" name="__codelineno-0-15"></a>
|
||
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-16" id="__codelineno-0-16" name="__codelineno-0-16"></a><span class="x">// IMAP quota root mailbox</span>
|
||
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-0-17" id="__codelineno-0-17" name="__codelineno-0-17"></a><span class="x">define('MAILQUOTA_IMAP_QUOTA_ROOT_MAILBOX', 'INBOX');</span>
|
||
</code></pre></div>
|
||
<p>Ci-dessous, vous trouverez un exemple de configuration de la fonction <code>mailquota_show_usage()</code>
|
||
comme <a href="#conf-lsobject-customactions-customactions">customActions</a> :</p>
|
||
<div class="highlight"><pre><span></span><code><a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-1-1" id="__codelineno-1-1" name="__codelineno-1-1"></a><span class="x">$GLOBALS['LSobjects']['LSpeople'] = array (</span>
|
||
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-1-2" id="__codelineno-1-2" name="__codelineno-1-2"></a><span class="x"> [...]</span>
|
||
<a href="#conf-lsaddon-lsaddon_mailquota-__codelineno-1-3" id="__codelineno-1-3" name="__codelineno-1-3"></a><span class="x"> 'customActions' => 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>
|
||
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
|
||
</div>
|
||
</main>
|
||
<footer class="md-footer">
|
||
<div class="md-footer-meta md-typeset">
|
||
<div class="md-footer-meta__inner md-grid">
|
||
<div class="md-copyright">
|
||
<div class="md-copyright__highlight">
|
||
Easter-eggs
|
||
</div>
|
||
|
||
|
||
Made with
|
||
<a href="https://squidfunk.github.io/mkdocs-material/" rel="noopener" target="_blank">
|
||
Material for MkDocs
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</footer>
|
||
</div>
|
||
<div class="md-dialog" data-md-component="dialog">
|
||
<div class="md-dialog__inner md-typeset"></div>
|
||
</div>
|
||
<script id="__config" type="application/json">{"base": "../..", "features": [], "search": "../assets/javascripts/workers/search.b8dbb3d2.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+e3ZhciBfaT1PYmplY3QuY3JlYXRlO3ZhciBicj1PYmplY3QuZGVmaW5lUHJvcGVydHk7dmFyIEFpPU9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3I7dmFyIENpPU9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzLEZ0PU9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMsa2k9T2JqZWN0LmdldFByb3RvdHlwZU9mLHZyPU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHksZW89T2JqZWN0LnByb3RvdHlwZS5wcm9wZXJ0eUlzRW51bWVyYWJsZTt2YXIgWnI9KGUsdCxyKT0+dCBpbiBlP2JyKGUsdCx7ZW51bWVyYWJsZTohMCxjb25maWd1cmFibGU6ITAsd3JpdGFibGU6ITAsdmFsdWU6cn0pOmVbdF09cixGPShlLHQpPT57Zm9yKHZhciByIGluIHR8fCh0PXt9KSl2ci5jYWxsKHQscikmJlpyKGUscix0W3JdKTtpZihGdClmb3IodmFyIHIgb2YgRnQodCkpZW8uY2FsbCh0LHIpJiZacihlLHIsdFtyXSk7cmV0dXJuIGV9O3ZhciB0bz0oZSx0KT0+e3ZhciByPXt9O2Zvcih2YXIgbyBpbiBlKXZyLmNhbGwoZSxvKSYmdC5pbmRleE9mKG8pPDAmJihyW29dPWVbb10pO2lmKGUhPW51bGwmJkZ0KWZvcih2YXIgbyBvZiBGdChlKSl0LmluZGV4T2Yobyk8MCYmZW8uY2FsbChlLG8pJiYocltvXT1lW29dKTtyZXR1cm4gcn07dmFyIGdyPShlLHQpPT4oKT0+KHR8fGUoKHQ9e2V4cG9ydHM6e319KS5leHBvcnRzLHQpLHQuZXhwb3J0cyk7dmFyIEhpPShlLHQscixvKT0+e2lmKHQmJnR5cGVvZiB0PT0ib2JqZWN0Inx8dHlwZW9mIHQ9PSJmdW5jdGlvbiIpZm9yKGxldCBuIG9mIENpKHQpKSF2ci5jYWxsKGUsbikmJm4hPT1yJiZicihlLG4se2dldDooKT0+dFtuXSxlbnVtZXJhYmxlOiEobz1BaSh0LG4pKXx8by5lbnVtZXJhYmxlfSk7cmV0dXJuIGV9O3ZhciBqdD0oZSx0LHIpPT4ocj1lIT1udWxsP19pKGtpKGUpKTp7fSxIaSh0fHwhZXx8IWUuX19lc01vZHVsZT9icihyLCJkZWZhdWx0Iix7dmFsdWU6ZSxlbnVtZXJhYmxlOiEwfSk6cixlKSk7dmFyIHJvPShlLHQscik9Pm5ldyBQcm9taXNlKChvLG4pPT57dmFyIGk9Yz0+e3RyeXthKHIubmV4dChjKSl9Y2F0Y2gocCl7bihwKX19LHM9Yz0+e3RyeXthKHIudGhyb3coYykpfWNhdGNoKHApe24ocCl9fSxhPWM9PmMuZG9uZT9vKGMudmFsdWUpOlByb21pc2UucmVzb2x2ZShjLnZhbHVlKS50aGVuKGkscyk7YSgocj1yLmFwcGx5KGUsdCkpLm5leHQoKSl9KTt2YXIgbm89Z3IoKHhyLG9vKT0+eyhmdW5jdGlvbihlLHQpe3R5cGVvZiB4cj09Im9iamVjdCImJnR5cGVvZiBvbyE9InVuZGVmaW5lZCI/dCgpOnR5cGVvZiBkZWZpbmU9PSJmdW5jdGlvbiImJmRlZmluZS5hbWQ/ZGVmaW5lKHQpOnQoKX0pKHhyLGZ1bmN0aW9uKCl7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIGUocil7dmFyIG89ITAsbj0hMSxpPW51bGwscz17dGV4dDohMCxzZWFyY2g6ITAsdXJsOiEwLHRlbDohMCxlbWFpbDohMCxwYXNzd29yZDohMCxudW1iZXI6ITAsZGF0ZTohMCxtb250aDohMCx3ZWVrOiEwLHRpbWU6ITAsZGF0ZXRpbWU6ITAsImRhdGV0aW1lLWxvY2FsIjohMH07ZnVuY3Rpb24gYShDKXtyZXR1cm4hIShDJiZDIT09ZG9jdW1lbnQmJkMubm9kZU5hbWUhPT0iSFRNTCImJkMubm9kZU5hbWUhPT0iQk9EWSImJiJjbGFzc0xpc3QiaW4gQyYmImNvbnRhaW5zImluIEMuY2xhc3NMaXN0KX1mdW5jdGlvbiBjKEMpe3ZhciBjdD1DLnR5cGUsTmU9Qy50YWdOYW1lO3JldHVybiEhKE5lPT09IklOUFVUIiYmc1tjdF0mJiFDLnJlYWRPbmx5fHxOZT09PSJURVhUQVJFQSImJiFDLnJlYWRPbmx5fHxDLmlzQ29udGVudEVkaXRhYmxlKX1mdW5jdGlvbiBwKEMpe0MuY2xhc3NMaXN0LmNvbnRhaW5zKCJmb2N1cy12aXNpYmxlIil8fChDLmNsYXNzTGlzdC5hZGQoImZvY3VzLXZpc2libGUiKSxDLnNldEF0dHJpYnV0ZSgiZGF0YS1mb2N1cy12aXNpYmxlLWFkZGVkIiwiIikpfWZ1bmN0aW9uIGwoQyl7Qy5oYXNBdHRyaWJ1dGUoImRhdGEtZm9jdXMtdmlzaWJsZS1hZGRlZCIpJiYoQy5jbGFzc0xpc3QucmVtb3ZlKCJmb2N1cy12aXNpYmxlIiksQy5yZW1vdmVBdHRyaWJ1dGUoImRhdGEtZm9jdXMtdmlzaWJsZS1hZGRlZCIpKX1mdW5jdGlvbiBmKEMpe0MubWV0YUtleXx8Qy5hbHRLZXl8fEMuY3RybEtleXx8KGEoci5hY3RpdmVFbGVtZW50KSYmcChyLmFjdGl2ZUVsZW1lbnQpLG89ITApfWZ1bmN0aW9uIHUoQyl7bz0hMX1mdW5jdGlvbiBoKEMpe2EoQy50YXJnZXQpJiYob3x8YyhDLnRhcmdldCkpJiZwKEMudGFyZ2V0KX1mdW5jdGlvbiB3KEMpe2EoQy50YXJnZXQpJiYoQy50YXJnZXQuY2xhc3NMaXN0LmNvbnRhaW5zKCJmb2N1cy12aXNpYmxlIil8fEMudGFyZ2V0Lmhhc0F0dHJpYnV0ZSgiZGF0YS1mb2N1cy12aXNpYmxlLWFkZGVkIikpJiYobj0hMCx3aW5kb3cuY2xlYXJUaW1lb3V0KGkpLGk9d2luZG93LnNldFRpbWVvdXQoZnVuY3Rpb24oKXtuPSExfSwxMDApLGwoQy50YXJnZXQpKX1mdW5jdGlvbiBBKEMpe2RvY3VtZW50LnZpc2liaWxpdHlTdGF0ZT09PSJoaWRkZW4iJiYobiYmKG89ITApLFooKSl9ZnVuY3Rpb24gWigpe2RvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoIm1vdXNlbW92ZSIsSiksZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigibW91c2Vkb3duIixKKSxkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCJtb3VzZXVwIixKKSxkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCJwb2ludGVybW92ZSIsSiksZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigicG9pbnRlcmRvd24iLEopLGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoInBvaW50ZXJ1cCIsSiksZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigidG91Y2htb3ZlIixKKSxkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCJ0b3VjaHN0YXJ0IixKKSxkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCJ0b3VjaGVuZCIsSil9ZnVuY3Rpb24gdGUoKXtkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCJtb3VzZW1vdmUiLEopLGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoIm1vdXNlZG93biIsSiksZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigibW91c2V1cCIsSiksZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigicG9pbnRlcm1vdmUiLEopLGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoInBvaW50ZXJkb3duIixKKSxkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCJwb2ludGVydXAiLEopLGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoInRvdWNobW92ZSIsSiksZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigidG91Y2hzdGFydCIsSiksZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigidG91Y2hlbmQiLEopfWZ1bmN0aW9uIEooQyl7Qy50YXJnZXQubm9kZU5hbWUmJkMudGFyZ2V0Lm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk9PT0iaHRtbCJ8fChvPSExLHRlKCkpfWRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoImtleWRvd24iLGYsITApLGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoIm1vdXNlZG93biIsdSwhMCksZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigicG9pbnRlcmRvd24iLHUsITApLGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoInRvdWNoc3RhcnQiLHUsITApLGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoInZpc2liaWxpdHljaGFuZ2UiLEEsITApLFooKSxyLmFkZEV2ZW50TGlzdGVuZXIoImZvY3VzIixoLCEwKSxyLmFkZEV2ZW50TGlzdGVuZXIoImJsdXIiLHcsITApLHIubm9kZVR5cGU9PT1Ob2RlLkRPQ1VNRU5UX0ZSQUdNRU5UX05PREUmJnIuaG9zdD9yLmhvc3Quc2V0QXR0cmlidXRlKCJkYXRhLWpzLWZvY3VzLXZpc2libGUiLCIiKTpyLm5vZGVUeXBlPT09Tm9kZS5ET0NVTUVOVF9OT0RFJiYoZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsYXNzTGlzdC5hZGQoImpzLWZvY3VzLXZpc2libGUiKSxkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuc2V0QXR0cmlidXRlKCJkYXRhLWpzLWZvY3VzLXZpc2libGUiLCIiKSl9aWYodHlwZW9mIHdpbmRvdyE9InVuZGVmaW5lZCImJnR5cGVvZiBkb2N1bWVudCE9InVuZGVmaW5lZCIpe3dpbmRvdy5hcHBseUZvY3VzVmlzaWJsZVBvbHlmaWxsPWU7dmFyIHQ7dHJ5e3Q9bmV3IEN1c3RvbUV2ZW50KCJmb2N1cy12aXNpYmxlLXBvbHlmaWxsLXJlYWR5Iil9Y2F0Y2gocil7dD1kb2N1bWVudC5jcmVhdGVFdmVudCgiQ3VzdG9tRXZlbnQiKSx0LmluaXRDdXN0b21FdmVudCgiZm9jdXMtdmlzaWJsZS1wb2x5ZmlsbC1yZWFkeSIsITEsITEse30pfXdpbmRvdy5kaXNwYXRjaEV2ZW50KHQpfXR5cGVvZiBkb2N1bWVudCE9InVuZGVmaW5lZCImJmUoZG9jdW1lbnQpfSl9KTt2YXIgenI9Z3IoKGt0LFZyKT0+ey8qIQogKiBjbGlwYm9hcmQuanMgdjIuMC4xMQogKiBodHRwczovL2NsaXBib2FyZGpzLmNvbS8KICoKICogTGljZW5zZWQgTUlUIMKpIFplbm8gUm9jaGEKICovKGZ1bmN0aW9uKHQscil7dHlwZW9mIGt0PT0ib2JqZWN0IiYmdHlwZW9mIFZyPT0ib2JqZWN0Ij9Wci5leHBvcnRzPXIoKTp0eXBlb2YgZGVmaW5lPT0iZnVuY3Rpb24iJiZkZWZpbmUuYW1kP2RlZmluZShbXSxyKTp0eXBlb2Yga3Q9PSJvYmplY3QiP2t0LkNsaXBib2FyZEpTPXIoKTp0LkNsaXBib2FyZEpTPXIoKX0pKGt0LGZ1bmN0aW9uKCl7cmV0dXJuIGZ1bmN0aW9uKCl7dmFyIGU9ezY4NjpmdW5jdGlvbihvLG4saSl7InVzZSBzdHJpY3QiO2kuZChuLHtkZWZhdWx0OmZ1bmN0aW9uKCl7cmV0dXJuIExpfX0pO3ZhciBzPWkoMjc5KSxhPWkubihzKSxjPWkoMzcwKSxwPWkubihjKSxsPWkoODE3KSxmPWkubihsKTtmdW5jdGlvbiB1KEQpe3RyeXtyZXR1cm4gZG9jdW1lbnQuZXhlY0NvbW1hbmQoRCl9Y2F0Y2goTSl7cmV0dXJuITF9fXZhciBoPWZ1bmN0aW9uKE0pe3ZhciBPPWYoKShNKTtyZXR1cm4gdSgiY3V0IiksT30sdz1oO2Z1bmN0aW9uIEEoRCl7dmFyIE09ZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmdldEF0dHJpYnV0ZSgiZGlyIik9PT0icnRsIixPPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoInRleHRhcmVhIik7Ty5zdHlsZS5mb250U2l6ZT0iMTJwdCIsTy5zdHlsZS5ib3JkZXI9IjAiLE8uc3R5bGUucGFkZGluZz0iMCIsTy5zdHlsZS5tYXJnaW49IjAiLE8uc3R5bGUucG9zaXRpb249ImFic29sdXRlIixPLnN0eWxlW00/InJpZ2h0IjoibGVmdCJdPSItOTk5OXB4Ijt2YXIgST13aW5kb3cucGFnZVlPZmZzZXR8fGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5zY3JvbGxUb3A7cmV0dXJuIE8uc3R5bGUudG9wPSIiLmNvbmNhdChJLCJweCIpLE8uc2V0QXR0cmlidXRlKCJyZWFkb25seSIsIiIpLE8udmFsdWU9RCxPfXZhciBaPWZ1bmN0aW9uKE0sTyl7dmFyIEk9QShNKTtPLmNvbnRhaW5lci5hcHBlbmRDaGlsZChJKTt2YXIgVz1mKCkoSSk7cmV0dXJuIHUoImNvcHkiKSxJLnJlbW92ZSgpLFd9LHRlPWZ1bmN0aW9uKE0pe3ZhciBPPWFyZ3VtZW50cy5sZW5ndGg+MSYmYXJndW1lbnRzWzFdIT09dm9pZCAwP2FyZ3VtZW50c1sxXTp7Y29udGFpbmVyOmRvY3VtZW50LmJvZHl9LEk9IiI7cmV0dXJuIHR5cGVvZiBNPT0ic3RyaW5nIj9JPVooTSxPKTpNIGluc3RhbmNlb2YgSFRNTElucHV0RWxlbWVudCYmIVsidGV4dCIsInNlYXJjaCIsInVybCIsInRlbCIsInBhc3N3b3JkIl0uaW5jbHVkZXMoTT09bnVsbD92b2lkIDA6TS50eXBlKT9JPVooTS52YWx1ZSxPKTooST1mKCkoTSksdSgiY29weSIpKSxJfSxKPXRlO2Z1bmN0aW9uIEMoRCl7IkBiYWJlbC9oZWxwZXJzIC0gdHlwZW9mIjtyZXR1cm4gdHlwZW9mIFN5bWJvbD09ImZ1bmN0aW9uIiYmdHlwZW9mIFN5bWJvbC5pdGVyYXRvcj09InN5bWJvbCI/Qz1mdW5jdGlvbihPKXtyZXR1cm4gdHlwZW9mIE99OkM9ZnVuY3Rpb24oTyl7cmV0dXJuIE8mJnR5cGVvZiBTeW1ib2w9PSJmdW5jdGlvbiImJk8uY29uc3RydWN0b3I9PT1TeW1ib2wmJk8hPT1TeW1ib2wucHJvdG90eXBlPyJzeW1ib2wiOnR5cGVvZiBPfSxDKEQpfXZhciBjdD1mdW5jdGlvbigpe3ZhciBNPWFyZ3VtZW50cy5sZW5ndGg+MCYmYXJndW1lbnRzWzBdIT09dm9pZCAwP2FyZ3VtZW50c1swXTp7fSxPPU0uYWN0aW9uLEk9Tz09PXZvaWQgMD8iY29weSI6TyxXPU0uY29udGFpbmVyLEs9TS50YXJnZXQsQ2U9TS50ZXh0O2lmKEkhPT0iY29weSImJkkhPT0iY3V0Iil0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgImFjdGlvbiIgdmFsdWUsIHVzZSBlaXRoZXIgImNvcHkiIG9yICJjdXQiJyk7aWYoSyE9PXZvaWQgMClpZihLJiZDKEspPT09Im9iamVjdCImJksubm9kZVR5cGU9PT0xKXtpZihJPT09ImNvcHkiJiZLLmhhc0F0dHJpYnV0ZSgiZGlzYWJsZWQiKSl0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgInRhcmdldCIgYXR0cmlidXRlLiBQbGVhc2UgdXNlICJyZWFkb25seSIgaW5zdGVhZCBvZiAiZGlzYWJsZWQiIGF0dHJpYnV0ZScpO2lmKEk9PT0iY3V0IiYmKEsuaGFzQXR0cmlidXRlKCJyZWFkb25seSIpfHxLLmhhc0F0dHJpYnV0ZSgiZGlzYWJsZWQiKSkpdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkICJ0YXJnZXQiIGF0dHJpYnV0ZS4gWW91IGNhbid0IGN1dCB0ZXh0IGZyb20gZWxlbWVudHMgd2l0aCAicmVhZG9ubHkiIG9yICJkaXNhYmxlZCIgYXR0cmlidXRlc2ApfWVsc2UgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkICJ0YXJnZXQiIHZhbHVlLCB1c2UgYSB2YWxpZCBFbGVtZW50Jyk7aWYoQ2UpcmV0dXJuIEooQ2Use2NvbnRhaW5lcjpXfSk7aWYoSylyZXR1cm4gST09PSJjdXQiP3coSyk6SihLLHtjb250YWluZXI6V30pfSxOZT1jdDtmdW5jdGlvbiBQZShEKXsiQGJhYmVsL2hlbHBlcnMgLSB0eXBlb2YiO3JldHVybiB0eXBlb2YgU3ltYm9sPT0iZnVuY3Rpb24iJiZ0eXBlb2YgU3ltYm9sLml0ZXJhdG9yPT0ic3ltYm9sIj9QZT1mdW5jdGlvbihPKXtyZXR1cm4gdHlwZW9mIE99OlBlPWZ1bmN0aW9uKE8pe3JldHVybiBPJiZ0eXBlb2YgU3ltYm9sPT0iZnVuY3Rpb24iJiZPLmNvbnN0cnVjdG9yPT09U3ltYm9sJiZPIT09U3ltYm9sLnByb3RvdHlwZT8ic3ltYm9sIjp0eXBlb2YgT30sUGUoRCl9ZnVuY3Rpb24geGkoRCxNKXtpZighKEQgaW5zdGFuY2VvZiBNKSl0aHJvdyBuZXcgVHlwZUVycm9yKCJDYW5ub3QgY2FsbCBhIGNsYXNzIGFzIGEgZnVuY3Rpb24iKX1mdW5jdGlvbiBYcihELE0pe2Zvcih2YXIgTz0wO088TS5sZW5ndGg7TysrKXt2YXIgST1NW09dO0kuZW51bWVyYWJsZT1JLmVudW1lcmFibGV8fCExLEkuY29uZmlndXJhYmxlPSEwLCJ2YWx1ZSJpbiBJJiYoSS53cml0YWJsZT0hMCksT2JqZWN0LmRlZmluZVByb3BlcnR5KEQsSS5rZXksSSl9fWZ1bmN0aW9uIHlpKEQsTSxPKXtyZXR1cm4gTSYmWHIoRC5wcm90b3R5cGUsTSksTyYmWHIoRCxPKSxEfWZ1bmN0aW9uIEVpKEQsTSl7aWYodHlwZW9mIE0hPSJmdW5jdGlvbiImJk0hPT1udWxsKXRocm93IG5ldyBUeXBlRXJyb3IoIlN1cGVyIGV4cHJlc3Npb24gbXVzdCBlaXRoZXIgYmUgbnVsbCBvciBhIGZ1bmN0aW9uIik7RC5wcm90b3R5cGU9T2JqZWN0LmNyZWF0ZShNJiZNLnByb3RvdHlwZSx7Y29uc3RydWN0b3I6e3ZhbHVlOkQsd3JpdGFibGU6ITAsY29uZmlndXJhYmxlOiEwfX0pLE0mJmRyKEQsTSl9ZnVuY3Rpb24gZHIoRCxNKXtyZXR1cm4gZHI9T2JqZWN0LnNldFByb3RvdHlwZU9mfHxmdW5jdGlvbihJLFcpe3JldHVybiBJLl9fcHJvdG9fXz1XLEl9LGRyKEQsTSl9ZnVuY3Rpb24gd2koRCl7dmFyIE09T2koKTtyZXR1cm4gZnVuY3Rpb24oKXt2YXIgST1QdChEKSxXO2lmKE0pe3ZhciBLPVB0KHRoaXMpLmNvbnN0cnVjdG9yO1c9UmVmbGVjdC5jb25zdHJ1Y3QoSSxhcmd1bWVudHMsSyl9ZWxzZSBXPUkuYXBwbHkodGhpcyxhcmd1bWVudHMpO3JldHVybiBUaSh0aGlzLFcpfX1mdW5jdGlvbiBUaShELE0pe3JldHVybiBNJiYoUGUoTSk9PT0ib2JqZWN0Inx8dHlwZW9mIE09PSJmdW5jdGlvbiIpP006U2koRCl9ZnVuY3Rpb24gU2koRCl7aWYoRD09PXZvaWQgMCl0aHJvdyBuZXcgUmVmZXJlbmNlRXJyb3IoInRoaXMgaGFzbid0IGJlZW4gaW5pdGlhbGlzZWQgLSBzdXBlcigpIGhhc24ndCBiZWVuIGNhbGxlZCIpO3JldHVybiBEfWZ1bmN0aW9uIE9pKCl7aWYodHlwZW9mIFJlZmxlY3Q9PSJ1bmRlZmluZWQifHwhUmVmbGVjdC5jb25zdHJ1Y3R8fFJlZmxlY3QuY29uc3RydWN0LnNoYW0pcmV0dXJuITE7aWYodHlwZW9mIFByb3h5PT0iZnVuY3Rpb24iKXJldHVybiEwO3RyeXtyZXR1cm4gRGF0ZS5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChSZWZsZWN0LmNvbnN0cnVjdChEYXRlLFtdLGZ1bmN0aW9uKCl7fSkpLCEwfWNhdGNoKEQpe3JldHVybiExfX1mdW5jdGlvbiBQdChEKXtyZXR1cm4gUHQ9T2JqZWN0LnNldFByb3RvdHlwZU9mP09iamVjdC5nZXRQcm90b3R5cGVPZjpmdW5jdGlvbihPKXtyZXR1cm4gTy5fX3Byb3RvX198fE9iamVjdC5nZXRQcm90b3R5cGVPZihPKX0sUHQoRCl9ZnVuY3Rpb24gaHIoRCxNKXt2YXIgTz0iZGF0YS1jbGlwYm9hcmQtIi5jb25jYXQoRCk7aWYoTS5oYXNBdHRyaWJ1dGUoTykpcmV0dXJuIE0uZ2V0QXR0cmlidXRlKE8pfXZhciBNaT1mdW5jdGlvbihEKXtFaShPLEQpO3ZhciBNPXdpKE8pO2Z1bmN0aW9uIE8oSSxXKXt2YXIgSztyZXR1cm4geGkodGhpcyxPKSxLPU0uY2FsbCh0aGlzKSxLLnJlc29sdmVPcHRpb25zKFcpLEsubGlzdGVuQ2xpY2soSSksS31yZXR1cm4geWkoTyxbe2tleToicmVzb2x2ZU9wdGlvbnMiLHZhbHVlOmZ1bmN0aW9uKCl7dmFyIFc9YXJndW1lbnRzLmxlbmd0aD4wJiZhcmd1bWVudHNbMF0hPT12b2lkIDA/YXJndW1lbnRzWzBdOnt9O3RoaXMuYWN0aW9uPXR5cGVvZiBXLmFjdGlvbj09ImZ1bmN0aW9uIj9XLmFjdGlvbjp0aGlzLmRlZmF1bHRBY3Rpb24sdGhpcy50YXJnZXQ9dHlwZW9mIFcudGFyZ2V0PT0iZnVuY3Rpb24iP1cudGFyZ2V0OnRoaXMuZGVmYXVsdFRhcmdldCx0aGlzLnRleHQ9dHlwZW9mIFcudGV4dD09ImZ1bmN0aW9uIj9XLnRleHQ6dGhpcy5kZWZhdWx0VGV4dCx0aGlzLmNvbnRhaW5lcj1QZShXLmNvbnRhaW5lcik9PT0ib2JqZWN0Ij9XLmNvbnRhaW5lcjpkb2N1bWVudC5ib2R5fX0se2tleToibGlzdGVuQ2xpY2siLHZhbHVlOmZ1bmN0aW9uKFcpe3ZhciBLPXRoaXM7dGhpcy5saXN0ZW5lcj1wKCkoVywiY2xpY2siLGZ1bmN0aW9uKENlKXtyZXR1cm4gSy5vbkNsaWNrKENlKX0pfX0se2tleToib25DbGljayIsdmFsdWU6ZnVuY3Rpb24oVyl7dmFyIEs9Vy5kZWxlZ2F0ZVRhcmdldHx8Vy5jdXJyZW50VGFyZ2V0LENlPXRoaXMuYWN0aW9uKEspfHwiY29weSIsSXQ9TmUoe2FjdGlvbjpDZSxjb250YWluZXI6dGhpcy5jb250YWluZXIsdGFyZ2V0OnRoaXMudGFyZ2V0KEspLHRleHQ6dGhpcy50ZXh0KEspfSk7dGhpcy5lbWl0KEl0PyJzdWNjZXNzIjoiZXJyb3IiLHthY3Rpb246Q2UsdGV4dDpJdCx0cmlnZ2VyOkssY2xlYXJTZWxlY3Rpb246ZnVuY3Rpb24oKXtLJiZLLmZvY3VzKCksd2luZG93LmdldFNlbGVjdGlvbigpLnJlbW92ZUFsbFJhbmdlcygpfX0pfX0se2tleToiZGVmYXVsdEFjdGlvbiIsdmFsdWU6ZnVuY3Rpb24oVyl7cmV0dXJuIGhyKCJhY3Rpb24iLFcpfX0se2tleToiZGVmYXVsdFRhcmdldCIsdmFsdWU6ZnVuY3Rpb24oVyl7dmFyIEs9aHIoInRhcmdldCIsVyk7aWYoSylyZXR1cm4gZG9jdW1lbnQucXVlcnlTZWxlY3RvcihLKX19LHtrZXk6ImRlZmF1bHRUZXh0Iix2YWx1ZTpmdW5jdGlvbihXKXtyZXR1cm4gaHIoInRleHQiLFcpfX0se2tleToiZGVzdHJveSIsdmFsdWU6ZnVuY3Rpb24oKXt0aGlzLmxpc3RlbmVyLmRlc3Ryb3koKX19XSxbe2tleToiY29weSIsdmFsdWU6ZnVuY3Rpb24oVyl7dmFyIEs9YXJndW1lbnRzLmxlbmd0aD4xJiZhcmd1bWVudHNbMV0hPT12b2lkIDA/YXJndW1lbnRzWzFdOntjb250YWluZXI6ZG9jdW1lbnQuYm9keX07cmV0dXJuIEooVyxLKX19LHtrZXk6ImN1dCIsdmFsdWU6ZnVuY3Rpb24oVyl7cmV0dXJuIHcoVyl9fSx7a2V5OiJpc1N1cHBvcnRlZCIsdmFsdWU6ZnVuY3Rpb24oKXt2YXIgVz1hcmd1bWVudHMubGVuZ3RoPjAmJmFyZ3VtZW50c1swXSE9PXZvaWQgMD9hcmd1bWVudHNbMF06WyJjb3B5IiwiY3V0Il0sSz10eXBlb2YgVz09InN0cmluZyI/W1ddOlcsQ2U9ISFkb2N1bWVudC5xdWVyeUNvbW1hbmRTdXBwb3J0ZWQ7cmV0dXJuIEsuZm9yRWFjaChmdW5jdGlvbihJdCl7Q2U9Q2UmJiEhZG9jdW1lbnQucXVlcnlDb21tYW5kU3VwcG9ydGVkKEl0KX0pLENlfX1dKSxPfShhKCkpLExpPU1pfSw4Mjg6ZnVuY3Rpb24obyl7dmFyIG49OTtpZih0eXBlb2YgRWxlbWVudCE9InVuZGVmaW5lZCImJiFFbGVtZW50LnByb3RvdHlwZS5tYXRjaGVzKXt2YXIgaT1FbGVtZW50LnByb3RvdHlwZTtpLm1hdGNoZXM9aS5tYXRjaGVzU2VsZWN0b3J8fGkubW96TWF0Y2hlc1NlbGVjdG9yfHxpLm1zTWF0Y2hlc1NlbGVjdG9yfHxpLm9NYXRjaGVzU2VsZWN0b3J8fGkud2Via2l0TWF0Y2hlc1NlbGVjdG9yfWZ1bmN0aW9uIHMoYSxjKXtmb3IoO2EmJmEubm9kZVR5cGUhPT1uOyl7aWYodHlwZW9mIGEubWF0Y2hlcz09ImZ1bmN0aW9uIiYmYS5tYXRjaGVzKGMpKXJldHVybiBhO2E9YS5wYXJlbnROb2RlfX1vLmV4cG9ydHM9c30sNDM4OmZ1bmN0aW9uKG8sbixpKXt2YXIgcz1pKDgyOCk7ZnVuY3Rpb24gYShsLGYsdSxoLHcpe3ZhciBBPXAuYXBwbHkodGhpcyxhcmd1bWVudHMpO3JldHVybiBsLmFkZEV2ZW50TGlzdGVuZXIodSxBLHcpLHtkZXN0cm95OmZ1bmN0aW9uKCl7bC5yZW1vdmVFdmVudExpc3RlbmVyKHUsQSx3KX19fWZ1bmN0aW9uIGMobCxmLHUsaCx3KXtyZXR1cm4gdHlwZW9mIGwuYWRkRXZlbnRMaXN0ZW5lcj09ImZ1bmN0aW9uIj9hLmFwcGx5KG51bGwsYXJndW1lbnRzKTp0eXBlb2YgdT09ImZ1bmN0aW9uIj9hLmJpbmQobnVsbCxkb2N1bWVudCkuYXBwbHkobnVsbCxhcmd1bWVudHMpOih0eXBlb2YgbD09InN0cmluZyImJihsPWRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwobCkpLEFycmF5LnByb3RvdHlwZS5tYXAuY2FsbChsLGZ1bmN0aW9uKEEpe3JldHVybiBhKEEsZix1LGgsdyl9KSl9ZnVuY3Rpb24gcChsLGYsdSxoKXtyZXR1cm4gZnVuY3Rpb24odyl7dy5kZWxlZ2F0ZVRhcmdldD1zKHcudGFyZ2V0LGYpLHcuZGVsZWdhdGVUYXJnZXQmJmguY2FsbChsLHcpfX1vLmV4cG9ydHM9Y30sODc5OmZ1bmN0aW9uKG8sbil7bi5ub2RlPWZ1bmN0aW9uKGkpe3JldHVybiBpIT09dm9pZCAwJiZpIGluc3RhbmNlb2YgSFRNTEVsZW1lbnQmJmkubm9kZVR5cGU9PT0xfSxuLm5vZGVMaXN0PWZ1bmN0aW9uKGkpe3ZhciBzPU9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChpKTtyZXR1cm4gaSE9PXZvaWQgMCYmKHM9PT0iW29iamVjdCBOb2RlTGlzdF0ifHxzPT09IltvYmplY3QgSFRNTENvbGxlY3Rpb25dIikmJiJsZW5ndGgiaW4gaSYmKGkubGVuZ3RoPT09MHx8bi5ub2RlKGlbMF0pKX0sbi5zdHJpbmc9ZnVuY3Rpb24oaSl7cmV0dXJuIHR5cGVvZiBpPT0ic3RyaW5nInx8aSBpbnN0YW5jZW9mIFN0cmluZ30sbi5mbj1mdW5jdGlvbihpKXt2YXIgcz1PYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoaSk7cmV0dXJuIHM9PT0iW29iamVjdCBGdW5jdGlvbl0ifX0sMzcwOmZ1bmN0aW9uKG8sbixpKXt2YXIgcz1pKDg3OSksYT1pKDQzOCk7ZnVuY3Rpb24gYyh1LGgsdyl7aWYoIXUmJiFoJiYhdyl0aHJvdyBuZXcgRXJyb3IoIk1pc3NpbmcgcmVxdWlyZWQgYXJndW1lbnRzIik7aWYoIXMuc3RyaW5nKGgpKXRocm93IG5ldyBUeXBlRXJyb3IoIlNlY29uZCBhcmd1bWVudCBtdXN0IGJlIGEgU3RyaW5nIik7aWYoIXMuZm4odykpdGhyb3cgbmV3IFR5cGVFcnJvcigiVGhpcmQgYXJndW1lbnQgbXVzdCBiZSBhIEZ1bmN0aW9uIik7aWYocy5ub2RlKHUpKXJldHVybiBwKHUsaCx3KTtpZihzLm5vZGVMaXN0KHUpKXJldHVybiBsKHUsaCx3KTtpZihzLnN0cmluZyh1KSlyZXR1cm4gZih1LGgsdyk7dGhyb3cgbmV3IFR5cGVFcnJvcigiRmlyc3QgYXJndW1lbnQgbXVzdCBiZSBhIFN0cmluZywgSFRNTEVsZW1lbnQsIEhUTUxDb2xsZWN0aW9uLCBvciBOb2RlTGlzdCIpfWZ1bmN0aW9uIHAodSxoLHcpe3JldHVybiB1LmFkZEV2ZW50TGlzdGVuZXIoaCx3KSx7ZGVzdHJveTpmdW5jdGlvbigpe3UucmVtb3ZlRXZlbnRMaXN0ZW5lcihoLHcpfX19ZnVuY3Rpb24gbCh1LGgsdyl7cmV0dXJuIEFycmF5LnByb3RvdHlwZS5mb3JFYWNoLmNhbGwodSxmdW5jdGlvbihBKXtBLmFkZEV2ZW50TGlzdGVuZXIoaCx3KX0pLHtkZXN0cm95OmZ1bmN0aW9uKCl7QXJyYXkucHJvdG90eXBlLmZvckVhY2guY2FsbCh1LGZ1bmN0aW9uKEEpe0EucmVtb3ZlRXZlbnRMaXN0ZW5lcihoLHcpfSl9fX1mdW5jdGlvbiBmKHUsaCx3KXtyZXR1cm4gYShkb2N1bWVudC5ib2R5LHUsaCx3KX1vLmV4cG9ydHM9Y30sODE3OmZ1bmN0aW9uKG8pe2Z1bmN0aW9uIG4oaSl7dmFyIHM7aWYoaS5ub2RlTmFtZT09PSJTRUxFQ1QiKWkuZm9jdXMoKSxzPWkudmFsdWU7ZWxzZSBpZihpLm5vZGVOYW1lPT09IklOUFVUInx8aS5ub2RlTmFtZT09PSJURVhUQVJFQSIpe3ZhciBhPWkuaGFzQXR0cmlidXRlKCJyZWFkb25seSIpO2F8fGkuc2V0QXR0cmlidXRlKCJyZWFkb25seSIsIiIpLGkuc2VsZWN0KCksaS5zZXRTZWxlY3Rpb25SYW5nZSgwLGkudmFsdWUubGVuZ3RoKSxhfHxpLnJlbW92ZUF0dHJpYnV0ZSgicmVhZG9ubHkiKSxzPWkudmFsdWV9ZWxzZXtpLmhhc0F0dHJpYnV0ZSgiY29udGVudGVkaXRhYmxlIikmJmkuZm9jdXMoKTt2YXIgYz13aW5kb3cuZ2V0U2VsZWN0aW9uKCkscD1kb2N1bWVudC5jcmVhdGVSYW5nZSgpO3Auc2VsZWN0Tm9kZUNvbnRlbnRzKGkpLGMucmVtb3ZlQWxsUmFuZ2VzKCksYy5hZGRSYW5nZShwKSxzPWMudG9TdHJpbmcoKX1yZXR1cm4gc31vLmV4cG9ydHM9bn0sMjc5OmZ1bmN0aW9uKG8pe2Z1bmN0aW9uIG4oKXt9bi5wcm90b3R5cGU9e29uOmZ1bmN0aW9uKGkscyxhKXt2YXIgYz10aGlzLmV8fCh0aGlzLmU9e30pO3JldHVybihjW2ldfHwoY1tpXT1bXSkpLnB1c2goe2ZuOnMsY3R4OmF9KSx0aGlzfSxvbmNlOmZ1bmN0aW9uKGkscyxhKXt2YXIgYz10aGlzO2Z1bmN0aW9uIHAoKXtjLm9mZihpLHApLHMuYXBwbHkoYSxhcmd1bWVudHMpfXJldHVybiBwLl89cyx0aGlzLm9uKGkscCxhKX0sZW1pdDpmdW5jdGlvbihpKXt2YXIgcz1bXS5zbGljZS5jYWxsKGFyZ3VtZW50cywxKSxhPSgodGhpcy5lfHwodGhpcy5lPXt9KSlbaV18fFtdKS5zbGljZSgpLGM9MCxwPWEubGVuZ3RoO2ZvcihjO2M8cDtjKyspYVtjXS5mbi5hcHBseShhW2NdLmN0eCxzKTtyZXR1cm4gdGhpc30sb2ZmOmZ1bmN0aW9uKGkscyl7dmFyIGE9dGhpcy5lfHwodGhpcy5lPXt9KSxjPWFbaV0scD1bXTtpZihjJiZzKWZvcih2YXIgbD0wLGY9Yy5sZW5ndGg7bDxmO2wrKyljW2xdLmZuIT09cyYmY1tsXS5mbi5fIT09cyYmcC5wdXNoKGNbbF0pO3JldHVybiBwLmxlbmd0aD9hW2ldPXA6ZGVsZXRlIGFbaV0sdGhpc319LG8uZXhwb3J0cz1uLG8uZXhwb3J0cy5UaW55RW1pdHRlcj1ufX0sdD17fTtmdW5jdGlvbiByKG8pe2lmKHRbb10pcmV0dXJuIHRbb10uZXhwb3J0czt2YXIgbj10W29dPXtleHBvcnRzOnt9fTtyZXR1cm4gZVtvXShuLG4uZXhwb3J0cyxyKSxuLmV4cG9ydHN9cmV0dXJuIGZ1bmN0aW9uKCl7ci5uPWZ1bmN0aW9uKG8pe3ZhciBuPW8mJm8uX19lc01vZHVsZT9mdW5jdGlvbigpe3JldHVybiBvLmRlZmF1bHR9OmZ1bmN0aW9uKCl7cmV0dXJuIG99O3JldHVybiByLmQobix7YTpufSksbn19KCksZnVuY3Rpb24oKXtyLmQ9ZnVuY3Rpb24obyxuKXtmb3IodmFyIGkgaW4gbilyLm8obixpKSYmIXIubyhvLGkpJiZPYmplY3QuZGVmaW5lUHJvcGVydHkobyxpLHtlbnVtZXJhYmxlOiEwLGdldDpuW2ldfSl9fSgpLGZ1bmN0aW9uKCl7ci5vPWZ1bmN0aW9uKG8sbil7cmV0dXJuIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvLG4pfX0oKSxyKDY4Nil9KCkuZGVmYXVsdH0pfSk7dmFyIEtuPWdyKChDdyxxbik9PnsidXNlIHN0cmljdCI7LyohCiAqIGVzY2FwZS1odG1sCiAqIENvcHlyaWdodChjKSAyMDEyLTIwMTMgVEogSG9sb3dheWNodWsKICogQ29weXJpZ2h0KGMpIDIwMTUgQW5kcmVhcyBMdWJiZQogKiBDb3B5cmlnaHQoYykgMjAxNSBUaWFuY2hlbmcgIlRpbW90aHkiIEd1CiAqIE1JVCBMaWNlbnNlZAogKi92YXIgVmE9L1siJyY8Pl0vO3FuLmV4cG9ydHM9emE7ZnVuY3Rpb24gemEoZSl7dmFyIHQ9IiIrZSxyPVZhLmV4ZWModCk7aWYoIXIpcmV0dXJuIHQ7dmFyIG8sbj0iIixpPTAscz0wO2ZvcihpPXIuaW5kZXg7aTx0Lmxlbmd0aDtpKyspe3N3aXRjaCh0LmNoYXJDb2RlQXQoaSkpe2Nhc2UgMzQ6bz0iJnF1b3Q7IjticmVhaztjYXNlIDM4Om89IiZhbXA7IjticmVhaztjYXNlIDM5Om89IiYjMzk7IjticmVhaztjYXNlIDYwOm89IiZsdDsiO2JyZWFrO2Nhc2UgNjI6bz0iJmd0OyI7YnJlYWs7ZGVmYXVsdDpjb250aW51ZX1zIT09aSYmKG4rPXQuc3Vic3RyaW5nKHMsaSkpLHM9aSsxLG4rPW99cmV0dXJuIHMhPT1pP24rdC5zdWJzdHJpbmcocyxpKTpufX0pO3ZhciBtTT1qdChubygpKTsvKiEgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioKQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uCgpQZXJtaXNzaW9uIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBhbmQvb3IgZGlzdHJpYnV0ZSB0aGlzIHNvZnR3YXJlIGZvciBhbnkKcHVycG9zZSB3aXRoIG9yIHdpdGhvdXQgZmVlIGlzIGhlcmVieSBncmFudGVkLgoKVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEICJBUyBJUyIgQU5EIFRIRSBBVVRIT1IgRElTQ0xBSU1TIEFMTCBXQVJSQU5USUVTIFdJVEgKUkVHQVJEIFRPIFRISVMgU09GVFdBUkUgSU5DTFVESU5HIEFMTCBJTVBMSUVEIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZCkFORCBGSVRORVNTLiBJTiBOTyBFVkVOVCBTSEFMTCBUSEUgQVVUSE9SIEJFIExJQUJMRSBGT1IgQU5ZIFNQRUNJQUwsIERJUkVDVCwKSU5ESVJFQ1QsIE9SIENPTlNFUVVFTlRJQUwgREFNQUdFUyBPUiBBTlkgREFNQUdFUyBXSEFUU09FVkVSIFJFU1VMVElORyBGUk9NCkxPU1MgT0YgVVNFLCBEQVRBIE9SIFBST0ZJVFMsIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBORUdMSUdFTkNFIE9SCk9USEVSIFRPUlRJT1VTIEFDVElPTiwgQVJJU0lORyBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBVU0UgT1IKUEVSRk9STUFOQ0UgT0YgVEhJUyBTT0ZUV0FSRS4KKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiogKi92YXIgeXI9ZnVuY3Rpb24oZSx0KXtyZXR1cm4geXI9T2JqZWN0LnNldFByb3RvdHlwZU9mfHx7X19wcm90b19fOltdfWluc3RhbmNlb2YgQXJyYXkmJmZ1bmN0aW9uKHIsbyl7ci5fX3Byb3RvX189b318fGZ1bmN0aW9uKHIsbyl7Zm9yKHZhciBuIGluIG8pT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG8sbikmJihyW25dPW9bbl0pfSx5cihlLHQpfTtmdW5jdGlvbiBzZShlLHQpe2lmKHR5cGVvZiB0IT0iZnVuY3Rpb24iJiZ0IT09bnVsbCl0aHJvdyBuZXcgVHlwZUVycm9yKCJDbGFzcyBleHRlbmRzIHZhbHVlICIrU3RyaW5nKHQpKyIgaXMgbm90IGEgY29uc3RydWN0b3Igb3IgbnVsbCIpO3lyKGUsdCk7ZnVuY3Rpb24gcigpe3RoaXMuY29uc3RydWN0b3I9ZX1lLnByb3RvdHlwZT10PT09bnVsbD9PYmplY3QuY3JlYXRlKHQpOihyLnByb3RvdHlwZT10LnByb3RvdHlwZSxuZXcgcil9ZnVuY3Rpb24gaW8oZSx0LHIsbyl7ZnVuY3Rpb24gbihpKXtyZXR1cm4gaSBpbnN0YW5jZW9mIHI/aTpuZXcgcihmdW5jdGlvbihzKXtzKGkpfSl9cmV0dXJuIG5ldyhyfHwocj1Qcm9taXNlKSkoZnVuY3Rpb24oaSxzKXtmdW5jdGlvbiBhKGwpe3RyeXtwKG8ubmV4dChsKSl9Y2F0Y2goZil7cyhmKX19ZnVuY3Rpb24gYyhsKXt0cnl7cChvLnRocm93KGwpKX1jYXRjaChmKXtzKGYpfX1mdW5jdGlvbiBwKGwpe2wuZG9uZT9pKGwudmFsdWUpOm4obC52YWx1ZSkudGhlbihhLGMpfXAoKG89by5hcHBseShlLHR8fFtdKSkubmV4dCgpKX0pfWZ1bmN0aW9uIFV0KGUsdCl7dmFyIHI9e2xhYmVsOjAsc2VudDpmdW5jdGlvbigpe2lmKGlbMF0mMSl0aHJvdyBpWzFdO3JldHVybiBpWzFdfSx0cnlzOltdLG9wczpbXX0sbyxuLGkscztyZXR1cm4gcz17bmV4dDphKDApLHRocm93OmEoMSkscmV0dXJuOmEoMil9LHR5cGVvZiBTeW1ib2w9PSJmdW5jdGlvbiImJihzW1N5bWJvbC5pdGVyYXRvcl09ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc30pLHM7ZnVuY3Rpb24gYShwKXtyZXR1cm4gZnVuY3Rpb24obCl7cmV0dXJuIGMoW3AsbF0pfX1mdW5jdGlvbiBjKHApe2lmKG8pdGhyb3cgbmV3IFR5cGVFcnJvcigiR2VuZXJhdG9yIGlzIGFscmVhZHkgZXhlY3V0aW5nLiIpO2Zvcig7cjspdHJ5e2lmKG89MSxuJiYoaT1wWzBdJjI/bi5yZXR1cm46cFswXT9uLnRocm93fHwoKGk9bi5yZXR1cm4pJiZpLmNhbGwobiksMCk6bi5uZXh0KSYmIShpPWkuY2FsbChuLHBbMV0pKS5kb25lKXJldHVybiBpO3N3aXRjaChuPTAsaSYmKHA9W3BbMF0mMixpLnZhbHVlXSkscFswXSl7Y2FzZSAwOmNhc2UgMTppPXA7YnJlYWs7Y2FzZSA0OnJldHVybiByLmxhYmVsKysse3ZhbHVlOnBbMV0sZG9uZTohMX07Y2FzZSA1OnIubGFiZWwrKyxuPXBbMV0scD1bMF07Y29udGludWU7Y2FzZSA3OnA9ci5vcHMucG9wKCksci50cnlzLnBvcCgpO2NvbnRpbnVlO2RlZmF1bHQ6aWYoaT1yLnRyeXMsIShpPWkubGVuZ3RoPjAmJmlbaS5sZW5ndGgtMV0pJiYocFswXT09PTZ8fHBbMF09PT0yKSl7cj0wO2NvbnRpbnVlfWlmKHBbMF09PT0zJiYoIWl8fHBbMV0+aVswXSYmcFsxXTxpWzNdKSl7ci5sYWJlbD1wWzFdO2JyZWFrfWlmKHBbMF09PT02JiZyLmxhYmVsPGlbMV0pe3IubGFiZWw9aVsxXSxpPXA7YnJlYWt9aWYoaSYmci5sYWJlbDxpWzJdKXtyLmxhYmVsPWlbMl0sci5vcHMucHVzaChwKTticmVha31pWzJdJiZyLm9wcy5wb3AoKSxyLnRyeXMucG9wKCk7Y29udGludWV9cD10LmNhbGwoZSxyKX1jYXRjaChsKXtwPVs2LGxdLG49MH1maW5hbGx5e289aT0wfWlmKHBbMF0mNSl0aHJvdyBwWzFdO3JldHVybnt2YWx1ZTpwWzBdP3BbMV06dm9pZCAwLGRvbmU6ITB9fX1mdW5jdGlvbiB1ZShlKXt2YXIgdD10eXBlb2YgU3ltYm9sPT0iZnVuY3Rpb24iJiZTeW1ib2wuaXRlcmF0b3Iscj10JiZlW3RdLG89MDtpZihyKXJldHVybiByLmNhbGwoZSk7aWYoZSYmdHlwZW9mIGUubGVuZ3RoPT0ibnVtYmVyIilyZXR1cm57bmV4dDpmdW5jdGlvbigpe3JldHVybiBlJiZvPj1lLmxlbmd0aCYmKGU9dm9pZCAwKSx7dmFsdWU6ZSYmZVtvKytdLGRvbmU6IWV9fX07dGhyb3cgbmV3IFR5cGVFcnJvcih0PyJPYmplY3QgaXMgbm90IGl0ZXJhYmxlLiI6IlN5bWJvbC5pdGVyYXRvciBpcyBub3QgZGVmaW5lZC4iKX1mdW5jdGlvbiBWKGUsdCl7dmFyIHI9dHlwZW9mIFN5bWJvbD09ImZ1bmN0aW9uIiYmZVtTeW1ib2wuaXRlcmF0b3JdO2lmKCFyKXJldHVybiBlO3ZhciBvPXIuY2FsbChlKSxuLGk9W10sczt0cnl7Zm9yKDsodD09PXZvaWQgMHx8dC0tID4wKSYmIShuPW8ubmV4dCgpKS5kb25lOylpLnB1c2gobi52YWx1ZSl9Y2F0Y2goYSl7cz17ZXJyb3I6YX19ZmluYWxseXt0cnl7biYmIW4uZG9uZSYmKHI9by5yZXR1cm4pJiZyLmNhbGwobyl9ZmluYWxseXtpZihzKXRocm93IHMuZXJyb3J9fXJldHVybiBpfWZ1bmN0aW9uIHooZSx0LHIpe2lmKHJ8fGFyZ3VtZW50cy5sZW5ndGg9PT0yKWZvcih2YXIgbz0wLG49dC5sZW5ndGgsaTtvPG47bysrKShpfHwhKG8gaW4gdCkpJiYoaXx8KGk9QXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwodCwwLG8pKSxpW29dPXRbb10pO3JldHVybiBlLmNvbmNhdChpfHxBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbCh0KSl9ZnVuY3Rpb24gb3QoZSl7cmV0dXJuIHRoaXMgaW5zdGFuY2VvZiBvdD8odGhpcy52PWUsdGhpcyk6bmV3IG90KGUpfWZ1bmN0aW9uIGFvKGUsdCxyKXtpZighU3ltYm9sLmFzeW5jSXRlcmF0b3IpdGhyb3cgbmV3IFR5cGVFcnJvcigiU3ltYm9sLmFzeW5jSXRlcmF0b3IgaXMgbm90IGRlZmluZWQuIik7dmFyIG89ci5hcHBseShlLHR8fFtdKSxuLGk9W107cmV0dXJuIG49e30scygibmV4dCIpLHMoInRocm93IikscygicmV0dXJuIiksbltTeW1ib2wuYXN5bmNJdGVyYXRvcl09ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc30sbjtmdW5jdGlvbiBzKHUpe29bdV0mJihuW3VdPWZ1bmN0aW9uKGgpe3JldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbih3LEEpe2kucHVzaChbdSxoLHcsQV0pPjF8fGEodSxoKX0pfSl9ZnVuY3Rpb24gYSh1LGgpe3RyeXtjKG9bdV0oaCkpfWNhdGNoKHcpe2YoaVswXVszXSx3KX19ZnVuY3Rpb24gYyh1KXt1LnZhbHVlIGluc3RhbmNlb2Ygb3Q/UHJvbWlzZS5yZXNvbHZlKHUudmFsdWUudikudGhlbihwLGwpOmYoaVswXVsyXSx1KX1mdW5jdGlvbiBwKHUpe2EoIm5leHQiLHUpfWZ1bmN0aW9uIGwodSl7YSgidGhyb3ciLHUpfWZ1bmN0aW9uIGYodSxoKXt1KGgpLGkuc2hpZnQoKSxpLmxlbmd0aCYmYShpWzBdWzBdLGlbMF1bMV0pfX1mdW5jdGlvbiBzbyhlKXtpZighU3ltYm9sLmFzeW5jSXRlcmF0b3IpdGhyb3cgbmV3IFR5cGVFcnJvcigiU3ltYm9sLmFzeW5jSXRlcmF0b3IgaXMgbm90IGRlZmluZWQuIik7dmFyIHQ9ZVtTeW1ib2wuYXN5bmNJdGVyYXRvcl0scjtyZXR1cm4gdD90LmNhbGwoZSk6KGU9dHlwZW9mIHVlPT0iZnVuY3Rpb24iP3VlKGUpOmVbU3ltYm9sLml0ZXJhdG9yXSgpLHI9e30sbygibmV4dCIpLG8oInRocm93IiksbygicmV0dXJuIikscltTeW1ib2wuYXN5bmNJdGVyYXRvcl09ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc30scik7ZnVuY3Rpb24gbyhpKXtyW2ldPWVbaV0mJmZ1bmN0aW9uKHMpe3JldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihhLGMpe3M9ZVtpXShzKSxuKGEsYyxzLmRvbmUscy52YWx1ZSl9KX19ZnVuY3Rpb24gbihpLHMsYSxjKXtQcm9taXNlLnJlc29sdmUoYykudGhlbihmdW5jdGlvbihwKXtpKHt2YWx1ZTpwLGRvbmU6YX0pfSxzKX19ZnVuY3Rpb24gayhlKXtyZXR1cm4gdHlwZW9mIGU9PSJmdW5jdGlvbiJ9ZnVuY3Rpb24gcHQoZSl7dmFyIHQ9ZnVuY3Rpb24obyl7RXJyb3IuY2FsbChvKSxvLnN0YWNrPW5ldyBFcnJvcigpLnN0YWNrfSxyPWUodCk7cmV0dXJuIHIucHJvdG90eXBlPU9iamVjdC5jcmVhdGUoRXJyb3IucHJvdG90eXBlKSxyLnByb3RvdHlwZS5jb25zdHJ1Y3Rvcj1yLHJ9dmFyIFd0PXB0KGZ1bmN0aW9uKGUpe3JldHVybiBmdW5jdGlvbihyKXtlKHRoaXMpLHRoaXMubWVzc2FnZT1yP3IubGVuZ3RoK2AgZXJyb3JzIG9jY3VycmVkIGR1cmluZyB1bnN1YnNjcmlwdGlvbjoKYCtyLm1hcChmdW5jdGlvbihvLG4pe3JldHVybiBuKzErIikgIitvLnRvU3RyaW5nKCl9KS5qb2luKGAKICBgKToiIix0aGlzLm5hbWU9IlVuc3Vic2NyaXB0aW9uRXJyb3IiLHRoaXMuZXJyb3JzPXJ9fSk7ZnVuY3Rpb24gVmUoZSx0KXtpZihlKXt2YXIgcj1lLmluZGV4T2YodCk7MDw9ciYmZS5zcGxpY2UociwxKX19dmFyIEllPWZ1bmN0aW9uKCl7ZnVuY3Rpb24gZSh0KXt0aGlzLmluaXRpYWxUZWFyZG93bj10LHRoaXMuY2xvc2VkPSExLHRoaXMuX3BhcmVudGFnZT1udWxsLHRoaXMuX2ZpbmFsaXplcnM9bnVsbH1yZXR1cm4gZS5wcm90b3R5cGUudW5zdWJzY3JpYmU9ZnVuY3Rpb24oKXt2YXIgdCxyLG8sbixpO2lmKCF0aGlzLmNsb3NlZCl7dGhpcy5jbG9zZWQ9ITA7dmFyIHM9dGhpcy5fcGFyZW50YWdlO2lmKHMpaWYodGhpcy5fcGFyZW50YWdlPW51bGwsQXJyYXkuaXNBcnJheShzKSl0cnl7Zm9yKHZhciBhPXVlKHMpLGM9YS5uZXh0KCk7IWMuZG9uZTtjPWEubmV4dCgpKXt2YXIgcD1jLnZhbHVlO3AucmVtb3ZlKHRoaXMpfX1jYXRjaChBKXt0PXtlcnJvcjpBfX1maW5hbGx5e3RyeXtjJiYhYy5kb25lJiYocj1hLnJldHVybikmJnIuY2FsbChhKX1maW5hbGx5e2lmKHQpdGhyb3cgdC5lcnJvcn19ZWxzZSBzLnJlbW92ZSh0aGlzKTt2YXIgbD10aGlzLmluaXRpYWxUZWFyZG93bjtpZihrKGwpKXRyeXtsKCl9Y2F0Y2goQSl7aT1BIGluc3RhbmNlb2YgV3Q/QS5lcnJvcnM6W0FdfXZhciBmPXRoaXMuX2ZpbmFsaXplcnM7aWYoZil7dGhpcy5fZmluYWxpemVycz1udWxsO3RyeXtmb3IodmFyIHU9dWUoZiksaD11Lm5leHQoKTshaC5kb25lO2g9dS5uZXh0KCkpe3ZhciB3PWgudmFsdWU7dHJ5e2NvKHcpfWNhdGNoKEEpe2k9aSE9bnVsbD9pOltdLEEgaW5zdGFuY2VvZiBXdD9pPXooeihbXSxWKGkpKSxWKEEuZXJyb3JzKSk6aS5wdXNoKEEpfX19Y2F0Y2goQSl7bz17ZXJyb3I6QX19ZmluYWxseXt0cnl7aCYmIWguZG9uZSYmKG49dS5yZXR1cm4pJiZuLmNhbGwodSl9ZmluYWxseXtpZihvKXRocm93IG8uZXJyb3J9fX1pZihpKXRocm93IG5ldyBXdChpKX19LGUucHJvdG90eXBlLmFkZD1mdW5jdGlvbih0KXt2YXIgcjtpZih0JiZ0IT09dGhpcylpZih0aGlzLmNsb3NlZCljbyh0KTtlbHNle2lmKHQgaW5zdGFuY2VvZiBlKXtpZih0LmNsb3NlZHx8dC5faGFzUGFyZW50KHRoaXMpKXJldHVybjt0Ll9hZGRQYXJlbnQodGhpcyl9KHRoaXMuX2ZpbmFsaXplcnM9KHI9dGhpcy5fZmluYWxpemVycykhPT1udWxsJiZyIT09dm9pZCAwP3I6W10pLnB1c2godCl9fSxlLnByb3RvdHlwZS5faGFzUGFyZW50PWZ1bmN0aW9uKHQpe3ZhciByPXRoaXMuX3BhcmVudGFnZTtyZXR1cm4gcj09PXR8fEFycmF5LmlzQXJyYXkocikmJnIuaW5jbHVkZXModCl9LGUucHJvdG90eXBlLl9hZGRQYXJlbnQ9ZnVuY3Rpb24odCl7dmFyIHI9dGhpcy5fcGFyZW50YWdlO3RoaXMuX3BhcmVudGFnZT1BcnJheS5pc0FycmF5KHIpPyhyLnB1c2godCkscik6cj9bcix0XTp0fSxlLnByb3RvdHlwZS5fcmVtb3ZlUGFyZW50PWZ1bmN0aW9uKHQpe3ZhciByPXRoaXMuX3BhcmVudGFnZTtyPT09dD90aGlzLl9wYXJlbnRhZ2U9bnVsbDpBcnJheS5pc0FycmF5KHIpJiZWZShyLHQpfSxlLnByb3RvdHlwZS5yZW1vdmU9ZnVuY3Rpb24odCl7dmFyIHI9dGhpcy5fZmluYWxpemVycztyJiZWZShyLHQpLHQgaW5zdGFuY2VvZiBlJiZ0Ll9yZW1vdmVQYXJlbnQodGhpcyl9LGUuRU1QVFk9ZnVuY3Rpb24oKXt2YXIgdD1uZXcgZTtyZXR1cm4gdC5jbG9zZWQ9ITAsdH0oKSxlfSgpO3ZhciBFcj1JZS5FTVBUWTtmdW5jdGlvbiBEdChlKXtyZXR1cm4gZSBpbnN0YW5jZW9mIEllfHxlJiYiY2xvc2VkImluIGUmJmsoZS5yZW1vdmUpJiZrKGUuYWRkKSYmayhlLnVuc3Vic2NyaWJlKX1mdW5jdGlvbiBjbyhlKXtrKGUpP2UoKTplLnVuc3Vic2NyaWJlKCl9dmFyIGtlPXtvblVuaGFuZGxlZEVycm9yOm51bGwsb25TdG9wcGVkTm90aWZpY2F0aW9uOm51bGwsUHJvbWlzZTp2b2lkIDAsdXNlRGVwcmVjYXRlZFN5bmNocm9ub3VzRXJyb3JIYW5kbGluZzohMSx1c2VEZXByZWNhdGVkTmV4dENvbnRleHQ6ITF9O3ZhciBsdD17c2V0VGltZW91dDpmdW5jdGlvbihlLHQpe2Zvcih2YXIgcj1bXSxvPTI7bzxhcmd1bWVudHMubGVuZ3RoO28rKylyW28tMl09YXJndW1lbnRzW29dO3ZhciBuPWx0LmRlbGVnYXRlO3JldHVybiBuIT1udWxsJiZuLnNldFRpbWVvdXQ/bi5zZXRUaW1lb3V0LmFwcGx5KG4seihbZSx0XSxWKHIpKSk6c2V0VGltZW91dC5hcHBseSh2b2lkIDAseihbZSx0XSxWKHIpKSl9LGNsZWFyVGltZW91dDpmdW5jdGlvbihlKXt2YXIgdD1sdC5kZWxlZ2F0ZTtyZXR1cm4oKHQ9PW51bGw/dm9pZCAwOnQuY2xlYXJUaW1lb3V0KXx8Y2xlYXJUaW1lb3V0KShlKX0sZGVsZWdhdGU6dm9pZCAwfTtmdW5jdGlvbiBOdChlKXtsdC5zZXRUaW1lb3V0KGZ1bmN0aW9uKCl7dmFyIHQ9a2Uub25VbmhhbmRsZWRFcnJvcjtpZih0KXQoZSk7ZWxzZSB0aHJvdyBlfSl9ZnVuY3Rpb24gU2UoKXt9dmFyIHBvPWZ1bmN0aW9uKCl7cmV0dXJuIHdyKCJDIix2b2lkIDAsdm9pZCAwKX0oKTtmdW5jdGlvbiBsbyhlKXtyZXR1cm4gd3IoIkUiLHZvaWQgMCxlKX1mdW5jdGlvbiBtbyhlKXtyZXR1cm4gd3IoIk4iLGUsdm9pZCAwKX1mdW5jdGlvbiB3cihlLHQscil7cmV0dXJue2tpbmQ6ZSx2YWx1ZTp0LGVycm9yOnJ9fXZhciBudD1udWxsO2Z1bmN0aW9uIG10KGUpe2lmKGtlLnVzZURlcHJlY2F0ZWRTeW5jaHJvbm91c0Vycm9ySGFuZGxpbmcpe3ZhciB0PSFudDtpZih0JiYobnQ9e2Vycm9yVGhyb3duOiExLGVycm9yOm51bGx9KSxlKCksdCl7dmFyIHI9bnQsbz1yLmVycm9yVGhyb3duLG49ci5lcnJvcjtpZihudD1udWxsLG8pdGhyb3cgbn19ZWxzZSBlKCl9ZnVuY3Rpb24gZm8oZSl7a2UudXNlRGVwcmVjYXRlZFN5bmNocm9ub3VzRXJyb3JIYW5kbGluZyYmbnQmJihudC5lcnJvclRocm93bj0hMCxudC5lcnJvcj1lKX12YXIgVHQ9ZnVuY3Rpb24oZSl7c2UodCxlKTtmdW5jdGlvbiB0KHIpe3ZhciBvPWUuY2FsbCh0aGlzKXx8dGhpcztyZXR1cm4gby5pc1N0b3BwZWQ9ITEscj8oby5kZXN0aW5hdGlvbj1yLER0KHIpJiZyLmFkZChvKSk6by5kZXN0aW5hdGlvbj1JaSxvfXJldHVybiB0LmNyZWF0ZT1mdW5jdGlvbihyLG8sbil7cmV0dXJuIG5ldyBpdChyLG8sbil9LHQucHJvdG90eXBlLm5leHQ9ZnVuY3Rpb24ocil7dGhpcy5pc1N0b3BwZWQ/U3IobW8ociksdGhpcyk6dGhpcy5fbmV4dChyKX0sdC5wcm90b3R5cGUuZXJyb3I9ZnVuY3Rpb24ocil7dGhpcy5pc1N0b3BwZWQ/U3IobG8ociksdGhpcyk6KHRoaXMuaXNTdG9wcGVkPSEwLHRoaXMuX2Vycm9yKHIpKX0sdC5wcm90b3R5cGUuY29tcGxldGU9ZnVuY3Rpb24oKXt0aGlzLmlzU3RvcHBlZD9Tcihwbyx0aGlzKToodGhpcy5pc1N0b3BwZWQ9ITAsdGhpcy5fY29tcGxldGUoKSl9LHQucHJvdG90eXBlLnVuc3Vic2NyaWJlPWZ1bmN0aW9uKCl7dGhpcy5jbG9zZWR8fCh0aGlzLmlzU3RvcHBlZD0hMCxlLnByb3RvdHlwZS51bnN1YnNjcmliZS5jYWxsKHRoaXMpLHRoaXMuZGVzdGluYXRpb249bnVsbCl9LHQucHJvdG90eXBlLl9uZXh0PWZ1bmN0aW9uKHIpe3RoaXMuZGVzdGluYXRpb24ubmV4dChyKX0sdC5wcm90b3R5cGUuX2Vycm9yPWZ1bmN0aW9uKHIpe3RyeXt0aGlzLmRlc3RpbmF0aW9uLmVycm9yKHIpfWZpbmFsbHl7dGhpcy51bnN1YnNjcmliZSgpfX0sdC5wcm90b3R5cGUuX2NvbXBsZXRlPWZ1bmN0aW9uKCl7dHJ5e3RoaXMuZGVzdGluYXRpb24uY29tcGxldGUoKX1maW5hbGx5e3RoaXMudW5zdWJzY3JpYmUoKX19LHR9KEllKTt2YXIgJGk9RnVuY3Rpb24ucHJvdG90eXBlLmJpbmQ7ZnVuY3Rpb24gVHIoZSx0KXtyZXR1cm4gJGkuY2FsbChlLHQpfXZhciBSaT1mdW5jdGlvbigpe2Z1bmN0aW9uIGUodCl7dGhpcy5wYXJ0aWFsT2JzZXJ2ZXI9dH1yZXR1cm4gZS5wcm90b3R5cGUubmV4dD1mdW5jdGlvbih0KXt2YXIgcj10aGlzLnBhcnRpYWxPYnNlcnZlcjtpZihyLm5leHQpdHJ5e3IubmV4dCh0KX1jYXRjaChvKXtWdChvKX19LGUucHJvdG90eXBlLmVycm9yPWZ1bmN0aW9uKHQpe3ZhciByPXRoaXMucGFydGlhbE9ic2VydmVyO2lmKHIuZXJyb3IpdHJ5e3IuZXJyb3IodCl9Y2F0Y2gobyl7VnQobyl9ZWxzZSBWdCh0KX0sZS5wcm90b3R5cGUuY29tcGxldGU9ZnVuY3Rpb24oKXt2YXIgdD10aGlzLnBhcnRpYWxPYnNlcnZlcjtpZih0LmNvbXBsZXRlKXRyeXt0LmNvbXBsZXRlKCl9Y2F0Y2gocil7VnQocil9fSxlfSgpLGl0PWZ1bmN0aW9uKGUpe3NlKHQsZSk7ZnVuY3Rpb24gdChyLG8sbil7dmFyIGk9ZS5jYWxsKHRoaXMpfHx0aGlzLHM7aWYoayhyKXx8IXIpcz17bmV4dDpyIT1udWxsP3I6dm9pZCAwLGVycm9yOm8hPW51bGw/bzp2b2lkIDAsY29tcGxldGU6biE9bnVsbD9uOnZvaWQgMH07ZWxzZXt2YXIgYTtpJiZrZS51c2VEZXByZWNhdGVkTmV4dENvbnRleHQ/KGE9T2JqZWN0LmNyZWF0ZShyKSxhLnVuc3Vic2NyaWJlPWZ1bmN0aW9uKCl7cmV0dXJuIGkudW5zdWJzY3JpYmUoKX0scz17bmV4dDpyLm5leHQmJlRyKHIubmV4dCxhKSxlcnJvcjpyLmVycm9yJiZUcihyLmVycm9yLGEpLGNvbXBsZXRlOnIuY29tcGxldGUmJlRyKHIuY29tcGxldGUsYSl9KTpzPXJ9cmV0dXJuIGkuZGVzdGluYXRpb249bmV3IFJpKHMpLGl9cmV0dXJuIHR9KFR0KTtmdW5jdGlvbiBWdChlKXtrZS51c2VEZXByZWNhdGVkU3luY2hyb25vdXNFcnJvckhhbmRsaW5nP2ZvKGUpOk50KGUpfWZ1bmN0aW9uIFBpKGUpe3Rocm93IGV9ZnVuY3Rpb24gU3IoZSx0KXt2YXIgcj1rZS5vblN0b3BwZWROb3RpZmljYXRpb247ciYmbHQuc2V0VGltZW91dChmdW5jdGlvbigpe3JldHVybiByKGUsdCl9KX12YXIgSWk9e2Nsb3NlZDohMCxuZXh0OlNlLGVycm9yOlBpLGNvbXBsZXRlOlNlfTt2YXIgZnQ9ZnVuY3Rpb24oKXtyZXR1cm4gdHlwZW9mIFN5bWJvbD09ImZ1bmN0aW9uIiYmU3ltYm9sLm9ic2VydmFibGV8fCJAQG9ic2VydmFibGUifSgpO2Z1bmN0aW9uIGNlKGUpe3JldHVybiBlfWZ1bmN0aW9uIHVvKCl7Zm9yKHZhciBlPVtdLHQ9MDt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKWVbdF09YXJndW1lbnRzW3RdO3JldHVybiBPcihlKX1mdW5jdGlvbiBPcihlKXtyZXR1cm4gZS5sZW5ndGg9PT0wP2NlOmUubGVuZ3RoPT09MT9lWzBdOmZ1bmN0aW9uKHIpe3JldHVybiBlLnJlZHVjZShmdW5jdGlvbihvLG4pe3JldHVybiBuKG8pfSxyKX19dmFyIGo9ZnVuY3Rpb24oKXtmdW5jdGlvbiBlKHQpe3QmJih0aGlzLl9zdWJzY3JpYmU9dCl9cmV0dXJuIGUucHJvdG90eXBlLmxpZnQ9ZnVuY3Rpb24odCl7dmFyIHI9bmV3IGU7cmV0dXJuIHIuc291cmNlPXRoaXMsci5vcGVyYXRvcj10LHJ9LGUucHJvdG90eXBlLnN1YnNjcmliZT1mdW5jdGlvbih0LHIsbyl7dmFyIG49dGhpcyxpPWppKHQpP3Q6bmV3IGl0KHQscixvKTtyZXR1cm4gbXQoZnVuY3Rpb24oKXt2YXIgcz1uLGE9cy5vcGVyYXRvcixjPXMuc291cmNlO2kuYWRkKGE/YS5jYWxsKGksYyk6Yz9uLl9zdWJzY3JpYmUoaSk6bi5fdHJ5U3Vic2NyaWJlKGkpKX0pLGl9LGUucHJvdG90eXBlLl90cnlTdWJzY3JpYmU9ZnVuY3Rpb24odCl7dHJ5e3JldHVybiB0aGlzLl9zdWJzY3JpYmUodCl9Y2F0Y2gocil7dC5lcnJvcihyKX19LGUucHJvdG90eXBlLmZvckVhY2g9ZnVuY3Rpb24odCxyKXt2YXIgbz10aGlzO3JldHVybiByPWhvKHIpLG5ldyByKGZ1bmN0aW9uKG4saSl7dmFyIHM9bmV3IGl0KHtuZXh0OmZ1bmN0aW9uKGEpe3RyeXt0KGEpfWNhdGNoKGMpe2koYykscy51bnN1YnNjcmliZSgpfX0sZXJyb3I6aSxjb21wbGV0ZTpufSk7by5zdWJzY3JpYmUocyl9KX0sZS5wcm90b3R5cGUuX3N1YnNjcmliZT1mdW5jdGlvbih0KXt2YXIgcjtyZXR1cm4ocj10aGlzLnNvdXJjZSk9PT1udWxsfHxyPT09dm9pZCAwP3ZvaWQgMDpyLnN1YnNjcmliZSh0KX0sZS5wcm90b3R5cGVbZnRdPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXN9LGUucHJvdG90eXBlLnBpcGU9ZnVuY3Rpb24oKXtmb3IodmFyIHQ9W10scj0wO3I8YXJndW1lbnRzLmxlbmd0aDtyKyspdFtyXT1hcmd1bWVudHNbcl07cmV0dXJuIE9yKHQpKHRoaXMpfSxlLnByb3RvdHlwZS50b1Byb21pc2U9ZnVuY3Rpb24odCl7dmFyIHI9dGhpcztyZXR1cm4gdD1obyh0KSxuZXcgdChmdW5jdGlvbihvLG4pe3ZhciBpO3Iuc3Vic2NyaWJlKGZ1bmN0aW9uKHMpe3JldHVybiBpPXN9LGZ1bmN0aW9uKHMpe3JldHVybiBuKHMpfSxmdW5jdGlvbigpe3JldHVybiBvKGkpfSl9KX0sZS5jcmVhdGU9ZnVuY3Rpb24odCl7cmV0dXJuIG5ldyBlKHQpfSxlfSgpO2Z1bmN0aW9uIGhvKGUpe3ZhciB0O3JldHVybih0PWUhPW51bGw/ZTprZS5Qcm9taXNlKSE9PW51bGwmJnQhPT12b2lkIDA/dDpQcm9taXNlfWZ1bmN0aW9uIEZpKGUpe3JldHVybiBlJiZrKGUubmV4dCkmJmsoZS5lcnJvcikmJmsoZS5jb21wbGV0ZSl9ZnVuY3Rpb24gamkoZSl7cmV0dXJuIGUmJmUgaW5zdGFuY2VvZiBUdHx8RmkoZSkmJkR0KGUpfWZ1bmN0aW9uIFVpKGUpe3JldHVybiBrKGU9PW51bGw/dm9pZCAwOmUubGlmdCl9ZnVuY3Rpb24geChlKXtyZXR1cm4gZnVuY3Rpb24odCl7aWYoVWkodCkpcmV0dXJuIHQubGlmdChmdW5jdGlvbihyKXt0cnl7cmV0dXJuIGUocix0aGlzKX1jYXRjaChvKXt0aGlzLmVycm9yKG8pfX0pO3Rocm93IG5ldyBUeXBlRXJyb3IoIlVuYWJsZSB0byBsaWZ0IHVua25vd24gT2JzZXJ2YWJsZSB0eXBlIil9fWZ1bmN0aW9uIFMoZSx0LHIsbyxuKXtyZXR1cm4gbmV3IFdpKGUsdCxyLG8sbil9dmFyIFdpPWZ1bmN0aW9uKGUpe3NlKHQsZSk7ZnVuY3Rpb24gdChyLG8sbixpLHMsYSl7dmFyIGM9ZS5jYWxsKHRoaXMscil8fHRoaXM7cmV0dXJuIGMub25GaW5hbGl6ZT1zLGMuc2hvdWxkVW5zdWJzY3JpYmU9YSxjLl9uZXh0PW8/ZnVuY3Rpb24ocCl7dHJ5e28ocCl9Y2F0Y2gobCl7ci5lcnJvcihsKX19OmUucHJvdG90eXBlLl9uZXh0LGMuX2Vycm9yPWk/ZnVuY3Rpb24ocCl7dHJ5e2kocCl9Y2F0Y2gobCl7ci5lcnJvcihsKX1maW5hbGx5e3RoaXMudW5zdWJzY3JpYmUoKX19OmUucHJvdG90eXBlLl9lcnJvcixjLl9jb21wbGV0ZT1uP2Z1bmN0aW9uKCl7dHJ5e24oKX1jYXRjaChwKXtyLmVycm9yKHApfWZpbmFsbHl7dGhpcy51bnN1YnNjcmliZSgpfX06ZS5wcm90b3R5cGUuX2NvbXBsZXRlLGN9cmV0dXJuIHQucHJvdG90eXBlLnVuc3Vic2NyaWJlPWZ1bmN0aW9uKCl7dmFyIHI7aWYoIXRoaXMuc2hvdWxkVW5zdWJzY3JpYmV8fHRoaXMuc2hvdWxkVW5zdWJzY3JpYmUoKSl7dmFyIG89dGhpcy5jbG9zZWQ7ZS5wcm90b3R5cGUudW5zdWJzY3JpYmUuY2FsbCh0aGlzKSwhbyYmKChyPXRoaXMub25GaW5hbGl6ZSk9PT1udWxsfHxyPT09dm9pZCAwfHxyLmNhbGwodGhpcykpfX0sdH0oVHQpO3ZhciB1dD17c2NoZWR1bGU6ZnVuY3Rpb24oZSl7dmFyIHQ9cmVxdWVzdEFuaW1hdGlvbkZyYW1lLHI9Y2FuY2VsQW5pbWF0aW9uRnJhbWUsbz11dC5kZWxlZ2F0ZTtvJiYodD1vLnJlcXVlc3RBbmltYXRpb25GcmFtZSxyPW8uY2FuY2VsQW5pbWF0aW9uRnJhbWUpO3ZhciBuPXQoZnVuY3Rpb24oaSl7cj12b2lkIDAsZShpKX0pO3JldHVybiBuZXcgSWUoZnVuY3Rpb24oKXtyZXR1cm4gcj09bnVsbD92b2lkIDA6cihuKX0pfSxyZXF1ZXN0QW5pbWF0aW9uRnJhbWU6ZnVuY3Rpb24oKXtmb3IodmFyIGU9W10sdD0wO3Q8YXJndW1lbnRzLmxlbmd0aDt0KyspZVt0XT1hcmd1bWVudHNbdF07dmFyIHI9dXQuZGVsZWdhdGU7cmV0dXJuKChyPT1udWxsP3ZvaWQgMDpyLnJlcXVlc3RBbmltYXRpb25GcmFtZSl8fHJlcXVlc3RBbmltYXRpb25GcmFtZSkuYXBwbHkodm9pZCAwLHooW10sVihlKSkpfSxjYW5jZWxBbmltYXRpb25GcmFtZTpmdW5jdGlvbigpe2Zvcih2YXIgZT1bXSx0PTA7dDxhcmd1bWVudHMubGVuZ3RoO3QrKyllW3RdPWFyZ3VtZW50c1t0XTt2YXIgcj11dC5kZWxlZ2F0ZTtyZXR1cm4oKHI9PW51bGw/dm9pZCAwOnIuY2FuY2VsQW5pbWF0aW9uRnJhbWUpfHxjYW5jZWxBbmltYXRpb25GcmFtZSkuYXBwbHkodm9pZCAwLHooW10sVihlKSkpfSxkZWxlZ2F0ZTp2b2lkIDB9O3ZhciBibz1wdChmdW5jdGlvbihlKXtyZXR1cm4gZnVuY3Rpb24oKXtlKHRoaXMpLHRoaXMubmFtZT0iT2JqZWN0VW5zdWJzY3JpYmVkRXJyb3IiLHRoaXMubWVzc2FnZT0ib2JqZWN0IHVuc3Vic2NyaWJlZCJ9fSk7dmFyIHY9ZnVuY3Rpb24oZSl7c2UodCxlKTtmdW5jdGlvbiB0KCl7dmFyIHI9ZS5jYWxsKHRoaXMpfHx0aGlzO3JldHVybiByLmNsb3NlZD0hMSxyLmN1cnJlbnRPYnNlcnZlcnM9bnVsbCxyLm9ic2VydmVycz1bXSxyLmlzU3RvcHBlZD0hMSxyLmhhc0Vycm9yPSExLHIudGhyb3duRXJyb3I9bnVsbCxyfXJldHVybiB0LnByb3RvdHlwZS5saWZ0PWZ1bmN0aW9uKHIpe3ZhciBvPW5ldyB2byh0aGlzLHRoaXMpO3JldHVybiBvLm9wZXJhdG9yPXIsb30sdC5wcm90b3R5cGUuX3Rocm93SWZDbG9zZWQ9ZnVuY3Rpb24oKXtpZih0aGlzLmNsb3NlZCl0aHJvdyBuZXcgYm99LHQucHJvdG90eXBlLm5leHQ9ZnVuY3Rpb24ocil7dmFyIG89dGhpczttdChmdW5jdGlvbigpe3ZhciBuLGk7aWYoby5fdGhyb3dJZkNsb3NlZCgpLCFvLmlzU3RvcHBlZCl7by5jdXJyZW50T2JzZXJ2ZXJzfHwoby5jdXJyZW50T2JzZXJ2ZXJzPUFycmF5LmZyb20oby5vYnNlcnZlcnMpKTt0cnl7Zm9yKHZhciBzPXVlKG8uY3VycmVudE9ic2VydmVycyksYT1zLm5leHQoKTshYS5kb25lO2E9cy5uZXh0KCkpe3ZhciBjPWEudmFsdWU7Yy5uZXh0KHIpfX1jYXRjaChwKXtuPXtlcnJvcjpwfX1maW5hbGx5e3RyeXthJiYhYS5kb25lJiYoaT1zLnJldHVybikmJmkuY2FsbChzKX1maW5hbGx5e2lmKG4pdGhyb3cgbi5lcnJvcn19fX0pfSx0LnByb3RvdHlwZS5lcnJvcj1mdW5jdGlvbihyKXt2YXIgbz10aGlzO210KGZ1bmN0aW9uKCl7aWYoby5fdGhyb3dJZkNsb3NlZCgpLCFvLmlzU3RvcHBlZCl7by5oYXNFcnJvcj1vLmlzU3RvcHBlZD0hMCxvLnRocm93bkVycm9yPXI7Zm9yKHZhciBuPW8ub2JzZXJ2ZXJzO24ubGVuZ3RoOyluLnNoaWZ0KCkuZXJyb3Iocil9fSl9LHQucHJvdG90eXBlLmNvbXBsZXRlPWZ1bmN0aW9uKCl7dmFyIHI9dGhpczttdChmdW5jdGlvbigpe2lmKHIuX3Rocm93SWZDbG9zZWQoKSwhci5pc1N0b3BwZWQpe3IuaXNTdG9wcGVkPSEwO2Zvcih2YXIgbz1yLm9ic2VydmVycztvLmxlbmd0aDspby5zaGlmdCgpLmNvbXBsZXRlKCl9fSl9LHQucHJvdG90eXBlLnVuc3Vic2NyaWJlPWZ1bmN0aW9uKCl7dGhpcy5pc1N0b3BwZWQ9dGhpcy5jbG9zZWQ9ITAsdGhpcy5vYnNlcnZlcnM9dGhpcy5jdXJyZW50T2JzZXJ2ZXJzPW51bGx9LE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LnByb3RvdHlwZSwib2JzZXJ2ZWQiLHtnZXQ6ZnVuY3Rpb24oKXt2YXIgcjtyZXR1cm4oKHI9dGhpcy5vYnNlcnZlcnMpPT09bnVsbHx8cj09PXZvaWQgMD92b2lkIDA6ci5sZW5ndGgpPjB9LGVudW1lcmFibGU6ITEsY29uZmlndXJhYmxlOiEwfSksdC5wcm90b3R5cGUuX3RyeVN1YnNjcmliZT1mdW5jdGlvbihyKXtyZXR1cm4gdGhpcy5fdGhyb3dJZkNsb3NlZCgpLGUucHJvdG90eXBlLl90cnlTdWJzY3JpYmUuY2FsbCh0aGlzLHIpfSx0LnByb3RvdHlwZS5fc3Vic2NyaWJlPWZ1bmN0aW9uKHIpe3JldHVybiB0aGlzLl90aHJvd0lmQ2xvc2VkKCksdGhpcy5fY2hlY2tGaW5hbGl6ZWRTdGF0dXNlcyhyKSx0aGlzLl9pbm5lclN1YnNjcmliZShyKX0sdC5wcm90b3R5cGUuX2lubmVyU3Vic2NyaWJlPWZ1bmN0aW9uKHIpe3ZhciBvPXRoaXMsbj10aGlzLGk9bi5oYXNFcnJvcixzPW4uaXNTdG9wcGVkLGE9bi5vYnNlcnZlcnM7cmV0dXJuIGl8fHM/RXI6KHRoaXMuY3VycmVudE9ic2VydmVycz1udWxsLGEucHVzaChyKSxuZXcgSWUoZnVuY3Rpb24oKXtvLmN1cnJlbnRPYnNlcnZlcnM9bnVsbCxWZShhLHIpfSkpfSx0LnByb3RvdHlwZS5fY2hlY2tGaW5hbGl6ZWRTdGF0dXNlcz1mdW5jdGlvbihyKXt2YXIgbz10aGlzLG49by5oYXNFcnJvcixpPW8udGhyb3duRXJyb3Iscz1vLmlzU3RvcHBlZDtuP3IuZXJyb3IoaSk6cyYmci5jb21wbGV0ZSgpfSx0LnByb3RvdHlwZS5hc09ic2VydmFibGU9ZnVuY3Rpb24oKXt2YXIgcj1uZXcgajtyZXR1cm4gci5zb3VyY2U9dGhpcyxyfSx0LmNyZWF0ZT1mdW5jdGlvbihyLG8pe3JldHVybiBuZXcgdm8ocixvKX0sdH0oaik7dmFyIHZvPWZ1bmN0aW9uKGUpe3NlKHQsZSk7ZnVuY3Rpb24gdChyLG8pe3ZhciBuPWUuY2FsbCh0aGlzKXx8dGhpcztyZXR1cm4gbi5kZXN0aW5hdGlvbj1yLG4uc291cmNlPW8sbn1yZXR1cm4gdC5wcm90b3R5cGUubmV4dD1mdW5jdGlvbihyKXt2YXIgbyxuOyhuPShvPXRoaXMuZGVzdGluYXRpb24pPT09bnVsbHx8bz09PXZvaWQgMD92b2lkIDA6by5uZXh0KT09PW51bGx8fG49PT12b2lkIDB8fG4uY2FsbChvLHIpfSx0LnByb3RvdHlwZS5lcnJvcj1mdW5jdGlvbihyKXt2YXIgbyxuOyhuPShvPXRoaXMuZGVzdGluYXRpb24pPT09bnVsbHx8bz09PXZvaWQgMD92b2lkIDA6by5lcnJvcik9PT1udWxsfHxuPT09dm9pZCAwfHxuLmNhbGwobyxyKX0sdC5wcm90b3R5cGUuY29tcGxldGU9ZnVuY3Rpb24oKXt2YXIgcixvOyhvPShyPXRoaXMuZGVzdGluYXRpb24pPT09bnVsbHx8cj09PXZvaWQgMD92b2lkIDA6ci5jb21wbGV0ZSk9PT1udWxsfHxvPT09dm9pZCAwfHxvLmNhbGwocil9LHQucHJvdG90eXBlLl9zdWJzY3JpYmU9ZnVuY3Rpb24ocil7dmFyIG8sbjtyZXR1cm4obj0obz10aGlzLnNvdXJjZSk9PT1udWxsfHxvPT09dm9pZCAwP3ZvaWQgMDpvLnN1YnNjcmliZShyKSkhPT1udWxsJiZuIT09dm9pZCAwP246RXJ9LHR9KHYpO3ZhciBTdD17bm93OmZ1bmN0aW9uKCl7cmV0dXJuKFN0LmRlbGVnYXRlfHxEYXRlKS5ub3coKX0sZGVsZWdhdGU6dm9pZCAwfTt2YXIgT3Q9ZnVuY3Rpb24oZSl7c2UodCxlKTtmdW5jdGlvbiB0KHIsbyxuKXtyPT09dm9pZCAwJiYocj0xLzApLG89PT12b2lkIDAmJihvPTEvMCksbj09PXZvaWQgMCYmKG49U3QpO3ZhciBpPWUuY2FsbCh0aGlzKXx8dGhpcztyZXR1cm4gaS5fYnVmZmVyU2l6ZT1yLGkuX3dpbmRvd1RpbWU9byxpLl90aW1lc3RhbXBQcm92aWRlcj1uLGkuX2J1ZmZlcj1bXSxpLl9pbmZpbml0ZVRpbWVXaW5kb3c9ITAsaS5faW5maW5pdGVUaW1lV2luZG93PW89PT0xLzAsaS5fYnVmZmVyU2l6ZT1NYXRoLm1heCgxLHIpLGkuX3dpbmRvd1RpbWU9TWF0aC5tYXgoMSxvKSxpfXJldHVybiB0LnByb3RvdHlwZS5uZXh0PWZ1bmN0aW9uKHIpe3ZhciBvPXRoaXMsbj1vLmlzU3RvcHBlZCxpPW8uX2J1ZmZlcixzPW8uX2luZmluaXRlVGltZVdpbmRvdyxhPW8uX3RpbWVzdGFtcFByb3ZpZGVyLGM9by5fd2luZG93VGltZTtufHwoaS5wdXNoKHIpLCFzJiZpLnB1c2goYS5ub3coKStjKSksdGhpcy5fdHJpbUJ1ZmZlcigpLGUucHJvdG90eXBlLm5leHQuY2FsbCh0aGlzLHIpfSx0LnByb3RvdHlwZS5fc3Vic2NyaWJlPWZ1bmN0aW9uKHIpe3RoaXMuX3Rocm93SWZDbG9zZWQoKSx0aGlzLl90cmltQnVmZmVyKCk7Zm9yKHZhciBvPXRoaXMuX2lubmVyU3Vic2NyaWJlKHIpLG49dGhpcyxpPW4uX2luZmluaXRlVGltZVdpbmRvdyxzPW4uX2J1ZmZlcixhPXMuc2xpY2UoKSxjPTA7YzxhLmxlbmd0aCYmIXIuY2xvc2VkO2MrPWk/MToyKXIubmV4dChhW2NdKTtyZXR1cm4gdGhpcy5fY2hlY2tGaW5hbGl6ZWRTdGF0dXNlcyhyKSxvfSx0LnByb3RvdHlwZS5fdHJpbUJ1ZmZlcj1mdW5jdGlvbigpe3ZhciByPXRoaXMsbz1yLl9idWZmZXJTaXplLG49ci5fdGltZXN0YW1wUHJvdmlkZXIsaT1yLl9idWZmZXIscz1yLl9pbmZpbml0ZVRpbWVXaW5kb3csYT0ocz8xOjIpKm87aWYobzwxLzAmJmE8aS5sZW5ndGgmJmkuc3BsaWNlKDAsaS5sZW5ndGgtYSksIXMpe2Zvcih2YXIgYz1uLm5vdygpLHA9MCxsPTE7bDxpLmxlbmd0aCYmaVtsXTw9YztsKz0yKXA9bDtwJiZpLnNwbGljZSgwLHArMSl9fSx0fSh2KTt2YXIgZ289ZnVuY3Rpb24oZSl7c2UodCxlKTtmdW5jdGlvbiB0KHIsbyl7cmV0dXJuIGUuY2FsbCh0aGlzKXx8dGhpc31yZXR1cm4gdC5wcm90b3R5cGUuc2NoZWR1bGU9ZnVuY3Rpb24ocixvKXtyZXR1cm4gbz09PXZvaWQgMCYmKG89MCksdGhpc30sdH0oSWUpO3ZhciBNdD17c2V0SW50ZXJ2YWw6ZnVuY3Rpb24oZSx0KXtmb3IodmFyIHI9W10sbz0yO288YXJndW1lbnRzLmxlbmd0aDtvKyspcltvLTJdPWFyZ3VtZW50c1tvXTt2YXIgbj1NdC5kZWxlZ2F0ZTtyZXR1cm4gbiE9bnVsbCYmbi5zZXRJbnRlcnZhbD9uLnNldEludGVydmFsLmFwcGx5KG4seihbZSx0XSxWKHIpKSk6c2V0SW50ZXJ2YWwuYXBwbHkodm9pZCAwLHooW2UsdF0sVihyKSkpfSxjbGVhckludGVydmFsOmZ1bmN0aW9uKGUpe3ZhciB0PU10LmRlbGVnYXRlO3JldHVybigodD09bnVsbD92b2lkIDA6dC5jbGVhckludGVydmFsKXx8Y2xlYXJJbnRlcnZhbCkoZSl9LGRlbGVnYXRlOnZvaWQgMH07dmFyIHp0PWZ1bmN0aW9uKGUpe3NlKHQsZSk7ZnVuY3Rpb24gdChyLG8pe3ZhciBuPWUuY2FsbCh0aGlzLHIsbyl8fHRoaXM7cmV0dXJuIG4uc2NoZWR1bGVyPXIsbi53b3JrPW8sbi5wZW5kaW5nPSExLG59cmV0dXJuIHQucHJvdG90eXBlLnNjaGVkdWxlPWZ1bmN0aW9uKHIsbyl7dmFyIG47aWYobz09PXZvaWQgMCYmKG89MCksdGhpcy5jbG9zZWQpcmV0dXJuIHRoaXM7dGhpcy5zdGF0ZT1yO3ZhciBpPXRoaXMuaWQscz10aGlzLnNjaGVkdWxlcjtyZXR1cm4gaSE9bnVsbCYmKHRoaXMuaWQ9dGhpcy5yZWN5Y2xlQXN5bmNJZChzLGksbykpLHRoaXMucGVuZGluZz0hMCx0aGlzLmRlbGF5PW8sdGhpcy5pZD0obj10aGlzLmlkKSE9PW51bGwmJm4hPT12b2lkIDA/bjp0aGlzLnJlcXVlc3RBc3luY0lkKHMsdGhpcy5pZCxvKSx0aGlzfSx0LnByb3RvdHlwZS5yZXF1ZXN0QXN5bmNJZD1mdW5jdGlvbihyLG8sbil7cmV0dXJuIG49PT12b2lkIDAmJihuPTApLE10LnNldEludGVydmFsKHIuZmx1c2guYmluZChyLHRoaXMpLG4pfSx0LnByb3RvdHlwZS5yZWN5Y2xlQXN5bmNJZD1mdW5jdGlvbihyLG8sbil7aWYobj09PXZvaWQgMCYmKG49MCksbiE9bnVsbCYmdGhpcy5kZWxheT09PW4mJnRoaXMucGVuZGluZz09PSExKXJldHVybiBvO28hPW51bGwmJk10LmNsZWFySW50ZXJ2YWwobyl9LHQucHJvdG90eXBlLmV4ZWN1dGU9ZnVuY3Rpb24ocixvKXtpZih0aGlzLmNsb3NlZClyZXR1cm4gbmV3IEVycm9yKCJleGVjdXRpbmcgYSBjYW5jZWxsZWQgYWN0aW9uIik7dGhpcy5wZW5kaW5nPSExO3ZhciBuPXRoaXMuX2V4ZWN1dGUocixvKTtpZihuKXJldHVybiBuO3RoaXMucGVuZGluZz09PSExJiZ0aGlzLmlkIT1udWxsJiYodGhpcy5pZD10aGlzLnJlY3ljbGVBc3luY0lkKHRoaXMuc2NoZWR1bGVyLHRoaXMuaWQsbnVsbCkpfSx0LnByb3RvdHlwZS5fZXhlY3V0ZT1mdW5jdGlvbihyLG8pe3ZhciBuPSExLGk7dHJ5e3RoaXMud29yayhyKX1jYXRjaChzKXtuPSEwLGk9c3x8bmV3IEVycm9yKCJTY2hlZHVsZWQgYWN0aW9uIHRocmV3IGZhbHN5IGVycm9yIil9aWYobilyZXR1cm4gdGhpcy51bnN1YnNjcmliZSgpLGl9LHQucHJvdG90eXBlLnVuc3Vic2NyaWJlPWZ1bmN0aW9uKCl7aWYoIXRoaXMuY2xvc2VkKXt2YXIgcj10aGlzLG89ci5pZCxuPXIuc2NoZWR1bGVyLGk9bi5hY3Rpb25zO3RoaXMud29yaz10aGlzLnN0YXRlPXRoaXMuc2NoZWR1bGVyPW51bGwsdGhpcy5wZW5kaW5nPSExLFZlKGksdGhpcyksbyE9bnVsbCYmKHRoaXMuaWQ9dGhpcy5yZWN5Y2xlQXN5bmNJZChuLG8sbnVsbCkpLHRoaXMuZGVsYXk9bnVsbCxlLnByb3RvdHlwZS51bnN1YnNjcmliZS5jYWxsKHRoaXMpfX0sdH0oZ28pO3ZhciBNcj1mdW5jdGlvbigpe2Z1bmN0aW9uIGUodCxyKXtyPT09dm9pZCAwJiYocj1lLm5vdyksdGhpcy5zY2hlZHVsZXJBY3Rpb25DdG9yPXQsdGhpcy5ub3c9cn1yZXR1cm4gZS5wcm90b3R5cGUuc2NoZWR1bGU9ZnVuY3Rpb24odCxyLG8pe3JldHVybiByPT09dm9pZCAwJiYocj0wKSxuZXcgdGhpcy5zY2hlZHVsZXJBY3Rpb25DdG9yKHRoaXMsdCkuc2NoZWR1bGUobyxyKX0sZS5ub3c9U3Qubm93LGV9KCk7dmFyIHF0PWZ1bmN0aW9uKGUpe3NlKHQsZSk7ZnVuY3Rpb24gdChyLG8pe289PT12b2lkIDAmJihvPU1yLm5vdyk7dmFyIG49ZS5jYWxsKHRoaXMscixvKXx8dGhpcztyZXR1cm4gbi5hY3Rpb25zPVtdLG4uX2FjdGl2ZT0hMSxufXJldHVybiB0LnByb3RvdHlwZS5mbHVzaD1mdW5jdGlvbihyKXt2YXIgbz10aGlzLmFjdGlvbnM7aWYodGhpcy5fYWN0aXZlKXtvLnB1c2gocik7cmV0dXJufXZhciBuO3RoaXMuX2FjdGl2ZT0hMDtkbyBpZihuPXIuZXhlY3V0ZShyLnN0YXRlLHIuZGVsYXkpKWJyZWFrO3doaWxlKHI9by5zaGlmdCgpKTtpZih0aGlzLl9hY3RpdmU9ITEsbil7Zm9yKDtyPW8uc2hpZnQoKTspci51bnN1YnNjcmliZSgpO3Rocm93IG59fSx0fShNcik7dmFyIGllPW5ldyBxdCh6dCksTHI9aWU7dmFyIHhvPWZ1bmN0aW9uKGUpe3NlKHQsZSk7ZnVuY3Rpb24gdChyLG8pe3ZhciBuPWUuY2FsbCh0aGlzLHIsbyl8fHRoaXM7cmV0dXJuIG4uc2NoZWR1bGVyPXIsbi53b3JrPW8sbn1yZXR1cm4gdC5wcm90b3R5cGUucmVxdWVzdEFzeW5jSWQ9ZnVuY3Rpb24ocixvLG4pe3JldHVybiBuPT09dm9pZCAwJiYobj0wKSxuIT09bnVsbCYmbj4wP2UucHJvdG90eXBlLnJlcXVlc3RBc3luY0lkLmNhbGwodGhpcyxyLG8sbik6KHIuYWN0aW9ucy5wdXNoKHRoaXMpLHIuX3NjaGVkdWxlZHx8KHIuX3NjaGVkdWxlZD11dC5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUoZnVuY3Rpb24oKXtyZXR1cm4gci5mbHVzaCh2b2lkIDApfSkpKX0sdC5wcm90b3R5cGUucmVjeWNsZUFzeW5jSWQ9ZnVuY3Rpb24ocixvLG4pe3ZhciBpO2lmKG49PT12b2lkIDAmJihuPTApLG4hPW51bGw/bj4wOnRoaXMuZGVsYXk+MClyZXR1cm4gZS5wcm90b3R5cGUucmVjeWNsZUFzeW5jSWQuY2FsbCh0aGlzLHIsbyxuKTt2YXIgcz1yLmFjdGlvbnM7byE9bnVsbCYmKChpPXNbcy5sZW5ndGgtMV0pPT09bnVsbHx8aT09PXZvaWQgMD92b2lkIDA6aS5pZCkhPT1vJiYodXQuY2FuY2VsQW5pbWF0aW9uRnJhbWUobyksci5fc2NoZWR1bGVkPXZvaWQgMCl9LHR9KHp0KTt2YXIgeW89ZnVuY3Rpb24oZSl7c2UodCxlKTtmdW5jdGlvbiB0KCl7cmV0dXJuIGUhPT1udWxsJiZlLmFwcGx5KHRoaXMsYXJndW1lbnRzKXx8dGhpc31yZXR1cm4gdC5wcm90b3R5cGUuZmx1c2g9ZnVuY3Rpb24ocil7dGhpcy5fYWN0aXZlPSEwO3ZhciBvPXRoaXMuX3NjaGVkdWxlZDt0aGlzLl9zY2hlZHVsZWQ9dm9pZCAwO3ZhciBuPXRoaXMuYWN0aW9ucyxpO3I9cnx8bi5zaGlmdCgpO2RvIGlmKGk9ci5leGVjdXRlKHIuc3RhdGUsci5kZWxheSkpYnJlYWs7d2hpbGUoKHI9blswXSkmJnIuaWQ9PT1vJiZuLnNoaWZ0KCkpO2lmKHRoaXMuX2FjdGl2ZT0hMSxpKXtmb3IoOyhyPW5bMF0pJiZyLmlkPT09byYmbi5zaGlmdCgpOylyLnVuc3Vic2NyaWJlKCk7dGhyb3cgaX19LHR9KHF0KTt2YXIgZGU9bmV3IHlvKHhvKTt2YXIgTD1uZXcgaihmdW5jdGlvbihlKXtyZXR1cm4gZS5jb21wbGV0ZSgpfSk7ZnVuY3Rpb24gS3QoZSl7cmV0dXJuIGUmJmsoZS5zY2hlZHVsZSl9ZnVuY3Rpb24gX3IoZSl7cmV0dXJuIGVbZS5sZW5ndGgtMV19ZnVuY3Rpb24gSmUoZSl7cmV0dXJuIGsoX3IoZSkpP2UucG9wKCk6dm9pZCAwfWZ1bmN0aW9uIEFlKGUpe3JldHVybiBLdChfcihlKSk/ZS5wb3AoKTp2b2lkIDB9ZnVuY3Rpb24gUXQoZSx0KXtyZXR1cm4gdHlwZW9mIF9yKGUpPT0ibnVtYmVyIj9lLnBvcCgpOnR9dmFyIGR0PWZ1bmN0aW9uKGUpe3JldHVybiBlJiZ0eXBlb2YgZS5sZW5ndGg9PSJudW1iZXIiJiZ0eXBlb2YgZSE9ImZ1bmN0aW9uIn07ZnVuY3Rpb24gWXQoZSl7cmV0dXJuIGsoZT09bnVsbD92b2lkIDA6ZS50aGVuKX1mdW5jdGlvbiBCdChlKXtyZXR1cm4gayhlW2Z0XSl9ZnVuY3Rpb24gR3QoZSl7cmV0dXJuIFN5bWJvbC5hc3luY0l0ZXJhdG9yJiZrKGU9PW51bGw/dm9pZCAwOmVbU3ltYm9sLmFzeW5jSXRlcmF0b3JdKX1mdW5jdGlvbiBKdChlKXtyZXR1cm4gbmV3IFR5cGVFcnJvcigiWW91IHByb3ZpZGVkICIrKGUhPT1udWxsJiZ0eXBlb2YgZT09Im9iamVjdCI/ImFuIGludmFsaWQgb2JqZWN0IjoiJyIrZSsiJyIpKyIgd2hlcmUgYSBzdHJlYW0gd2FzIGV4cGVjdGVkLiBZb3UgY2FuIHByb3ZpZGUgYW4gT2JzZXJ2YWJsZSwgUHJvbWlzZSwgUmVhZGFibGVTdHJlYW0sIEFycmF5LCBBc3luY0l0ZXJhYmxlLCBvciBJdGVyYWJsZS4iKX1mdW5jdGlvbiBEaSgpe3JldHVybiB0eXBlb2YgU3ltYm9sIT0iZnVuY3Rpb24ifHwhU3ltYm9sLml0ZXJhdG9yPyJAQGl0ZXJhdG9yIjpTeW1ib2wuaXRlcmF0b3J9dmFyIFh0PURpKCk7ZnVuY3Rpb24gWnQoZSl7cmV0dXJuIGsoZT09bnVsbD92b2lkIDA6ZVtYdF0pfWZ1bmN0aW9uIGVyKGUpe3JldHVybiBhbyh0aGlzLGFyZ3VtZW50cyxmdW5jdGlvbigpe3ZhciByLG8sbixpO3JldHVybiBVdCh0aGlzLGZ1bmN0aW9uKHMpe3N3aXRjaChzLmxhYmVsKXtjYXNlIDA6cj1lLmdldFJlYWRlcigpLHMubGFiZWw9MTtjYXNlIDE6cy50cnlzLnB1c2goWzEsLDksMTBdKSxzLmxhYmVsPTI7Y2FzZSAyOnJldHVybls0LG90KHIucmVhZCgpKV07Y2FzZSAzOnJldHVybiBvPXMuc2VudCgpLG49by52YWx1ZSxpPW8uZG9uZSxpP1s0LG90KHZvaWQgMCldOlszLDVdO2Nhc2UgNDpyZXR1cm5bMixzLnNlbnQoKV07Y2FzZSA1OnJldHVybls0LG90KG4pXTtjYXNlIDY6cmV0dXJuWzQscy5zZW50KCldO2Nhc2UgNzpyZXR1cm4gcy5zZW50KCksWzMsMl07Y2FzZSA4OnJldHVyblszLDEwXTtjYXNlIDk6cmV0dXJuIHIucmVsZWFzZUxvY2soKSxbN107Y2FzZSAxMDpyZXR1cm5bMl19fSl9KX1mdW5jdGlvbiB0cihlKXtyZXR1cm4gayhlPT1udWxsP3ZvaWQgMDplLmdldFJlYWRlcil9ZnVuY3Rpb24gTihlKXtpZihlIGluc3RhbmNlb2YgailyZXR1cm4gZTtpZihlIT1udWxsKXtpZihCdChlKSlyZXR1cm4gTmkoZSk7aWYoZHQoZSkpcmV0dXJuIFZpKGUpO2lmKFl0KGUpKXJldHVybiB6aShlKTtpZihHdChlKSlyZXR1cm4gRW8oZSk7aWYoWnQoZSkpcmV0dXJuIHFpKGUpO2lmKHRyKGUpKXJldHVybiBLaShlKX10aHJvdyBKdChlKX1mdW5jdGlvbiBOaShlKXtyZXR1cm4gbmV3IGooZnVuY3Rpb24odCl7dmFyIHI9ZVtmdF0oKTtpZihrKHIuc3Vic2NyaWJlKSlyZXR1cm4gci5zdWJzY3JpYmUodCk7dGhyb3cgbmV3IFR5cGVFcnJvcigiUHJvdmlkZWQgb2JqZWN0IGRvZXMgbm90IGNvcnJlY3RseSBpbXBsZW1lbnQgU3ltYm9sLm9ic2VydmFibGUiKX0pfWZ1bmN0aW9uIFZpKGUpe3JldHVybiBuZXcgaihmdW5jdGlvbih0KXtmb3IodmFyIHI9MDtyPGUubGVuZ3RoJiYhdC5jbG9zZWQ7cisrKXQubmV4dChlW3JdKTt0LmNvbXBsZXRlKCl9KX1mdW5jdGlvbiB6aShlKXtyZXR1cm4gbmV3IGooZnVuY3Rpb24odCl7ZS50aGVuKGZ1bmN0aW9uKHIpe3QuY2xvc2VkfHwodC5uZXh0KHIpLHQuY29tcGxldGUoKSl9LGZ1bmN0aW9uKHIpe3JldHVybiB0LmVycm9yKHIpfSkudGhlbihudWxsLE50KX0pfWZ1bmN0aW9uIHFpKGUpe3JldHVybiBuZXcgaihmdW5jdGlvbih0KXt2YXIgcixvO3RyeXtmb3IodmFyIG49dWUoZSksaT1uLm5leHQoKTshaS5kb25lO2k9bi5uZXh0KCkpe3ZhciBzPWkudmFsdWU7aWYodC5uZXh0KHMpLHQuY2xvc2VkKXJldHVybn19Y2F0Y2goYSl7cj17ZXJyb3I6YX19ZmluYWxseXt0cnl7aSYmIWkuZG9uZSYmKG89bi5yZXR1cm4pJiZvLmNhbGwobil9ZmluYWxseXtpZihyKXRocm93IHIuZXJyb3J9fXQuY29tcGxldGUoKX0pfWZ1bmN0aW9uIEVvKGUpe3JldHVybiBuZXcgaihmdW5jdGlvbih0KXtRaShlLHQpLmNhdGNoKGZ1bmN0aW9uKHIpe3JldHVybiB0LmVycm9yKHIpfSl9KX1mdW5jdGlvbiBLaShlKXtyZXR1cm4gRW8oZXIoZSkpfWZ1bmN0aW9uIFFpKGUsdCl7dmFyIHIsbyxuLGk7cmV0dXJuIGlvKHRoaXMsdm9pZCAwLHZvaWQgMCxmdW5jdGlvbigpe3ZhciBzLGE7cmV0dXJuIFV0KHRoaXMsZnVuY3Rpb24oYyl7c3dpdGNoKGMubGFiZWwpe2Nhc2UgMDpjLnRyeXMucHVzaChbMCw1LDYsMTFdKSxyPXNvKGUpLGMubGFiZWw9MTtjYXNlIDE6cmV0dXJuWzQsci5uZXh0KCldO2Nhc2UgMjppZihvPWMuc2VudCgpLCEhby5kb25lKXJldHVyblszLDRdO2lmKHM9by52YWx1ZSx0Lm5leHQocyksdC5jbG9zZWQpcmV0dXJuWzJdO2MubGFiZWw9MztjYXNlIDM6cmV0dXJuWzMsMV07Y2FzZSA0OnJldHVyblszLDExXTtjYXNlIDU6cmV0dXJuIGE9Yy5zZW50KCksbj17ZXJyb3I6YX0sWzMsMTFdO2Nhc2UgNjpyZXR1cm4gYy50cnlzLnB1c2goWzYsLDksMTBdKSxvJiYhby5kb25lJiYoaT1yLnJldHVybik/WzQsaS5jYWxsKHIpXTpbMyw4XTtjYXNlIDc6Yy5zZW50KCksYy5sYWJlbD04O2Nhc2UgODpyZXR1cm5bMywxMF07Y2FzZSA5OmlmKG4pdGhyb3cgbi5lcnJvcjtyZXR1cm5bN107Y2FzZSAxMDpyZXR1cm5bN107Y2FzZSAxMTpyZXR1cm4gdC5jb21wbGV0ZSgpLFsyXX19KX0pfWZ1bmN0aW9uIHhlKGUsdCxyLG8sbil7bz09PXZvaWQgMCYmKG89MCksbj09PXZvaWQgMCYmKG49ITEpO3ZhciBpPXQuc2NoZWR1bGUoZnVuY3Rpb24oKXtyKCksbj9lLmFkZCh0aGlzLnNjaGVkdWxlKG51bGwsbykpOnRoaXMudW5zdWJzY3JpYmUoKX0sbyk7aWYoZS5hZGQoaSksIW4pcmV0dXJuIGl9ZnVuY3Rpb24gT2UoZSx0KXtyZXR1cm4gdD09PXZvaWQgMCYmKHQ9MCkseChmdW5jdGlvbihyLG8pe3Iuc3Vic2NyaWJlKFMobyxmdW5jdGlvbihuKXtyZXR1cm4geGUobyxlLGZ1bmN0aW9uKCl7cmV0dXJuIG8ubmV4dChuKX0sdCl9LGZ1bmN0aW9uKCl7cmV0dXJuIHhlKG8sZSxmdW5jdGlvbigpe3JldHVybiBvLmNvbXBsZXRlKCl9LHQpfSxmdW5jdGlvbihuKXtyZXR1cm4geGUobyxlLGZ1bmN0aW9uKCl7cmV0dXJuIG8uZXJyb3Iobil9LHQpfSkpfSl9ZnVuY3Rpb24gemUoZSx0KXtyZXR1cm4gdD09PXZvaWQgMCYmKHQ9MCkseChmdW5jdGlvbihyLG8pe28uYWRkKGUuc2NoZWR1bGUoZnVuY3Rpb24oKXtyZXR1cm4gci5zdWJzY3JpYmUobyl9LHQpKX0pfWZ1bmN0aW9uIHdvKGUsdCl7cmV0dXJuIE4oZSkucGlwZSh6ZSh0KSxPZSh0KSl9ZnVuY3Rpb24gVG8oZSx0KXtyZXR1cm4gTihlKS5waXBlKHplKHQpLE9lKHQpKX1mdW5jdGlvbiBTbyhlLHQpe3JldHVybiBuZXcgaihmdW5jdGlvbihyKXt2YXIgbz0wO3JldHVybiB0LnNjaGVkdWxlKGZ1bmN0aW9uKCl7bz09PWUubGVuZ3RoP3IuY29tcGxldGUoKTooci5uZXh0KGVbbysrXSksci5jbG9zZWR8fHRoaXMuc2NoZWR1bGUoKSl9KX0pfWZ1bmN0aW9uIE9vKGUsdCl7cmV0dXJuIG5ldyBqKGZ1bmN0aW9uKHIpe3ZhciBvO3JldHVybiB4ZShyLHQsZnVuY3Rpb24oKXtvPWVbWHRdKCkseGUocix0LGZ1bmN0aW9uKCl7dmFyIG4saSxzO3RyeXtuPW8ubmV4dCgpLGk9bi52YWx1ZSxzPW4uZG9uZX1jYXRjaChhKXtyLmVycm9yKGEpO3JldHVybn1zP3IuY29tcGxldGUoKTpyLm5leHQoaSl9LDAsITApfSksZnVuY3Rpb24oKXtyZXR1cm4gayhvPT1udWxsP3ZvaWQgMDpvLnJldHVybikmJm8ucmV0dXJuKCl9fSl9ZnVuY3Rpb24gcnIoZSx0KXtpZighZSl0aHJvdyBuZXcgRXJyb3IoIkl0ZXJhYmxlIGNhbm5vdCBiZSBudWxsIik7cmV0dXJuIG5ldyBqKGZ1bmN0aW9uKHIpe3hlKHIsdCxmdW5jdGlvbigpe3ZhciBvPWVbU3ltYm9sLmFzeW5jSXRlcmF0b3JdKCk7eGUocix0LGZ1bmN0aW9uKCl7by5uZXh0KCkudGhlbihmdW5jdGlvbihuKXtuLmRvbmU/ci5jb21wbGV0ZSgpOnIubmV4dChuLnZhbHVlKX0pfSwwLCEwKX0pfSl9ZnVuY3Rpb24gTW8oZSx0KXtyZXR1cm4gcnIoZXIoZSksdCl9ZnVuY3Rpb24gTG8oZSx0KXtpZihlIT1udWxsKXtpZihCdChlKSlyZXR1cm4gd28oZSx0KTtpZihkdChlKSlyZXR1cm4gU28oZSx0KTtpZihZdChlKSlyZXR1cm4gVG8oZSx0KTtpZihHdChlKSlyZXR1cm4gcnIoZSx0KTtpZihadChlKSlyZXR1cm4gT28oZSx0KTtpZih0cihlKSlyZXR1cm4gTW8oZSx0KX10aHJvdyBKdChlKX1mdW5jdGlvbiBmZShlLHQpe3JldHVybiB0P0xvKGUsdCk6TihlKX1mdW5jdGlvbiAkKCl7Zm9yKHZhciBlPVtdLHQ9MDt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKWVbdF09YXJndW1lbnRzW3RdO3ZhciByPUFlKGUpO3JldHVybiBmZShlLHIpfWZ1bmN0aW9uIEFyKGUsdCl7dmFyIHI9ayhlKT9lOmZ1bmN0aW9uKCl7cmV0dXJuIGV9LG89ZnVuY3Rpb24obil7cmV0dXJuIG4uZXJyb3IocigpKX07cmV0dXJuIG5ldyBqKHQ/ZnVuY3Rpb24obil7cmV0dXJuIHQuc2NoZWR1bGUobywwLG4pfTpvKX12YXIgb3I9cHQoZnVuY3Rpb24oZSl7cmV0dXJuIGZ1bmN0aW9uKCl7ZSh0aGlzKSx0aGlzLm5hbWU9IkVtcHR5RXJyb3IiLHRoaXMubWVzc2FnZT0ibm8gZWxlbWVudHMgaW4gc2VxdWVuY2UifX0pO2Z1bmN0aW9uIF9vKGUpe3JldHVybiBlIGluc3RhbmNlb2YgRGF0ZSYmIWlzTmFOKGUpfWZ1bmN0aW9uIG0oZSx0KXtyZXR1cm4geChmdW5jdGlvbihyLG8pe3ZhciBuPTA7ci5zdWJzY3JpYmUoUyhvLGZ1bmN0aW9uKGkpe28ubmV4dChlLmNhbGwodCxpLG4rKykpfSkpfSl9dmFyIFlpPUFycmF5LmlzQXJyYXk7ZnVuY3Rpb24gQmkoZSx0KXtyZXR1cm4gWWkodCk/ZS5hcHBseSh2b2lkIDAseihbXSxWKHQpKSk6ZSh0KX1mdW5jdGlvbiBYZShlKXtyZXR1cm4gbShmdW5jdGlvbih0KXtyZXR1cm4gQmkoZSx0KX0pfXZhciBHaT1BcnJheS5pc0FycmF5LEppPU9iamVjdC5nZXRQcm90b3R5cGVPZixYaT1PYmplY3QucHJvdG90eXBlLFppPU9iamVjdC5rZXlzO2Z1bmN0aW9uIEFvKGUpe2lmKGUubGVuZ3RoPT09MSl7dmFyIHQ9ZVswXTtpZihHaSh0KSlyZXR1cm57YXJnczp0LGtleXM6bnVsbH07aWYoZWEodCkpe3ZhciByPVppKHQpO3JldHVybnthcmdzOnIubWFwKGZ1bmN0aW9uKG8pe3JldHVybiB0W29dfSksa2V5czpyfX19cmV0dXJue2FyZ3M6ZSxrZXlzOm51bGx9fWZ1bmN0aW9uIGVhKGUpe3JldHVybiBlJiZ0eXBlb2YgZT09Im9iamVjdCImJkppKGUpPT09WGl9ZnVuY3Rpb24gQ28oZSx0KXtyZXR1cm4gZS5yZWR1Y2UoZnVuY3Rpb24ocixvLG4pe3JldHVybiByW29dPXRbbl0scn0se30pfWZ1bmN0aW9uIFEoKXtmb3IodmFyIGU9W10sdD0wO3Q8YXJndW1lbnRzLmxlbmd0aDt0KyspZVt0XT1hcmd1bWVudHNbdF07dmFyIHI9QWUoZSksbz1KZShlKSxuPUFvKGUpLGk9bi5hcmdzLHM9bi5rZXlzO2lmKGkubGVuZ3RoPT09MClyZXR1cm4gZmUoW10scik7dmFyIGE9bmV3IGooQ3IoaSxyLHM/ZnVuY3Rpb24oYyl7cmV0dXJuIENvKHMsYyl9OmNlKSk7cmV0dXJuIG8/YS5waXBlKFhlKG8pKTphfWZ1bmN0aW9uIENyKGUsdCxyKXtyZXR1cm4gcj09PXZvaWQgMCYmKHI9Y2UpLGZ1bmN0aW9uKG8pe2tvKHQsZnVuY3Rpb24oKXtmb3IodmFyIG49ZS5sZW5ndGgsaT1uZXcgQXJyYXkobikscz1uLGE9bixjPWZ1bmN0aW9uKGwpe2tvKHQsZnVuY3Rpb24oKXt2YXIgZj1mZShlW2xdLHQpLHU9ITE7Zi5zdWJzY3JpYmUoUyhvLGZ1bmN0aW9uKGgpe2lbbF09aCx1fHwodT0hMCxhLS0pLGF8fG8ubmV4dChyKGkuc2xpY2UoKSkpfSxmdW5jdGlvbigpey0tc3x8by5jb21wbGV0ZSgpfSkpfSxvKX0scD0wO3A8bjtwKyspYyhwKX0sbyl9fWZ1bmN0aW9uIGtvKGUsdCxyKXtlP3hlKHIsZSx0KTp0KCl9ZnVuY3Rpb24gSG8oZSx0LHIsbyxuLGkscyxhKXt2YXIgYz1bXSxwPTAsbD0wLGY9ITEsdT1mdW5jdGlvbigpe2YmJiFjLmxlbmd0aCYmIXAmJnQuY29tcGxldGUoKX0saD1mdW5jdGlvbihBKXtyZXR1cm4gcDxvP3coQSk6Yy5wdXNoKEEpfSx3PWZ1bmN0aW9uKEEpe2kmJnQubmV4dChBKSxwKys7dmFyIFo9ITE7TihyKEEsbCsrKSkuc3Vic2NyaWJlKFModCxmdW5jdGlvbih0ZSl7bj09bnVsbHx8bih0ZSksaT9oKHRlKTp0Lm5leHQodGUpfSxmdW5jdGlvbigpe1o9ITB9LHZvaWQgMCxmdW5jdGlvbigpe2lmKFopdHJ5e3AtLTtmb3IodmFyIHRlPWZ1bmN0aW9uKCl7dmFyIEo9Yy5zaGlmdCgpO3M/eGUodCxzLGZ1bmN0aW9uKCl7cmV0dXJuIHcoSil9KTp3KEopfTtjLmxlbmd0aCYmcDxvOyl0ZSgpO3UoKX1jYXRjaChKKXt0LmVycm9yKEopfX0pKX07cmV0dXJuIGUuc3Vic2NyaWJlKFModCxoLGZ1bmN0aW9uKCl7Zj0hMCx1KCl9KSksZnVuY3Rpb24oKXthPT1udWxsfHxhKCl9fWZ1bmN0aW9uIHJlKGUsdCxyKXtyZXR1cm4gcj09PXZvaWQgMCYmKHI9MS8wKSxrKHQpP3JlKGZ1bmN0aW9uKG8sbil7cmV0dXJuIG0oZnVuY3Rpb24oaSxzKXtyZXR1cm4gdChvLGksbixzKX0pKE4oZShvLG4pKSl9LHIpOih0eXBlb2YgdD09Im51bWJlciImJihyPXQpLHgoZnVuY3Rpb24obyxuKXtyZXR1cm4gSG8obyxuLGUscil9KSl9ZnVuY3Rpb24gaHQoZSl7cmV0dXJuIGU9PT12b2lkIDAmJihlPTEvMCkscmUoY2UsZSl9ZnVuY3Rpb24gJG8oKXtyZXR1cm4gaHQoMSl9ZnVuY3Rpb24gRmUoKXtmb3IodmFyIGU9W10sdD0wO3Q8YXJndW1lbnRzLmxlbmd0aDt0KyspZVt0XT1hcmd1bWVudHNbdF07cmV0dXJuICRvKCkoZmUoZSxBZShlKSkpfWZ1bmN0aW9uIEgoZSl7cmV0dXJuIG5ldyBqKGZ1bmN0aW9uKHQpe04oZSgpKS5zdWJzY3JpYmUodCl9KX12YXIgdGE9WyJhZGRMaXN0ZW5lciIsInJlbW92ZUxpc3RlbmVyIl0scmE9WyJhZGRFdmVudExpc3RlbmVyIiwicmVtb3ZlRXZlbnRMaXN0ZW5lciJdLG9hPVsib24iLCJvZmYiXTtmdW5jdGlvbiBkKGUsdCxyLG8pe2lmKGsocikmJihvPXIscj12b2lkIDApLG8pcmV0dXJuIGQoZSx0LHIpLnBpcGUoWGUobykpO3ZhciBuPVYoYWEoZSk/cmEubWFwKGZ1bmN0aW9uKGEpe3JldHVybiBmdW5jdGlvbihjKXtyZXR1cm4gZVthXSh0LGMscil9fSk6bmEoZSk/dGEubWFwKFJvKGUsdCkpOmlhKGUpP29hLm1hcChSbyhlLHQpKTpbXSwyKSxpPW5bMF0scz1uWzFdO2lmKCFpJiZkdChlKSlyZXR1cm4gcmUoZnVuY3Rpb24oYSl7cmV0dXJuIGQoYSx0LHIpfSkoTihlKSk7aWYoIWkpdGhyb3cgbmV3IFR5cGVFcnJvcigiSW52YWxpZCBldmVudCB0YXJnZXQiKTtyZXR1cm4gbmV3IGooZnVuY3Rpb24oYSl7dmFyIGM9ZnVuY3Rpb24oKXtmb3IodmFyIHA9W10sbD0wO2w8YXJndW1lbnRzLmxlbmd0aDtsKyspcFtsXT1hcmd1bWVudHNbbF07cmV0dXJuIGEubmV4dCgxPHAubGVuZ3RoP3A6cFswXSl9O3JldHVybiBpKGMpLGZ1bmN0aW9uKCl7cmV0dXJuIHMoYyl9fSl9ZnVuY3Rpb24gUm8oZSx0KXtyZXR1cm4gZnVuY3Rpb24ocil7cmV0dXJuIGZ1bmN0aW9uKG8pe3JldHVybiBlW3JdKHQsbyl9fX1mdW5jdGlvbiBuYShlKXtyZXR1cm4gayhlLmFkZExpc3RlbmVyKSYmayhlLnJlbW92ZUxpc3RlbmVyKX1mdW5jdGlvbiBpYShlKXtyZXR1cm4gayhlLm9uKSYmayhlLm9mZil9ZnVuY3Rpb24gYWEoZSl7cmV0dXJuIGsoZS5hZGRFdmVudExpc3RlbmVyKSYmayhlLnJlbW92ZUV2ZW50TGlzdGVuZXIpfWZ1bmN0aW9uIG5yKGUsdCxyKXtyZXR1cm4gcj9ucihlLHQpLnBpcGUoWGUocikpOm5ldyBqKGZ1bmN0aW9uKG8pe3ZhciBuPWZ1bmN0aW9uKCl7Zm9yKHZhciBzPVtdLGE9MDthPGFyZ3VtZW50cy5sZW5ndGg7YSsrKXNbYV09YXJndW1lbnRzW2FdO3JldHVybiBvLm5leHQocy5sZW5ndGg9PT0xP3NbMF06cyl9LGk9ZShuKTtyZXR1cm4gayh0KT9mdW5jdGlvbigpe3JldHVybiB0KG4saSl9OnZvaWQgMH0pfWZ1bmN0aW9uIFplKGUsdCxyKXtlPT09dm9pZCAwJiYoZT0wKSxyPT09dm9pZCAwJiYocj1Mcik7dmFyIG89LTE7cmV0dXJuIHQhPW51bGwmJihLdCh0KT9yPXQ6bz10KSxuZXcgaihmdW5jdGlvbihuKXt2YXIgaT1fbyhlKT8rZS1yLm5vdygpOmU7aTwwJiYoaT0wKTt2YXIgcz0wO3JldHVybiByLnNjaGVkdWxlKGZ1bmN0aW9uKCl7bi5jbG9zZWR8fChuLm5leHQocysrKSwwPD1vP3RoaXMuc2NoZWR1bGUodm9pZCAwLG8pOm4uY29tcGxldGUoKSl9LGkpfSl9ZnVuY3Rpb24gVCgpe2Zvcih2YXIgZT1bXSx0PTA7dDxhcmd1bWVudHMubGVuZ3RoO3QrKyllW3RdPWFyZ3VtZW50c1t0XTt2YXIgcj1BZShlKSxvPVF0KGUsMS8wKSxuPWU7cmV0dXJuIG4ubGVuZ3RoP24ubGVuZ3RoPT09MT9OKG5bMF0pOmh0KG8pKGZlKG4scikpOkx9dmFyIHFlPW5ldyBqKFNlKTt2YXIgc2E9QXJyYXkuaXNBcnJheTtmdW5jdGlvbiBidChlKXtyZXR1cm4gZS5sZW5ndGg9PT0xJiZzYShlWzBdKT9lWzBdOmV9ZnVuY3Rpb24gZyhlLHQpe3JldHVybiB4KGZ1bmN0aW9uKHIsbyl7dmFyIG49MDtyLnN1YnNjcmliZShTKG8sZnVuY3Rpb24oaSl7cmV0dXJuIGUuY2FsbCh0LGksbisrKSYmby5uZXh0KGkpfSkpfSl9ZnVuY3Rpb24gTHQoKXtmb3IodmFyIGU9W10sdD0wO3Q8YXJndW1lbnRzLmxlbmd0aDt0KyspZVt0XT1hcmd1bWVudHNbdF07dmFyIHI9SmUoZSksbz1idChlKTtyZXR1cm4gby5sZW5ndGg/bmV3IGooZnVuY3Rpb24obil7dmFyIGk9by5tYXAoZnVuY3Rpb24oKXtyZXR1cm5bXX0pLHM9by5tYXAoZnVuY3Rpb24oKXtyZXR1cm4hMX0pO24uYWRkKGZ1bmN0aW9uKCl7aT1zPW51bGx9KTtmb3IodmFyIGE9ZnVuY3Rpb24ocCl7TihvW3BdKS5zdWJzY3JpYmUoUyhuLGZ1bmN0aW9uKGwpe2lmKGlbcF0ucHVzaChsKSxpLmV2ZXJ5KGZ1bmN0aW9uKHUpe3JldHVybiB1Lmxlbmd0aH0pKXt2YXIgZj1pLm1hcChmdW5jdGlvbih1KXtyZXR1cm4gdS5zaGlmdCgpfSk7bi5uZXh0KHI/ci5hcHBseSh2b2lkIDAseihbXSxWKGYpKSk6ZiksaS5zb21lKGZ1bmN0aW9uKHUsaCl7cmV0dXJuIXUubGVuZ3RoJiZzW2hdfSkmJm4uY29tcGxldGUoKX19LGZ1bmN0aW9uKCl7c1twXT0hMCwhaVtwXS5sZW5ndGgmJm4uY29tcGxldGUoKX0pKX0sYz0wOyFuLmNsb3NlZCYmYzxvLmxlbmd0aDtjKyspYShjKTtyZXR1cm4gZnVuY3Rpb24oKXtpPXM9bnVsbH19KTpMfWZ1bmN0aW9uIFBvKGUpe3JldHVybiB4KGZ1bmN0aW9uKHQscil7dmFyIG89ITEsbj1udWxsLGk9bnVsbCxzPSExLGE9ZnVuY3Rpb24oKXtpZihpPT1udWxsfHxpLnVuc3Vic2NyaWJlKCksaT1udWxsLG8pe289ITE7dmFyIHA9bjtuPW51bGwsci5uZXh0KHApfXMmJnIuY29tcGxldGUoKX0sYz1mdW5jdGlvbigpe2k9bnVsbCxzJiZyLmNvbXBsZXRlKCl9O3Quc3Vic2NyaWJlKFMocixmdW5jdGlvbihwKXtvPSEwLG49cCxpfHxOKGUocCkpLnN1YnNjcmliZShpPVMocixhLGMpKX0sZnVuY3Rpb24oKXtzPSEwLCghb3x8IWl8fGkuY2xvc2VkKSYmci5jb21wbGV0ZSgpfSkpfSl9ZnVuY3Rpb24gTWUoZSx0KXtyZXR1cm4gdD09PXZvaWQgMCYmKHQ9aWUpLFBvKGZ1bmN0aW9uKCl7cmV0dXJuIFplKGUsdCl9KX1mdW5jdGlvbiBLZShlLHQpe3JldHVybiB0PT09dm9pZCAwJiYodD1udWxsKSx0PXQhPW51bGw/dDplLHgoZnVuY3Rpb24ocixvKXt2YXIgbj1bXSxpPTA7ci5zdWJzY3JpYmUoUyhvLGZ1bmN0aW9uKHMpe3ZhciBhLGMscCxsLGY9bnVsbDtpKysldD09PTAmJm4ucHVzaChbXSk7dHJ5e2Zvcih2YXIgdT11ZShuKSxoPXUubmV4dCgpOyFoLmRvbmU7aD11Lm5leHQoKSl7dmFyIHc9aC52YWx1ZTt3LnB1c2gocyksZTw9dy5sZW5ndGgmJihmPWYhPW51bGw/ZjpbXSxmLnB1c2godykpfX1jYXRjaCh0ZSl7YT17ZXJyb3I6dGV9fWZpbmFsbHl7dHJ5e2gmJiFoLmRvbmUmJihjPXUucmV0dXJuKSYmYy5jYWxsKHUpfWZpbmFsbHl7aWYoYSl0aHJvdyBhLmVycm9yfX1pZihmKXRyeXtmb3IodmFyIEE9dWUoZiksWj1BLm5leHQoKTshWi5kb25lO1o9QS5uZXh0KCkpe3ZhciB3PVoudmFsdWU7VmUobix3KSxvLm5leHQodyl9fWNhdGNoKHRlKXtwPXtlcnJvcjp0ZX19ZmluYWxseXt0cnl7WiYmIVouZG9uZSYmKGw9QS5yZXR1cm4pJiZsLmNhbGwoQSl9ZmluYWxseXtpZihwKXRocm93IHAuZXJyb3J9fX0sZnVuY3Rpb24oKXt2YXIgcyxhO3RyeXtmb3IodmFyIGM9dWUobikscD1jLm5leHQoKTshcC5kb25lO3A9Yy5uZXh0KCkpe3ZhciBsPXAudmFsdWU7by5uZXh0KGwpfX1jYXRjaChmKXtzPXtlcnJvcjpmfX1maW5hbGx5e3RyeXtwJiYhcC5kb25lJiYoYT1jLnJldHVybikmJmEuY2FsbChjKX1maW5hbGx5e2lmKHMpdGhyb3cgcy5lcnJvcn19by5jb21wbGV0ZSgpfSx2b2lkIDAsZnVuY3Rpb24oKXtuPW51bGx9KSl9KX1mdW5jdGlvbiBoZShlKXtyZXR1cm4geChmdW5jdGlvbih0LHIpe3ZhciBvPW51bGwsbj0hMSxpO289dC5zdWJzY3JpYmUoUyhyLHZvaWQgMCx2b2lkIDAsZnVuY3Rpb24ocyl7aT1OKGUocyxoZShlKSh0KSkpLG8/KG8udW5zdWJzY3JpYmUoKSxvPW51bGwsaS5zdWJzY3JpYmUocikpOm49ITB9KSksbiYmKG8udW5zdWJzY3JpYmUoKSxvPW51bGwsaS5zdWJzY3JpYmUocikpfSl9ZnVuY3Rpb24gSW8oZSx0LHIsbyxuKXtyZXR1cm4gZnVuY3Rpb24oaSxzKXt2YXIgYT1yLGM9dCxwPTA7aS5zdWJzY3JpYmUoUyhzLGZ1bmN0aW9uKGwpe3ZhciBmPXArKztjPWE/ZShjLGwsZik6KGE9ITAsbCksbyYmcy5uZXh0KGMpfSxuJiZmdW5jdGlvbigpe2EmJnMubmV4dChjKSxzLmNvbXBsZXRlKCl9KSl9fWZ1bmN0aW9uIGtyKCl7Zm9yKHZhciBlPVtdLHQ9MDt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKWVbdF09YXJndW1lbnRzW3RdO3ZhciByPUplKGUpO3JldHVybiByP3VvKGtyLmFwcGx5KHZvaWQgMCx6KFtdLFYoZSkpKSxYZShyKSk6eChmdW5jdGlvbihvLG4pe0NyKHooW29dLFYoYnQoZSkpKSkobil9KX1mdW5jdGlvbiBqZSgpe2Zvcih2YXIgZT1bXSx0PTA7dDxhcmd1bWVudHMubGVuZ3RoO3QrKyllW3RdPWFyZ3VtZW50c1t0XTtyZXR1cm4ga3IuYXBwbHkodm9pZCAwLHooW10sVihlKSkpfWZ1bmN0aW9uIGJlKGUsdCl7cmV0dXJuIHQ9PT12b2lkIDAmJih0PWllKSx4KGZ1bmN0aW9uKHIsbyl7dmFyIG49bnVsbCxpPW51bGwscz1udWxsLGE9ZnVuY3Rpb24oKXtpZihuKXtuLnVuc3Vic2NyaWJlKCksbj1udWxsO3ZhciBwPWk7aT1udWxsLG8ubmV4dChwKX19O2Z1bmN0aW9uIGMoKXt2YXIgcD1zK2UsbD10Lm5vdygpO2lmKGw8cCl7bj10aGlzLnNjaGVkdWxlKHZvaWQgMCxwLWwpLG8uYWRkKG4pO3JldHVybn1hKCl9ci5zdWJzY3JpYmUoUyhvLGZ1bmN0aW9uKHApe2k9cCxzPXQubm93KCksbnx8KG49dC5zY2hlZHVsZShjLGUpLG8uYWRkKG4pKX0sZnVuY3Rpb24oKXthKCksby5jb21wbGV0ZSgpfSx2b2lkIDAsZnVuY3Rpb24oKXtpPW49bnVsbH0pKX0pfWZ1bmN0aW9uIFFlKGUpe3JldHVybiB4KGZ1bmN0aW9uKHQscil7dmFyIG89ITE7dC5zdWJzY3JpYmUoUyhyLGZ1bmN0aW9uKG4pe289ITAsci5uZXh0KG4pfSxmdW5jdGlvbigpe298fHIubmV4dChlKSxyLmNvbXBsZXRlKCl9KSl9KX1mdW5jdGlvbiB5ZShlKXtyZXR1cm4gZTw9MD9mdW5jdGlvbigpe3JldHVybiBMfTp4KGZ1bmN0aW9uKHQscil7dmFyIG89MDt0LnN1YnNjcmliZShTKHIsZnVuY3Rpb24obil7KytvPD1lJiYoci5uZXh0KG4pLGU8PW8mJnIuY29tcGxldGUoKSl9KSl9KX1mdW5jdGlvbiBlZSgpe3JldHVybiB4KGZ1bmN0aW9uKGUsdCl7ZS5zdWJzY3JpYmUoUyh0LFNlKSl9KX1mdW5jdGlvbiBGbyhlKXtyZXR1cm4gbShmdW5jdGlvbigpe3JldHVybiBlfSl9ZnVuY3Rpb24gSHIoZSx0KXtyZXR1cm4gdD9mdW5jdGlvbihyKXtyZXR1cm4gRmUodC5waXBlKHllKDEpLGVlKCkpLHIucGlwZShIcihlKSkpfTpyZShmdW5jdGlvbihyLG8pe3JldHVybiBOKGUocixvKSkucGlwZSh5ZSgxKSxGbyhyKSl9KX1mdW5jdGlvbiBZZShlLHQpe3Q9PT12b2lkIDAmJih0PWllKTt2YXIgcj1aZShlLHQpO3JldHVybiBIcihmdW5jdGlvbigpe3JldHVybiByfSl9ZnVuY3Rpb24gWShlLHQpe3JldHVybiB0PT09dm9pZCAwJiYodD1jZSksZT1lIT1udWxsP2U6Y2EseChmdW5jdGlvbihyLG8pe3ZhciBuLGk9ITA7ci5zdWJzY3JpYmUoUyhvLGZ1bmN0aW9uKHMpe3ZhciBhPXQocyk7KGl8fCFlKG4sYSkpJiYoaT0hMSxuPWEsby5uZXh0KHMpKX0pKX0pfWZ1bmN0aW9uIGNhKGUsdCl7cmV0dXJuIGU9PT10fWZ1bmN0aW9uIFgoZSx0KXtyZXR1cm4gWShmdW5jdGlvbihyLG8pe3JldHVybiB0P3QocltlXSxvW2VdKTpyW2VdPT09b1tlXX0pfWZ1bmN0aW9uIGpvKGUpe3JldHVybiBlPT09dm9pZCAwJiYoZT1wYSkseChmdW5jdGlvbih0LHIpe3ZhciBvPSExO3Quc3Vic2NyaWJlKFMocixmdW5jdGlvbihuKXtvPSEwLHIubmV4dChuKX0sZnVuY3Rpb24oKXtyZXR1cm4gbz9yLmNvbXBsZXRlKCk6ci5lcnJvcihlKCkpfSkpfSl9ZnVuY3Rpb24gcGEoKXtyZXR1cm4gbmV3IG9yfWZ1bmN0aW9uIG9lKCl7Zm9yKHZhciBlPVtdLHQ9MDt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKWVbdF09YXJndW1lbnRzW3RdO3JldHVybiBmdW5jdGlvbihyKXtyZXR1cm4gRmUociwkLmFwcGx5KHZvaWQgMCx6KFtdLFYoZSkpKSl9fWZ1bmN0aW9uIF8oZSl7cmV0dXJuIHgoZnVuY3Rpb24odCxyKXt0cnl7dC5zdWJzY3JpYmUocil9ZmluYWxseXtyLmFkZChlKX19KX1mdW5jdGlvbiBIZShlLHQpe3ZhciByPWFyZ3VtZW50cy5sZW5ndGg+PTI7cmV0dXJuIGZ1bmN0aW9uKG8pe3JldHVybiBvLnBpcGUoZT9nKGZ1bmN0aW9uKG4saSl7cmV0dXJuIGUobixpLG8pfSk6Y2UseWUoMSkscj9RZSh0KTpqbyhmdW5jdGlvbigpe3JldHVybiBuZXcgb3J9KSl9fWZ1bmN0aW9uICRyKGUpe3JldHVybiBlPD0wP2Z1bmN0aW9uKCl7cmV0dXJuIEx9OngoZnVuY3Rpb24odCxyKXt2YXIgbz1bXTt0LnN1YnNjcmliZShTKHIsZnVuY3Rpb24obil7by5wdXNoKG4pLGU8by5sZW5ndGgmJm8uc2hpZnQoKX0sZnVuY3Rpb24oKXt2YXIgbixpO3RyeXtmb3IodmFyIHM9dWUobyksYT1zLm5leHQoKTshYS5kb25lO2E9cy5uZXh0KCkpe3ZhciBjPWEudmFsdWU7ci5uZXh0KGMpfX1jYXRjaChwKXtuPXtlcnJvcjpwfX1maW5hbGx5e3RyeXthJiYhYS5kb25lJiYoaT1zLnJldHVybikmJmkuY2FsbChzKX1maW5hbGx5e2lmKG4pdGhyb3cgbi5lcnJvcn19ci5jb21wbGV0ZSgpfSx2b2lkIDAsZnVuY3Rpb24oKXtvPW51bGx9KSl9KX1mdW5jdGlvbiBVbygpe2Zvcih2YXIgZT1bXSx0PTA7dDxhcmd1bWVudHMubGVuZ3RoO3QrKyllW3RdPWFyZ3VtZW50c1t0XTt2YXIgcj1BZShlKSxvPVF0KGUsMS8wKTtyZXR1cm4gZT1idChlKSx4KGZ1bmN0aW9uKG4saSl7aHQobykoZmUoeihbbl0sVihlKSkscikpLnN1YnNjcmliZShpKX0pfWZ1bmN0aW9uICRlKCl7Zm9yKHZhciBlPVtdLHQ9MDt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKWVbdF09YXJndW1lbnRzW3RdO3JldHVybiBVby5hcHBseSh2b2lkIDAseihbXSxWKGUpKSl9ZnVuY3Rpb24gYXQoZSl7dmFyIHQscj0xLzAsbztyZXR1cm4gZSE9bnVsbCYmKHR5cGVvZiBlPT0ib2JqZWN0Ij8odD1lLmNvdW50LHI9dD09PXZvaWQgMD8xLzA6dCxvPWUuZGVsYXkpOnI9ZSkscjw9MD9mdW5jdGlvbigpe3JldHVybiBMfTp4KGZ1bmN0aW9uKG4saSl7dmFyIHM9MCxhLGM9ZnVuY3Rpb24oKXtpZihhPT1udWxsfHxhLnVuc3Vic2NyaWJlKCksYT1udWxsLG8hPW51bGwpe3ZhciBsPXR5cGVvZiBvPT0ibnVtYmVyIj9aZShvKTpOKG8ocykpLGY9UyhpLGZ1bmN0aW9uKCl7Zi51bnN1YnNjcmliZSgpLHAoKX0pO2wuc3Vic2NyaWJlKGYpfWVsc2UgcCgpfSxwPWZ1bmN0aW9uKCl7dmFyIGw9ITE7YT1uLnN1YnNjcmliZShTKGksdm9pZCAwLGZ1bmN0aW9uKCl7KytzPHI/YT9jKCk6bD0hMDppLmNvbXBsZXRlKCl9KSksbCYmYygpfTtwKCl9KX1mdW5jdGlvbiBScihlLHQpe3JldHVybiB4KElvKGUsdCxhcmd1bWVudHMubGVuZ3RoPj0yLCEwKSl9ZnVuY3Rpb24gbGUoZSl7ZT09PXZvaWQgMCYmKGU9e30pO3ZhciB0PWUuY29ubmVjdG9yLHI9dD09PXZvaWQgMD9mdW5jdGlvbigpe3JldHVybiBuZXcgdn06dCxvPWUucmVzZXRPbkVycm9yLG49bz09PXZvaWQgMD8hMDpvLGk9ZS5yZXNldE9uQ29tcGxldGUscz1pPT09dm9pZCAwPyEwOmksYT1lLnJlc2V0T25SZWZDb3VudFplcm8sYz1hPT09dm9pZCAwPyEwOmE7cmV0dXJuIGZ1bmN0aW9uKHApe3ZhciBsLGYsdSxoPTAsdz0hMSxBPSExLFo9ZnVuY3Rpb24oKXtmPT1udWxsfHxmLnVuc3Vic2NyaWJlKCksZj12b2lkIDB9LHRlPWZ1bmN0aW9uKCl7WigpLGw9dT12b2lkIDAsdz1BPSExfSxKPWZ1bmN0aW9uKCl7dmFyIEM9bDt0ZSgpLEM9PW51bGx8fEMudW5zdWJzY3JpYmUoKX07cmV0dXJuIHgoZnVuY3Rpb24oQyxjdCl7aCsrLCFBJiYhdyYmWigpO3ZhciBOZT11PXUhPW51bGw/dTpyKCk7Y3QuYWRkKGZ1bmN0aW9uKCl7aC0tLGg9PT0wJiYhQSYmIXcmJihmPVByKEosYykpfSksTmUuc3Vic2NyaWJlKGN0KSwhbCYmaD4wJiYobD1uZXcgaXQoe25leHQ6ZnVuY3Rpb24oUGUpe3JldHVybiBOZS5uZXh0KFBlKX0sZXJyb3I6ZnVuY3Rpb24oUGUpe0E9ITAsWigpLGY9UHIodGUsbixQZSksTmUuZXJyb3IoUGUpfSxjb21wbGV0ZTpmdW5jdGlvbigpe3c9ITAsWigpLGY9UHIodGUscyksTmUuY29tcGxldGUoKX19KSxOKEMpLnN1YnNjcmliZShsKSl9KShwKX19ZnVuY3Rpb24gUHIoZSx0KXtmb3IodmFyIHI9W10sbz0yO288YXJndW1lbnRzLmxlbmd0aDtvKyspcltvLTJdPWFyZ3VtZW50c1tvXTtpZih0PT09ITApe2UoKTtyZXR1cm59aWYodCE9PSExKXt2YXIgbj1uZXcgaXQoe25leHQ6ZnVuY3Rpb24oKXtuLnVuc3Vic2NyaWJlKCksZSgpfX0pO3JldHVybiBOKHQuYXBwbHkodm9pZCAwLHooW10sVihyKSkpKS5zdWJzY3JpYmUobil9fWZ1bmN0aW9uIEIoZSx0LHIpe3ZhciBvLG4saSxzLGE9ITE7cmV0dXJuIGUmJnR5cGVvZiBlPT0ib2JqZWN0Ij8obz1lLmJ1ZmZlclNpemUscz1vPT09dm9pZCAwPzEvMDpvLG49ZS53aW5kb3dUaW1lLHQ9bj09PXZvaWQgMD8xLzA6bixpPWUucmVmQ291bnQsYT1pPT09dm9pZCAwPyExOmkscj1lLnNjaGVkdWxlcik6cz1lIT1udWxsP2U6MS8wLGxlKHtjb25uZWN0b3I6ZnVuY3Rpb24oKXtyZXR1cm4gbmV3IE90KHMsdCxyKX0scmVzZXRPbkVycm9yOiEwLHJlc2V0T25Db21wbGV0ZTohMSxyZXNldE9uUmVmQ291bnRaZXJvOmF9KX1mdW5jdGlvbiBMZShlKXtyZXR1cm4gZyhmdW5jdGlvbih0LHIpe3JldHVybiBlPD1yfSl9ZnVuY3Rpb24gSXIoZSl7cmV0dXJuIHgoZnVuY3Rpb24odCxyKXt2YXIgbz0hMSxuPVMocixmdW5jdGlvbigpe249PW51bGx8fG4udW5zdWJzY3JpYmUoKSxvPSEwfSxTZSk7TihlKS5zdWJzY3JpYmUobiksdC5zdWJzY3JpYmUoUyhyLGZ1bmN0aW9uKGkpe3JldHVybiBvJiZyLm5leHQoaSl9KSl9KX1mdW5jdGlvbiBxKCl7Zm9yKHZhciBlPVtdLHQ9MDt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKWVbdF09YXJndW1lbnRzW3RdO3ZhciByPUFlKGUpO3JldHVybiB4KGZ1bmN0aW9uKG8sbil7KHI/RmUoZSxvLHIpOkZlKGUsbykpLnN1YnNjcmliZShuKX0pfWZ1bmN0aW9uIGIoZSx0KXtyZXR1cm4geChmdW5jdGlvbihyLG8pe3ZhciBuPW51bGwsaT0wLHM9ITEsYT1mdW5jdGlvbigpe3JldHVybiBzJiYhbiYmby5jb21wbGV0ZSgpfTtyLnN1YnNjcmliZShTKG8sZnVuY3Rpb24oYyl7bj09bnVsbHx8bi51bnN1YnNjcmliZSgpO3ZhciBwPTAsbD1pKys7TihlKGMsbCkpLnN1YnNjcmliZShuPVMobyxmdW5jdGlvbihmKXtyZXR1cm4gby5uZXh0KHQ/dChjLGYsbCxwKyspOmYpfSxmdW5jdGlvbigpe249bnVsbCxhKCl9KSl9LGZ1bmN0aW9uKCl7cz0hMCxhKCl9KSl9KX1mdW5jdGlvbiBVKGUpe3JldHVybiB4KGZ1bmN0aW9uKHQscil7TihlKS5zdWJzY3JpYmUoUyhyLGZ1bmN0aW9uKCl7cmV0dXJuIHIuY29tcGxldGUoKX0sU2UpKSwhci5jbG9zZWQmJnQuc3Vic2NyaWJlKHIpfSl9ZnVuY3Rpb24gRnIoZSx0KXtyZXR1cm4gdD09PXZvaWQgMCYmKHQ9ITEpLHgoZnVuY3Rpb24ocixvKXt2YXIgbj0wO3Iuc3Vic2NyaWJlKFMobyxmdW5jdGlvbihpKXt2YXIgcz1lKGksbisrKTsoc3x8dCkmJm8ubmV4dChpKSwhcyYmby5jb21wbGV0ZSgpfSkpfSl9ZnVuY3Rpb24geShlLHQscil7dmFyIG89ayhlKXx8dHx8cj97bmV4dDplLGVycm9yOnQsY29tcGxldGU6cn06ZTtyZXR1cm4gbz94KGZ1bmN0aW9uKG4saSl7dmFyIHM7KHM9by5zdWJzY3JpYmUpPT09bnVsbHx8cz09PXZvaWQgMHx8cy5jYWxsKG8pO3ZhciBhPSEwO24uc3Vic2NyaWJlKFMoaSxmdW5jdGlvbihjKXt2YXIgcDsocD1vLm5leHQpPT09bnVsbHx8cD09PXZvaWQgMHx8cC5jYWxsKG8sYyksaS5uZXh0KGMpfSxmdW5jdGlvbigpe3ZhciBjO2E9ITEsKGM9by5jb21wbGV0ZSk9PT1udWxsfHxjPT09dm9pZCAwfHxjLmNhbGwobyksaS5jb21wbGV0ZSgpfSxmdW5jdGlvbihjKXt2YXIgcDthPSExLChwPW8uZXJyb3IpPT09bnVsbHx8cD09PXZvaWQgMHx8cC5jYWxsKG8sYyksaS5lcnJvcihjKX0sZnVuY3Rpb24oKXt2YXIgYyxwO2EmJigoYz1vLnVuc3Vic2NyaWJlKT09PW51bGx8fGM9PT12b2lkIDB8fGMuY2FsbChvKSksKHA9by5maW5hbGl6ZSk9PT1udWxsfHxwPT09dm9pZCAwfHxwLmNhbGwobyl9KSl9KTpjZX1mdW5jdGlvbiBXbyhlLHQpe3JldHVybiB4KGZ1bmN0aW9uKHIsbyl7dmFyIG49dCE9bnVsbD90Ont9LGk9bi5sZWFkaW5nLHM9aT09PXZvaWQgMD8hMDppLGE9bi50cmFpbGluZyxjPWE9PT12b2lkIDA/ITE6YSxwPSExLGw9bnVsbCxmPW51bGwsdT0hMSxoPWZ1bmN0aW9uKCl7Zj09bnVsbHx8Zi51bnN1YnNjcmliZSgpLGY9bnVsbCxjJiYoWigpLHUmJm8uY29tcGxldGUoKSl9LHc9ZnVuY3Rpb24oKXtmPW51bGwsdSYmby5jb21wbGV0ZSgpfSxBPWZ1bmN0aW9uKHRlKXtyZXR1cm4gZj1OKGUodGUpKS5zdWJzY3JpYmUoUyhvLGgsdykpfSxaPWZ1bmN0aW9uKCl7aWYocCl7cD0hMTt2YXIgdGU9bDtsPW51bGwsby5uZXh0KHRlKSwhdSYmQSh0ZSl9fTtyLnN1YnNjcmliZShTKG8sZnVuY3Rpb24odGUpe3A9ITAsbD10ZSwhKGYmJiFmLmNsb3NlZCkmJihzP1ooKTpBKHRlKSl9LGZ1bmN0aW9uKCl7dT0hMCwhKGMmJnAmJmYmJiFmLmNsb3NlZCkmJm8uY29tcGxldGUoKX0pKX0pfWZ1bmN0aW9uIF90KGUsdCxyKXt0PT09dm9pZCAwJiYodD1pZSk7dmFyIG89WmUoZSx0KTtyZXR1cm4gV28oZnVuY3Rpb24oKXtyZXR1cm4gb30scil9ZnVuY3Rpb24gYWUoKXtmb3IodmFyIGU9W10sdD0wO3Q8YXJndW1lbnRzLmxlbmd0aDt0KyspZVt0XT1hcmd1bWVudHNbdF07dmFyIHI9SmUoZSk7cmV0dXJuIHgoZnVuY3Rpb24obyxuKXtmb3IodmFyIGk9ZS5sZW5ndGgscz1uZXcgQXJyYXkoaSksYT1lLm1hcChmdW5jdGlvbigpe3JldHVybiExfSksYz0hMSxwPWZ1bmN0aW9uKGYpe04oZVtmXSkuc3Vic2NyaWJlKFMobixmdW5jdGlvbih1KXtzW2ZdPXUsIWMmJiFhW2ZdJiYoYVtmXT0hMCwoYz1hLmV2ZXJ5KGNlKSkmJihhPW51bGwpKX0sU2UpKX0sbD0wO2w8aTtsKyspcChsKTtvLnN1YnNjcmliZShTKG4sZnVuY3Rpb24oZil7aWYoYyl7dmFyIHU9eihbZl0sVihzKSk7bi5uZXh0KHI/ci5hcHBseSh2b2lkIDAseihbXSxWKHUpKSk6dSl9fSkpfSl9ZnVuY3Rpb24gRG8oKXtmb3IodmFyIGU9W10sdD0wO3Q8YXJndW1lbnRzLmxlbmd0aDt0KyspZVt0XT1hcmd1bWVudHNbdF07cmV0dXJuIHgoZnVuY3Rpb24ocixvKXtMdC5hcHBseSh2b2lkIDAseihbcl0sVihlKSkpLnN1YnNjcmliZShvKX0pfWZ1bmN0aW9uIGpyKCl7Zm9yKHZhciBlPVtdLHQ9MDt0PGFyZ3VtZW50cy5sZW5ndGg7dCsrKWVbdF09YXJndW1lbnRzW3RdO3JldHVybiBEby5hcHBseSh2b2lkIDAseihbXSxWKGUpKSl9ZnVuY3Rpb24gTm8oKXtsZXQgZT1uZXcgT3QoMSk7cmV0dXJuIGQoZG9jdW1lbnQsIkRPTUNvbnRlbnRMb2FkZWQiLHtvbmNlOiEwfSkuc3Vic2NyaWJlKCgpPT5lLm5leHQoZG9jdW1lbnQpKSxlfWZ1bmN0aW9uIFIoZSx0PWRvY3VtZW50KXtyZXR1cm4gQXJyYXkuZnJvbSh0LnF1ZXJ5U2VsZWN0b3JBbGwoZSkpfWZ1bmN0aW9uIFAoZSx0PWRvY3VtZW50KXtsZXQgcj1tZShlLHQpO2lmKHR5cGVvZiByPT0idW5kZWZpbmVkIil0aHJvdyBuZXcgUmVmZXJlbmNlRXJyb3IoYE1pc3NpbmcgZWxlbWVudDogZXhwZWN0ZWQgIiR7ZX0iIHRvIGJlIHByZXNlbnRgKTtyZXR1cm4gcn1mdW5jdGlvbiBtZShlLHQ9ZG9jdW1lbnQpe3JldHVybiB0LnF1ZXJ5U2VsZWN0b3IoZSl8fHZvaWQgMH1mdW5jdGlvbiBSZSgpe3ZhciBlLHQscixvO3JldHVybihvPShyPSh0PShlPWRvY3VtZW50LmFjdGl2ZUVsZW1lbnQpPT1udWxsP3ZvaWQgMDplLnNoYWRvd1Jvb3QpPT1udWxsP3ZvaWQgMDp0LmFjdGl2ZUVsZW1lbnQpIT1udWxsP3I6ZG9jdW1lbnQuYWN0aXZlRWxlbWVudCkhPW51bGw/bzp2b2lkIDB9dmFyIGxhPVQoZChkb2N1bWVudC5ib2R5LCJmb2N1c2luIiksZChkb2N1bWVudC5ib2R5LCJmb2N1c291dCIpKS5waXBlKGJlKDEpLHEodm9pZCAwKSxtKCgpPT5SZSgpfHxkb2N1bWVudC5ib2R5KSxCKDEpKTtmdW5jdGlvbiB2dChlKXtyZXR1cm4gbGEucGlwZShtKHQ9PmUuY29udGFpbnModCkpLFkoKSl9ZnVuY3Rpb24gVm8oZSx0KXtyZXR1cm4gVChkKGUsIm1vdXNlZW50ZXIiKS5waXBlKG0oKCk9PiEwKSksZChlLCJtb3VzZWxlYXZlIikucGlwZShtKCgpPT4hMSkpKS5waXBlKHQ/YmUodCk6Y2UscSghMSkpfWZ1bmN0aW9uIFVlKGUpe3JldHVybnt4OmUub2Zmc2V0TGVmdCx5OmUub2Zmc2V0VG9wfX1mdW5jdGlvbiB6byhlKXtyZXR1cm4gVChkKHdpbmRvdywibG9hZCIpLGQod2luZG93LCJyZXNpemUiKSkucGlwZShNZSgwLGRlKSxtKCgpPT5VZShlKSkscShVZShlKSkpfWZ1bmN0aW9uIGlyKGUpe3JldHVybnt4OmUuc2Nyb2xsTGVmdCx5OmUuc2Nyb2xsVG9wfX1mdW5jdGlvbiBldChlKXtyZXR1cm4gVChkKGUsInNjcm9sbCIpLGQod2luZG93LCJyZXNpemUiKSkucGlwZShNZSgwLGRlKSxtKCgpPT5pcihlKSkscShpcihlKSkpfWZ1bmN0aW9uIHFvKGUsdCl7aWYodHlwZW9mIHQ9PSJzdHJpbmcifHx0eXBlb2YgdD09Im51bWJlciIpZS5pbm5lckhUTUwrPXQudG9TdHJpbmcoKTtlbHNlIGlmKHQgaW5zdGFuY2VvZiBOb2RlKWUuYXBwZW5kQ2hpbGQodCk7ZWxzZSBpZihBcnJheS5pc0FycmF5KHQpKWZvcihsZXQgciBvZiB0KXFvKGUscil9ZnVuY3Rpb24gRShlLHQsLi4ucil7bGV0IG89ZG9jdW1lbnQuY3JlYXRlRWxlbWVudChlKTtpZih0KWZvcihsZXQgbiBvZiBPYmplY3Qua2V5cyh0KSl0eXBlb2YgdFtuXSE9InVuZGVmaW5lZCImJih0eXBlb2YgdFtuXSE9ImJvb2xlYW4iP28uc2V0QXR0cmlidXRlKG4sdFtuXSk6by5zZXRBdHRyaWJ1dGUobiwiIikpO2ZvcihsZXQgbiBvZiByKXFvKG8sbik7cmV0dXJuIG99ZnVuY3Rpb24gYXIoZSl7aWYoZT45OTkpe2xldCB0PSsoKGUtOTUwKSUxZTM+OTkpO3JldHVybmAkeygoZSsxZS02KS8xZTMpLnRvRml4ZWQodCl9a2B9ZWxzZSByZXR1cm4gZS50b1N0cmluZygpfWZ1bmN0aW9uIGd0KGUpe2xldCB0PUUoInNjcmlwdCIse3NyYzplfSk7cmV0dXJuIEgoKCk9Pihkb2N1bWVudC5oZWFkLmFwcGVuZENoaWxkKHQpLFQoZCh0LCJsb2FkIiksZCh0LCJlcnJvciIpLnBpcGUoYigoKT0+QXIoKCk9Pm5ldyBSZWZlcmVuY2VFcnJvcihgSW52YWxpZCBzY3JpcHQ6ICR7ZX1gKSkpKSkucGlwZShtKCgpPT57fSksXygoKT0+ZG9jdW1lbnQuaGVhZC5yZW1vdmVDaGlsZCh0KSkseWUoMSkpKSl9dmFyIEtvPW5ldyB2LG1hPUgoKCk9PnR5cGVvZiBSZXNpemVPYnNlcnZlcj09InVuZGVmaW5lZCI/Z3QoImh0dHBzOi8vdW5wa2cuY29tL3Jlc2l6ZS1vYnNlcnZlci1wb2x5ZmlsbCIpOiQodm9pZCAwKSkucGlwZShtKCgpPT5uZXcgUmVzaXplT2JzZXJ2ZXIoZT0+e2ZvcihsZXQgdCBvZiBlKUtvLm5leHQodCl9KSksYihlPT5UKHFlLCQoZSkpLnBpcGUoXygoKT0+ZS5kaXNjb25uZWN0KCkpKSksQigxKSk7ZnVuY3Rpb24gcGUoZSl7cmV0dXJue3dpZHRoOmUub2Zmc2V0V2lkdGgsaGVpZ2h0OmUub2Zmc2V0SGVpZ2h0fX1mdW5jdGlvbiBFZShlKXtyZXR1cm4gbWEucGlwZSh5KHQ9PnQub2JzZXJ2ZShlKSksYih0PT5Lby5waXBlKGcoKHt0YXJnZXQ6cn0pPT5yPT09ZSksXygoKT0+dC51bm9ic2VydmUoZSkpLG0oKCk9PnBlKGUpKSkpLHEocGUoZSkpKX1mdW5jdGlvbiB4dChlKXtyZXR1cm57d2lkdGg6ZS5zY3JvbGxXaWR0aCxoZWlnaHQ6ZS5zY3JvbGxIZWlnaHR9fWZ1bmN0aW9uIHNyKGUpe2xldCB0PWUucGFyZW50RWxlbWVudDtmb3IoO3QmJihlLnNjcm9sbFdpZHRoPD10LnNjcm9sbFdpZHRoJiZlLnNjcm9sbEhlaWdodDw9dC5zY3JvbGxIZWlnaHQpOyl0PShlPXQpLnBhcmVudEVsZW1lbnQ7cmV0dXJuIHQ/ZTp2b2lkIDB9dmFyIFFvPW5ldyB2LGZhPUgoKCk9PiQobmV3IEludGVyc2VjdGlvbk9ic2VydmVyKGU9Pntmb3IobGV0IHQgb2YgZSlRby5uZXh0KHQpfSx7dGhyZXNob2xkOjB9KSkpLnBpcGUoYihlPT5UKHFlLCQoZSkpLnBpcGUoXygoKT0+ZS5kaXNjb25uZWN0KCkpKSksQigxKSk7ZnVuY3Rpb24geXQoZSl7cmV0dXJuIGZhLnBpcGUoeSh0PT50Lm9ic2VydmUoZSkpLGIodD0+UW8ucGlwZShnKCh7dGFyZ2V0OnJ9KT0+cj09PWUpLF8oKCk9PnQudW5vYnNlcnZlKGUpKSxtKCh7aXNJbnRlcnNlY3Rpbmc6cn0pPT5yKSkpKX1mdW5jdGlvbiBZbyhlLHQ9MTYpe3JldHVybiBldChlKS5waXBlKG0oKHt5OnJ9KT0+e2xldCBvPXBlKGUpLG49eHQoZSk7cmV0dXJuIHI+PW4uaGVpZ2h0LW8uaGVpZ2h0LXR9KSxZKCkpfXZhciBjcj17ZHJhd2VyOlAoIltkYXRhLW1kLXRvZ2dsZT1kcmF3ZXJdIiksc2VhcmNoOlAoIltkYXRhLW1kLXRvZ2dsZT1zZWFyY2hdIil9O2Z1bmN0aW9uIEJvKGUpe3JldHVybiBjcltlXS5jaGVja2VkfWZ1bmN0aW9uIEJlKGUsdCl7Y3JbZV0uY2hlY2tlZCE9PXQmJmNyW2VdLmNsaWNrKCl9ZnVuY3Rpb24gV2UoZSl7bGV0IHQ9Y3JbZV07cmV0dXJuIGQodCwiY2hhbmdlIikucGlwZShtKCgpPT50LmNoZWNrZWQpLHEodC5jaGVja2VkKSl9ZnVuY3Rpb24gdWEoZSx0KXtzd2l0Y2goZS5jb25zdHJ1Y3Rvcil7Y2FzZSBIVE1MSW5wdXRFbGVtZW50OnJldHVybiBlLnR5cGU9PT0icmFkaW8iPy9eQXJyb3cvLnRlc3QodCk6ITA7Y2FzZSBIVE1MU2VsZWN0RWxlbWVudDpjYXNlIEhUTUxUZXh0QXJlYUVsZW1lbnQ6cmV0dXJuITA7ZGVmYXVsdDpyZXR1cm4gZS5pc0NvbnRlbnRFZGl0YWJsZX19ZnVuY3Rpb24gZGEoKXtyZXR1cm4gVChkKHdpbmRvdywiY29tcG9zaXRpb25zdGFydCIpLnBpcGUobSgoKT0+ITApKSxkKHdpbmRvdywiY29tcG9zaXRpb25lbmQiKS5waXBlKG0oKCk9PiExKSkpLnBpcGUocSghMSkpfWZ1bmN0aW9uIEdvKCl7bGV0IGU9ZCh3aW5kb3csImtleWRvd24iKS5waXBlKGcodD0+ISh0Lm1ldGFLZXl8fHQuY3RybEtleSkpLG0odD0+KHttb2RlOkJvKCJzZWFyY2giKT8ic2VhcmNoIjoiZ2xvYmFsIix0eXBlOnQua2V5LGNsYWltKCl7dC5wcmV2ZW50RGVmYXVsdCgpLHQuc3RvcFByb3BhZ2F0aW9uKCl9fSkpLGcoKHttb2RlOnQsdHlwZTpyfSk9PntpZih0PT09Imdsb2JhbCIpe2xldCBvPVJlKCk7aWYodHlwZW9mIG8hPSJ1bmRlZmluZWQiKXJldHVybiF1YShvLHIpfXJldHVybiEwfSksbGUoKSk7cmV0dXJuIGRhKCkucGlwZShiKHQ9PnQ/TDplKSl9ZnVuY3Rpb24gdmUoKXtyZXR1cm4gbmV3IFVSTChsb2NhdGlvbi5ocmVmKX1mdW5jdGlvbiBzdChlLHQ9ITEpe2lmKEcoIm5hdmlnYXRpb24uaW5zdGFudCIpJiYhdCl7bGV0IHI9RSgiYSIse2hyZWY6ZS5ocmVmfSk7ZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChyKSxyLmNsaWNrKCksci5yZW1vdmUoKX1lbHNlIGxvY2F0aW9uLmhyZWY9ZS5ocmVmfWZ1bmN0aW9uIEpvKCl7cmV0dXJuIG5ldyB2fWZ1bmN0aW9uIFhvKCl7cmV0dXJuIGxvY2F0aW9uLmhhc2guc2xpY2UoMSl9ZnVuY3Rpb24gWm8oZSl7bGV0IHQ9RSgiYSIse2hyZWY6ZX0pO3QuYWRkRXZlbnRMaXN0ZW5lcigiY2xpY2siLHI9PnIuc3RvcFByb3BhZ2F0aW9uKCkpLHQuY2xpY2soKX1mdW5jdGlvbiBoYShlKXtyZXR1cm4gVChkKHdpbmRvdywiaGFzaGNoYW5nZSIpLGUpLnBpcGUobShYbykscShYbygpKSxnKHQ9PnQubGVuZ3RoPjApLEIoMSkpfWZ1bmN0aW9uIGVuKGUpe3JldHVybiBoYShlKS5waXBlKG0odD0+bWUoYFtpZD0iJHt0fSJdYCkpLGcodD0+dHlwZW9mIHQhPSJ1bmRlZmluZWQiKSl9ZnVuY3Rpb24gQXQoZSl7bGV0IHQ9bWF0Y2hNZWRpYShlKTtyZXR1cm4gbnIocj0+dC5hZGRMaXN0ZW5lcigoKT0+cih0Lm1hdGNoZXMpKSkucGlwZShxKHQubWF0Y2hlcykpfWZ1bmN0aW9uIHRuKCl7bGV0IGU9bWF0Y2hNZWRpYSgicHJpbnQiKTtyZXR1cm4gVChkKHdpbmRvdywiYmVmb3JlcHJpbnQiKS5waXBlKG0oKCk9PiEwKSksZCh3aW5kb3csImFmdGVycHJpbnQiKS5waXBlKG0oKCk9PiExKSkpLnBpcGUocShlLm1hdGNoZXMpKX1mdW5jdGlvbiBVcihlLHQpe3JldHVybiBlLnBpcGUoYihyPT5yP3QoKTpMKSl9ZnVuY3Rpb24gV3IoZSx0KXtyZXR1cm4gbmV3IGoocj0+e2xldCBvPW5ldyBYTUxIdHRwUmVxdWVzdDtyZXR1cm4gby5vcGVuKCJHRVQiLGAke2V9YCksby5yZXNwb25zZVR5cGU9ImJsb2IiLG8uYWRkRXZlbnRMaXN0ZW5lcigibG9hZCIsKCk9PntvLnN0YXR1cz49MjAwJiZvLnN0YXR1czwzMDA/KHIubmV4dChvLnJlc3BvbnNlKSxyLmNvbXBsZXRlKCkpOnIuZXJyb3IobmV3IEVycm9yKG8uc3RhdHVzVGV4dCkpfSksby5hZGRFdmVudExpc3RlbmVyKCJlcnJvciIsKCk9PntyLmVycm9yKG5ldyBFcnJvcigiTmV0d29yayBlcnJvciIpKX0pLG8uYWRkRXZlbnRMaXN0ZW5lcigiYWJvcnQiLCgpPT57ci5jb21wbGV0ZSgpfSksdHlwZW9mKHQ9PW51bGw/dm9pZCAwOnQucHJvZ3Jlc3MkKSE9InVuZGVmaW5lZCImJihvLmFkZEV2ZW50TGlzdGVuZXIoInByb2dyZXNzIixuPT57dmFyIGk7aWYobi5sZW5ndGhDb21wdXRhYmxlKXQucHJvZ3Jlc3MkLm5leHQobi5sb2FkZWQvbi50b3RhbCoxMDApO2Vsc2V7bGV0IHM9KGk9by5nZXRSZXNwb25zZUhlYWRlcigiQ29udGVudC1MZW5ndGgiKSkhPW51bGw/aTowO3QucHJvZ3Jlc3MkLm5leHQobi5sb2FkZWQvK3MqMTAwKX19KSx0LnByb2dyZXNzJC5uZXh0KDUpKSxvLnNlbmQoKSwoKT0+by5hYm9ydCgpfSl9ZnVuY3Rpb24gRGUoZSx0KXtyZXR1cm4gV3IoZSx0KS5waXBlKGIocj0+ci50ZXh0KCkpLG0ocj0+SlNPTi5wYXJzZShyKSksQigxKSl9ZnVuY3Rpb24gcm4oZSx0KXtsZXQgcj1uZXcgRE9NUGFyc2VyO3JldHVybiBXcihlLHQpLnBpcGUoYihvPT5vLnRleHQoKSksbShvPT5yLnBhcnNlRnJvbVN0cmluZyhvLCJ0ZXh0L2h0bWwiKSksQigxKSl9ZnVuY3Rpb24gb24oZSx0KXtsZXQgcj1uZXcgRE9NUGFyc2VyO3JldHVybiBXcihlLHQpLnBpcGUoYihvPT5vLnRleHQoKSksbShvPT5yLnBhcnNlRnJvbVN0cmluZyhvLCJ0ZXh0L3htbCIpKSxCKDEpKX1mdW5jdGlvbiBubigpe3JldHVybnt4Ok1hdGgubWF4KDAsc2Nyb2xsWCkseTpNYXRoLm1heCgwLHNjcm9sbFkpfX1mdW5jdGlvbiBhbigpe3JldHVybiBUKGQod2luZG93LCJzY3JvbGwiLHtwYXNzaXZlOiEwfSksZCh3aW5kb3csInJlc2l6ZSIse3Bhc3NpdmU6ITB9KSkucGlwZShtKG5uKSxxKG5uKCkpKX1mdW5jdGlvbiBzbigpe3JldHVybnt3aWR0aDppbm5lcldpZHRoLGhlaWdodDppbm5lckhlaWdodH19ZnVuY3Rpb24gY24oKXtyZXR1cm4gZCh3aW5kb3csInJlc2l6ZSIse3Bhc3NpdmU6ITB9KS5waXBlKG0oc24pLHEoc24oKSkpfWZ1bmN0aW9uIHBuKCl7cmV0dXJuIFEoW2FuKCksY24oKV0pLnBpcGUobSgoW2UsdF0pPT4oe29mZnNldDplLHNpemU6dH0pKSxCKDEpKX1mdW5jdGlvbiBwcihlLHt2aWV3cG9ydCQ6dCxoZWFkZXIkOnJ9KXtsZXQgbz10LnBpcGUoWCgic2l6ZSIpKSxuPVEoW28scl0pLnBpcGUobSgoKT0+VWUoZSkpKTtyZXR1cm4gUShbcix0LG5dKS5waXBlKG0oKFt7aGVpZ2h0Oml9LHtvZmZzZXQ6cyxzaXplOmF9LHt4OmMseTpwfV0pPT4oe29mZnNldDp7eDpzLngtYyx5OnMueS1wK2l9LHNpemU6YX0pKSl9ZnVuY3Rpb24gYmEoZSl7cmV0dXJuIGQoZSwibWVzc2FnZSIsdD0+dC5kYXRhKX1mdW5jdGlvbiB2YShlKXtsZXQgdD1uZXcgdjtyZXR1cm4gdC5zdWJzY3JpYmUocj0+ZS5wb3N0TWVzc2FnZShyKSksdH1mdW5jdGlvbiBsbihlLHQ9bmV3IFdvcmtlcihlKSl7bGV0IHI9YmEodCksbz12YSh0KSxuPW5ldyB2O24uc3Vic2NyaWJlKG8pO2xldCBpPW8ucGlwZShlZSgpLG9lKCEwKSk7cmV0dXJuIG4ucGlwZShlZSgpLCRlKHIucGlwZShVKGkpKSksbGUoKSl9dmFyIGdhPVAoIiNfX2NvbmZpZyIpLEV0PUpTT04ucGFyc2UoZ2EudGV4dENvbnRlbnQpO0V0LmJhc2U9YCR7bmV3IFVSTChFdC5iYXNlLHZlKCkpfWA7ZnVuY3Rpb24gd2UoKXtyZXR1cm4gRXR9ZnVuY3Rpb24gRyhlKXtyZXR1cm4gRXQuZmVhdHVyZXMuaW5jbHVkZXMoZSl9ZnVuY3Rpb24gZ2UoZSx0KXtyZXR1cm4gdHlwZW9mIHQhPSJ1bmRlZmluZWQiP0V0LnRyYW5zbGF0aW9uc1tlXS5yZXBsYWNlKCIjIix0LnRvU3RyaW5nKCkpOkV0LnRyYW5zbGF0aW9uc1tlXX1mdW5jdGlvbiBUZShlLHQ9ZG9jdW1lbnQpe3JldHVybiBQKGBbZGF0YS1tZC1jb21wb25lbnQ9JHtlfV1gLHQpfWZ1bmN0aW9uIG5lKGUsdD1kb2N1bWVudCl7cmV0dXJuIFIoYFtkYXRhLW1kLWNvbXBvbmVudD0ke2V9XWAsdCl9ZnVuY3Rpb24geGEoZSl7bGV0IHQ9UCgiLm1kLXR5cGVzZXQgPiA6Zmlyc3QtY2hpbGQiLGUpO3JldHVybiBkKHQsImNsaWNrIix7b25jZTohMH0pLnBpcGUobSgoKT0+UCgiLm1kLXR5cGVzZXQiLGUpKSxtKHI9Pih7aGFzaDpfX21kX2hhc2goci5pbm5lckhUTUwpfSkpKX1mdW5jdGlvbiBtbihlKXtpZighRygiYW5ub3VuY2UuZGlzbWlzcyIpfHwhZS5jaGlsZEVsZW1lbnRDb3VudClyZXR1cm4gTDtpZighZS5oaWRkZW4pe2xldCB0PVAoIi5tZC10eXBlc2V0IixlKTtfX21kX2hhc2godC5pbm5lckhUTUwpPT09X19tZF9nZXQoIl9fYW5ub3VuY2UiKSYmKGUuaGlkZGVuPSEwKX1yZXR1cm4gSCgoKT0+e2xldCB0PW5ldyB2O3JldHVybiB0LnN1YnNjcmliZSgoe2hhc2g6cn0pPT57ZS5oaWRkZW49ITAsX19tZF9zZXQoIl9fYW5ub3VuY2UiLHIpfSkseGEoZSkucGlwZSh5KHI9PnQubmV4dChyKSksXygoKT0+dC5jb21wbGV0ZSgpKSxtKHI9PkYoe3JlZjplfSxyKSkpfSl9ZnVuY3Rpb24geWEoZSx7dGFyZ2V0JDp0fSl7cmV0dXJuIHQucGlwZShtKHI9Pih7aGlkZGVuOnIhPT1lfSkpKX1mdW5jdGlvbiBmbihlLHQpe2xldCByPW5ldyB2O3JldHVybiByLnN1YnNjcmliZSgoe2hpZGRlbjpvfSk9PntlLmhpZGRlbj1vfSkseWEoZSx0KS5waXBlKHkobz0+ci5uZXh0KG8pKSxfKCgpPT5yLmNvbXBsZXRlKCkpLG0obz0+Rih7cmVmOmV9LG8pKSl9ZnVuY3Rpb24gQ3QoZSx0KXtyZXR1cm4gdD09PSJpbmxpbmUiP0UoImRpdiIse2NsYXNzOiJtZC10b29sdGlwIG1kLXRvb2x0aXAtLWlubGluZSIsaWQ6ZSxyb2xlOiJ0b29sdGlwIn0sRSgiZGl2Iix7Y2xhc3M6Im1kLXRvb2x0aXBfX2lubmVyIG1kLXR5cGVzZXQifSkpOkUoImRpdiIse2NsYXNzOiJtZC10b29sdGlwIixpZDplLHJvbGU6InRvb2x0aXAifSxFKCJkaXYiLHtjbGFzczoibWQtdG9vbHRpcF9faW5uZXIgbWQtdHlwZXNldCJ9KSl9ZnVuY3Rpb24gdW4oZSx0KXtpZih0PXQ/YCR7dH1fYW5ub3RhdGlvbl8ke2V9YDp2b2lkIDAsdCl7bGV0IHI9dD9gIyR7dH1gOnZvaWQgMDtyZXR1cm4gRSgiYXNpZGUiLHtjbGFzczoibWQtYW5ub3RhdGlvbiIsdGFiSW5kZXg6MH0sQ3QodCksRSgiYSIse2hyZWY6cixjbGFzczoibWQtYW5ub3RhdGlvbl9faW5kZXgiLHRhYkluZGV4Oi0xfSxFKCJzcGFuIix7ImRhdGEtbWQtYW5ub3RhdGlvbi1pZCI6ZX0pKSl9ZWxzZSByZXR1cm4gRSgiYXNpZGUiLHtjbGFzczoibWQtYW5ub3RhdGlvbiIsdGFiSW5kZXg6MH0sQ3QodCksRSgic3BhbiIse2NsYXNzOiJtZC1hbm5vdGF0aW9uX19pbmRleCIsdGFiSW5kZXg6LTF9LEUoInNwYW4iLHsiZGF0YS1tZC1hbm5vdGF0aW9uLWlkIjplfSkpKX1mdW5jdGlvbiBkbihlKXtyZXR1cm4gRSgiYnV0dG9uIix7Y2xhc3M6Im1kLWNsaXBib2FyZCBtZC1pY29uIix0aXRsZTpnZSgiY2xpcGJvYXJkLmNvcHkiKSwiZGF0YS1jbGlwYm9hcmQtdGFyZ2V0IjpgIyR7ZX0gPiBjb2RlYH0pfWZ1bmN0aW9uIERyKGUsdCl7bGV0IHI9dCYyLG89dCYxLG49T2JqZWN0LmtleXMoZS50ZXJtcykuZmlsdGVyKGM9PiFlLnRlcm1zW2NdKS5yZWR1Y2UoKGMscCk9PlsuLi5jLEUoImRlbCIsbnVsbCxwKSwiICJdLFtdKS5zbGljZSgwLC0xKSxpPXdlKCkscz1uZXcgVVJMKGUubG9jYXRpb24saS5iYXNlKTtHKCJzZWFyY2guaGlnaGxpZ2h0IikmJnMuc2VhcmNoUGFyYW1zLnNldCgiaCIsT2JqZWN0LmVudHJpZXMoZS50ZXJtcykuZmlsdGVyKChbLGNdKT0+YykucmVkdWNlKChjLFtwXSk9PmAke2N9ICR7cH1gLnRyaW0oKSwiIikpO2xldHt0YWdzOmF9PXdlKCk7cmV0dXJuIEUoImEiLHtocmVmOmAke3N9YCxjbGFzczoibWQtc2VhcmNoLXJlc3VsdF9fbGluayIsdGFiSW5kZXg6LTF9LEUoImFydGljbGUiLHtjbGFzczoibWQtc2VhcmNoLXJlc3VsdF9fYXJ0aWNsZSBtZC10eXBlc2V0IiwiZGF0YS1tZC1zY29yZSI6ZS5zY29yZS50b0ZpeGVkKDIpfSxyPjAmJkUoImRpdiIse2NsYXNzOiJtZC1zZWFyY2gtcmVzdWx0X19pY29uIG1kLWljb24ifSkscj4wJiZFKCJoMSIsbnVsbCxlLnRpdGxlKSxyPD0wJiZFKCJoMiIsbnVsbCxlLnRpdGxlKSxvPjAmJmUudGV4dC5sZW5ndGg+MCYmZS50ZXh0LGUudGFncyYmZS50YWdzLm1hcChjPT57bGV0IHA9YT9jIGluIGE/YG1kLXRhZy1pY29uIG1kLXRhZy0tJHthW2NdfWA6Im1kLXRhZy1pY29uIjoiIjtyZXR1cm4gRSgic3BhbiIse2NsYXNzOmBtZC10YWcgJHtwfWB9LGMpfSksbz4wJiZuLmxlbmd0aD4wJiZFKCJwIix7Y2xhc3M6Im1kLXNlYXJjaC1yZXN1bHRfX3Rlcm1zIn0sZ2UoInNlYXJjaC5yZXN1bHQudGVybS5taXNzaW5nIiksIjogIiwuLi5uKSkpfWZ1bmN0aW9uIGhuKGUpe2xldCB0PWVbMF0uc2NvcmUscj1bLi4uZV0sbz13ZSgpLG49ci5maW5kSW5kZXgobD0+IWAke25ldyBVUkwobC5sb2NhdGlvbixvLmJhc2UpfWAuaW5jbHVkZXMoIiMiKSksW2ldPXIuc3BsaWNlKG4sMSkscz1yLmZpbmRJbmRleChsPT5sLnNjb3JlPHQpO3M9PT0tMSYmKHM9ci5sZW5ndGgpO2xldCBhPXIuc2xpY2UoMCxzKSxjPXIuc2xpY2UocykscD1bRHIoaSwyfCsoIW4mJnM9PT0wKSksLi4uYS5tYXAobD0+RHIobCwxKSksLi4uYy5sZW5ndGg/W0UoImRldGFpbHMiLHtjbGFzczoibWQtc2VhcmNoLXJlc3VsdF9fbW9yZSJ9LEUoInN1bW1hcnkiLHt0YWJJbmRleDotMX0sRSgiZGl2IixudWxsLGMubGVuZ3RoPjAmJmMubGVuZ3RoPT09MT9nZSgic2VhcmNoLnJlc3VsdC5tb3JlLm9uZSIpOmdlKCJzZWFyY2gucmVzdWx0Lm1vcmUub3RoZXIiLGMubGVuZ3RoKSkpLC4uLmMubWFwKGw9PkRyKGwsMSkpKV06W11dO3JldHVybiBFKCJsaSIse2NsYXNzOiJtZC1zZWFyY2gtcmVzdWx0X19pdGVtIn0scCl9ZnVuY3Rpb24gYm4oZSl7cmV0dXJuIEUoInVsIix7Y2xhc3M6Im1kLXNvdXJjZV9fZmFjdHMifSxPYmplY3QuZW50cmllcyhlKS5tYXAoKFt0LHJdKT0+RSgibGkiLHtjbGFzczpgbWQtc291cmNlX19mYWN0IG1kLXNvdXJjZV9fZmFjdC0tJHt0fWB9LHR5cGVvZiByPT0ibnVtYmVyIj9hcihyKTpyKSkpfWZ1bmN0aW9uIE5yKGUpe2xldCB0PWB0YWJiZWQtY29udHJvbCB0YWJiZWQtY29udHJvbC0tJHtlfWA7cmV0dXJuIEUoImRpdiIse2NsYXNzOnQsaGlkZGVuOiEwfSxFKCJidXR0b24iLHtjbGFzczoidGFiYmVkLWJ1dHRvbiIsdGFiSW5kZXg6LTEsImFyaWEtaGlkZGVuIjoidHJ1ZSJ9KSl9ZnVuY3Rpb24gdm4oZSl7cmV0dXJuIEUoImRpdiIse2NsYXNzOiJtZC10eXBlc2V0X19zY3JvbGx3cmFwIn0sRSgiZGl2Iix7Y2xhc3M6Im1kLXR5cGVzZXRfX3RhYmxlIn0sZSkpfWZ1bmN0aW9uIEVhKGUpe2xldCB0PXdlKCkscj1uZXcgVVJMKGAuLi8ke2UudmVyc2lvbn0vYCx0LmJhc2UpO3JldHVybiBFKCJsaSIse2NsYXNzOiJtZC12ZXJzaW9uX19pdGVtIn0sRSgiYSIse2hyZWY6YCR7cn1gLGNsYXNzOiJtZC12ZXJzaW9uX19saW5rIn0sZS50aXRsZSkpfWZ1bmN0aW9uIGduKGUsdCl7cmV0dXJuIEUoImRpdiIse2NsYXNzOiJtZC12ZXJzaW9uIn0sRSgiYnV0dG9uIix7Y2xhc3M6Im1kLXZlcnNpb25fX2N1cnJlbnQiLCJhcmlhLWxhYmVsIjpnZSgic2VsZWN0LnZlcnNpb24iKX0sdC50aXRsZSksRSgidWwiLHtjbGFzczoibWQtdmVyc2lvbl9fbGlzdCJ9LGUubWFwKEVhKSkpfXZhciB3YT0wO2Z1bmN0aW9uIFRhKGUsdCl7ZG9jdW1lbnQuYm9keS5hcHBlbmQoZSk7bGV0e3dpZHRoOnJ9PXBlKGUpO2Uuc3R5bGUuc2V0UHJvcGVydHkoIi0tbWQtdG9vbHRpcC13aWR0aCIsYCR7cn1weGApLGUucmVtb3ZlKCk7bGV0IG89c3IodCksbj10eXBlb2YgbyE9InVuZGVmaW5lZCI/ZXQobyk6JCh7eDowLHk6MH0pLGk9VCh2dCh0KSxWbyh0KSkucGlwZShZKCkpO3JldHVybiBRKFtpLG5dKS5waXBlKG0oKFtzLGFdKT0+e2xldHt4OmMseTpwfT1VZSh0KSxsPXBlKHQpLGY9dC5jbG9zZXN0KCJ0YWJsZSIpO3JldHVybiBmJiZ0LnBhcmVudEVsZW1lbnQmJihjKz1mLm9mZnNldExlZnQrdC5wYXJlbnRFbGVtZW50Lm9mZnNldExlZnQscCs9Zi5vZmZzZXRUb3ArdC5wYXJlbnRFbGVtZW50Lm9mZnNldFRvcCkse2FjdGl2ZTpzLG9mZnNldDp7eDpjLWEueCtsLndpZHRoLzItci8yLHk6cC1hLnkrbC5oZWlnaHQrOH19fSkpfWZ1bmN0aW9uIEdlKGUpe2xldCB0PWUudGl0bGU7aWYoIXQubGVuZ3RoKXJldHVybiBMO2xldCByPWBfX3Rvb2x0aXBfJHt3YSsrfWAsbz1DdChyLCJpbmxpbmUiKSxuPVAoIi5tZC10eXBlc2V0IixvKTtyZXR1cm4gbi5pbm5lckhUTUw9dCxIKCgpPT57bGV0IGk9bmV3IHY7cmV0dXJuIGkuc3Vic2NyaWJlKHtuZXh0KHtvZmZzZXQ6c30pe28uc3R5bGUuc2V0UHJvcGVydHkoIi0tbWQtdG9vbHRpcC14IixgJHtzLnh9cHhgKSxvLnN0eWxlLnNldFByb3BlcnR5KCItLW1kLXRvb2x0aXAteSIsYCR7cy55fXB4YCl9LGNvbXBsZXRlKCl7by5zdHlsZS5yZW1vdmVQcm9wZXJ0eSgiLS1tZC10b29sdGlwLXgiKSxvLnN0eWxlLnJlbW92ZVByb3BlcnR5KCItLW1kLXRvb2x0aXAteSIpfX0pLFQoaS5waXBlKGcoKHthY3RpdmU6c30pPT5zKSksaS5waXBlKGJlKDI1MCksZygoe2FjdGl2ZTpzfSk9PiFzKSkpLnN1YnNjcmliZSh7bmV4dCh7YWN0aXZlOnN9KXtzPyhlLmluc2VydEFkamFjZW50RWxlbWVudCgiYWZ0ZXJlbmQiLG8pLGUuc2V0QXR0cmlidXRlKCJhcmlhLWRlc2NyaWJlZGJ5IixyKSxlLnJlbW92ZUF0dHJpYnV0ZSgidGl0bGUiKSk6KG8ucmVtb3ZlKCksZS5yZW1vdmVBdHRyaWJ1dGUoImFyaWEtZGVzY3JpYmVkYnkiKSxlLnNldEF0dHJpYnV0ZSgidGl0bGUiLHQpKX0sY29tcGxldGUoKXtvLnJlbW92ZSgpLGUucmVtb3ZlQXR0cmlidXRlKCJhcmlhLWRlc2NyaWJlZGJ5IiksZS5zZXRBdHRyaWJ1dGUoInRpdGxlIix0KX19KSxpLnBpcGUoTWUoMTYsZGUpKS5zdWJzY3JpYmUoKHthY3RpdmU6c30pPT57by5jbGFzc0xpc3QudG9nZ2xlKCJtZC10b29sdGlwLS1hY3RpdmUiLHMpfSksaS5waXBlKF90KDEyNSxkZSksZygoKT0+ISFlLm9mZnNldFBhcmVudCksbSgoKT0+ZS5vZmZzZXRQYXJlbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkpLG0oKHt4OnN9KT0+cykpLnN1YnNjcmliZSh7bmV4dChzKXtzP28uc3R5bGUuc2V0UHJvcGVydHkoIi0tbWQtdG9vbHRpcC0wIixgJHstc31weGApOm8uc3R5bGUucmVtb3ZlUHJvcGVydHkoIi0tbWQtdG9vbHRpcC0wIil9LGNvbXBsZXRlKCl7by5zdHlsZS5yZW1vdmVQcm9wZXJ0eSgiLS1tZC10b29sdGlwLTAiKX19KSxUYShvLGUpLnBpcGUoeShzPT5pLm5leHQocykpLF8oKCk9PmkuY29tcGxldGUoKSksbShzPT5GKHtyZWY6ZX0scykpKX0pLnBpcGUoemUoaWUpKX1mdW5jdGlvbiBTYShlLHQpe2xldCByPUgoKCk9PlEoW3pvKGUpLGV0KHQpXSkpLnBpcGUobSgoW3t4Om8seTpufSxpXSk9PntsZXR7d2lkdGg6cyxoZWlnaHQ6YX09cGUoZSk7cmV0dXJue3g6by1pLngrcy8yLHk6bi1pLnkrYS8yfX0pKTtyZXR1cm4gdnQoZSkucGlwZShiKG89PnIucGlwZShtKG49Pih7YWN0aXZlOm8sb2Zmc2V0Om59KSkseWUoKyFvfHwxLzApKSkpfWZ1bmN0aW9uIHhuKGUsdCx7dGFyZ2V0JDpyfSl7bGV0W28sbl09QXJyYXkuZnJvbShlLmNoaWxkcmVuKTtyZXR1cm4gSCgoKT0+e2xldCBpPW5ldyB2LHM9aS5waXBlKGVlKCksb2UoITApKTtyZXR1cm4gaS5zdWJzY3JpYmUoe25leHQoe29mZnNldDphfSl7ZS5zdHlsZS5zZXRQcm9wZXJ0eSgiLS1tZC10b29sdGlwLXgiLGAke2EueH1weGApLGUuc3R5bGUuc2V0UHJvcGVydHkoIi0tbWQtdG9vbHRpcC15IixgJHthLnl9cHhgKX0sY29tcGxldGUoKXtlLnN0eWxlLnJlbW92ZVByb3BlcnR5KCItLW1kLXRvb2x0aXAteCIpLGUuc3R5bGUucmVtb3ZlUHJvcGVydHkoIi0tbWQtdG9vbHRpcC15Iil9fSkseXQoZSkucGlwZShVKHMpKS5zdWJzY3JpYmUoYT0+e2UudG9nZ2xlQXR0cmlidXRlKCJkYXRhLW1kLXZpc2libGUiLGEpfSksVChpLnBpcGUoZygoe2FjdGl2ZTphfSk9PmEpKSxpLnBpcGUoYmUoMjUwKSxnKCh7YWN0aXZlOmF9KT0+IWEpKSkuc3Vic2NyaWJlKHtuZXh0KHthY3RpdmU6YX0pe2E/ZS5wcmVwZW5kKG8pOm8ucmVtb3ZlKCl9LGNvbXBsZXRlKCl7ZS5wcmVwZW5kKG8pfX0pLGkucGlwZShNZSgxNixkZSkpLnN1YnNjcmliZSgoe2FjdGl2ZTphfSk9PntvLmNsYXNzTGlzdC50b2dnbGUoIm1kLXRvb2x0aXAtLWFjdGl2ZSIsYSl9KSxpLnBpcGUoX3QoMTI1LGRlKSxnKCgpPT4hIWUub2Zmc2V0UGFyZW50KSxtKCgpPT5lLm9mZnNldFBhcmVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKSksbSgoe3g6YX0pPT5hKSkuc3Vic2NyaWJlKHtuZXh0KGEpe2E/ZS5zdHlsZS5zZXRQcm9wZXJ0eSgiLS1tZC10b29sdGlwLTAiLGAkey1hfXB4YCk6ZS5zdHlsZS5yZW1vdmVQcm9wZXJ0eSgiLS1tZC10b29sdGlwLTAiKX0sY29tcGxldGUoKXtlLnN0eWxlLnJlbW92ZVByb3BlcnR5KCItLW1kLXRvb2x0aXAtMCIpfX0pLGQobiwiY2xpY2siKS5waXBlKFUocyksZyhhPT4hKGEubWV0YUtleXx8YS5jdHJsS2V5KSkpLnN1YnNjcmliZShhPT57YS5zdG9wUHJvcGFnYXRpb24oKSxhLnByZXZlbnREZWZhdWx0KCl9KSxkKG4sIm1vdXNlZG93biIpLnBpcGUoVShzKSxhZShpKSkuc3Vic2NyaWJlKChbYSx7YWN0aXZlOmN9XSk9Pnt2YXIgcDtpZihhLmJ1dHRvbiE9PTB8fGEubWV0YUtleXx8YS5jdHJsS2V5KWEucHJldmVudERlZmF1bHQoKTtlbHNlIGlmKGMpe2EucHJldmVudERlZmF1bHQoKTtsZXQgbD1lLnBhcmVudEVsZW1lbnQuY2xvc2VzdCgiLm1kLWFubm90YXRpb24iKTtsIGluc3RhbmNlb2YgSFRNTEVsZW1lbnQ/bC5mb2N1cygpOihwPVJlKCkpPT1udWxsfHxwLmJsdXIoKX19KSxyLnBpcGUoVShzKSxnKGE9PmE9PT1vKSxZZSgxMjUpKS5zdWJzY3JpYmUoKCk9PmUuZm9jdXMoKSksU2EoZSx0KS5waXBlKHkoYT0+aS5uZXh0KGEpKSxfKCgpPT5pLmNvbXBsZXRlKCkpLG0oYT0+Rih7cmVmOmV9LGEpKSl9KX1mdW5jdGlvbiBPYShlKXtyZXR1cm4gZS50YWdOYW1lPT09IkNPREUiP1IoIi5jLCAuYzEsIC5jbSIsZSk6W2VdfWZ1bmN0aW9uIE1hKGUpe2xldCB0PVtdO2ZvcihsZXQgciBvZiBPYShlKSl7bGV0IG89W10sbj1kb2N1bWVudC5jcmVhdGVOb2RlSXRlcmF0b3IocixOb2RlRmlsdGVyLlNIT1dfVEVYVCk7Zm9yKGxldCBpPW4ubmV4dE5vZGUoKTtpO2k9bi5uZXh0Tm9kZSgpKW8ucHVzaChpKTtmb3IobGV0IGkgb2Ygbyl7bGV0IHM7Zm9yKDtzPS8oXChcZCtcKSkoISk/Ly5leGVjKGkudGV4dENvbnRlbnQpOyl7bGV0WyxhLGNdPXM7aWYodHlwZW9mIGM9PSJ1bmRlZmluZWQiKXtsZXQgcD1pLnNwbGl0VGV4dChzLmluZGV4KTtpPXAuc3BsaXRUZXh0KGEubGVuZ3RoKSx0LnB1c2gocCl9ZWxzZXtpLnRleHRDb250ZW50PWEsdC5wdXNoKGkpO2JyZWFrfX19fXJldHVybiB0fWZ1bmN0aW9uIHluKGUsdCl7dC5hcHBlbmQoLi4uQXJyYXkuZnJvbShlLmNoaWxkTm9kZXMpKX1mdW5jdGlvbiBscihlLHQse3RhcmdldCQ6cixwcmludCQ6b30pe2xldCBuPXQuY2xvc2VzdCgiW2lkXSIpLGk9bj09bnVsbD92b2lkIDA6bi5pZCxzPW5ldyBNYXA7Zm9yKGxldCBhIG9mIE1hKHQpKXtsZXRbLGNdPWEudGV4dENvbnRlbnQubWF0Y2goL1woKFxkKylcKS8pO21lKGA6c2NvcGUgPiBsaTpudGgtY2hpbGQoJHtjfSlgLGUpJiYocy5zZXQoYyx1bihjLGkpKSxhLnJlcGxhY2VXaXRoKHMuZ2V0KGMpKSl9cmV0dXJuIHMuc2l6ZT09PTA/TDpIKCgpPT57bGV0IGE9bmV3IHYsYz1hLnBpcGUoZWUoKSxvZSghMCkpLHA9W107Zm9yKGxldFtsLGZdb2YgcylwLnB1c2goW1AoIi5tZC10eXBlc2V0IixmKSxQKGA6c2NvcGUgPiBsaTpudGgtY2hpbGQoJHtsfSlgLGUpXSk7cmV0dXJuIG8ucGlwZShVKGMpKS5zdWJzY3JpYmUobD0+e2UuaGlkZGVuPSFsLGUuY2xhc3NMaXN0LnRvZ2dsZSgibWQtYW5ub3RhdGlvbi1saXN0IixsKTtmb3IobGV0W2YsdV1vZiBwKWw/eW4oZix1KTp5bih1LGYpfSksVCguLi5bLi4uc10ubWFwKChbLGxdKT0+eG4obCx0LHt0YXJnZXQkOnJ9KSkpLnBpcGUoXygoKT0+YS5jb21wbGV0ZSgpKSxsZSgpKX0pfWZ1bmN0aW9uIEVuKGUpe2lmKGUubmV4dEVsZW1lbnRTaWJsaW5nKXtsZXQgdD1lLm5leHRFbGVtZW50U2libGluZztpZih0LnRhZ05hbWU9PT0iT0wiKXJldHVybiB0O2lmKHQudGFnTmFtZT09PSJQIiYmIXQuY2hpbGRyZW4ubGVuZ3RoKXJldHVybiBFbih0KX19ZnVuY3Rpb24gd24oZSx0KXtyZXR1cm4gSCgoKT0+e2xldCByPUVuKGUpO3JldHVybiB0eXBlb2YgciE9InVuZGVmaW5lZCI/bHIocixlLHQpOkx9KX12YXIgVG49anQoenIoKSk7dmFyIExhPTA7ZnVuY3Rpb24gU24oZSl7aWYoZS5uZXh0RWxlbWVudFNpYmxpbmcpe2xldCB0PWUubmV4dEVsZW1lbnRTaWJsaW5nO2lmKHQudGFnTmFtZT09PSJPTCIpcmV0dXJuIHQ7aWYodC50YWdOYW1lPT09IlAiJiYhdC5jaGlsZHJlbi5sZW5ndGgpcmV0dXJuIFNuKHQpfX1mdW5jdGlvbiBfYShlKXtyZXR1cm4gRWUoZSkucGlwZShtKCh7d2lkdGg6dH0pPT4oe3Njcm9sbGFibGU6eHQoZSkud2lkdGg+dH0pKSxYKCJzY3JvbGxhYmxlIikpfWZ1bmN0aW9uIE9uKGUsdCl7bGV0e21hdGNoZXM6cn09bWF0Y2hNZWRpYSgiKGhvdmVyKSIpLG89SCgoKT0+e2xldCBuPW5ldyB2LGk9bi5waXBlKCRyKDEpKTtuLnN1YnNjcmliZSgoe3Njcm9sbGFibGU6Y30pPT57YyYmcj9lLnNldEF0dHJpYnV0ZSgidGFiaW5kZXgiLCIwIik6ZS5yZW1vdmVBdHRyaWJ1dGUoInRhYmluZGV4Iil9KTtsZXQgcz1bXTtpZihUbi5kZWZhdWx0LmlzU3VwcG9ydGVkKCkmJihlLmNsb3Nlc3QoIi5jb3B5Iil8fEcoImNvbnRlbnQuY29kZS5jb3B5IikmJiFlLmNsb3Nlc3QoIi5uby1jb3B5IikpKXtsZXQgYz1lLmNsb3Nlc3QoInByZSIpO2MuaWQ9YF9fY29kZV8ke0xhKyt9YDtsZXQgcD1kbihjLmlkKTtjLmluc2VydEJlZm9yZShwLGUpLEcoImNvbnRlbnQudG9vbHRpcHMiKSYmcy5wdXNoKEdlKHApKX1sZXQgYT1lLmNsb3Nlc3QoIi5oaWdobGlnaHQiKTtpZihhIGluc3RhbmNlb2YgSFRNTEVsZW1lbnQpe2xldCBjPVNuKGEpO2lmKHR5cGVvZiBjIT0idW5kZWZpbmVkIiYmKGEuY2xhc3NMaXN0LmNvbnRhaW5zKCJhbm5vdGF0ZSIpfHxHKCJjb250ZW50LmNvZGUuYW5ub3RhdGUiKSkpe2xldCBwPWxyKGMsZSx0KTtzLnB1c2goRWUoYSkucGlwZShVKGkpLG0oKHt3aWR0aDpsLGhlaWdodDpmfSk9PmwmJmYpLFkoKSxiKGw9Pmw/cDpMKSkpfX1yZXR1cm4gX2EoZSkucGlwZSh5KGM9Pm4ubmV4dChjKSksXygoKT0+bi5jb21wbGV0ZSgpKSxtKGM9PkYoe3JlZjplfSxjKSksJGUoLi4ucykpfSk7cmV0dXJuIEcoImNvbnRlbnQubGF6eSIpP3l0KGUpLnBpcGUoZyhuPT5uKSx5ZSgxKSxiKCgpPT5vKSk6b31mdW5jdGlvbiBBYShlLHt0YXJnZXQkOnQscHJpbnQkOnJ9KXtsZXQgbz0hMDtyZXR1cm4gVCh0LnBpcGUobShuPT5uLmNsb3Nlc3QoImRldGFpbHM6bm90KFtvcGVuXSkiKSksZyhuPT5lPT09biksbSgoKT0+KHthY3Rpb246Im9wZW4iLHJldmVhbDohMH0pKSksci5waXBlKGcobj0+bnx8IW8pLHkoKCk9Pm89ZS5vcGVuKSxtKG49Pih7YWN0aW9uOm4/Im9wZW4iOiJjbG9zZSJ9KSkpKX1mdW5jdGlvbiBNbihlLHQpe3JldHVybiBIKCgpPT57bGV0IHI9bmV3IHY7cmV0dXJuIHIuc3Vic2NyaWJlKCh7YWN0aW9uOm8scmV2ZWFsOm59KT0+e2UudG9nZ2xlQXR0cmlidXRlKCJvcGVuIixvPT09Im9wZW4iKSxuJiZlLnNjcm9sbEludG9WaWV3KCl9KSxBYShlLHQpLnBpcGUoeShvPT5yLm5leHQobykpLF8oKCk9PnIuY29tcGxldGUoKSksbShvPT5GKHtyZWY6ZX0sbykpKX0pfXZhciBMbj0iLm5vZGUgY2lyY2xlLC5ub2RlIGVsbGlwc2UsLm5vZGUgcGF0aCwubm9kZSBwb2x5Z29uLC5ub2RlIHJlY3R7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLW5vZGUtYmctY29sb3IpO3N0cm9rZTp2YXIoLS1tZC1tZXJtYWlkLW5vZGUtZmctY29sb3IpfW1hcmtlcntmaWxsOnZhcigtLW1kLW1lcm1haWQtZWRnZS1jb2xvcikhaW1wb3J0YW50fS5lZGdlTGFiZWwgLmxhYmVsIHJlY3R7ZmlsbDojMDAwMH0ubGFiZWx7Y29sb3I6dmFyKC0tbWQtbWVybWFpZC1sYWJlbC1mZy1jb2xvcik7Zm9udC1mYW1pbHk6dmFyKC0tbWQtbWVybWFpZC1mb250LWZhbWlseSl9LmxhYmVsIGZvcmVpZ25PYmplY3R7bGluZS1oZWlnaHQ6bm9ybWFsO292ZXJmbG93OnZpc2libGV9LmxhYmVsIGRpdiAuZWRnZUxhYmVse2NvbG9yOnZhcigtLW1kLW1lcm1haWQtbGFiZWwtZmctY29sb3IpfS5lZGdlTGFiZWwsLmVkZ2VMYWJlbCByZWN0LC5sYWJlbCBkaXYgLmVkZ2VMYWJlbHtiYWNrZ3JvdW5kLWNvbG9yOnZhcigtLW1kLW1lcm1haWQtbGFiZWwtYmctY29sb3IpfS5lZGdlTGFiZWwsLmVkZ2VMYWJlbCByZWN0e2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1sYWJlbC1iZy1jb2xvcik7Y29sb3I6dmFyKC0tbWQtbWVybWFpZC1lZGdlLWNvbG9yKX0uZWRnZVBhdGggLnBhdGgsLmZsb3djaGFydC1saW5re3N0cm9rZTp2YXIoLS1tZC1tZXJtYWlkLWVkZ2UtY29sb3IpO3N0cm9rZS13aWR0aDouMDVyZW19LmVkZ2VQYXRoIC5hcnJvd2hlYWRQYXRoe2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1lZGdlLWNvbG9yKTtzdHJva2U6bm9uZX0uY2x1c3RlciByZWN0e2ZpbGw6dmFyKC0tbWQtZGVmYXVsdC1mZy1jb2xvci0tbGlnaHRlc3QpO3N0cm9rZTp2YXIoLS1tZC1kZWZhdWx0LWZnLWNvbG9yLS1saWdodGVyKX0uY2x1c3RlciBzcGFue2NvbG9yOnZhcigtLW1kLW1lcm1haWQtbGFiZWwtZmctY29sb3IpO2ZvbnQtZmFtaWx5OnZhcigtLW1kLW1lcm1haWQtZm9udC1mYW1pbHkpfWcgI2Zsb3djaGFydC1jaXJjbGVFbmQsZyAjZmxvd2NoYXJ0LWNpcmNsZVN0YXJ0LGcgI2Zsb3djaGFydC1jcm9zc0VuZCxnICNmbG93Y2hhcnQtY3Jvc3NTdGFydCxnICNmbG93Y2hhcnQtcG9pbnRFbmQsZyAjZmxvd2NoYXJ0LXBvaW50U3RhcnR7c3Ryb2tlOm5vbmV9Zy5jbGFzc0dyb3VwIGxpbmUsZy5jbGFzc0dyb3VwIHJlY3R7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLW5vZGUtYmctY29sb3IpO3N0cm9rZTp2YXIoLS1tZC1tZXJtYWlkLW5vZGUtZmctY29sb3IpfWcuY2xhc3NHcm91cCB0ZXh0e2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1sYWJlbC1mZy1jb2xvcik7Zm9udC1mYW1pbHk6dmFyKC0tbWQtbWVybWFpZC1mb250LWZhbWlseSl9LmNsYXNzTGFiZWwgLmJveHtmaWxsOnZhcigtLW1kLW1lcm1haWQtbGFiZWwtYmctY29sb3IpO2JhY2tncm91bmQtY29sb3I6dmFyKC0tbWQtbWVybWFpZC1sYWJlbC1iZy1jb2xvcik7b3BhY2l0eToxfS5jbGFzc0xhYmVsIC5sYWJlbHtmaWxsOnZhcigtLW1kLW1lcm1haWQtbGFiZWwtZmctY29sb3IpO2ZvbnQtZmFtaWx5OnZhcigtLW1kLW1lcm1haWQtZm9udC1mYW1pbHkpfS5ub2RlIC5kaXZpZGVye3N0cm9rZTp2YXIoLS1tZC1tZXJtYWlkLW5vZGUtZmctY29sb3IpfS5yZWxhdGlvbntzdHJva2U6dmFyKC0tbWQtbWVybWFpZC1lZGdlLWNvbG9yKX0uY2FyZGluYWxpdHl7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLWxhYmVsLWZnLWNvbG9yKTtmb250LWZhbWlseTp2YXIoLS1tZC1tZXJtYWlkLWZvbnQtZmFtaWx5KX0uY2FyZGluYWxpdHkgdGV4dHtmaWxsOmluaGVyaXQhaW1wb3J0YW50fWRlZnMgI2NsYXNzRGlhZ3JhbS1jb21wb3NpdGlvbkVuZCxkZWZzICNjbGFzc0RpYWdyYW0tY29tcG9zaXRpb25TdGFydCxkZWZzICNjbGFzc0RpYWdyYW0tZGVwZW5kZW5jeUVuZCxkZWZzICNjbGFzc0RpYWdyYW0tZGVwZW5kZW5jeVN0YXJ0LGRlZnMgI2NsYXNzRGlhZ3JhbS1leHRlbnNpb25FbmQsZGVmcyAjY2xhc3NEaWFncmFtLWV4dGVuc2lvblN0YXJ0e2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1lZGdlLWNvbG9yKSFpbXBvcnRhbnQ7c3Ryb2tlOnZhcigtLW1kLW1lcm1haWQtZWRnZS1jb2xvcikhaW1wb3J0YW50fWRlZnMgI2NsYXNzRGlhZ3JhbS1hZ2dyZWdhdGlvbkVuZCxkZWZzICNjbGFzc0RpYWdyYW0tYWdncmVnYXRpb25TdGFydHtmaWxsOnZhcigtLW1kLW1lcm1haWQtbGFiZWwtYmctY29sb3IpIWltcG9ydGFudDtzdHJva2U6dmFyKC0tbWQtbWVybWFpZC1lZGdlLWNvbG9yKSFpbXBvcnRhbnR9Zy5zdGF0ZUdyb3VwIHJlY3R7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLW5vZGUtYmctY29sb3IpO3N0cm9rZTp2YXIoLS1tZC1tZXJtYWlkLW5vZGUtZmctY29sb3IpfWcuc3RhdGVHcm91cCAuc3RhdGUtdGl0bGV7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLWxhYmVsLWZnLWNvbG9yKSFpbXBvcnRhbnQ7Zm9udC1mYW1pbHk6dmFyKC0tbWQtbWVybWFpZC1mb250LWZhbWlseSl9Zy5zdGF0ZUdyb3VwIC5jb21wb3NpdHtmaWxsOnZhcigtLW1kLW1lcm1haWQtbGFiZWwtYmctY29sb3IpfS5ub2RlTGFiZWwsLm5vZGVMYWJlbCBwe2NvbG9yOnZhcigtLW1kLW1lcm1haWQtbGFiZWwtZmctY29sb3IpO2ZvbnQtZmFtaWx5OnZhcigtLW1kLW1lcm1haWQtZm9udC1mYW1pbHkpfS5ub2RlIGNpcmNsZS5zdGF0ZS1lbmQsLm5vZGUgY2lyY2xlLnN0YXRlLXN0YXJ0LC5zdGFydC1zdGF0ZXtmaWxsOnZhcigtLW1kLW1lcm1haWQtZWRnZS1jb2xvcik7c3Ryb2tlOm5vbmV9LmVuZC1zdGF0ZS1pbm5lciwuZW5kLXN0YXRlLW91dGVye2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1lZGdlLWNvbG9yKX0uZW5kLXN0YXRlLWlubmVyLC5ub2RlIGNpcmNsZS5zdGF0ZS1lbmR7c3Ryb2tlOnZhcigtLW1kLW1lcm1haWQtbGFiZWwtYmctY29sb3IpfS50cmFuc2l0aW9ue3N0cm9rZTp2YXIoLS1tZC1tZXJtYWlkLWVkZ2UtY29sb3IpfVtpZF49c3RhdGUtZm9ya10gcmVjdCxbaWRePXN0YXRlLWpvaW5dIHJlY3R7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLWVkZ2UtY29sb3IpIWltcG9ydGFudDtzdHJva2U6bm9uZSFpbXBvcnRhbnR9LnN0YXRlZGlhZ3JhbS1jbHVzdGVyLnN0YXRlZGlhZ3JhbS1jbHVzdGVyIC5pbm5lcntmaWxsOnZhcigtLW1kLWRlZmF1bHQtYmctY29sb3IpfS5zdGF0ZWRpYWdyYW0tY2x1c3RlciByZWN0e2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1ub2RlLWJnLWNvbG9yKTtzdHJva2U6dmFyKC0tbWQtbWVybWFpZC1ub2RlLWZnLWNvbG9yKX0uc3RhdGVkaWFncmFtLXN0YXRlIHJlY3QuZGl2aWRlcntmaWxsOnZhcigtLW1kLWRlZmF1bHQtZmctY29sb3ItLWxpZ2h0ZXN0KTtzdHJva2U6dmFyKC0tbWQtZGVmYXVsdC1mZy1jb2xvci0tbGlnaHRlcil9ZGVmcyAjc3RhdGVkaWFncmFtLWJhcmJFbmR7c3Ryb2tlOnZhcigtLW1kLW1lcm1haWQtZWRnZS1jb2xvcil9LmF0dHJpYnV0ZUJveEV2ZW4sLmF0dHJpYnV0ZUJveE9kZHtmaWxsOnZhcigtLW1kLW1lcm1haWQtbm9kZS1iZy1jb2xvcik7c3Ryb2tlOnZhcigtLW1kLW1lcm1haWQtbm9kZS1mZy1jb2xvcil9LmVudGl0eUJveHtmaWxsOnZhcigtLW1kLW1lcm1haWQtbGFiZWwtYmctY29sb3IpO3N0cm9rZTp2YXIoLS1tZC1tZXJtYWlkLW5vZGUtZmctY29sb3IpfS5lbnRpdHlMYWJlbHtmaWxsOnZhcigtLW1kLW1lcm1haWQtbGFiZWwtZmctY29sb3IpO2ZvbnQtZmFtaWx5OnZhcigtLW1kLW1lcm1haWQtZm9udC1mYW1pbHkpfS5yZWxhdGlvbnNoaXBMYWJlbEJveHtmaWxsOnZhcigtLW1kLW1lcm1haWQtbGFiZWwtYmctY29sb3IpO2ZpbGwtb3BhY2l0eToxO2JhY2tncm91bmQtY29sb3I6dmFyKC0tbWQtbWVybWFpZC1sYWJlbC1iZy1jb2xvcik7b3BhY2l0eToxfS5yZWxhdGlvbnNoaXBMYWJlbHtmaWxsOnZhcigtLW1kLW1lcm1haWQtbGFiZWwtZmctY29sb3IpfS5yZWxhdGlvbnNoaXBMaW5le3N0cm9rZTp2YXIoLS1tZC1tZXJtYWlkLWVkZ2UtY29sb3IpfWRlZnMgI09ORV9PUl9NT1JFX0VORCAqLGRlZnMgI09ORV9PUl9NT1JFX1NUQVJUICosZGVmcyAjT05MWV9PTkVfRU5EICosZGVmcyAjT05MWV9PTkVfU1RBUlQgKixkZWZzICNaRVJPX09SX01PUkVfRU5EICosZGVmcyAjWkVST19PUl9NT1JFX1NUQVJUICosZGVmcyAjWkVST19PUl9PTkVfRU5EICosZGVmcyAjWkVST19PUl9PTkVfU1RBUlQgKntzdHJva2U6dmFyKC0tbWQtbWVybWFpZC1lZGdlLWNvbG9yKSFpbXBvcnRhbnR9ZGVmcyAjWkVST19PUl9NT1JFX0VORCBjaXJjbGUsZGVmcyAjWkVST19PUl9NT1JFX1NUQVJUIGNpcmNsZXtmaWxsOnZhcigtLW1kLW1lcm1haWQtbGFiZWwtYmctY29sb3IpfS5hY3RvcntmaWxsOnZhcigtLW1kLW1lcm1haWQtc2VxdWVuY2UtYWN0b3ItYmctY29sb3IpO3N0cm9rZTp2YXIoLS1tZC1tZXJtYWlkLXNlcXVlbmNlLWFjdG9yLWJvcmRlci1jb2xvcil9dGV4dC5hY3Rvcj50c3BhbntmaWxsOnZhcigtLW1kLW1lcm1haWQtc2VxdWVuY2UtYWN0b3ItZmctY29sb3IpO2ZvbnQtZmFtaWx5OnZhcigtLW1kLW1lcm1haWQtZm9udC1mYW1pbHkpfWxpbmV7c3Ryb2tlOnZhcigtLW1kLW1lcm1haWQtc2VxdWVuY2UtYWN0b3ItbGluZS1jb2xvcil9LmFjdG9yLW1hbiBjaXJjbGUsLmFjdG9yLW1hbiBsaW5le2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1zZXF1ZW5jZS1hY3Rvcm1hbi1iZy1jb2xvcik7c3Ryb2tlOnZhcigtLW1kLW1lcm1haWQtc2VxdWVuY2UtYWN0b3JtYW4tbGluZS1jb2xvcil9Lm1lc3NhZ2VMaW5lMCwubWVzc2FnZUxpbmUxe3N0cm9rZTp2YXIoLS1tZC1tZXJtYWlkLXNlcXVlbmNlLW1lc3NhZ2UtbGluZS1jb2xvcil9Lm5vdGV7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLXNlcXVlbmNlLW5vdGUtYmctY29sb3IpO3N0cm9rZTp2YXIoLS1tZC1tZXJtYWlkLXNlcXVlbmNlLW5vdGUtYm9yZGVyLWNvbG9yKX0ubG9vcFRleHQsLmxvb3BUZXh0PnRzcGFuLC5tZXNzYWdlVGV4dCwubm90ZVRleHQ+dHNwYW57c3Ryb2tlOm5vbmU7Zm9udC1mYW1pbHk6dmFyKC0tbWQtbWVybWFpZC1mb250LWZhbWlseSkhaW1wb3J0YW50fS5tZXNzYWdlVGV4dHtmaWxsOnZhcigtLW1kLW1lcm1haWQtc2VxdWVuY2UtbWVzc2FnZS1mZy1jb2xvcil9Lmxvb3BUZXh0LC5sb29wVGV4dD50c3BhbntmaWxsOnZhcigtLW1kLW1lcm1haWQtc2VxdWVuY2UtbG9vcC1mZy1jb2xvcil9Lm5vdGVUZXh0PnRzcGFue2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1zZXF1ZW5jZS1ub3RlLWZnLWNvbG9yKX0jYXJyb3doZWFkIHBhdGh7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLXNlcXVlbmNlLW1lc3NhZ2UtbGluZS1jb2xvcik7c3Ryb2tlOm5vbmV9Lmxvb3BMaW5le2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1zZXF1ZW5jZS1sb29wLWJnLWNvbG9yKTtzdHJva2U6dmFyKC0tbWQtbWVybWFpZC1zZXF1ZW5jZS1sb29wLWJvcmRlci1jb2xvcil9LmxhYmVsQm94e2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1zZXF1ZW5jZS1sYWJlbC1iZy1jb2xvcik7c3Ryb2tlOm5vbmV9LmxhYmVsVGV4dCwubGFiZWxUZXh0PnNwYW57ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLXNlcXVlbmNlLWxhYmVsLWZnLWNvbG9yKTtmb250LWZhbWlseTp2YXIoLS1tZC1tZXJtYWlkLWZvbnQtZmFtaWx5KX0uc2VxdWVuY2VOdW1iZXJ7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLXNlcXVlbmNlLW51bWJlci1mZy1jb2xvcil9cmVjdC5yZWN0e2ZpbGw6dmFyKC0tbWQtbWVybWFpZC1zZXF1ZW5jZS1ib3gtYmctY29sb3IpO3N0cm9rZTpub25lfXJlY3QucmVjdCt0ZXh0LnRleHR7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLXNlcXVlbmNlLWJveC1mZy1jb2xvcil9ZGVmcyAjc2VxdWVuY2VudW1iZXJ7ZmlsbDp2YXIoLS1tZC1tZXJtYWlkLXNlcXVlbmNlLW51bWJlci1iZy1jb2xvcikhaW1wb3J0YW50fSI7dmFyIHFyLGthPTA7ZnVuY3Rpb24gSGEoKXtyZXR1cm4gdHlwZW9mIG1lcm1haWQ9PSJ1bmRlZmluZWQifHxtZXJtYWlkIGluc3RhbmNlb2YgRWxlbWVudD9ndCgiaHR0cHM6Ly91bnBrZy5jb20vbWVybWFpZEAxMC43LjAvZGlzdC9tZXJtYWlkLm1pbi5qcyIpOiQodm9pZCAwKX1mdW5jdGlvbiBfbihlKXtyZXR1cm4gZS5jbGFzc0xpc3QucmVtb3ZlKCJtZXJtYWlkIikscXJ8fChxcj1IYSgpLnBpcGUoeSgoKT0+bWVybWFpZC5pbml0aWFsaXplKHtzdGFydE9uTG9hZDohMSx0aGVtZUNTUzpMbixzZXF1ZW5jZTp7YWN0b3JGb250U2l6ZToiMTZweCIsbWVzc2FnZUZvbnRTaXplOiIxNnB4Iixub3RlRm9udFNpemU6IjE2cHgifX0pKSxtKCgpPT57fSksQigxKSkpLHFyLnN1YnNjcmliZSgoKT0+cm8odGhpcyxudWxsLGZ1bmN0aW9uKigpe2UuY2xhc3NMaXN0LmFkZCgibWVybWFpZCIpO2xldCB0PWBfX21lcm1haWRfJHtrYSsrfWAscj1FKCJkaXYiLHtjbGFzczoibWVybWFpZCJ9KSxvPWUudGV4dENvbnRlbnQse3N2ZzpuLGZuOml9PXlpZWxkIG1lcm1haWQucmVuZGVyKHQsbykscz1yLmF0dGFjaFNoYWRvdyh7bW9kZToiY2xvc2VkIn0pO3MuaW5uZXJIVE1MPW4sZS5yZXBsYWNlV2l0aChyKSxpPT1udWxsfHxpKHMpfSkpLHFyLnBpcGUobSgoKT0+KHtyZWY6ZX0pKSl9dmFyIEFuPUUoInRhYmxlIik7ZnVuY3Rpb24gQ24oZSl7cmV0dXJuIGUucmVwbGFjZVdpdGgoQW4pLEFuLnJlcGxhY2VXaXRoKHZuKGUpKSwkKHtyZWY6ZX0pfWZ1bmN0aW9uICRhKGUpe2xldCB0PWUuZmluZChyPT5yLmNoZWNrZWQpfHxlWzBdO3JldHVybiBUKC4uLmUubWFwKHI9PmQociwiY2hhbmdlIikucGlwZShtKCgpPT5QKGBsYWJlbFtmb3I9IiR7ci5pZH0iXWApKSkpKS5waXBlKHEoUChgbGFiZWxbZm9yPSIke3QuaWR9Il1gKSksbShyPT4oe2FjdGl2ZTpyfSkpKX1mdW5jdGlvbiBrbihlLHt2aWV3cG9ydCQ6dCx0YXJnZXQkOnJ9KXtsZXQgbz1QKCIudGFiYmVkLWxhYmVscyIsZSksbj1SKCI6c2NvcGUgPiBpbnB1dCIsZSksaT1OcigicHJldiIpO2UuYXBwZW5kKGkpO2xldCBzPU5yKCJuZXh0Iik7cmV0dXJuIGUuYXBwZW5kKHMpLEgoKCk9PntsZXQgYT1uZXcgdixjPWEucGlwZShlZSgpLG9lKCEwKSk7UShbYSxFZShlKV0pLnBpcGUoVShjKSxNZSgxLGRlKSkuc3Vic2NyaWJlKHtuZXh0KFt7YWN0aXZlOnB9LGxdKXtsZXQgZj1VZShwKSx7d2lkdGg6dX09cGUocCk7ZS5zdHlsZS5zZXRQcm9wZXJ0eSgiLS1tZC1pbmRpY2F0b3IteCIsYCR7Zi54fXB4YCksZS5zdHlsZS5zZXRQcm9wZXJ0eSgiLS1tZC1pbmRpY2F0b3Itd2lkdGgiLGAke3V9cHhgKTtsZXQgaD1pcihvKTsoZi54PGgueHx8Zi54K3U+aC54K2wud2lkdGgpJiZvLnNjcm9sbFRvKHtsZWZ0Ok1hdGgubWF4KDAsZi54LTE2KSxiZWhhdmlvcjoic21vb3RoIn0pfSxjb21wbGV0ZSgpe2Uuc3R5bGUucmVtb3ZlUHJvcGVydHkoIi0tbWQtaW5kaWNhdG9yLXgiKSxlLnN0eWxlLnJlbW92ZVByb3BlcnR5KCItLW1kLWluZGljYXRvci13aWR0aCIpfX0pLFEoW2V0KG8pLEVlKG8pXSkucGlwZShVKGMpKS5zdWJzY3JpYmUoKFtwLGxdKT0+e2xldCBmPXh0KG8pO2kuaGlkZGVuPXAueDwxNixzLmhpZGRlbj1wLng+Zi53aWR0aC1sLndpZHRoLTE2fSksVChkKGksImNsaWNrIikucGlwZShtKCgpPT4tMSkpLGQocywiY2xpY2siKS5waXBlKG0oKCk9PjEpKSkucGlwZShVKGMpKS5zdWJzY3JpYmUocD0+e2xldHt3aWR0aDpsfT1wZShvKTtvLnNjcm9sbEJ5KHtsZWZ0OmwqcCxiZWhhdmlvcjoic21vb3RoIn0pfSksci5waXBlKFUoYyksZyhwPT5uLmluY2x1ZGVzKHApKSkuc3Vic2NyaWJlKHA9PnAuY2xpY2soKSksby5jbGFzc0xpc3QuYWRkKCJ0YWJiZWQtbGFiZWxzLS1saW5rZWQiKTtmb3IobGV0IHAgb2Ygbil7bGV0IGw9UChgbGFiZWxbZm9yPSIke3AuaWR9Il1gKTtsLnJlcGxhY2VDaGlsZHJlbihFKCJhIix7aHJlZjpgIyR7bC5odG1sRm9yfWAsdGFiSW5kZXg6LTF9LC4uLkFycmF5LmZyb20obC5jaGlsZE5vZGVzKSkpLGQobC5maXJzdEVsZW1lbnRDaGlsZCwiY2xpY2siKS5waXBlKFUoYyksZyhmPT4hKGYubWV0YUtleXx8Zi5jdHJsS2V5KSkseShmPT57Zi5wcmV2ZW50RGVmYXVsdCgpLGYuc3RvcFByb3BhZ2F0aW9uKCl9KSkuc3Vic2NyaWJlKCgpPT57aGlzdG9yeS5yZXBsYWNlU3RhdGUoe30sIiIsYCMke2wuaHRtbEZvcn1gKSxsLmNsaWNrKCl9KX1yZXR1cm4gRygiY29udGVudC50YWJzLmxpbmsiKSYmYS5waXBlKExlKDEpLGFlKHQpKS5zdWJzY3JpYmUoKFt7YWN0aXZlOnB9LHtvZmZzZXQ6bH1dKT0+e2xldCBmPXAuaW5uZXJUZXh0LnRyaW0oKTtpZihwLmhhc0F0dHJpYnV0ZSgiZGF0YS1tZC1zd2l0Y2hpbmciKSlwLnJlbW92ZUF0dHJpYnV0ZSgiZGF0YS1tZC1zd2l0Y2hpbmciKTtlbHNle2xldCB1PWUub2Zmc2V0VG9wLWwueTtmb3IobGV0IHcgb2YgUigiW2RhdGEtdGFic10iKSlmb3IobGV0IEEgb2YgUigiOnNjb3BlID4gaW5wdXQiLHcpKXtsZXQgWj1QKGBsYWJlbFtmb3I9IiR7QS5pZH0iXWApO2lmKFohPT1wJiZaLmlubmVyVGV4dC50cmltKCk9PT1mKXtaLnNldEF0dHJpYnV0ZSgiZGF0YS1tZC1zd2l0Y2hpbmciLCIiKSxBLmNsaWNrKCk7YnJlYWt9fXdpbmRvdy5zY3JvbGxUbyh7dG9wOmUub2Zmc2V0VG9wLXV9KTtsZXQgaD1fX21kX2dldCgiX190YWJzIil8fFtdO19fbWRfc2V0KCJfX3RhYnMiLFsuLi5uZXcgU2V0KFtmLC4uLmhdKV0pfX0pLGEucGlwZShVKGMpKS5zdWJzY3JpYmUoKCk9Pntmb3IobGV0IHAgb2YgUigiYXVkaW8sIHZpZGVvIixlKSlwLnBhdXNlKCl9KSwkYShuKS5waXBlKHkocD0+YS5uZXh0KHApKSxfKCgpPT5hLmNvbXBsZXRlKCkpLG0ocD0+Rih7cmVmOmV9LHApKSl9KS5waXBlKHplKGllKSl9ZnVuY3Rpb24gSG4oZSx7dmlld3BvcnQkOnQsdGFyZ2V0JDpyLHByaW50JDpvfSl7cmV0dXJuIFQoLi4uUigiLmFubm90YXRlOm5vdCguaGlnaGxpZ2h0KSIsZSkubWFwKG49PnduKG4se3RhcmdldCQ6cixwcmludCQ6b30pKSwuLi5SKCJwcmU6bm90KC5tZXJtYWlkKSA+IGNvZGUiLGUpLm1hcChuPT5PbihuLHt0YXJnZXQkOnIscHJpbnQkOm99KSksLi4uUigicHJlLm1lcm1haWQiLGUpLm1hcChuPT5fbihuKSksLi4uUigidGFibGU6bm90KFtjbGFzc10pIixlKS5tYXAobj0+Q24obikpLC4uLlIoImRldGFpbHMiLGUpLm1hcChuPT5NbihuLHt0YXJnZXQkOnIscHJpbnQkOm99KSksLi4uUigiW2RhdGEtdGFic10iLGUpLm1hcChuPT5rbihuLHt2aWV3cG9ydCQ6dCx0YXJnZXQkOnJ9KSksLi4uUigiW3RpdGxlXSIsZSkuZmlsdGVyKCgpPT5HKCJjb250ZW50LnRvb2x0aXBzIikpLm1hcChuPT5HZShuKSkpfWZ1bmN0aW9uIFJhKGUse2FsZXJ0JDp0fSl7cmV0dXJuIHQucGlwZShiKHI9PlQoJCghMCksJCghMSkucGlwZShZZSgyZTMpKSkucGlwZShtKG89Pih7bWVzc2FnZTpyLGFjdGl2ZTpvfSkpKSkpfWZ1bmN0aW9uICRuKGUsdCl7bGV0IHI9UCgiLm1kLXR5cGVzZXQiLGUpO3JldHVybiBIKCgpPT57bGV0IG89bmV3IHY7cmV0dXJuIG8uc3Vic2NyaWJlKCh7bWVzc2FnZTpuLGFjdGl2ZTppfSk9PntlLmNsYXNzTGlzdC50b2dnbGUoIm1kLWRpYWxvZy0tYWN0aXZlIixpKSxyLnRleHRDb250ZW50PW59KSxSYShlLHQpLnBpcGUoeShuPT5vLm5leHQobikpLF8oKCk9Pm8uY29tcGxldGUoKSksbShuPT5GKHtyZWY6ZX0sbikpKX0pfWZ1bmN0aW9uIFBhKHt2aWV3cG9ydCQ6ZX0pe2lmKCFHKCJoZWFkZXIuYXV0b2hpZGUiKSlyZXR1cm4gJCghMSk7bGV0IHQ9ZS5waXBlKG0oKHtvZmZzZXQ6e3k6bn19KT0+biksS2UoMiwxKSxtKChbbixpXSk9PltuPGksaV0pLFgoMCkpLHI9UShbZSx0XSkucGlwZShnKChbe29mZnNldDpufSxbLGldXSk9Pk1hdGguYWJzKGktbi55KT4xMDApLG0oKFssW25dXSk9Pm4pLFkoKSksbz1XZSgic2VhcmNoIik7cmV0dXJuIFEoW2Usb10pLnBpcGUobSgoW3tvZmZzZXQ6bn0saV0pPT5uLnk+NDAwJiYhaSksWSgpLGIobj0+bj9yOiQoITEpKSxxKCExKSl9ZnVuY3Rpb24gUm4oZSx0KXtyZXR1cm4gSCgoKT0+UShbRWUoZSksUGEodCldKSkucGlwZShtKChbe2hlaWdodDpyfSxvXSk9Pih7aGVpZ2h0OnIsaGlkZGVuOm99KSksWSgocixvKT0+ci5oZWlnaHQ9PT1vLmhlaWdodCYmci5oaWRkZW49PT1vLmhpZGRlbiksQigxKSl9ZnVuY3Rpb24gUG4oZSx7aGVhZGVyJDp0LG1haW4kOnJ9KXtyZXR1cm4gSCgoKT0+e2xldCBvPW5ldyB2LG49by5waXBlKGVlKCksb2UoITApKTtvLnBpcGUoWCgiYWN0aXZlIiksamUodCkpLnN1YnNjcmliZSgoW3thY3RpdmU6c30se2hpZGRlbjphfV0pPT57ZS5jbGFzc0xpc3QudG9nZ2xlKCJtZC1oZWFkZXItLXNoYWRvdyIscyYmIWEpLGUuaGlkZGVuPWF9KTtsZXQgaT1mZShSKCJbdGl0bGVdIixlKSkucGlwZShnKCgpPT5HKCJjb250ZW50LnRvb2x0aXBzIikpLHJlKHM9PkdlKHMpKSk7cmV0dXJuIHIuc3Vic2NyaWJlKG8pLHQucGlwZShVKG4pLG0ocz0+Rih7cmVmOmV9LHMpKSwkZShpLnBpcGUoVShuKSkpKX0pfWZ1bmN0aW9uIElhKGUse3ZpZXdwb3J0JDp0LGhlYWRlciQ6cn0pe3JldHVybiBwcihlLHt2aWV3cG9ydCQ6dCxoZWFkZXIkOnJ9KS5waXBlKG0oKHtvZmZzZXQ6e3k6b319KT0+e2xldHtoZWlnaHQ6bn09cGUoZSk7cmV0dXJue2FjdGl2ZTpvPj1ufX0pLFgoImFjdGl2ZSIpKX1mdW5jdGlvbiBJbihlLHQpe3JldHVybiBIKCgpPT57bGV0IHI9bmV3IHY7ci5zdWJzY3JpYmUoe25leHQoe2FjdGl2ZTpufSl7ZS5jbGFzc0xpc3QudG9nZ2xlKCJtZC1oZWFkZXJfX3RpdGxlLS1hY3RpdmUiLG4pfSxjb21wbGV0ZSgpe2UuY2xhc3NMaXN0LnJlbW92ZSgibWQtaGVhZGVyX190aXRsZS0tYWN0aXZlIil9fSk7bGV0IG89bWUoIi5tZC1jb250ZW50IGgxIik7cmV0dXJuIHR5cGVvZiBvPT0idW5kZWZpbmVkIj9MOklhKG8sdCkucGlwZSh5KG49PnIubmV4dChuKSksXygoKT0+ci5jb21wbGV0ZSgpKSxtKG49PkYoe3JlZjplfSxuKSkpfSl9ZnVuY3Rpb24gRm4oZSx7dmlld3BvcnQkOnQsaGVhZGVyJDpyfSl7bGV0IG89ci5waXBlKG0oKHtoZWlnaHQ6aX0pPT5pKSxZKCkpLG49by5waXBlKGIoKCk9PkVlKGUpLnBpcGUobSgoe2hlaWdodDppfSk9Pih7dG9wOmUub2Zmc2V0VG9wLGJvdHRvbTplLm9mZnNldFRvcCtpfSkpLFgoImJvdHRvbSIpKSkpO3JldHVybiBRKFtvLG4sdF0pLnBpcGUobSgoW2kse3RvcDpzLGJvdHRvbTphfSx7b2Zmc2V0Ont5OmN9LHNpemU6e2hlaWdodDpwfX1dKT0+KHA9TWF0aC5tYXgoMCxwLU1hdGgubWF4KDAscy1jLGkpLU1hdGgubWF4KDAscCtjLWEpKSx7b2Zmc2V0OnMtaSxoZWlnaHQ6cCxhY3RpdmU6cy1pPD1jfSkpLFkoKGkscyk9Pmkub2Zmc2V0PT09cy5vZmZzZXQmJmkuaGVpZ2h0PT09cy5oZWlnaHQmJmkuYWN0aXZlPT09cy5hY3RpdmUpKX1mdW5jdGlvbiBGYShlKXtsZXQgdD1fX21kX2dldCgiX19wYWxldHRlIil8fHtpbmRleDplLmZpbmRJbmRleChvPT5tYXRjaE1lZGlhKG8uZ2V0QXR0cmlidXRlKCJkYXRhLW1kLWNvbG9yLW1lZGlhIikpLm1hdGNoZXMpfSxyPU1hdGgubWF4KDAsTWF0aC5taW4odC5pbmRleCxlLmxlbmd0aC0xKSk7cmV0dXJuICQoLi4uZSkucGlwZShyZShvPT5kKG8sImNoYW5nZSIpLnBpcGUobSgoKT0+bykpKSxxKGVbcl0pLG0obz0+KHtpbmRleDplLmluZGV4T2YobyksY29sb3I6e21lZGlhOm8uZ2V0QXR0cmlidXRlKCJkYXRhLW1kLWNvbG9yLW1lZGlhIiksc2NoZW1lOm8uZ2V0QXR0cmlidXRlKCJkYXRhLW1kLWNvbG9yLXNjaGVtZSIpLHByaW1hcnk6by5nZXRBdHRyaWJ1dGUoImRhdGEtbWQtY29sb3ItcHJpbWFyeSIpLGFjY2VudDpvLmdldEF0dHJpYnV0ZSgiZGF0YS1tZC1jb2xvci1hY2NlbnQiKX19KSksQigxKSl9ZnVuY3Rpb24gam4oZSl7bGV0IHQ9UigiaW5wdXQiLGUpLHI9RSgibWV0YSIse25hbWU6InRoZW1lLWNvbG9yIn0pO2RvY3VtZW50LmhlYWQuYXBwZW5kQ2hpbGQocik7bGV0IG89RSgibWV0YSIse25hbWU6ImNvbG9yLXNjaGVtZSJ9KTtkb2N1bWVudC5oZWFkLmFwcGVuZENoaWxkKG8pO2xldCBuPUF0KCIocHJlZmVycy1jb2xvci1zY2hlbWU6IGxpZ2h0KSIpO3JldHVybiBIKCgpPT57bGV0IGk9bmV3IHY7cmV0dXJuIGkuc3Vic2NyaWJlKHM9PntpZihkb2N1bWVudC5ib2R5LnNldEF0dHJpYnV0ZSgiZGF0YS1tZC1jb2xvci1zd2l0Y2hpbmciLCIiKSxzLmNvbG9yLm1lZGlhPT09IihwcmVmZXJzLWNvbG9yLXNjaGVtZSkiKXtsZXQgYT1tYXRjaE1lZGlhKCIocHJlZmVycy1jb2xvci1zY2hlbWU6IGxpZ2h0KSIpLGM9ZG9jdW1lbnQucXVlcnlTZWxlY3RvcihhLm1hdGNoZXM/IltkYXRhLW1kLWNvbG9yLW1lZGlhPScocHJlZmVycy1jb2xvci1zY2hlbWU6IGxpZ2h0KSddIjoiW2RhdGEtbWQtY29sb3ItbWVkaWE9JyhwcmVmZXJzLWNvbG9yLXNjaGVtZTogZGFyayknXSIpO3MuY29sb3Iuc2NoZW1lPWMuZ2V0QXR0cmlidXRlKCJkYXRhLW1kLWNvbG9yLXNjaGVtZSIpLHMuY29sb3IucHJpbWFyeT1jLmdldEF0dHJpYnV0ZSgiZGF0YS1tZC1jb2xvci1wcmltYXJ5Iikscy5jb2xvci5hY2NlbnQ9Yy5nZXRBdHRyaWJ1dGUoImRhdGEtbWQtY29sb3ItYWNjZW50Iil9Zm9yKGxldFthLGNdb2YgT2JqZWN0LmVudHJpZXMocy5jb2xvcikpZG9jdW1lbnQuYm9keS5zZXRBdHRyaWJ1dGUoYGRhdGEtbWQtY29sb3ItJHthfWAsYyk7Zm9yKGxldCBhPTA7YTx0Lmxlbmd0aDthKyspe2xldCBjPXRbYV0ubmV4dEVsZW1lbnRTaWJsaW5nO2MgaW5zdGFuY2VvZiBIVE1MRWxlbWVudCYmKGMuaGlkZGVuPXMuaW5kZXghPT1hKX1fX21kX3NldCgiX19wYWxldHRlIixzKX0pLGkucGlwZShtKCgpPT57bGV0IHM9VGUoImhlYWRlciIpLGE9d2luZG93LmdldENvbXB1dGVkU3R5bGUocyk7cmV0dXJuIG8uY29udGVudD1hLmNvbG9yU2NoZW1lLGEuYmFja2dyb3VuZENvbG9yLm1hdGNoKC9cZCsvZykubWFwKGM9PigrYykudG9TdHJpbmcoMTYpLnBhZFN0YXJ0KDIsIjAiKSkuam9pbigiIil9KSkuc3Vic2NyaWJlKHM9PnIuY29udGVudD1gIyR7c31gKSxpLnBpcGUoT2UoaWUpKS5zdWJzY3JpYmUoKCk9Pntkb2N1bWVudC5ib2R5LnJlbW92ZUF0dHJpYnV0ZSgiZGF0YS1tZC1jb2xvci1zd2l0Y2hpbmciKX0pLEZhKHQpLnBpcGUoVShuLnBpcGUoTGUoMSkpKSxhdCgpLHkocz0+aS5uZXh0KHMpKSxfKCgpPT5pLmNvbXBsZXRlKCkpLG0ocz0+Rih7cmVmOmV9LHMpKSl9KX1mdW5jdGlvbiBVbihlLHtwcm9ncmVzcyQ6dH0pe3JldHVybiBIKCgpPT57bGV0IHI9bmV3IHY7cmV0dXJuIHIuc3Vic2NyaWJlKCh7dmFsdWU6b30pPT57ZS5zdHlsZS5zZXRQcm9wZXJ0eSgiLS1tZC1wcm9ncmVzcy12YWx1ZSIsYCR7b31gKX0pLHQucGlwZSh5KG89PnIubmV4dCh7dmFsdWU6b30pKSxfKCgpPT5yLmNvbXBsZXRlKCkpLG0obz0+KHtyZWY6ZSx2YWx1ZTpvfSkpKX0pfXZhciBLcj1qdCh6cigpKTtmdW5jdGlvbiBqYShlKXtlLnNldEF0dHJpYnV0ZSgiZGF0YS1tZC1jb3B5aW5nIiwiIik7bGV0IHQ9ZS5jbG9zZXN0KCJbZGF0YS1jb3B5XSIpLHI9dD90LmdldEF0dHJpYnV0ZSgiZGF0YS1jb3B5Iik6ZS5pbm5lclRleHQ7cmV0dXJuIGUucmVtb3ZlQXR0cmlidXRlKCJkYXRhLW1kLWNvcHlpbmciKSxyLnRyaW1FbmQoKX1mdW5jdGlvbiBXbih7YWxlcnQkOmV9KXtLci5kZWZhdWx0LmlzU3VwcG9ydGVkKCkmJm5ldyBqKHQ9PntuZXcgS3IuZGVmYXVsdCgiW2RhdGEtY2xpcGJvYXJkLXRhcmdldF0sIFtkYXRhLWNsaXBib2FyZC10ZXh0XSIse3RleHQ6cj0+ci5nZXRBdHRyaWJ1dGUoImRhdGEtY2xpcGJvYXJkLXRleHQiKXx8amEoUChyLmdldEF0dHJpYnV0ZSgiZGF0YS1jbGlwYm9hcmQtdGFyZ2V0IikpKX0pLm9uKCJzdWNjZXNzIixyPT50Lm5leHQocikpfSkucGlwZSh5KHQ9Pnt0LnRyaWdnZXIuZm9jdXMoKX0pLG0oKCk9PmdlKCJjbGlwYm9hcmQuY29waWVkIikpKS5zdWJzY3JpYmUoZSl9ZnVuY3Rpb24gRG4oZSx0KXtyZXR1cm4gZS5wcm90b2NvbD10LnByb3RvY29sLGUuaG9zdG5hbWU9dC5ob3N0bmFtZSxlfWZ1bmN0aW9uIFVhKGUsdCl7bGV0IHI9bmV3IE1hcDtmb3IobGV0IG8gb2YgUigidXJsIixlKSl7bGV0IG49UCgibG9jIixvKSxpPVtEbihuZXcgVVJMKG4udGV4dENvbnRlbnQpLHQpXTtyLnNldChgJHtpWzBdfWAsaSk7Zm9yKGxldCBzIG9mIFIoIltyZWw9YWx0ZXJuYXRlXSIsbykpe2xldCBhPXMuZ2V0QXR0cmlidXRlKCJocmVmIik7YSE9bnVsbCYmaS5wdXNoKERuKG5ldyBVUkwoYSksdCkpfX1yZXR1cm4gcn1mdW5jdGlvbiBtcihlKXtyZXR1cm4gb24obmV3IFVSTCgic2l0ZW1hcC54bWwiLGUpKS5waXBlKG0odD0+VWEodCxuZXcgVVJMKGUpKSksaGUoKCk9PiQobmV3IE1hcCkpKX1mdW5jdGlvbiBXYShlLHQpe2lmKCEoZS50YXJnZXQgaW5zdGFuY2VvZiBFbGVtZW50KSlyZXR1cm4gTDtsZXQgcj1lLnRhcmdldC5jbG9zZXN0KCJhIik7aWYocj09PW51bGwpcmV0dXJuIEw7aWYoci50YXJnZXR8fGUubWV0YUtleXx8ZS5jdHJsS2V5KXJldHVybiBMO2xldCBvPW5ldyBVUkwoci5ocmVmKTtyZXR1cm4gby5zZWFyY2g9by5oYXNoPSIiLHQuaGFzKGAke299YCk/KGUucHJldmVudERlZmF1bHQoKSwkKG5ldyBVUkwoci5ocmVmKSkpOkx9ZnVuY3Rpb24gTm4oZSl7bGV0IHQ9bmV3IE1hcDtmb3IobGV0IHIgb2YgUigiOnNjb3BlID4gKiIsZS5oZWFkKSl0LnNldChyLm91dGVySFRNTCxyKTtyZXR1cm4gdH1mdW5jdGlvbiBWbihlKXtmb3IobGV0IHQgb2YgUigiW2hyZWZdLCBbc3JjXSIsZSkpZm9yKGxldCByIG9mWyJocmVmIiwic3JjIl0pe2xldCBvPXQuZ2V0QXR0cmlidXRlKHIpO2lmKG8mJiEvXig/OlthLXpdKzopP1wvXC8vaS50ZXN0KG8pKXt0W3JdPXRbcl07YnJlYWt9fXJldHVybiAkKGUpfWZ1bmN0aW9uIERhKGUpe2ZvcihsZXQgbyBvZlsiW2RhdGEtbWQtY29tcG9uZW50PWFubm91bmNlXSIsIltkYXRhLW1kLWNvbXBvbmVudD1jb250YWluZXJdIiwiW2RhdGEtbWQtY29tcG9uZW50PWhlYWRlci10b3BpY10iLCJbZGF0YS1tZC1jb21wb25lbnQ9b3V0ZGF0ZWRdIiwiW2RhdGEtbWQtY29tcG9uZW50PWxvZ29dIiwiW2RhdGEtbWQtY29tcG9uZW50PXNraXBdIiwuLi5HKCJuYXZpZ2F0aW9uLnRhYnMuc3RpY2t5Iik/WyJbZGF0YS1tZC1jb21wb25lbnQ9dGFic10iXTpbXV0pe2xldCBuPW1lKG8pLGk9bWUobyxlKTt0eXBlb2YgbiE9InVuZGVmaW5lZCImJnR5cGVvZiBpIT0idW5kZWZpbmVkIiYmbi5yZXBsYWNlV2l0aChpKX1sZXQgdD1Obihkb2N1bWVudCk7Zm9yKGxldFtvLG5db2YgTm4oZSkpdC5oYXMobyk/dC5kZWxldGUobyk6ZG9jdW1lbnQuaGVhZC5hcHBlbmRDaGlsZChuKTtmb3IobGV0IG8gb2YgdC52YWx1ZXMoKSl7bGV0IG49by5nZXRBdHRyaWJ1dGUoIm5hbWUiKTtuIT09InRoZW1lLWNvbG9yIiYmbiE9PSJjb2xvci1zY2hlbWUiJiZvLnJlbW92ZSgpfWxldCByPVRlKCJjb250YWluZXIiKTtyZXR1cm4gRmUoUigic2NyaXB0IixyKSkucGlwZShiKG89PntsZXQgbj1lLmNyZWF0ZUVsZW1lbnQoInNjcmlwdCIpO2lmKG8uc3JjKXtmb3IobGV0IGkgb2Ygby5nZXRBdHRyaWJ1dGVOYW1lcygpKW4uc2V0QXR0cmlidXRlKGksby5nZXRBdHRyaWJ1dGUoaSkpO3JldHVybiBvLnJlcGxhY2VXaXRoKG4pLG5ldyBqKGk9PntuLm9ubG9hZD0oKT0+aS5jb21wbGV0ZSgpfSl9ZWxzZSByZXR1cm4gbi50ZXh0Q29udGVudD1vLnRleHRDb250ZW50LG8ucmVwbGFjZVdpdGgobiksTH0pLGVlKCksb2UoZG9jdW1lbnQpKX1mdW5jdGlvbiB6bih7bG9jYXRpb24kOmUsdmlld3BvcnQkOnQscHJvZ3Jlc3MkOnJ9KXtsZXQgbz13ZSgpO2lmKGxvY2F0aW9uLnByb3RvY29sPT09ImZpbGU6IilyZXR1cm4gTDtsZXQgbj1tcihvLmJhc2UpOyQoZG9jdW1lbnQpLnN1YnNjcmliZShWbik7bGV0IGk9ZChkb2N1bWVudC5ib2R5LCJjbGljayIpLnBpcGUoamUobiksYigoW2MscF0pPT5XYShjLHApKSxsZSgpKSxzPWQod2luZG93LCJwb3BzdGF0ZSIpLnBpcGUobSh2ZSksbGUoKSk7aS5waXBlKGFlKHQpKS5zdWJzY3JpYmUoKFtjLHtvZmZzZXQ6cH1dKT0+e2hpc3RvcnkucmVwbGFjZVN0YXRlKHAsIiIpLGhpc3RvcnkucHVzaFN0YXRlKG51bGwsIiIsYyl9KSxUKGkscykuc3Vic2NyaWJlKGUpO2xldCBhPWUucGlwZShYKCJwYXRobmFtZSIpLGIoYz0+cm4oYyx7cHJvZ3Jlc3MkOnJ9KS5waXBlKGhlKCgpPT4oc3QoYywhMCksTCkpKSksYihWbiksYihEYSksbGUoKSk7cmV0dXJuIFQoYS5waXBlKGFlKGUsKGMscCk9PnApKSxlLnBpcGUoWCgicGF0aG5hbWUiKSxiKCgpPT5lKSxYKCJoYXNoIikpLGUucGlwZShZKChjLHApPT5jLnBhdGhuYW1lPT09cC5wYXRobmFtZSYmYy5oYXNoPT09cC5oYXNoKSxiKCgpPT5pKSx5KCgpPT5oaXN0b3J5LmJhY2soKSkpKS5zdWJzY3JpYmUoYz0+e3ZhciBwLGw7aGlzdG9yeS5zdGF0ZSE9PW51bGx8fCFjLmhhc2g/d2luZG93LnNjcm9sbFRvKDAsKGw9KHA9aGlzdG9yeS5zdGF0ZSk9PW51bGw/dm9pZCAwOnAueSkhPW51bGw/bDowKTooaGlzdG9yeS5zY3JvbGxSZXN0b3JhdGlvbj0iYXV0byIsWm8oYy5oYXNoKSxoaXN0b3J5LnNjcm9sbFJlc3RvcmF0aW9uPSJtYW51YWwiKX0pLGUuc3Vic2NyaWJlKCgpPT57aGlzdG9yeS5zY3JvbGxSZXN0b3JhdGlvbj0ibWFudWFsIn0pLGQod2luZG93LCJiZWZvcmV1bmxvYWQiKS5zdWJzY3JpYmUoKCk9PntoaXN0b3J5LnNjcm9sbFJlc3RvcmF0aW9uPSJhdXRvIn0pLHQucGlwZShYKCJvZmZzZXQiKSxiZSgxMDApKS5zdWJzY3JpYmUoKHtvZmZzZXQ6Y30pPT57aGlzdG9yeS5yZXBsYWNlU3RhdGUoYywiIil9KSxhfXZhciBRbj1qdChLbigpKTtmdW5jdGlvbiBZbihlKXtsZXQgdD1lLnNlcGFyYXRvci5zcGxpdCgifCIpLm1hcChuPT5uLnJlcGxhY2UoLyhcKFw/WyE9PF1bXildK1wpKS9nLCIiKS5sZW5ndGg9PT0wPyJcdUZGRkQiOm4pLmpvaW4oInwiKSxyPW5ldyBSZWdFeHAodCwiaW1nIiksbz0obixpLHMpPT5gJHtpfTxtYXJrIGRhdGEtbWQtaGlnaGxpZ2h0PiR7c308L21hcms+YDtyZXR1cm4gbj0+e249bi5yZXBsYWNlKC9bXHMqK1wtOn5eXSsvZywiICIpLnRyaW0oKTtsZXQgaT1uZXcgUmVnRXhwKGAoXnwke2Uuc2VwYXJhdG9yfXwpKCR7bi5yZXBsYWNlKC9bfFxce30oKVtcXV4kKyo/Li1dL2csIlxcJCYiKS5yZXBsYWNlKHIsInwiKX0pYCwiaW1nIik7cmV0dXJuIHM9PigwLFFuLmRlZmF1bHQpKHMpLnJlcGxhY2UoaSxvKS5yZXBsYWNlKC88XC9tYXJrPihccyspPG1hcmtbXj5dKj4vaW1nLCIkMSIpfX1mdW5jdGlvbiBIdChlKXtyZXR1cm4gZS50eXBlPT09MX1mdW5jdGlvbiBmcihlKXtyZXR1cm4gZS50eXBlPT09M31mdW5jdGlvbiBCbihlLHQpe2xldCByPWxuKGUpO3JldHVybiBUKCQobG9jYXRpb24ucHJvdG9jb2whPT0iZmlsZToiKSxXZSgic2VhcmNoIikpLnBpcGUoSGUobz0+byksYigoKT0+dCkpLnN1YnNjcmliZSgoe2NvbmZpZzpvLGRvY3M6bn0pPT5yLm5leHQoe3R5cGU6MCxkYXRhOntjb25maWc6byxkb2NzOm4sb3B0aW9uczp7c3VnZ2VzdDpHKCJzZWFyY2guc3VnZ2VzdCIpfX19KSkscn1mdW5jdGlvbiBHbih7ZG9jdW1lbnQkOmV9KXtsZXQgdD13ZSgpLHI9RGUobmV3IFVSTCgiLi4vdmVyc2lvbnMuanNvbiIsdC5iYXNlKSkucGlwZShoZSgoKT0+TCkpLG89ci5waXBlKG0obj0+e2xldFssaV09dC5iYXNlLm1hdGNoKC8oW14vXSspXC8/JC8pO3JldHVybiBuLmZpbmQoKHt2ZXJzaW9uOnMsYWxpYXNlczphfSk9PnM9PT1pfHxhLmluY2x1ZGVzKGkpKXx8blswXX0pKTtyLnBpcGUobShuPT5uZXcgTWFwKG4ubWFwKGk9PltgJHtuZXcgVVJMKGAuLi8ke2kudmVyc2lvbn0vYCx0LmJhc2UpfWAsaV0pKSksYihuPT5kKGRvY3VtZW50LmJvZHksImNsaWNrIikucGlwZShnKGk9PiFpLm1ldGFLZXkmJiFpLmN0cmxLZXkpLGFlKG8pLGIoKFtpLHNdKT0+e2lmKGkudGFyZ2V0IGluc3RhbmNlb2YgRWxlbWVudCl7bGV0IGE9aS50YXJnZXQuY2xvc2VzdCgiYSIpO2lmKGEmJiFhLnRhcmdldCYmbi5oYXMoYS5ocmVmKSl7bGV0IGM9YS5ocmVmO3JldHVybiFpLnRhcmdldC5jbG9zZXN0KCIubWQtdmVyc2lvbiIpJiZuLmdldChjKT09PXM/TDooaS5wcmV2ZW50RGVmYXVsdCgpLCQoYykpfX1yZXR1cm4gTH0pLGIoaT0+e2xldHt2ZXJzaW9uOnN9PW4uZ2V0KGkpO3JldHVybiBtcihuZXcgVVJMKGkpKS5waXBlKG0oYT0+e2xldCBwPXZlKCkuaHJlZi5yZXBsYWNlKHQuYmFzZSwiIik7cmV0dXJuIGEuaGFzKHAuc3BsaXQoIiMiKVswXSk/bmV3IFVSTChgLi4vJHtzfS8ke3B9YCx0LmJhc2UpOm5ldyBVUkwoaSl9KSl9KSkpKS5zdWJzY3JpYmUobj0+c3QobiwhMCkpLFEoW3Isb10pLnN1YnNjcmliZSgoW24saV0pPT57UCgiLm1kLWhlYWRlcl9fdG9waWMiKS5hcHBlbmRDaGlsZChnbihuLGkpKX0pLGUucGlwZShiKCgpPT5vKSkuc3Vic2NyaWJlKG49Pnt2YXIgcztsZXQgaT1fX21kX2dldCgiX19vdXRkYXRlZCIsc2Vzc2lvblN0b3JhZ2UpO2lmKGk9PT1udWxsKXtpPSEwO2xldCBhPSgocz10LnZlcnNpb24pPT1udWxsP3ZvaWQgMDpzLmRlZmF1bHQpfHwibGF0ZXN0IjtBcnJheS5pc0FycmF5KGEpfHwoYT1bYV0pO2U6Zm9yKGxldCBjIG9mIGEpZm9yKGxldCBwIG9mIG4uYWxpYXNlcy5jb25jYXQobi52ZXJzaW9uKSlpZihuZXcgUmVnRXhwKGMsImkiKS50ZXN0KHApKXtpPSExO2JyZWFrIGV9X19tZF9zZXQoIl9fb3V0ZGF0ZWQiLGksc2Vzc2lvblN0b3JhZ2UpfWlmKGkpZm9yKGxldCBhIG9mIG5lKCJvdXRkYXRlZCIpKWEuaGlkZGVuPSExfSl9ZnVuY3Rpb24gS2EoZSx7d29ya2VyJDp0fSl7bGV0e3NlYXJjaFBhcmFtczpyfT12ZSgpO3IuaGFzKCJxIikmJihCZSgic2VhcmNoIiwhMCksZS52YWx1ZT1yLmdldCgicSIpLGUuZm9jdXMoKSxXZSgic2VhcmNoIikucGlwZShIZShpPT4haSkpLnN1YnNjcmliZSgoKT0+e2xldCBpPXZlKCk7aS5zZWFyY2hQYXJhbXMuZGVsZXRlKCJxIiksaGlzdG9yeS5yZXBsYWNlU3RhdGUoe30sIiIsYCR7aX1gKX0pKTtsZXQgbz12dChlKSxuPVQodC5waXBlKEhlKEh0KSksZChlLCJrZXl1cCIpLG8pLnBpcGUobSgoKT0+ZS52YWx1ZSksWSgpKTtyZXR1cm4gUShbbixvXSkucGlwZShtKChbaSxzXSk9Pih7dmFsdWU6aSxmb2N1czpzfSkpLEIoMSkpfWZ1bmN0aW9uIEpuKGUse3dvcmtlciQ6dH0pe2xldCByPW5ldyB2LG89ci5waXBlKGVlKCksb2UoITApKTtRKFt0LnBpcGUoSGUoSHQpKSxyXSwoaSxzKT0+cykucGlwZShYKCJ2YWx1ZSIpKS5zdWJzY3JpYmUoKHt2YWx1ZTppfSk9PnQubmV4dCh7dHlwZToyLGRhdGE6aX0pKSxyLnBpcGUoWCgiZm9jdXMiKSkuc3Vic2NyaWJlKCh7Zm9jdXM6aX0pPT57aSYmQmUoInNlYXJjaCIsaSl9KSxkKGUuZm9ybSwicmVzZXQiKS5waXBlKFUobykpLnN1YnNjcmliZSgoKT0+ZS5mb2N1cygpKTtsZXQgbj1QKCJoZWFkZXIgW2Zvcj1fX3NlYXJjaF0iKTtyZXR1cm4gZChuLCJjbGljayIpLnN1YnNjcmliZSgoKT0+ZS5mb2N1cygpKSxLYShlLHt3b3JrZXIkOnR9KS5waXBlKHkoaT0+ci5uZXh0KGkpKSxfKCgpPT5yLmNvbXBsZXRlKCkpLG0oaT0+Rih7cmVmOmV9LGkpKSxCKDEpKX1mdW5jdGlvbiBYbihlLHt3b3JrZXIkOnQscXVlcnkkOnJ9KXtsZXQgbz1uZXcgdixuPVlvKGUucGFyZW50RWxlbWVudCkucGlwZShnKEJvb2xlYW4pKSxpPWUucGFyZW50RWxlbWVudCxzPVAoIjpzY29wZSA+IDpmaXJzdC1jaGlsZCIsZSksYT1QKCI6c2NvcGUgPiA6bGFzdC1jaGlsZCIsZSk7V2UoInNlYXJjaCIpLnN1YnNjcmliZShsPT5hLnNldEF0dHJpYnV0ZSgicm9sZSIsbD8ibGlzdCI6InByZXNlbnRhdGlvbiIpKSxvLnBpcGUoYWUociksSXIodC5waXBlKEhlKEh0KSkpKS5zdWJzY3JpYmUoKFt7aXRlbXM6bH0se3ZhbHVlOmZ9XSk9Pntzd2l0Y2gobC5sZW5ndGgpe2Nhc2UgMDpzLnRleHRDb250ZW50PWYubGVuZ3RoP2dlKCJzZWFyY2gucmVzdWx0Lm5vbmUiKTpnZSgic2VhcmNoLnJlc3VsdC5wbGFjZWhvbGRlciIpO2JyZWFrO2Nhc2UgMTpzLnRleHRDb250ZW50PWdlKCJzZWFyY2gucmVzdWx0Lm9uZSIpO2JyZWFrO2RlZmF1bHQ6bGV0IHU9YXIobC5sZW5ndGgpO3MudGV4dENvbnRlbnQ9Z2UoInNlYXJjaC5yZXN1bHQub3RoZXIiLHUpfX0pO2xldCBjPW8ucGlwZSh5KCgpPT5hLmlubmVySFRNTD0iIiksYigoe2l0ZW1zOmx9KT0+VCgkKC4uLmwuc2xpY2UoMCwxMCkpLCQoLi4ubC5zbGljZSgxMCkpLnBpcGUoS2UoNCksanIobiksYigoW2ZdKT0+ZikpKSksbShobiksbGUoKSk7cmV0dXJuIGMuc3Vic2NyaWJlKGw9PmEuYXBwZW5kQ2hpbGQobCkpLGMucGlwZShyZShsPT57bGV0IGY9bWUoImRldGFpbHMiLGwpO3JldHVybiB0eXBlb2YgZj09InVuZGVmaW5lZCI/TDpkKGYsInRvZ2dsZSIpLnBpcGUoVShvKSxtKCgpPT5mKSl9KSkuc3Vic2NyaWJlKGw9PntsLm9wZW49PT0hMSYmbC5vZmZzZXRUb3A8PWkuc2Nyb2xsVG9wJiZpLnNjcm9sbFRvKHt0b3A6bC5vZmZzZXRUb3B9KX0pLHQucGlwZShnKGZyKSxtKCh7ZGF0YTpsfSk9PmwpKS5waXBlKHkobD0+by5uZXh0KGwpKSxfKCgpPT5vLmNvbXBsZXRlKCkpLG0obD0+Rih7cmVmOmV9LGwpKSl9ZnVuY3Rpb24gUWEoZSx7cXVlcnkkOnR9KXtyZXR1cm4gdC5waXBlKG0oKHt2YWx1ZTpyfSk9PntsZXQgbz12ZSgpO3JldHVybiBvLmhhc2g9IiIscj1yLnJlcGxhY2UoL1xzKy9nLCIrIikucmVwbGFjZSgvJi9nLCIlMjYiKS5yZXBsYWNlKC89L2csIiUzRCIpLG8uc2VhcmNoPWBxPSR7cn1gLHt1cmw6b319KSl9ZnVuY3Rpb24gWm4oZSx0KXtsZXQgcj1uZXcgdixvPXIucGlwZShlZSgpLG9lKCEwKSk7cmV0dXJuIHIuc3Vic2NyaWJlKCh7dXJsOm59KT0+e2Uuc2V0QXR0cmlidXRlKCJkYXRhLWNsaXBib2FyZC10ZXh0IixlLmhyZWYpLGUuaHJlZj1gJHtufWB9KSxkKGUsImNsaWNrIikucGlwZShVKG8pKS5zdWJzY3JpYmUobj0+bi5wcmV2ZW50RGVmYXVsdCgpKSxRYShlLHQpLnBpcGUoeShuPT5yLm5leHQobikpLF8oKCk9PnIuY29tcGxldGUoKSksbShuPT5GKHtyZWY6ZX0sbikpKX1mdW5jdGlvbiBlaShlLHt3b3JrZXIkOnQsa2V5Ym9hcmQkOnJ9KXtsZXQgbz1uZXcgdixuPVRlKCJzZWFyY2gtcXVlcnkiKSxpPVQoZChuLCJrZXlkb3duIiksZChuLCJmb2N1cyIpKS5waXBlKE9lKGllKSxtKCgpPT5uLnZhbHVlKSxZKCkpO3JldHVybiBvLnBpcGUoamUoaSksbSgoW3tzdWdnZXN0OmF9LGNdKT0+e2xldCBwPWMuc3BsaXQoLyhbXHMtXSspLyk7aWYoYSE9bnVsbCYmYS5sZW5ndGgmJnBbcC5sZW5ndGgtMV0pe2xldCBsPWFbYS5sZW5ndGgtMV07bC5zdGFydHNXaXRoKHBbcC5sZW5ndGgtMV0pJiYocFtwLmxlbmd0aC0xXT1sKX1lbHNlIHAubGVuZ3RoPTA7cmV0dXJuIHB9KSkuc3Vic2NyaWJlKGE9PmUuaW5uZXJIVE1MPWEuam9pbigiIikucmVwbGFjZSgvXHMvZywiJm5ic3A7IikpLHIucGlwZShnKCh7bW9kZTphfSk9PmE9PT0ic2VhcmNoIikpLnN1YnNjcmliZShhPT57c3dpdGNoKGEudHlwZSl7Y2FzZSJBcnJvd1JpZ2h0IjplLmlubmVyVGV4dC5sZW5ndGgmJm4uc2VsZWN0aW9uU3RhcnQ9PT1uLnZhbHVlLmxlbmd0aCYmKG4udmFsdWU9ZS5pbm5lclRleHQpO2JyZWFrfX0pLHQucGlwZShnKGZyKSxtKCh7ZGF0YTphfSk9PmEpKS5waXBlKHkoYT0+by5uZXh0KGEpKSxfKCgpPT5vLmNvbXBsZXRlKCkpLG0oKCk9Pih7cmVmOmV9KSkpfWZ1bmN0aW9uIHRpKGUse2luZGV4JDp0LGtleWJvYXJkJDpyfSl7bGV0IG89d2UoKTt0cnl7bGV0IG49Qm4oby5zZWFyY2gsdCksaT1UZSgic2VhcmNoLXF1ZXJ5IixlKSxzPVRlKCJzZWFyY2gtcmVzdWx0IixlKTtkKGUsImNsaWNrIikucGlwZShnKCh7dGFyZ2V0OmN9KT0+YyBpbnN0YW5jZW9mIEVsZW1lbnQmJiEhYy5jbG9zZXN0KCJhIikpKS5zdWJzY3JpYmUoKCk9PkJlKCJzZWFyY2giLCExKSksci5waXBlKGcoKHttb2RlOmN9KT0+Yz09PSJzZWFyY2giKSkuc3Vic2NyaWJlKGM9PntsZXQgcD1SZSgpO3N3aXRjaChjLnR5cGUpe2Nhc2UiRW50ZXIiOmlmKHA9PT1pKXtsZXQgbD1uZXcgTWFwO2ZvcihsZXQgZiBvZiBSKCI6Zmlyc3QtY2hpbGQgW2hyZWZdIixzKSl7bGV0IHU9Zi5maXJzdEVsZW1lbnRDaGlsZDtsLnNldChmLHBhcnNlRmxvYXQodS5nZXRBdHRyaWJ1dGUoImRhdGEtbWQtc2NvcmUiKSkpfWlmKGwuc2l6ZSl7bGV0W1tmXV09Wy4uLmxdLnNvcnQoKFssdV0sWyxoXSk9PmgtdSk7Zi5jbGljaygpfWMuY2xhaW0oKX1icmVhaztjYXNlIkVzY2FwZSI6Y2FzZSJUYWIiOkJlKCJzZWFyY2giLCExKSxpLmJsdXIoKTticmVhaztjYXNlIkFycm93VXAiOmNhc2UiQXJyb3dEb3duIjppZih0eXBlb2YgcD09InVuZGVmaW5lZCIpaS5mb2N1cygpO2Vsc2V7bGV0IGw9W2ksLi4uUigiOm5vdChkZXRhaWxzKSA+IFtocmVmXSwgc3VtbWFyeSwgZGV0YWlsc1tvcGVuXSBbaHJlZl0iLHMpXSxmPU1hdGgubWF4KDAsKE1hdGgubWF4KDAsbC5pbmRleE9mKHApKStsLmxlbmd0aCsoYy50eXBlPT09IkFycm93VXAiPy0xOjEpKSVsLmxlbmd0aCk7bFtmXS5mb2N1cygpfWMuY2xhaW0oKTticmVhaztkZWZhdWx0OmkhPT1SZSgpJiZpLmZvY3VzKCl9fSksci5waXBlKGcoKHttb2RlOmN9KT0+Yz09PSJnbG9iYWwiKSkuc3Vic2NyaWJlKGM9Pntzd2l0Y2goYy50eXBlKXtjYXNlImYiOmNhc2UicyI6Y2FzZSIvIjppLmZvY3VzKCksaS5zZWxlY3QoKSxjLmNsYWltKCk7YnJlYWt9fSk7bGV0IGE9Sm4oaSx7d29ya2VyJDpufSk7cmV0dXJuIFQoYSxYbihzLHt3b3JrZXIkOm4scXVlcnkkOmF9KSkucGlwZSgkZSguLi5uZSgic2VhcmNoLXNoYXJlIixlKS5tYXAoYz0+Wm4oYyx7cXVlcnkkOmF9KSksLi4ubmUoInNlYXJjaC1zdWdnZXN0IixlKS5tYXAoYz0+ZWkoYyx7d29ya2VyJDpuLGtleWJvYXJkJDpyfSkpKSl9Y2F0Y2gobil7cmV0dXJuIGUuaGlkZGVuPSEwLHFlfX1mdW5jdGlvbiByaShlLHtpbmRleCQ6dCxsb2NhdGlvbiQ6cn0pe3JldHVybiBRKFt0LHIucGlwZShxKHZlKCkpLGcobz0+ISFvLnNlYXJjaFBhcmFtcy5nZXQoImgiKSkpXSkucGlwZShtKChbbyxuXSk9PlluKG8uY29uZmlnKShuLnNlYXJjaFBhcmFtcy5nZXQoImgiKSkpLG0obz0+e3ZhciBzO2xldCBuPW5ldyBNYXAsaT1kb2N1bWVudC5jcmVhdGVOb2RlSXRlcmF0b3IoZSxOb2RlRmlsdGVyLlNIT1dfVEVYVCk7Zm9yKGxldCBhPWkubmV4dE5vZGUoKTthO2E9aS5uZXh0Tm9kZSgpKWlmKChzPWEucGFyZW50RWxlbWVudCkhPW51bGwmJnMub2Zmc2V0SGVpZ2h0KXtsZXQgYz1hLnRleHRDb250ZW50LHA9byhjKTtwLmxlbmd0aD5jLmxlbmd0aCYmbi5zZXQoYSxwKX1mb3IobGV0W2EsY11vZiBuKXtsZXR7Y2hpbGROb2RlczpwfT1FKCJzcGFuIixudWxsLGMpO2EucmVwbGFjZVdpdGgoLi4uQXJyYXkuZnJvbShwKSl9cmV0dXJue3JlZjplLG5vZGVzOm59fSkpfWZ1bmN0aW9uIFlhKGUse3ZpZXdwb3J0JDp0LG1haW4kOnJ9KXtsZXQgbz1lLmNsb3Nlc3QoIi5tZC1ncmlkIiksbj1vLm9mZnNldFRvcC1vLnBhcmVudEVsZW1lbnQub2Zmc2V0VG9wO3JldHVybiBRKFtyLHRdKS5waXBlKG0oKFt7b2Zmc2V0OmksaGVpZ2h0OnN9LHtvZmZzZXQ6e3k6YX19XSk9PihzPXMrTWF0aC5taW4obixNYXRoLm1heCgwLGEtaSkpLW4se2hlaWdodDpzLGxvY2tlZDphPj1pK259KSksWSgoaSxzKT0+aS5oZWlnaHQ9PT1zLmhlaWdodCYmaS5sb2NrZWQ9PT1zLmxvY2tlZCkpfWZ1bmN0aW9uIFFyKGUsbyl7dmFyIG49byx7aGVhZGVyJDp0fT1uLHI9dG8obixbImhlYWRlciQiXSk7bGV0IGk9UCgiLm1kLXNpZGViYXJfX3Njcm9sbHdyYXAiLGUpLHt5OnN9PVVlKGkpO3JldHVybiBIKCgpPT57bGV0IGE9bmV3IHYsYz1hLnBpcGUoZWUoKSxvZSghMCkpLHA9YS5waXBlKE1lKDAsZGUpKTtyZXR1cm4gcC5waXBlKGFlKHQpKS5zdWJzY3JpYmUoe25leHQoW3toZWlnaHQ6bH0se2hlaWdodDpmfV0pe2kuc3R5bGUuaGVpZ2h0PWAke2wtMipzfXB4YCxlLnN0eWxlLnRvcD1gJHtmfXB4YH0sY29tcGxldGUoKXtpLnN0eWxlLmhlaWdodD0iIixlLnN0eWxlLnRvcD0iIn19KSxwLnBpcGUoSGUoKSkuc3Vic2NyaWJlKCgpPT57Zm9yKGxldCBsIG9mIFIoIi5tZC1uYXZfX2xpbmstLWFjdGl2ZVtocmVmXSIsZSkpe2lmKCFsLmNsaWVudEhlaWdodCljb250aW51ZTtsZXQgZj1sLmNsb3Nlc3QoIi5tZC1zaWRlYmFyX19zY3JvbGx3cmFwIik7aWYodHlwZW9mIGYhPSJ1bmRlZmluZWQiKXtsZXQgdT1sLm9mZnNldFRvcC1mLm9mZnNldFRvcCx7aGVpZ2h0Omh9PXBlKGYpO2Yuc2Nyb2xsVG8oe3RvcDp1LWgvMn0pfX19KSxmZShSKCJsYWJlbFt0YWJpbmRleF0iLGUpKS5waXBlKHJlKGw9PmQobCwiY2xpY2siKS5waXBlKE9lKGllKSxtKCgpPT5sKSxVKGMpKSkpLnN1YnNjcmliZShsPT57bGV0IGY9UChgW2lkPSIke2wuaHRtbEZvcn0iXWApO1AoYFthcmlhLWxhYmVsbGVkYnk9IiR7bC5pZH0iXWApLnNldEF0dHJpYnV0ZSgiYXJpYS1leHBhbmRlZCIsYCR7Zi5jaGVja2VkfWApfSksWWEoZSxyKS5waXBlKHkobD0+YS5uZXh0KGwpKSxfKCgpPT5hLmNvbXBsZXRlKCkpLG0obD0+Rih7cmVmOmV9LGwpKSl9KX1mdW5jdGlvbiBvaShlLHQpe2lmKHR5cGVvZiB0IT0idW5kZWZpbmVkIil7bGV0IHI9YGh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvJHtlfS8ke3R9YDtyZXR1cm4gTHQoRGUoYCR7cn0vcmVsZWFzZXMvbGF0ZXN0YCkucGlwZShoZSgoKT0+TCksbShvPT4oe3ZlcnNpb246by50YWdfbmFtZX0pKSxRZSh7fSkpLERlKHIpLnBpcGUoaGUoKCk9PkwpLG0obz0+KHtzdGFyczpvLnN0YXJnYXplcnNfY291bnQsZm9ya3M6by5mb3Jrc19jb3VudH0pKSxRZSh7fSkpKS5waXBlKG0oKFtvLG5dKT0+RihGKHt9LG8pLG4pKSl9ZWxzZXtsZXQgcj1gaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS91c2Vycy8ke2V9YDtyZXR1cm4gRGUocikucGlwZShtKG89Pih7cmVwb3NpdG9yaWVzOm8ucHVibGljX3JlcG9zfSkpLFFlKHt9KSl9fWZ1bmN0aW9uIG5pKGUsdCl7bGV0IHI9YGh0dHBzOi8vJHtlfS9hcGkvdjQvcHJvamVjdHMvJHtlbmNvZGVVUklDb21wb25lbnQodCl9YDtyZXR1cm4gRGUocikucGlwZShoZSgoKT0+TCksbSgoe3N0YXJfY291bnQ6byxmb3Jrc19jb3VudDpufSk9Pih7c3RhcnM6byxmb3JrczpufSkpLFFlKHt9KSl9ZnVuY3Rpb24gaWkoZSl7bGV0IHQ9ZS5tYXRjaCgvXi4rZ2l0aHViXC5jb21cLyhbXi9dKylcLz8oW14vXSspPy9pKTtpZih0KXtsZXRbLHIsb109dDtyZXR1cm4gb2kocixvKX1pZih0PWUubWF0Y2goL14uKz8oW14vXSpnaXRsYWJbXi9dKylcLyguKz8pXC8/JC9pKSx0KXtsZXRbLHIsb109dDtyZXR1cm4gbmkocixvKX1yZXR1cm4gTH12YXIgQmE7ZnVuY3Rpb24gR2EoZSl7cmV0dXJuIEJhfHwoQmE9SCgoKT0+e2xldCB0PV9fbWRfZ2V0KCJfX3NvdXJjZSIsc2Vzc2lvblN0b3JhZ2UpO2lmKHQpcmV0dXJuICQodCk7aWYobmUoImNvbnNlbnQiKS5sZW5ndGgpe2xldCBvPV9fbWRfZ2V0KCJfX2NvbnNlbnQiKTtpZighKG8mJm8uZ2l0aHViKSlyZXR1cm4gTH1yZXR1cm4gaWkoZS5ocmVmKS5waXBlKHkobz0+X19tZF9zZXQoIl9fc291cmNlIixvLHNlc3Npb25TdG9yYWdlKSkpfSkucGlwZShoZSgoKT0+TCksZyh0PT5PYmplY3Qua2V5cyh0KS5sZW5ndGg+MCksbSh0PT4oe2ZhY3RzOnR9KSksQigxKSkpfWZ1bmN0aW9uIGFpKGUpe2xldCB0PVAoIjpzY29wZSA+IDpsYXN0LWNoaWxkIixlKTtyZXR1cm4gSCgoKT0+e2xldCByPW5ldyB2O3JldHVybiByLnN1YnNjcmliZSgoe2ZhY3RzOm99KT0+e3QuYXBwZW5kQ2hpbGQoYm4obykpLHQuY2xhc3NMaXN0LmFkZCgibWQtc291cmNlX19yZXBvc2l0b3J5LS1hY3RpdmUiKX0pLEdhKGUpLnBpcGUoeShvPT5yLm5leHQobykpLF8oKCk9PnIuY29tcGxldGUoKSksbShvPT5GKHtyZWY6ZX0sbykpKX0pfWZ1bmN0aW9uIEphKGUse3ZpZXdwb3J0JDp0LGhlYWRlciQ6cn0pe3JldHVybiBFZShkb2N1bWVudC5ib2R5KS5waXBlKGIoKCk9PnByKGUse2hlYWRlciQ6cix2aWV3cG9ydCQ6dH0pKSxtKCh7b2Zmc2V0Ont5Om99fSk9Pih7aGlkZGVuOm8+PTEwfSkpLFgoImhpZGRlbiIpKX1mdW5jdGlvbiBzaShlLHQpe3JldHVybiBIKCgpPT57bGV0IHI9bmV3IHY7cmV0dXJuIHIuc3Vic2NyaWJlKHtuZXh0KHtoaWRkZW46b30pe2UuaGlkZGVuPW99LGNvbXBsZXRlKCl7ZS5oaWRkZW49ITF9fSksKEcoIm5hdmlnYXRpb24udGFicy5zdGlja3kiKT8kKHtoaWRkZW46ITF9KTpKYShlLHQpKS5waXBlKHkobz0+ci5uZXh0KG8pKSxfKCgpPT5yLmNvbXBsZXRlKCkpLG0obz0+Rih7cmVmOmV9LG8pKSl9KX1mdW5jdGlvbiBYYShlLHt2aWV3cG9ydCQ6dCxoZWFkZXIkOnJ9KXtsZXQgbz1uZXcgTWFwLG49UigiLm1kLW5hdl9fbGluayIsZSk7Zm9yKGxldCBhIG9mIG4pe2xldCBjPWRlY29kZVVSSUNvbXBvbmVudChhLmhhc2guc3Vic3RyaW5nKDEpKSxwPW1lKGBbaWQ9IiR7Y30iXWApO3R5cGVvZiBwIT0idW5kZWZpbmVkIiYmby5zZXQoYSxwKX1sZXQgaT1yLnBpcGUoWCgiaGVpZ2h0IiksbSgoe2hlaWdodDphfSk9PntsZXQgYz1UZSgibWFpbiIpLHA9UCgiOnNjb3BlID4gOmZpcnN0LWNoaWxkIixjKTtyZXR1cm4gYSsuOCoocC5vZmZzZXRUb3AtYy5vZmZzZXRUb3ApfSksbGUoKSk7cmV0dXJuIEVlKGRvY3VtZW50LmJvZHkpLnBpcGUoWCgiaGVpZ2h0IiksYihhPT5IKCgpPT57bGV0IGM9W107cmV0dXJuICQoWy4uLm9dLnJlZHVjZSgocCxbbCxmXSk9Pntmb3IoO2MubGVuZ3RoJiZvLmdldChjW2MubGVuZ3RoLTFdKS50YWdOYW1lPj1mLnRhZ05hbWU7KWMucG9wKCk7bGV0IHU9Zi5vZmZzZXRUb3A7Zm9yKDshdSYmZi5wYXJlbnRFbGVtZW50OylmPWYucGFyZW50RWxlbWVudCx1PWYub2Zmc2V0VG9wO2xldCBoPWYub2Zmc2V0UGFyZW50O2Zvcig7aDtoPWgub2Zmc2V0UGFyZW50KXUrPWgub2Zmc2V0VG9wO3JldHVybiBwLnNldChbLi4uYz1bLi4uYyxsXV0ucmV2ZXJzZSgpLHUpfSxuZXcgTWFwKSl9KS5waXBlKG0oYz0+bmV3IE1hcChbLi4uY10uc29ydCgoWyxwXSxbLGxdKT0+cC1sKSkpLGplKGkpLGIoKFtjLHBdKT0+dC5waXBlKFJyKChbbCxmXSx7b2Zmc2V0Ont5OnV9LHNpemU6aH0pPT57bGV0IHc9dStoLmhlaWdodD49TWF0aC5mbG9vcihhLmhlaWdodCk7Zm9yKDtmLmxlbmd0aDspe2xldFssQV09ZlswXTtpZihBLXA8dXx8dylsPVsuLi5sLGYuc2hpZnQoKV07ZWxzZSBicmVha31mb3IoO2wubGVuZ3RoOyl7bGV0WyxBXT1sW2wubGVuZ3RoLTFdO2lmKEEtcD49dSYmIXcpZj1bbC5wb3AoKSwuLi5mXTtlbHNlIGJyZWFrfXJldHVybltsLGZdfSxbW10sWy4uLmNdXSksWSgobCxmKT0+bFswXT09PWZbMF0mJmxbMV09PT1mWzFdKSkpKSkpLnBpcGUobSgoW2EsY10pPT4oe3ByZXY6YS5tYXAoKFtwXSk9PnApLG5leHQ6Yy5tYXAoKFtwXSk9PnApfSkpLHEoe3ByZXY6W10sbmV4dDpbXX0pLEtlKDIsMSksbSgoW2EsY10pPT5hLnByZXYubGVuZ3RoPGMucHJldi5sZW5ndGg/e3ByZXY6Yy5wcmV2LnNsaWNlKE1hdGgubWF4KDAsYS5wcmV2Lmxlbmd0aC0xKSxjLnByZXYubGVuZ3RoKSxuZXh0OltdfTp7cHJldjpjLnByZXYuc2xpY2UoLTEpLG5leHQ6Yy5uZXh0LnNsaWNlKDAsYy5uZXh0Lmxlbmd0aC1hLm5leHQubGVuZ3RoKX0pKX1mdW5jdGlvbiBjaShlLHt2aWV3cG9ydCQ6dCxoZWFkZXIkOnIsbWFpbiQ6byx0YXJnZXQkOm59KXtyZXR1cm4gSCgoKT0+e2xldCBpPW5ldyB2LHM9aS5waXBlKGVlKCksb2UoITApKTtpZihpLnN1YnNjcmliZSgoe3ByZXY6YSxuZXh0OmN9KT0+e2ZvcihsZXRbcF1vZiBjKXAuY2xhc3NMaXN0LnJlbW92ZSgibWQtbmF2X19saW5rLS1wYXNzZWQiKSxwLmNsYXNzTGlzdC5yZW1vdmUoIm1kLW5hdl9fbGluay0tYWN0aXZlIik7Zm9yKGxldFtwLFtsXV1vZiBhLmVudHJpZXMoKSlsLmNsYXNzTGlzdC5hZGQoIm1kLW5hdl9fbGluay0tcGFzc2VkIiksbC5jbGFzc0xpc3QudG9nZ2xlKCJtZC1uYXZfX2xpbmstLWFjdGl2ZSIscD09PWEubGVuZ3RoLTEpfSksRygidG9jLmZvbGxvdyIpKXtsZXQgYT1UKHQucGlwZShiZSgxKSxtKCgpPT57fSkpLHQucGlwZShiZSgyNTApLG0oKCk9PiJzbW9vdGgiKSkpO2kucGlwZShnKCh7cHJldjpjfSk9PmMubGVuZ3RoPjApLGplKG8ucGlwZShPZShpZSkpKSxhZShhKSkuc3Vic2NyaWJlKChbW3twcmV2OmN9XSxwXSk9PntsZXRbbF09Y1tjLmxlbmd0aC0xXTtpZihsLm9mZnNldEhlaWdodCl7bGV0IGY9c3IobCk7aWYodHlwZW9mIGYhPSJ1bmRlZmluZWQiKXtsZXQgdT1sLm9mZnNldFRvcC1mLm9mZnNldFRvcCx7aGVpZ2h0Omh9PXBlKGYpO2Yuc2Nyb2xsVG8oe3RvcDp1LWgvMixiZWhhdmlvcjpwfSl9fX0pfXJldHVybiBHKCJuYXZpZ2F0aW9uLnRyYWNraW5nIikmJnQucGlwZShVKHMpLFgoIm9mZnNldCIpLGJlKDI1MCksTGUoMSksVShuLnBpcGUoTGUoMSkpKSxhdCh7ZGVsYXk6MjUwfSksYWUoaSkpLnN1YnNjcmliZSgoWyx7cHJldjphfV0pPT57bGV0IGM9dmUoKSxwPWFbYS5sZW5ndGgtMV07aWYocCYmcC5sZW5ndGgpe2xldFtsXT1wLHtoYXNoOmZ9PW5ldyBVUkwobC5ocmVmKTtjLmhhc2ghPT1mJiYoYy5oYXNoPWYsaGlzdG9yeS5yZXBsYWNlU3RhdGUoe30sIiIsYCR7Y31gKSl9ZWxzZSBjLmhhc2g9IiIsaGlzdG9yeS5yZXBsYWNlU3RhdGUoe30sIiIsYCR7Y31gKX0pLFhhKGUse3ZpZXdwb3J0JDp0LGhlYWRlciQ6cn0pLnBpcGUoeShhPT5pLm5leHQoYSkpLF8oKCk9PmkuY29tcGxldGUoKSksbShhPT5GKHtyZWY6ZX0sYSkpKX0pfWZ1bmN0aW9uIFphKGUse3ZpZXdwb3J0JDp0LG1haW4kOnIsdGFyZ2V0JDpvfSl7bGV0IG49dC5waXBlKG0oKHtvZmZzZXQ6e3k6c319KT0+cyksS2UoMiwxKSxtKChbcyxhXSk9PnM+YSYmYT4wKSxZKCkpLGk9ci5waXBlKG0oKHthY3RpdmU6c30pPT5zKSk7cmV0dXJuIFEoW2ksbl0pLnBpcGUobSgoW3MsYV0pPT4hKHMmJmEpKSxZKCksVShvLnBpcGUoTGUoMSkpKSxvZSghMCksYXQoe2RlbGF5OjI1MH0pLG0ocz0+KHtoaWRkZW46c30pKSl9ZnVuY3Rpb24gcGkoZSx7dmlld3BvcnQkOnQsaGVhZGVyJDpyLG1haW4kOm8sdGFyZ2V0JDpufSl7bGV0IGk9bmV3IHYscz1pLnBpcGUoZWUoKSxvZSghMCkpO3JldHVybiBpLnN1YnNjcmliZSh7bmV4dCh7aGlkZGVuOmF9KXtlLmhpZGRlbj1hLGE/KGUuc2V0QXR0cmlidXRlKCJ0YWJpbmRleCIsIi0xIiksZS5ibHVyKCkpOmUucmVtb3ZlQXR0cmlidXRlKCJ0YWJpbmRleCIpfSxjb21wbGV0ZSgpe2Uuc3R5bGUudG9wPSIiLGUuaGlkZGVuPSEwLGUucmVtb3ZlQXR0cmlidXRlKCJ0YWJpbmRleCIpfX0pLHIucGlwZShVKHMpLFgoImhlaWdodCIpKS5zdWJzY3JpYmUoKHtoZWlnaHQ6YX0pPT57ZS5zdHlsZS50b3A9YCR7YSsxNn1weGB9KSxkKGUsImNsaWNrIikuc3Vic2NyaWJlKGE9PnthLnByZXZlbnREZWZhdWx0KCksd2luZG93LnNjcm9sbFRvKHt0b3A6MH0pfSksWmEoZSx7dmlld3BvcnQkOnQsbWFpbiQ6byx0YXJnZXQkOm59KS5waXBlKHkoYT0+aS5uZXh0KGEpKSxfKCgpPT5pLmNvbXBsZXRlKCkpLG0oYT0+Rih7cmVmOmV9LGEpKSl9ZnVuY3Rpb24gbGkoe2RvY3VtZW50JDplfSl7ZS5waXBlKGIoKCk9PlIoIi5tZC1lbGxpcHNpcyIpKSxyZSh0PT55dCh0KS5waXBlKFUoZS5waXBlKExlKDEpKSksZyhyPT5yKSxtKCgpPT50KSx5ZSgxKSkpLGcodD0+dC5vZmZzZXRXaWR0aDx0LnNjcm9sbFdpZHRoKSxyZSh0PT57bGV0IHI9dC5pbm5lclRleHQsbz10LmNsb3Nlc3QoImEiKXx8dDtyZXR1cm4gby50aXRsZT1yLEdlKG8pLnBpcGUoVShlLnBpcGUoTGUoMSkpKSxfKCgpPT5vLnJlbW92ZUF0dHJpYnV0ZSgidGl0bGUiKSkpfSkpLnN1YnNjcmliZSgpLGUucGlwZShiKCgpPT5SKCIubWQtc3RhdHVzIikpLHJlKHQ9PkdlKHQpKSkuc3Vic2NyaWJlKCl9ZnVuY3Rpb24gbWkoe2RvY3VtZW50JDplLHRhYmxldCQ6dH0pe2UucGlwZShiKCgpPT5SKCIubWQtdG9nZ2xlLS1pbmRldGVybWluYXRlIikpLHkocj0+e3IuaW5kZXRlcm1pbmF0ZT0hMCxyLmNoZWNrZWQ9ITF9KSxyZShyPT5kKHIsImNoYW5nZSIpLnBpcGUoRnIoKCk9PnIuY2xhc3NMaXN0LmNvbnRhaW5zKCJtZC10b2dnbGUtLWluZGV0ZXJtaW5hdGUiKSksbSgoKT0+cikpKSxhZSh0KSkuc3Vic2NyaWJlKChbcixvXSk9PntyLmNsYXNzTGlzdC5yZW1vdmUoIm1kLXRvZ2dsZS0taW5kZXRlcm1pbmF0ZSIpLG8mJihyLmNoZWNrZWQ9ITEpfSl9ZnVuY3Rpb24gZXMoKXtyZXR1cm4vKGlQYWR8aVBob25lfGlQb2QpLy50ZXN0KG5hdmlnYXRvci51c2VyQWdlbnQpfWZ1bmN0aW9uIGZpKHtkb2N1bWVudCQ6ZX0pe2UucGlwZShiKCgpPT5SKCJbZGF0YS1tZC1zY3JvbGxmaXhdIikpLHkodD0+dC5yZW1vdmVBdHRyaWJ1dGUoImRhdGEtbWQtc2Nyb2xsZml4IikpLGcoZXMpLHJlKHQ9PmQodCwidG91Y2hzdGFydCIpLnBpcGUobSgoKT0+dCkpKSkuc3Vic2NyaWJlKHQ9PntsZXQgcj10LnNjcm9sbFRvcDtyPT09MD90LnNjcm9sbFRvcD0xOnIrdC5vZmZzZXRIZWlnaHQ9PT10LnNjcm9sbEhlaWdodCYmKHQuc2Nyb2xsVG9wPXItMSl9KX1mdW5jdGlvbiB1aSh7dmlld3BvcnQkOmUsdGFibGV0JDp0fSl7UShbV2UoInNlYXJjaCIpLHRdKS5waXBlKG0oKFtyLG9dKT0+ciYmIW8pLGIocj0+JChyKS5waXBlKFllKHI/NDAwOjEwMCkpKSxhZShlKSkuc3Vic2NyaWJlKChbcix7b2Zmc2V0Ont5Om99fV0pPT57aWYocilkb2N1bWVudC5ib2R5LnNldEF0dHJpYnV0ZSgiZGF0YS1tZC1zY3JvbGxsb2NrIiwiIiksZG9jdW1lbnQuYm9keS5zdHlsZS50b3A9YC0ke299cHhgO2Vsc2V7bGV0IG49LTEqcGFyc2VJbnQoZG9jdW1lbnQuYm9keS5zdHlsZS50b3AsMTApO2RvY3VtZW50LmJvZHkucmVtb3ZlQXR0cmlidXRlKCJkYXRhLW1kLXNjcm9sbGxvY2siKSxkb2N1bWVudC5ib2R5LnN0eWxlLnRvcD0iIixuJiZ3aW5kb3cuc2Nyb2xsVG8oMCxuKX19KX1PYmplY3QuZW50cmllc3x8KE9iamVjdC5lbnRyaWVzPWZ1bmN0aW9uKGUpe2xldCB0PVtdO2ZvcihsZXQgciBvZiBPYmplY3Qua2V5cyhlKSl0LnB1c2goW3IsZVtyXV0pO3JldHVybiB0fSk7T2JqZWN0LnZhbHVlc3x8KE9iamVjdC52YWx1ZXM9ZnVuY3Rpb24oZSl7bGV0IHQ9W107Zm9yKGxldCByIG9mIE9iamVjdC5rZXlzKGUpKXQucHVzaChlW3JdKTtyZXR1cm4gdH0pO3R5cGVvZiBFbGVtZW50IT0idW5kZWZpbmVkIiYmKEVsZW1lbnQucHJvdG90eXBlLnNjcm9sbFRvfHwoRWxlbWVudC5wcm90b3R5cGUuc2Nyb2xsVG89ZnVuY3Rpb24oZSx0KXt0eXBlb2YgZT09Im9iamVjdCI/KHRoaXMuc2Nyb2xsTGVmdD1lLmxlZnQsdGhpcy5zY3JvbGxUb3A9ZS50b3ApOih0aGlzLnNjcm9sbExlZnQ9ZSx0aGlzLnNjcm9sbFRvcD10KX0pLEVsZW1lbnQucHJvdG90eXBlLnJlcGxhY2VXaXRofHwoRWxlbWVudC5wcm90b3R5cGUucmVwbGFjZVdpdGg9ZnVuY3Rpb24oLi4uZSl7bGV0IHQ9dGhpcy5wYXJlbnROb2RlO2lmKHQpe2UubGVuZ3RoPT09MCYmdC5yZW1vdmVDaGlsZCh0aGlzKTtmb3IobGV0IHI9ZS5sZW5ndGgtMTtyPj0wO3ItLSl7bGV0IG89ZVtyXTt0eXBlb2Ygbz09InN0cmluZyI/bz1kb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShvKTpvLnBhcmVudE5vZGUmJm8ucGFyZW50Tm9kZS5yZW1vdmVDaGlsZChvKSxyP3QuaW5zZXJ0QmVmb3JlKHRoaXMucHJldmlvdXNTaWJsaW5nLG8pOnQucmVwbGFjZUNoaWxkKG8sdGhpcyl9fX0pKTtmdW5jdGlvbiB0cygpe3JldHVybiBsb2NhdGlvbi5wcm90b2NvbD09PSJmaWxlOiI/Z3QoYCR7bmV3IFVSTCgic2VhcmNoL3NlYXJjaF9pbmRleC5qcyIsWXIuYmFzZSl9YCkucGlwZShtKCgpPT5fX2luZGV4KSxCKDEpKTpEZShuZXcgVVJMKCJzZWFyY2gvc2VhcmNoX2luZGV4Lmpzb24iLFlyLmJhc2UpKX1kb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY2xhc3NMaXN0LnJlbW92ZSgibm8tanMiKTtkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY2xhc3NMaXN0LmFkZCgianMiKTt2YXIgcnQ9Tm8oKSxSdD1KbygpLHd0PWVuKFJ0KSxCcj1HbygpLF9lPXBuKCksdXI9QXQoIihtaW4td2lkdGg6IDk2MHB4KSIpLGhpPUF0KCIobWluLXdpZHRoOiAxMjIwcHgpIiksYmk9dG4oKSxZcj13ZSgpLHZpPWRvY3VtZW50LmZvcm1zLm5hbWVkSXRlbSgic2VhcmNoIik/dHMoKTpxZSxHcj1uZXcgdjtXbih7YWxlcnQkOkdyfSk7dmFyIEpyPW5ldyB2O0coIm5hdmlnYXRpb24uaW5zdGFudCIpJiZ6bih7bG9jYXRpb24kOlJ0LHZpZXdwb3J0JDpfZSxwcm9ncmVzcyQ6SnJ9KS5zdWJzY3JpYmUocnQpO3ZhciBkaTsoKGRpPVlyLnZlcnNpb24pPT1udWxsP3ZvaWQgMDpkaS5wcm92aWRlcik9PT0ibWlrZSImJkduKHtkb2N1bWVudCQ6cnR9KTtUKFJ0LHd0KS5waXBlKFllKDEyNSkpLnN1YnNjcmliZSgoKT0+e0JlKCJkcmF3ZXIiLCExKSxCZSgic2VhcmNoIiwhMSl9KTtCci5waXBlKGcoKHttb2RlOmV9KT0+ZT09PSJnbG9iYWwiKSkuc3Vic2NyaWJlKGU9Pntzd2l0Y2goZS50eXBlKXtjYXNlInAiOmNhc2UiLCI6bGV0IHQ9bWUoImxpbmtbcmVsPXByZXZdIik7dHlwZW9mIHQhPSJ1bmRlZmluZWQiJiZzdCh0KTticmVhaztjYXNlIm4iOmNhc2UiLiI6bGV0IHI9bWUoImxpbmtbcmVsPW5leHRdIik7dHlwZW9mIHIhPSJ1bmRlZmluZWQiJiZzdChyKTticmVhaztjYXNlIkVudGVyIjpsZXQgbz1SZSgpO28gaW5zdGFuY2VvZiBIVE1MTGFiZWxFbGVtZW50JiZvLmNsaWNrKCl9fSk7bGkoe2RvY3VtZW50JDpydH0pO21pKHtkb2N1bWVudCQ6cnQsdGFibGV0JDp1cn0pO2ZpKHtkb2N1bWVudCQ6cnR9KTt1aSh7dmlld3BvcnQkOl9lLHRhYmxldCQ6dXJ9KTt2YXIgdHQ9Um4oVGUoImhlYWRlciIpLHt2aWV3cG9ydCQ6X2V9KSwkdD1ydC5waXBlKG0oKCk9PlRlKCJtYWluIikpLGIoZT0+Rm4oZSx7dmlld3BvcnQkOl9lLGhlYWRlciQ6dHR9KSksQigxKSkscnM9VCguLi5uZSgiY29uc2VudCIpLm1hcChlPT5mbihlLHt0YXJnZXQkOnd0fSkpLC4uLm5lKCJkaWFsb2ciKS5tYXAoZT0+JG4oZSx7YWxlcnQkOkdyfSkpLC4uLm5lKCJoZWFkZXIiKS5tYXAoZT0+UG4oZSx7dmlld3BvcnQkOl9lLGhlYWRlciQ6dHQsbWFpbiQ6JHR9KSksLi4ubmUoInBhbGV0dGUiKS5tYXAoZT0+am4oZSkpLC4uLm5lKCJwcm9ncmVzcyIpLm1hcChlPT5VbihlLHtwcm9ncmVzcyQ6SnJ9KSksLi4ubmUoInNlYXJjaCIpLm1hcChlPT50aShlLHtpbmRleCQ6dmksa2V5Ym9hcmQkOkJyfSkpLC4uLm5lKCJzb3VyY2UiKS5tYXAoZT0+YWkoZSkpKSxvcz1IKCgpPT5UKC4uLm5lKCJhbm5vdW5jZSIpLm1hcChlPT5tbihlKSksLi4ubmUoImNvbnRlbnQiKS5tYXAoZT0+SG4oZSx7dmlld3BvcnQkOl9lLHRhcmdldCQ6d3QscHJpbnQkOmJpfSkpLC4uLm5lKCJjb250ZW50IikubWFwKGU9PkcoInNlYXJjaC5oaWdobGlnaHQiKT9yaShlLHtpbmRleCQ6dmksbG9jYXRpb24kOlJ0fSk6TCksLi4ubmUoImhlYWRlci10aXRsZSIpLm1hcChlPT5JbihlLHt2aWV3cG9ydCQ6X2UsaGVhZGVyJDp0dH0pKSwuLi5uZSgic2lkZWJhciIpLm1hcChlPT5lLmdldEF0dHJpYnV0ZSgiZGF0YS1tZC10eXBlIik9PT0ibmF2aWdhdGlvbiI/VXIoaGksKCk9PlFyKGUse3ZpZXdwb3J0JDpfZSxoZWFkZXIkOnR0LG1haW4kOiR0fSkpOlVyKHVyLCgpPT5RcihlLHt2aWV3cG9ydCQ6X2UsaGVhZGVyJDp0dCxtYWluJDokdH0pKSksLi4ubmUoInRhYnMiKS5tYXAoZT0+c2koZSx7dmlld3BvcnQkOl9lLGhlYWRlciQ6dHR9KSksLi4ubmUoInRvYyIpLm1hcChlPT5jaShlLHt2aWV3cG9ydCQ6X2UsaGVhZGVyJDp0dCxtYWluJDokdCx0YXJnZXQkOnd0fSkpLC4uLm5lKCJ0b3AiKS5tYXAoZT0+cGkoZSx7dmlld3BvcnQkOl9lLGhlYWRlciQ6dHQsbWFpbiQ6JHQsdGFyZ2V0JDp3dH0pKSkpLGdpPXJ0LnBpcGUoYigoKT0+b3MpLCRlKHJzKSxCKDEpKTtnaS5zdWJzY3JpYmUoKTt3aW5kb3cuZG9jdW1lbnQkPXJ0O3dpbmRvdy5sb2NhdGlvbiQ9UnQ7d2luZG93LnRhcmdldCQ9d3Q7d2luZG93LmtleWJvYXJkJD1Ccjt3aW5kb3cudmlld3BvcnQkPV9lO3dpbmRvdy50YWJsZXQkPXVyO3dpbmRvdy5zY3JlZW4kPWhpO3dpbmRvdy5wcmludCQ9Ymk7d2luZG93LmFsZXJ0JD1Hcjt3aW5kb3cucHJvZ3Jlc3MkPUpyO3dpbmRvdy5jb21wb25lbnQkPWdpO30pKCk7Ci8vIyBzb3VyY2VNYXBwaW5nVVJMPWJ1bmRsZS5jOGQyZWZmMS5taW4uanMubWFwCgo="></script><!--URL:../assets/javascripts/bundle.c8d2eff1.min.js-->
|
||
<script src="data:text/javascript;base64,LyogCkphdmFzY3JpcHQgZnVuY3Rpb25zIHRvIGhlbHAgbWFrZSB0aGUgcHJpbnQgcGFnZSBtb3JlIFBERiBmcmllbmRseQoqLwoKLyoKR2VuZXJhdGVzIGEgdGFibGUgb2YgY29udGVudHMgZm9yIHRoZSBwcmludCBzaXRlIHBhZ2UuCk9ubHkgY2FsbGVkIHdoZW4gcHJpbnQtc2l0ZS1wbHVnaW4gb3B0aW9uICdhZGRfdGFibGVfb2ZfY29udGVudHMnIGlzIHNldCB0byB0cnVlCiovCmZ1bmN0aW9uIGdlbmVyYXRlX3RvYygpIHsKCiAgdmFyIFRvQyA9ICIiCgogIHZhciBuZXdMaW5lLCBlbCwgdGl0bGUsIGxpbms7CgogIGNvbnN0IHRvY19lbGVtZW50cyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoCiAgICAiI3ByaW50LXNpdGUtcGFnZSBoMS5uYXYtc2VjdGlvbi10aXRsZSwgI3ByaW50LXNpdGUtcGFnZSBoMS5uYXYtc2VjdGlvbi10aXRsZS1lbmQsIiArCiAgICAiI3ByaW50LXNpdGUtcGFnZSBoMi5uYXYtc2VjdGlvbi10aXRsZSwgI3ByaW50LXNpdGUtcGFnZSBoMi5uYXYtc2VjdGlvbi10aXRsZS1lbmQsIiArCiAgICAiI3ByaW50LXNpdGUtcGFnZSBoMy5uYXYtc2VjdGlvbi10aXRsZSwgI3ByaW50LXNpdGUtcGFnZSBoMy5uYXYtc2VjdGlvbi10aXRsZS1lbmQsIiArCiAgICAiI3ByaW50LXNpdGUtcGFnZSBoNC5uYXYtc2VjdGlvbi10aXRsZSwgI3ByaW50LXNpdGUtcGFnZSBoNC5uYXYtc2VjdGlvbi10aXRsZS1lbmQsIiArCiAgICAiI3ByaW50LXNpdGUtcGFnZSBoNS5uYXYtc2VjdGlvbi10aXRsZSwgI3ByaW50LXNpdGUtcGFnZSBoNS5uYXYtc2VjdGlvbi10aXRsZS1lbmQsIiArCiAgICAiI3ByaW50LXNpdGUtcGFnZSBoNi5uYXYtc2VjdGlvbi10aXRsZSwgI3ByaW50LXNpdGUtcGFnZSBoNi5uYXYtc2VjdGlvbi10aXRsZS1lbmQsIiArCiAgICAic2VjdGlvbi5wcmludC1wYWdlIGgxLHNlY3Rpb24ucHJpbnQtcGFnZSBoMixzZWN0aW9uLnByaW50LXBhZ2UgaDMsIiArCiAgICAic2VjdGlvbi5wcmludC1wYWdlIGg0LHNlY3Rpb24ucHJpbnQtcGFnZSBoNSxzZWN0aW9uLnByaW50LXBhZ2UgaDYiKQogIAogIHZhciBjdXJyZW50X2hlYWRpbmdfZGVwdGggPSAwOwogIHZhciBjdXJyZW50X3NlY3Rpb25fZGVwdGggPSAwOwoKICAvLyBFeHRyYWN0IHRhYmxlIG9mIGNvbnRlbnRzIGRlcHRoCiAgLy8gYmFzaWNhbGx5IHBsdWdpbiBzZXR0aW5nLCBwYXNzZWQgdmlhIGEgZGF0YSBhdHRyaWJ1dGUKICB2YXIgdG9jX2RlcHRoID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoInByaW50LXBhZ2UtdG9jIikuZ2V0QXR0cmlidXRlKCJkYXRhLXRvYy1kZXB0aCIpCgogIGZvciAodmFyIGkgPSAwOyBpIDwgdG9jX2VsZW1lbnRzLmxlbmd0aDsgaSsrKSB7CiAgICAKICAgIC8vIEdldCB0aGUgaW5mbyBmcm9tIHRoZSBlbGVtZW50CiAgICBlbCA9IHRvY19lbGVtZW50c1tpXQogICAgbGluayA9ICIjIiArIGVsLmlkOwogICAgdGFnID0gZWwudGFnTmFtZQogICAgdGFnX2xldmVsID0gdGFnLnN1YnN0cmluZygxKQogICAgLy8gR2V0IHRoZSB0ZXh0IG9mIGEgaGVhZGluZwogICAgLy8gV2UgdXNlIC5maXJzdENoaWxkLm5vZGVWYWx1ZSBpbnN0ZWFkIG9mIC5pbm5lclRleHQKICAgIC8vIGJlY2F1c2Ugb2YgZWxlbWVudHMgbGlrZToKICAgIC8vIDxoMSBpZD0iaW5kZXgtbWtkb2NzLXByaW50LXNpdGUtcGx1Z2luIj4KICAgIC8vICAgICBta2RvY3MtcHJpbnQtc2l0ZS1wbHVnaW48YSBjbGFzcz0iaGVhZGVybGluayIgaHJlZj0iI2luZGV4LW1rZG9jcy1wcmludC1zaXRlLXBsdWdpbiIgdGl0bGU9IlBlcm1hbmVudCBsaW5rIj7ihrU8L2E+CiAgICAvLyAgPC9oMT4KICAgIHRpdGxlID0gZWwuZmlyc3RDaGlsZC5ub2RlVmFsdWU7CiAgICBpZiAoICEgdGl0bGUgKSB7CiAgICAgIGNvbnRpbnVlOwogICAgfQoKICAgIC8vIERvbid0IHB1dCB0aGUgdG9jIGgxIGluIHRoZSB0b2MKICAgIGlmICggZWwuY2xhc3NMaXN0LmNvbnRhaW5zKCdwcmludC1wYWdlLXRvYy10aXRsZScpICkgewogICAgICBjb250aW51ZTsKICAgIH0KICAgIC8vIElnbm9yZSB0aGUgTWtEb2NzIGtleWJvYXJkIE1vZGVsCiAgICBpZiAoIGVsLmlkLmluZGV4T2YoImtleWJvYXJkTW9kYWxMYWJlbCIpID4gLTEgKSB7CiAgICAgIGNvbnRpbnVlOwogICAgfQoKICAgIC8vIHByaW50LXNpdGUtcGx1Z2luIGhhcyBhIHNldHRpbmcgdG8gY29udHJvbCBUT0MgZGVwdGgKICAgIGlmICggdGFnX2xldmVsID4gdG9jX2RlcHRoICkgewogICAgICBjb250aW51ZTsKICAgIH0KCiAgICBpZiAoZWwuY2xhc3NMaXN0LmNvbnRhaW5zKCduYXYtc2VjdGlvbi10aXRsZScpICkgewogICAgICAvLyBVc2UgdGhlIHRhZyBsZXZlbCBvZiB0aGUgZmlyc3QgaXRlbSBpbiB0aGUgc2VjdGlvbiB0byBjbG9zZSBvZmYgYW55IG5lc3RlZCA8dWw+CiAgICAgIGVsID0gdG9jX2VsZW1lbnRzW2krMV0KICAgICAgbGluayA9ICIjIiArIGVsLmlkOwogICAgICB0YWcgPSBlbC50YWdOYW1lCiAgICAgIHRhZ19sZXZlbCA9IHRhZy5zdWJzdHJpbmcoMSkKICAgICAgd2hpbGUgKHRhZ19sZXZlbCA+IGN1cnJlbnRfaGVhZGluZ19kZXB0aCkgewogICAgICAgIGN1cnJlbnRfaGVhZGluZ19kZXB0aCsrOwogICAgICAgIFRvQyArPSAiPHVsIGNsYXNzPSdwcmludC1zaXRlLXRvYy1sZXZlbC0iICsgY3VycmVudF9oZWFkaW5nX2RlcHRoICsgIic+IjsKICAgICAgfQogICAgICB3aGlsZSAodGFnX2xldmVsIDwgY3VycmVudF9oZWFkaW5nX2RlcHRoKSB7CiAgICAgICAgY3VycmVudF9oZWFkaW5nX2RlcHRoLS07CiAgICAgICAgVG9DICs9ICI8L3VsPiI7IAogICAgICB9CgogICAgICAvLyBJbnNlcnQgYSBzZWN0aW9uIGhlYWRpbmcgPGxpPiBpdGVtLCBob3dldmVyIGRlZXBseSB3ZSBhcmUgbmVzdGVkLgogICAgICBjdXJyZW50X3NlY3Rpb25fZGVwdGgrKzsKICAgICAgLy8gSW5zZXJ0IGl0ZW0gYXMgYSBzZWN0aW9uIHRpdGxlIGluIHRoZSBjdXJyZW50IGxpc3QKICAgICAgVG9DICs9ICI8bGkgY2xhc3M9J3RvYy1uYXYtc2VjdGlvbi10aXRsZSB0b2MtbmF2LXNlY3Rpb24tdGl0bGUtbGV2ZWwtIiArIChjdXJyZW50X3NlY3Rpb25fZGVwdGgpICsgIic+IiArIHRpdGxlICsgIjwvbGk+IjsKICAgICAgCiAgICAgIC8vIFN0YXJ0IGEgbmV3IHVsIGZvciB0aGUgc2VjdGlvbgogICAgICBUb0MgKz0gIjx1bCBjbGFzcz0ncHJpbnQtc2l0ZS10b2MtbGV2ZWwtIiArIGN1cnJlbnRfaGVhZGluZ19kZXB0aCArICIgdG9jLXNlY3Rpb24tbGluZS1ib3JkZXInPiI7CiAgICAgIGNvbnRpbnVlOwogICAgfQoKCiAgICBpZiAoZWwuY2xhc3NMaXN0LmNvbnRhaW5zKCduYXYtc2VjdGlvbi10aXRsZS1lbmQnKSApIHsKCiAgICAgIGN1cnJlbnRfc2VjdGlvbl9kZXB0aC0tOwogICAgICAvLyBDbG9zZSB0aGUgc3BlY2lhbCBzZWN0aW9uIHVsCiAgICAgIFRvQyArPSAiPC91bD4iOwoKICAgICAgY29udGludWU7CiAgICB9CgogICAgd2hpbGUgKHRhZ19sZXZlbCA+IGN1cnJlbnRfaGVhZGluZ19kZXB0aCkgewogICAgICBjdXJyZW50X2hlYWRpbmdfZGVwdGgrKzsKICAgICAgVG9DICs9ICI8dWwgY2xhc3M9J3ByaW50LXNpdGUtdG9jLWxldmVsLSIgKyBjdXJyZW50X2hlYWRpbmdfZGVwdGggKyAiJz4iOwogICAgfQogICAgd2hpbGUgKHRhZ19sZXZlbCA8IGN1cnJlbnRfaGVhZGluZ19kZXB0aCkgewogICAgICBjdXJyZW50X2hlYWRpbmdfZGVwdGgtLTsKICAgICAgVG9DICs9ICI8L3VsPiI7IAogICAgfQoKCiAgICBuZXdMaW5lID0gIjxsaT4iICsKICAgICAgIjxhIGhyZWY9JyIgKyBsaW5rICsgIic+IiArCiAgICAgICAgdGl0bGUgKwogICAgICAiPC9hPiIgKwogICAgIjwvbGk+IjsKCiAgICBUb0MgKz0gbmV3TGluZTsKCiAgfTsKCiAgVG9DICs9ICI8L3VsPiIKCiAgZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgiI3ByaW50LXBhZ2UtdG9jIG5hdiIpWzBdLmluc2VydEFkamFjZW50SFRNTCgiYmVmb3JlZW5kIiwgVG9DKTsKCn0="></script><!--URL:../js/print-site.js-->
|
||
</body></html><!--Generated by HTMLArk 2024-03-04 10:38:42.322803. Original URL public_html/print_page/index.html--> |