12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142 |
- <!DOCTYPE html><html><head><meta charset="utf-8"><style>body {
- width: 45em;
- border: 1px solid #ddd;
- outline: 1300px solid #fff;
- margin: 16px auto;
- }
- body .markdown-body
- {
- padding: 30px;
- }
- @font-face {
- font-family: fontawesome-mini;
- src: url(data:font/woff;charset=utf-8;base64,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) format('woff');
- }
- @font-face {
- font-family: octicons-anchor;
- src: url(data:font/woff;charset=utf-8;base64,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) format('woff');
- }
- .markdown-body {
- font-family: sans-serif;
- -ms-text-size-adjust: 100%;
- -webkit-text-size-adjust: 100%;
- color: #333333;
- overflow: hidden;
- font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;
- font-size: 16px;
- line-height: 1.6;
- word-wrap: break-word;
- }
- .markdown-body a {
- background: transparent;
- }
- .markdown-body a:active,
- .markdown-body a:hover {
- outline: 0;
- }
- .markdown-body b,
- .markdown-body strong {
- font-weight: bold;
- }
- .markdown-body mark {
- background: #ff0;
- color: #000;
- font-style: italic;
- font-weight: bold;
- }
- .markdown-body sub,
- .markdown-body sup {
- font-size: 75%;
- line-height: 0;
- position: relative;
- vertical-align: baseline;
- }
- .markdown-body sup {
- top: -0.5em;
- }
- .markdown-body sub {
- bottom: -0.25em;
- }
- .markdown-body h1 {
- font-size: 2em;
- margin: 0.67em 0;
- }
- .markdown-body img {
- border: 0;
- }
- .markdown-body hr {
- -moz-box-sizing: content-box;
- box-sizing: content-box;
- height: 0;
- }
- .markdown-body pre {
- overflow: auto;
- }
- .markdown-body code,
- .markdown-body kbd,
- .markdown-body pre,
- .markdown-body samp {
- font-family: monospace, monospace;
- font-size: 1em;
- }
- .markdown-body input {
- color: inherit;
- font: inherit;
- margin: 0;
- }
- .markdown-body html input[disabled] {
- cursor: default;
- }
- .markdown-body input {
- line-height: normal;
- }
- .markdown-body input[type="checkbox"] {
- box-sizing: border-box;
- padding: 0;
- }
- .markdown-body table {
- border-collapse: collapse;
- border-spacing: 0;
- }
- .markdown-body td,
- .markdown-body th {
- padding: 0;
- }
- .markdown-body .codehilitetable {
- border: 0;
- border-spacing: 0;
- }
- .markdown-body .codehilitetable tr {
- border: 0;
- }
- .markdown-body .codehilitetable pre,
- .markdown-body .codehilitetable div.codehilite {
- margin: 0;
- }
- .markdown-body .linenos,
- .markdown-body .code,
- .markdown-body .codehilitetable td {
- border: 0;
- padding: 0;
- }
- .markdown-body td:not(.linenos) .linenodiv {
- padding: 0 !important;
- }
- .markdown-body .code {
- width: 100%;
- }
- .markdown-body .linenos div pre,
- .markdown-body .linenodiv pre,
- .markdown-body .linenodiv {
- border: 0;
- -webkit-border-radius: 0;
- -moz-border-radius: 0;
- border-radius: 0;
- -webkit-border-top-left-radius: 3px;
- -webkit-border-bottom-left-radius: 3px;
- -moz-border-radius-topleft: 3px;
- -moz-border-radius-bottomleft: 3px;
- border-top-left-radius: 3px;
- border-bottom-left-radius: 3px;
- }
- .markdown-body .code div pre,
- .markdown-body .code div {
- border: 0;
- -webkit-border-radius: 0;
- -moz-border-radius: 0;
- border-radius: 0;
- -webkit-border-top-right-radius: 3px;
- -webkit-border-bottom-right-radius: 3px;
- -moz-border-radius-topright: 3px;
- -moz-border-radius-bottomright: 3px;
- border-top-right-radius: 3px;
- border-bottom-right-radius: 3px;
- }
- .markdown-body * {
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- }
- .markdown-body input {
- font: 13px Helvetica, arial, freesans, clean, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol";
- line-height: 1.4;
- }
- .markdown-body a {
- color: #4183c4;
- text-decoration: none;
- }
- .markdown-body a:hover,
- .markdown-body a:focus,
- .markdown-body a:active {
- text-decoration: underline;
- }
- .markdown-body hr {
- height: 0;
- margin: 15px 0;
- overflow: hidden;
- background: transparent;
- border: 0;
- border-bottom: 1px solid #ddd;
- }
- .markdown-body hr:before,
- .markdown-body hr:after {
- display: table;
- content: " ";
- }
- .markdown-body hr:after {
- clear: both;
- }
- .markdown-body h1,
- .markdown-body h2,
- .markdown-body h3,
- .markdown-body h4,
- .markdown-body h5,
- .markdown-body h6 {
- margin-top: 15px;
- margin-bottom: 15px;
- line-height: 1.1;
- }
- .markdown-body h1 {
- font-size: 30px;
- }
- .markdown-body h2 {
- font-size: 21px;
- }
- .markdown-body h3 {
- font-size: 16px;
- }
- .markdown-body h4 {
- font-size: 14px;
- }
- .markdown-body h5 {
- font-size: 12px;
- }
- .markdown-body h6 {
- font-size: 11px;
- }
- .markdown-body blockquote {
- margin: 0;
- }
- .markdown-body ul,
- .markdown-body ol {
- padding: 0;
- margin-top: 0;
- margin-bottom: 0;
- }
- .markdown-body ol ol,
- .markdown-body ul ol {
- list-style-type: lower-roman;
- }
- .markdown-body ul ul ol,
- .markdown-body ul ol ol,
- .markdown-body ol ul ol,
- .markdown-body ol ol ol {
- list-style-type: lower-alpha;
- }
- .markdown-body dd {
- margin-left: 0;
- }
- .markdown-body code,
- .markdown-body pre,
- .markdown-body samp {
- font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
- font-size: 12px;
- }
- .markdown-body pre {
- margin-top: 0;
- margin-bottom: 0;
- }
- .markdown-body kbd {
- background-color: #e7e7e7;
- background-image: -moz-linear-gradient(#fefefe, #e7e7e7);
- background-image: -webkit-linear-gradient(#fefefe, #e7e7e7);
- background-image: linear-gradient(#fefefe, #e7e7e7);
- background-repeat: repeat-x;
- border-radius: 2px;
- border: 1px solid #cfcfcf;
- color: #000;
- padding: 3px 5px;
- line-height: 10px;
- font: 11px Consolas, "Liberation Mono", Menlo, Courier, monospace;
- display: inline-block;
- }
- .markdown-body>*:first-child {
- margin-top: 0 !important;
- }
- .markdown-body>*:last-child {
- margin-bottom: 0 !important;
- }
- .markdown-body .headeranchor-link {
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- display: block;
- padding-right: 6px;
- padding-left: 30px;
- margin-left: -30px;
- }
- .markdown-body .headeranchor-link:focus {
- outline: none;
- }
- .markdown-body h1,
- .markdown-body h2,
- .markdown-body h3,
- .markdown-body h4,
- .markdown-body h5,
- .markdown-body h6 {
- position: relative;
- margin-top: 1em;
- margin-bottom: 16px;
- font-weight: bold;
- line-height: 1.4;
- }
- .markdown-body h1 .headeranchor,
- .markdown-body h2 .headeranchor,
- .markdown-body h3 .headeranchor,
- .markdown-body h4 .headeranchor,
- .markdown-body h5 .headeranchor,
- .markdown-body h6 .headeranchor {
- display: none;
- color: #000;
- vertical-align: middle;
- }
- .markdown-body h1:hover .headeranchor-link,
- .markdown-body h2:hover .headeranchor-link,
- .markdown-body h3:hover .headeranchor-link,
- .markdown-body h4:hover .headeranchor-link,
- .markdown-body h5:hover .headeranchor-link,
- .markdown-body h6:hover .headeranchor-link {
- height: 1em;
- padding-left: 8px;
- margin-left: -30px;
- line-height: 1;
- text-decoration: none;
- }
- .markdown-body h1:hover .headeranchor-link .headeranchor,
- .markdown-body h2:hover .headeranchor-link .headeranchor,
- .markdown-body h3:hover .headeranchor-link .headeranchor,
- .markdown-body h4:hover .headeranchor-link .headeranchor,
- .markdown-body h5:hover .headeranchor-link .headeranchor,
- .markdown-body h6:hover .headeranchor-link .headeranchor {
- display: inline-block;
- }
- .markdown-body h1 {
- padding-bottom: 0.3em;
- font-size: 2.25em;
- line-height: 1.2;
- border-bottom: 1px solid #eee;
- }
- .markdown-body h2 {
- padding-bottom: 0.3em;
- font-size: 1.75em;
- line-height: 1.225;
- border-bottom: 1px solid #eee;
- }
- .markdown-body h3 {
- font-size: 1.5em;
- line-height: 1.43;
- }
- .markdown-body h4 {
- font-size: 1.25em;
- }
- .markdown-body h5 {
- font-size: 1em;
- }
- .markdown-body h6 {
- font-size: 1em;
- color: #777;
- }
- .markdown-body p,
- .markdown-body blockquote,
- .markdown-body ul,
- .markdown-body ol,
- .markdown-body dl,
- .markdown-body table,
- .markdown-body pre,
- .markdown-body .admonition {
- margin-top: 0;
- margin-bottom: 16px;
- }
- .markdown-body hr {
- height: 4px;
- padding: 0;
- margin: 16px 0;
- background-color: #e7e7e7;
- border: 0 none;
- }
- .markdown-body ul,
- .markdown-body ol {
- padding-left: 2em;
- }
- .markdown-body ul ul,
- .markdown-body ul ol,
- .markdown-body ol ol,
- .markdown-body ol ul {
- margin-top: 0;
- margin-bottom: 0;
- }
- .markdown-body li>p {
- margin-top: 16px;
- }
- .markdown-body dl {
- padding: 0;
- }
- .markdown-body dl dt {
- padding: 0;
- margin-top: 16px;
- font-size: 1em;
- font-style: italic;
- font-weight: bold;
- }
- .markdown-body dl dd {
- padding: 0 16px;
- margin-bottom: 16px;
- }
- .markdown-body blockquote {
- padding: 0 15px;
- color: #777;
- border-left: 4px solid #ddd;
- }
- .markdown-body blockquote>:first-child {
- margin-top: 0;
- }
- .markdown-body blockquote>:last-child {
- margin-bottom: 0;
- }
- .markdown-body table {
- display: block;
- width: 100%;
- overflow: auto;
- word-break: normal;
- word-break: keep-all;
- }
- .markdown-body table th {
- font-weight: bold;
- }
- .markdown-body table th,
- .markdown-body table td {
- padding: 6px 13px;
- border: 1px solid #ddd;
- }
- .markdown-body table tr {
- background-color: #fff;
- border-top: 1px solid #ccc;
- }
- .markdown-body table tr:nth-child(2n) {
- background-color: #f8f8f8;
- }
- .markdown-body img {
- max-width: 100%;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- }
- .markdown-body code,
- .markdown-body samp {
- padding: 0;
- padding-top: 0.2em;
- padding-bottom: 0.2em;
- margin: 0;
- font-size: 85%;
- background-color: rgba(0,0,0,0.04);
- border-radius: 3px;
- }
- .markdown-body code:before,
- .markdown-body code:after {
- letter-spacing: -0.2em;
- content: "\00a0";
- }
- .markdown-body pre>code {
- padding: 0;
- margin: 0;
- font-size: 100%;
- word-break: normal;
- white-space: pre;
- background: transparent;
- border: 0;
- }
- .markdown-body .codehilite {
- margin-bottom: 16px;
- }
- .markdown-body .codehilite pre,
- .markdown-body pre {
- padding: 16px;
- overflow: auto;
- font-size: 85%;
- line-height: 1.45;
- background-color: #f7f7f7;
- border-radius: 3px;
- }
- .markdown-body .codehilite pre {
- margin-bottom: 0;
- word-break: normal;
- }
- .markdown-body pre {
- word-wrap: normal;
- }
- .markdown-body pre code {
- display: inline;
- max-width: initial;
- padding: 0;
- margin: 0;
- overflow: initial;
- line-height: inherit;
- word-wrap: normal;
- background-color: transparent;
- border: 0;
- }
- .markdown-body pre code:before,
- .markdown-body pre code:after {
- content: normal;
- }
- /* Admonition */
- .markdown-body .admonition {
- -webkit-border-radius: 3px;
- -moz-border-radius: 3px;
- position: relative;
- border-radius: 3px;
- border: 1px solid #e0e0e0;
- border-left: 6px solid #333;
- padding: 10px 10px 10px 30px;
- }
- .markdown-body .admonition table {
- color: #333;
- }
- .markdown-body .admonition p {
- padding: 0;
- }
- .markdown-body .admonition-title {
- font-weight: bold;
- margin: 0;
- }
- .markdown-body .admonition>.admonition-title {
- color: #333;
- }
- .markdown-body .attention>.admonition-title {
- color: #a6d796;
- }
- .markdown-body .caution>.admonition-title {
- color: #d7a796;
- }
- .markdown-body .hint>.admonition-title {
- color: #96c6d7;
- }
- .markdown-body .danger>.admonition-title {
- color: #c25f77;
- }
- .markdown-body .question>.admonition-title {
- color: #96a6d7;
- }
- .markdown-body .note>.admonition-title {
- color: #d7c896;
- }
- .markdown-body .admonition:before,
- .markdown-body .attention:before,
- .markdown-body .caution:before,
- .markdown-body .hint:before,
- .markdown-body .danger:before,
- .markdown-body .question:before,
- .markdown-body .note:before {
- font: normal normal 16px fontawesome-mini;
- -moz-osx-font-smoothing: grayscale;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- line-height: 1.5;
- color: #333;
- position: absolute;
- left: 0;
- top: 0;
- padding-top: 10px;
- padding-left: 10px;
- }
- .markdown-body .admonition:before {
- content: "\f056\00a0";
- color: 333;
- }
- .markdown-body .attention:before {
- content: "\f058\00a0";
- color: #a6d796;
- }
- .markdown-body .caution:before {
- content: "\f06a\00a0";
- color: #d7a796;
- }
- .markdown-body .hint:before {
- content: "\f05a\00a0";
- color: #96c6d7;
- }
- .markdown-body .danger:before {
- content: "\f057\00a0";
- color: #c25f77;
- }
- .markdown-body .question:before {
- content: "\f059\00a0";
- color: #96a6d7;
- }
- .markdown-body .note:before {
- content: "\f040\00a0";
- color: #d7c896;
- }
- .markdown-body .admonition::after {
- content: normal;
- }
- .markdown-body .attention {
- border-left: 6px solid #a6d796;
- }
- .markdown-body .caution {
- border-left: 6px solid #d7a796;
- }
- .markdown-body .hint {
- border-left: 6px solid #96c6d7;
- }
- .markdown-body .danger {
- border-left: 6px solid #c25f77;
- }
- .markdown-body .question {
- border-left: 6px solid #96a6d7;
- }
- .markdown-body .note {
- border-left: 6px solid #d7c896;
- }
- .markdown-body .admonition>*:first-child {
- margin-top: 0 !important;
- }
- .markdown-body .admonition>*:last-child {
- margin-bottom: 0 !important;
- }
- /* progress bar*/
- .markdown-body .progress {
- display: block;
- width: 300px;
- margin: 10px 0;
- height: 24px;
- -webkit-border-radius: 3px;
- -moz-border-radius: 3px;
- border-radius: 3px;
- background-color: #ededed;
- position: relative;
- box-shadow: inset -1px 1px 3px rgba(0, 0, 0, .1);
- }
- .markdown-body .progress-label {
- position: absolute;
- text-align: center;
- font-weight: bold;
- width: 100%; margin: 0;
- line-height: 24px;
- color: #333;
- text-shadow: 1px 1px 0 #fefefe, -1px -1px 0 #fefefe, -1px 1px 0 #fefefe, 1px -1px 0 #fefefe, 0 1px 0 #fefefe, 0 -1px 0 #fefefe, 1px 0 0 #fefefe, -1px 0 0 #fefefe, 1px 1px 2px #000;
- -webkit-font-smoothing: antialiased !important;
- white-space: nowrap;
- overflow: hidden;
- }
- .markdown-body .progress-bar {
- height: 24px;
- float: left;
- -webkit-border-radius: 3px;
- -moz-border-radius: 3px;
- border-radius: 3px;
- background-color: #96c6d7;
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, .5), inset 0 -1px 0 rgba(0, 0, 0, .1);
- background-size: 30px 30px;
- background-image: -webkit-linear-gradient(
- 135deg, rgba(255, 255, 255, .4) 27%,
- transparent 27%,
- transparent 52%, rgba(255, 255, 255, .4) 52%,
- rgba(255, 255, 255, .4) 77%,
- transparent 77%, transparent
- );
- background-image: -moz-linear-gradient(
- 135deg,
- rgba(255, 255, 255, .4) 27%, transparent 27%,
- transparent 52%, rgba(255, 255, 255, .4) 52%,
- rgba(255, 255, 255, .4) 77%, transparent 77%,
- transparent
- );
- background-image: -ms-linear-gradient(
- 135deg,
- rgba(255, 255, 255, .4) 27%, transparent 27%,
- transparent 52%, rgba(255, 255, 255, .4) 52%,
- rgba(255, 255, 255, .4) 77%, transparent 77%,
- transparent
- );
- background-image: -o-linear-gradient(
- 135deg,
- rgba(255, 255, 255, .4) 27%, transparent 27%,
- transparent 52%, rgba(255, 255, 255, .4) 52%,
- rgba(255, 255, 255, .4) 77%, transparent 77%,
- transparent
- );
- background-image: linear-gradient(
- 135deg,
- rgba(255, 255, 255, .4) 27%, transparent 27%,
- transparent 52%, rgba(255, 255, 255, .4) 52%,
- rgba(255, 255, 255, .4) 77%, transparent 77%,
- transparent
- );
- }
- .markdown-body .progress-100plus .progress-bar {
- background-color: #a6d796;
- }
- .markdown-body .progress-80plus .progress-bar {
- background-color: #c6d796;
- }
- .markdown-body .progress-60plus .progress-bar {
- background-color: #d7c896;
- }
- .markdown-body .progress-40plus .progress-bar {
- background-color: #d7a796;
- }
- .markdown-body .progress-20plus .progress-bar {
- background-color: #d796a6;
- }
- .markdown-body .progress-0plus .progress-bar {
- background-color: #c25f77;
- }
- .markdown-body .candystripe-animate .progress-bar{
- -webkit-animation: animate-stripes 3s linear infinite;
- -moz-animation: animate-stripes 3s linear infinite;
- animation: animate-stripes 3s linear infinite;
- }
- @-webkit-keyframes animate-stripes {
- 0% {
- background-position: 0 0;
- }
- 100% {
- background-position: 60px 0;
- }
- }
- @-moz-keyframes animate-stripes {
- 0% {
- background-position: 0 0;
- }
- 100% {
- background-position: 60px 0;
- }
- }
- @keyframes animate-stripes {
- 0% {
- background-position: 0 0;
- }
- 100% {
- background-position: 60px 0;
- }
- }
- .markdown-body .gloss .progress-bar {
- box-shadow:
- inset 0 4px 12px rgba(255, 255, 255, .7),
- inset 0 -12px 0 rgba(0, 0, 0, .05);
- }
- /* Multimarkdown Critic Blocks */
- .markdown-body .critic_mark {
- background: #ff0;
- }
- .markdown-body .critic_delete {
- color: #c82829;
- text-decoration: line-through;
- }
- .markdown-body .critic_insert {
- color: #718c00 ;
- text-decoration: underline;
- }
- .markdown-body .critic_comment {
- color: #8e908c;
- font-style: italic;
- }
- .markdown-body .headeranchor {
- font: normal normal 16px octicons-anchor;
- line-height: 1;
- display: inline-block;
- text-decoration: none;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- }
- .headeranchor:before {
- content: '\f05c';
- }
- .markdown-body .task-list-item {
- list-style-type: none;
- }
- .markdown-body .task-list-item+.task-list-item {
- margin-top: 3px;
- }
- .markdown-body .task-list-item input {
- margin: 0 4px 0.25em -20px;
- vertical-align: middle;
- }
- /* Media */
- @media only screen and (min-width: 480px) {
- .markdown-body {
- font-size:14px;
- }
- }
- @media only screen and (min-width: 768px) {
- .markdown-body {
- font-size:16px;
- }
- }
- @media print {
- .markdown-body * {
- background: transparent !important;
- color: black !important;
- filter:none !important;
- -ms-filter: none !important;
- }
- .markdown-body {
- font-size:12pt;
- max-width:100%;
- outline:none;
- border: 0;
- }
- .markdown-body a,
- .markdown-body a:visited {
- text-decoration: underline;
- }
- .markdown-body .headeranchor-link {
- display: none;
- }
- .markdown-body a[href]:after {
- content: " (" attr(href) ")";
- }
- .markdown-body abbr[title]:after {
- content: " (" attr(title) ")";
- }
- .markdown-body .ir a:after,
- .markdown-body a[href^="javascript:"]:after,
- .markdown-body a[href^="#"]:after {
- content: "";
- }
- .markdown-body pre {
- white-space: pre;
- white-space: pre-wrap;
- word-wrap: break-word;
- }
- .markdown-body pre,
- .markdown-body blockquote {
- border: 1px solid #999;
- padding-right: 1em;
- page-break-inside: avoid;
- }
- .markdown-body .progress,
- .markdown-body .progress-bar {
- -moz-box-shadow: none;
- -webkit-box-shadow: none;
- box-shadow: none;
- }
- .markdown-body .progress {
- border: 1px solid #ddd;
- }
- .markdown-body .progress-bar {
- height: 22px;
- border-right: 1px solid #ddd;
- }
- .markdown-body tr,
- .markdown-body img {
- page-break-inside: avoid;
- }
- .markdown-body img {
- max-width: 100% !important;
- }
- .markdown-body p,
- .markdown-body h2,
- .markdown-body h3 {
- orphans: 3;
- widows: 3;
- }
- .markdown-body h2,
- .markdown-body h3 {
- page-break-after: avoid;
- }
- }
- </style><title>readme</title></head><body><article class="markdown-body"><h2 id="vuemvvm"><a name="user-content-vuemvvm" href="#vuemvvm" class="headeranchor-link" aria-hidden="true"><span class="headeranchor"></span></a>剖析Vue实现原理,实现一个MVVM</h2>
- <blockquote>
- <p>本文主要是在分析Vue源码的基础上,对其相关核心思想和逻辑进行简化,并通过实现一个简单的实现来阐述相关原理和思想,文中并不会涉及太多源码片段的解析,但其核心思想都会在文中表现出来,对阅读Vue源码会有更好的帮助,相信会让你的思路更加清晰~</p>
- </blockquote>
- <h4 id="1vuehello-world"><a name="user-content-1vuehello-world" href="#1vuehello-world" class="headeranchor-link" aria-hidden="true"><span class="headeranchor"></span></a>1、一个简单的Vue例子:<a href="///E://personal/%E5%89%8D%E7%AB%AF/mvvm/vue-demo/index.html">Hello World!</a></h4>
- <p><strong>code:</strong> <br />
- <pre><code><div id="vue-app">
- <input type="text" v-model="word">
- <p>{{word}}</p>
- <button v-on:click="sayHi">change model</button>
- </div>
- <script src="http://cdn.bootcss.com/vue/1.0.25/vue.js"></script>
- <script>
- var vm = new Vue({
- el: '#vue-app',
- data: {
- word: 'Hello World!'
- },
- methods: {
- sayHi: function() {
- this.word = 'Hi, everybody!';
- }
- }
- });
- </script>
- </code></pre></p>
- <h4 id="2my-mvvm"><a name="user-content-2my-mvvm" href="#2my-mvvm" class="headeranchor-link" aria-hidden="true"><span class="headeranchor"></span></a>2、如题,今天要跟大家分享的就是实现上面的功能,是这样子的:<a href="///E://personal/%E5%89%8D%E7%AB%AF/mvvm/mvvm.html">My mvvm</a></h4>
- <p><strong>code:</strong><br />
- <pre><code><div id="mvvm-app">
- <input type="text" v-model="name">
- <input type="text" v-model="child.name">
- <p v-class="className" class="abc">
- {{child.child.name}}
- </p>
- <span v-text="child.name"></span>
- <p v-html="child.html"></p>
- <button v-on:click="clickBtn">change model</button>
- </div>
- <script src="./js/observer.js"></script>
- <script src="./js/watcher.js"></script>
- <script src="./js/compile.js"></script>
- <script src="./js/mvvm.js"></script>
- <script>
- var vm = new MVVM({
- el: '#mvvm-app',
- data: {
- name: 'hello ',
- className: 'btn',
- spanText: 'hello world!',
- child: {
- name: '孩子名字',
- html: '<span style="color: #f00;">red</span>',
- child: {
- name: '孩子的孩子名字 '
- }
- }
- },
- methods: {
- clickBtn: function(e) {
- var randomStrArr = ['childOne', 'childTwo', 'childThree'];
- this.child.name = randomStrArr[parseInt(Math.random() * 3)];
- }
- }
- });
- </script>
- </code></pre></p>
- <h4 id="3"><a name="user-content-3" href="#3" class="headeranchor-link" aria-hidden="true"><span class="headeranchor"></span></a>3、目前实现数据绑定的几种做法</h4>
- <blockquote>
- <p>观察者模式(backbone.js)</p>
- <p>脏值检查(angular.js) </p>
- <p>数据劫持(vue.js) </p>
- </blockquote>
- <p>观察者模式一般通过sub, pub的方式实现数据和视图的绑定监听,更新数据方式通常 <code>vm.set('property', value)</code>, 这种方式现在毕竟太low了,我们更希望通过 <code>vm.property = value</code>这种方式更新数据,同时自动更新视图。</p>
- <p>angular.js 是通过脏值检测的方式比对数据是否有变更,来决定是否更新视图,最简单的方式就是通过 <code>setInterval()</code> 定时轮询检测数据变动,当然Google不会这么low,angular只有在指定的事件触发时进入脏值检测,大致如下:</p>
- <ul>
- <li>DOM事件,譬如用户输入文本,点击按钮等。( ng-click ) </li>
- <li>XHR响应事件 ( $http ) </li>
- <li>浏览器Location变更事件 ( $location ) </li>
- <li>Timer事件( $timeout , $interval ) </li>
- <li>执行 $digest() 或 $apply()</li>
- </ul>
- <p><strong> vue.js 则是数据劫持结合观察者模式,通过<code>Object.defineProperty()</code>来劫持各个属性的<code>setter</code>,<code>getter</code>,在数据变动时发布消息给订阅者,触发相应的监听回调。</strong></p>
- <h4 id="4vue-github"><a name="user-content-4vue-github" href="#4vue-github" class="headeranchor-link" aria-hidden="true"><span class="headeranchor"></span></a>4、Vue的生命周期 (<a href="https://github.com/vuejs/vue/">Github</a>)</h4>
- <p><img src="https://vuejs.org.cn/images/lifecycle.png" width="640px"></p>
- <h4 id="5"><a name="user-content-5" href="#5" class="headeranchor-link" aria-hidden="true"><span class="headeranchor"></span></a>5、我们要实现的关键点:</h4>
- <ul>
- <li>数据监听 Observer.js 和消息订阅器 Dep.js</li>
- <li>订阅者 Watcher.js</li>
- <li>指令编译器 Compile.js</li>
- <li>入口 mvvm</li>
- </ul>
- <h4 id="6objectdefineproperty"><a name="user-content-6objectdefineproperty" href="#6objectdefineproperty" class="headeranchor-link" aria-hidden="true"><span class="headeranchor"></span></a>6、一切基于此Object.defineProperty()</h4>
- <p><em>IE8+</em></p>
- <p><strong>code:</strong><br />
- <pre><code>function defineReative(data) {
- var val;
- Object.defineProperty(data, 'name', {
- enumerable: true, // 可枚举
- configurable: true, // 不能再define
- get: function() {
- return val;
- },
- set: function(newVal) {
- console.log('你变了:', val, ' ==> ', newVal);
- val = newVal;
- }
- });
- }
- var data = {};
- defineReative(data);
- </code></pre></p>
- <h4 id="7observerjs"><a name="user-content-7observerjs" href="#7observerjs" class="headeranchor-link" aria-hidden="true"><span class="headeranchor"></span></a>7、实现Observer.js</h4>
- <p>负责监听源数据所有属性,一旦发生变化,通知订阅者更新视图</p>
- <p><a href="///E://personal/%E5%89%8D%E7%AB%AF/mvvm/js/observer.js">code</a></p>
- <h4 id="8compilejs"><a name="user-content-8compilejs" href="#8compilejs" class="headeranchor-link" aria-hidden="true"><span class="headeranchor"></span></a>8、实现Compile.js</h4>
- <p>负责解析模板指令,不同的指令绑定不同的处理回调及视图更新方法</p>
- <p><a href="///E://personal/%E5%89%8D%E7%AB%AF/mvvm/js/compile.js">code</a></p>
- <h4 id="9observe-compile-watcherjs"><a name="user-content-9observe-compile-watcherjs" href="#9observe-compile-watcherjs" class="headeranchor-link" aria-hidden="true"><span class="headeranchor"></span></a>9、如何连接observe 和 compile –> watcher.js(桥梁)</h4>
- <p>充当数据更新的订阅者,每一个属性的变化都会通知它,在compile阶段实例化并注入回调函数</p>
- <p>每一个属性都有一个watcher</p>
- <p><a href="///E://personal/%E5%89%8D%E7%AB%AF/mvvm/js/watcher.js">code</a></p></article></body></html>
|