ofs | hex dump | ascii |
---|
0000 | 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 07 6b 00 00 03 e3 08 06 00 00 00 9a 8f e5 | .PNG........IHDR...k............ |
0020 | a7 00 00 00 09 70 48 59 73 00 00 24 e9 00 00 24 e9 01 50 24 e7 f8 00 00 00 07 74 49 4d 45 07 e2 | .....pHYs..$...$..P$......tIME.. |
0040 | 07 0d 11 39 27 61 78 e5 72 00 00 00 07 74 45 58 74 41 75 74 68 6f 72 00 a9 ae cc 48 00 00 00 0c | ...9'ax.r....tEXtAuthor....H.... |
0060 | 74 45 58 74 44 65 73 63 72 69 70 74 69 6f 6e 00 13 09 21 23 00 00 00 0a 74 45 58 74 43 6f 70 79 | tEXtDescription...!#....tEXtCopy |
0080 | 72 69 67 68 74 00 ac 0f cc 3a 00 00 00 0e 74 45 58 74 43 72 65 61 74 69 6f 6e 20 74 69 6d 65 00 | right....:....tEXtCreation.time. |
00a0 | 35 f7 0f 09 00 00 00 09 74 45 58 74 53 6f 66 74 77 61 72 65 00 5d 70 ff 3a 00 00 00 0b 74 45 58 | 5.......tEXtSoftware.]p.:....tEX |
00c0 | 74 44 69 73 63 6c 61 69 6d 65 72 00 b7 c0 b4 8f 00 00 00 08 74 45 58 74 57 61 72 6e 69 6e 67 00 | tDisclaimer.........tEXtWarning. |
00e0 | c0 1b e6 87 00 00 00 07 74 45 58 74 53 6f 75 72 63 65 00 f5 ff 83 eb 00 00 00 08 74 45 58 74 43 | ........tEXtSource.........tEXtC |
0100 | 6f 6d 6d 65 6e 74 00 f6 cc 96 bf 00 00 00 06 74 45 58 74 54 69 74 6c 65 00 a8 ee d2 27 00 00 20 | omment.........tEXtTitle....'... |
0120 | 00 49 44 41 54 78 9c ec dd ff 6b 5b f7 bd f8 f1 97 2f fb 75 cd 8e b5 9f 4a 29 41 72 e1 96 15 1c | .IDATx....k[...../.u....J)Ar.... |
0140 | d2 e3 74 b4 4e c1 85 58 9a 57 46 cb d2 49 49 4b 09 a4 c4 96 36 06 6d ba b8 b5 5b 2e 97 d6 6e a4 | ..t.N..X.WF..IIK....6.m...[...n. |
0160 | b2 0e c6 66 d9 25 83 72 59 63 b9 69 69 18 b5 67 39 d0 c0 a4 95 bb 46 0b 16 b7 a5 17 92 23 42 e9 | ...f.%.rYc.ii..g9.....F......#B. |
0180 | ed 4f 56 4f b3 fd 01 fa fc e0 8f ce ce 39 3a df 64 4b 3a b2 f3 7c 80 e1 48 3a 7a 9f f7 39 ef f7 | .OVO.........9:.dK:..|..H:z..9.. |
01a0 | 39 51 5e af f3 7e 9f 81 46 a3 d1 10 00 00 00 00 00 00 00 00 00 00 40 4f fd 5b d8 15 00 00 00 00 | 9Q^..~..F.............@O.[...... |
01c0 | 00 00 00 00 00 00 80 3b 11 c9 5a 00 00 00 00 00 00 00 00 00 00 08 01 c9 5a 00 00 00 00 00 00 00 | .......;..Z.............Z....... |
01e0 | 00 00 00 08 01 c9 5a 00 00 00 00 00 00 00 00 00 00 08 01 c9 5a 00 00 00 00 00 00 00 00 00 00 08 | ......Z.............Z........... |
0200 | 01 c9 5a 00 00 00 00 00 00 00 00 00 00 08 01 c9 5a 00 00 00 00 00 00 00 00 00 00 08 01 c9 5a 00 | ..Z.............Z.............Z. |
0220 | 00 00 00 00 00 00 00 00 00 08 01 c9 5a 00 00 00 00 00 00 00 00 00 00 08 01 c9 5a 00 00 00 00 00 | ............Z.............Z..... |
0240 | 00 00 00 00 00 08 01 c9 5a 00 00 00 00 00 00 00 00 00 00 08 01 c9 5a 00 00 00 00 00 00 00 00 00 | ........Z.............Z......... |
0260 | 00 08 01 c9 5a 00 00 00 00 00 00 00 00 00 00 08 01 c9 5a 00 00 00 00 00 00 00 00 00 00 08 01 c9 | ....Z.............Z............. |
0280 | 5a 00 00 00 00 00 00 00 00 00 00 08 01 c9 5a 00 00 00 00 00 00 00 00 00 00 08 01 c9 5a 00 00 00 | Z.............Z.............Z... |
02a0 | 00 00 00 00 00 00 00 08 01 c9 5a 00 00 00 00 00 00 00 00 00 00 08 01 c9 5a 00 00 00 00 00 00 00 | ..........Z.............Z....... |
02c0 | 00 00 00 08 01 c9 5a 00 00 00 00 00 00 00 00 00 00 08 01 c9 5a 00 00 00 00 00 00 00 00 00 00 08 | ......Z.............Z........... |
02e0 | 41 e8 c9 da d9 d9 59 19 18 18 b0 fc 0d 0d 0d b5 5d ce e0 e0 60 4b 39 85 42 c1 f8 dc fe d9 c0 c0 | A.....Y.........]...`K9.B....... |
0300 | 80 ac ad ad 05 2a db fe bd 44 22 e1 b8 5e 2e 97 73 dc ce 4e fe ca e5 b2 67 1d 76 f3 e7 56 7f 00 | .....*...D"..^..s..N....g.v..V.. |
0320 | 00 00 00 00 00 60 2f e9 55 6c 31 91 48 b4 7c be 5b 4e 71 bb a0 eb f9 fd 0d 0e 0e 4a 22 91 90 d9 | .....`/.Ul1.H.|.[Nq........J"... |
0340 | d9 59 a9 56 ab bb ae 2b 00 00 e8 9e d0 93 b5 3f fb d9 cf 5a de d3 34 ad 25 59 e9 a5 50 28 88 ae | .Y.V...+.......?...Z..4.%Y..P(.. |
0360 | eb 96 f7 14 45 91 63 c7 8e 79 7e ef 97 bf fc a5 d4 eb f5 c0 db 01 00 00 00 00 00 00 d0 3f c2 8c | ....E.c..y~..................?.. |
0380 | 2d f6 33 5d d7 a5 58 2c ca fc fc bc 1c 3a 74 48 66 67 67 c3 ae 12 00 00 70 11 7a b2 76 78 78 58 | -.3]..X,.....:tHfgg.....p.z.vxxX |
03a0 | 62 b1 58 cb fb 17 2f 5e 0c 5c c6 e5 cb 97 5b de 4b a5 52 12 89 44 3c bf a7 69 9a bc f5 d6 5b 81 | b.X.../^.\....[.K.R..D<..i....[. |
03c0 | b7 03 00 00 00 00 00 00 a0 7f 84 19 5b dc 4b e6 e7 e7 25 93 c9 84 5d 0d 00 00 e0 20 f4 64 ad 88 | ............[.K...%...]......d.. |
03e0 | c8 99 33 67 5a de 33 4f 33 e2 a5 5e af cb ca ca 4a cb fb 27 4f 9e 0c f4 fd f9 f9 79 a6 02 01 00 | ..3gZ.3O3..^....J..'O......y.... |
0400 | 00 00 00 00 00 f6 a8 30 63 8b 7b 49 3e 9f 0f 7c 5c 00 00 40 ef f4 45 b2 f6 f8 f1 e3 2d ef e9 ba | .......0c.{I>..|\..@..E.....-... |
0420 | 1e e8 99 b2 57 ae 5c 69 79 2f 16 8b c9 e8 e8 68 e0 ed 4f 4f 4f 07 5e b7 5d d9 6c 56 1a 8d 46 db | ....W.\iy/.....h..OOO.^.].lV..F. |
0440 | 7f f6 fa 7b ad 1b 8f c7 5b b6 5b 2a 95 5c d7 5f 5f 5f ef da fe 02 00 00 00 00 00 00 bd 14 76 6c | ...{....[.[*.\.___............vl |
0460 | 31 0c 5e b1 c2 ad ad 2d 59 5d 5d 75 1c 71 fc eb 5f ff 3a 84 da 02 00 00 2f 7d 91 ac 8d 46 a3 a2 | 1.^....-Y]]u.q.._.:...../}...F.. |
0480 | aa 6a cb fb 1f 7d f4 91 ef 77 9d a6 29 71 ba 9b ce 4b b1 58 e4 ae 32 00 00 00 00 00 00 60 0f 0a | .j...}...w..)q...K.X..2......`.. |
04a0 | 3b b6 d8 6f 22 91 88 4c 4c 4c c8 07 1f 7c d0 f2 59 a5 52 09 a1 46 00 00 c0 4b 5f 24 6b 45 44 9e | ;..o"..LLL...|..Y.R..F...K_$kED. |
04c0 | 7b ee b9 96 f7 fc 12 a8 6e d3 94 38 dd 4d e7 27 93 c9 48 bd 5e 6f fb 7b 00 00 00 00 00 00 00 c2 | {.......n..8.M.'..H.^o.{........ |
04e0 | 15 76 6c b1 1f 0d 0f 0f 3b 26 b1 01 00 40 7f e9 9b 64 ed 4e a6 2b 79 ff fd f7 5b de 8b c7 e3 12 | .vl.....;&...@...d.N.+y...[..... |
0500 | 8d 46 db de be ae eb f2 d6 5b 6f b5 fd 3d 00 00 00 00 00 00 00 e1 0a 3b b6 b8 57 28 8a 12 76 15 | .F.......[o..=.........;..W(..v. |
0520 | 00 00 80 4d df 24 6b 23 91 88 24 93 c9 96 f7 bd a6 2b b9 70 e1 42 cb 7b a7 4e 9d da 71 1d e6 e7 | ...M.$k#..$......+.p.B.{.N..q... |
0540 | e7 a5 5c 2e ef f8 fb 00 00 00 00 00 00 00 7a af 1f 62 8b fd a6 5c 2e b7 4c 7b 9c 4a a5 42 aa 0d | ..\...........z..b...\..L{.J.B.. |
0560 | 00 00 70 d3 37 c9 5a 11 91 27 9e 78 a2 e5 3d b7 e9 4a 6a b5 5a cb 8f 0d 45 51 e4 d8 b1 63 81 b6 | ..p.7.Z..'.x..=..Jj.Z...EQ...c.. |
0580 | 15 8f c7 25 1e 8f b7 bc ff fc f3 cf 07 fa 3e 00 00 00 00 00 00 80 fe d1 cb d8 62 3f ab d5 6a 52 | ...%..........>...........b?..jR |
05a0 | 28 14 e4 27 3f f9 89 e5 7d 45 51 e4 c5 17 5f 0c a9 56 00 00 c0 4d 5f 25 6b 9d 7e 0c e9 ba ee f8 | (..'?...}EQ..._..V...M_%k.~..... |
05c0 | a3 ea ca 95 2b 2d ef a5 52 29 89 44 22 81 b7 97 cd 66 5b de ab 54 2a b2 b4 b4 14 b8 0c 3f d3 d3 | ....+-..R).D"....f[..T*......?.. |
05e0 | d3 32 30 30 d0 d6 1f a3 7b 01 00 00 00 00 00 80 f6 f4 3a b6 18 26 af d8 62 2c 16 93 13 27 4e 88 | .200....{.........:..&..b,...'N. |
0600 | ae eb 96 ef 2c 2c 2c ec eb 29 9e 01 00 d8 ab fa 2a 59 1b 89 44 24 9d 4e b7 bc 7f f9 f2 e5 96 f7 | ....,,,..)......*Y..D$.N........ |
0620 | 9c a6 29 39 79 f2 64 5b db 1b 1e 1e 76 4c d8 be fc f2 cb 52 af d7 db 2a 0b 00 00 00 00 00 00 40 | ..)9y.d[....vL.....R...*.......@ |
0640 | 78 7a 1d 5b dc 2b 14 45 91 cd cd 4d a6 40 06 00 a0 4f f5 55 b2 56 44 e4 f1 c7 1f 6f 79 6f 65 65 | xz.[.+.E...M.@...O.U.VD....oyoee |
0660 | c5 92 3c ad 56 ab 2d d3 94 c4 62 31 19 1d 1d 6d 7b 7b a7 4f 9f 96 58 2c 66 79 4f d7 75 f9 f9 cf | ..<.V.-...b1...m{{.O..X,fyO.u... |
0680 | 7f de 76 59 00 00 00 00 00 00 00 c2 d3 eb d8 e2 5e a0 eb ba 8c 8d 8d 75 74 36 41 00 00 d0 39 7d | ..vY............^......ut6A...9} |
06a0 | 97 ac 9d 98 98 10 45 51 5a de 37 4f 4d f2 de 7b ef b5 7c 7e e6 cc 99 1d 6d 2f 12 89 c8 6f 7f fb | ......EQZ.7OM..{..|~....m/...o.. |
06c0 | db 96 f7 57 56 56 98 8e 18 00 00 00 00 00 00 d8 43 7a 1d 5b dc 2b 74 5d 97 a9 a9 29 c9 64 32 61 | ...WVV..........Cz.[.+t]...).d2a |
06e0 | 57 05 00 00 d8 f4 5d b2 56 44 1c a7 e4 30 4f 57 b2 b2 b2 d2 f2 f9 f1 e3 c7 77 bc bd 89 89 09 89 | W.....].VD...0OW.........w...... |
0700 | c7 e3 2d ef 9f 3a 75 6a c7 65 36 65 b3 59 69 34 1a 6d fd ed d7 bb f8 00 00 00 00 00 00 80 6e eb | ..-..:uj.e6e.Yi4.m............n. |
0720 | 75 6c 31 0c 5e b1 45 4d d3 64 75 75 55 92 c9 64 cb f7 f2 f9 3c 23 6c 01 00 e8 33 7d 99 ac 9d 9c | ul1.^.EM.duuU..d....<#l...3}.... |
0740 | 9c 6c 79 af 39 5d 49 b5 5a 15 4d d3 2c 9f c5 e3 71 89 46 a3 bb da e6 c2 c2 42 cb 5d 77 9a a6 49 | .ly.9]I.Z.M.,...q.F......B.]w..I |
0760 | 2e 97 db 55 b9 00 00 00 00 00 00 00 7a 27 8c d8 62 3f 89 46 a3 32 31 31 21 85 42 c1 f1 19 be 2f | ...U........z'..b?.F.211!.B..../ |
0780 | bf fc 72 08 b5 02 00 00 6e fa 32 59 3b 3c 3c dc f2 1c 59 91 ed e9 4a 9c a6 29 e9 c4 08 d8 68 34 | ..r.....n.2Y;<<...Y...J..)....h4 |
07a0 | 2a 2f bd f4 52 cb fb e7 cf 9f df 75 d9 00 00 00 00 00 00 00 7a 23 8c d8 62 bf 7a ed b5 d7 5a de | */..R......u........z#..b.z...Z. |
07c0 | d3 75 5d aa d5 6a 08 b5 01 00 00 4e fa 32 59 2b 22 8e d3 74 5c be 7c 59 f2 f9 bc e5 3d 45 51 e4 | .u]..j.....N.2Y+"..t\.|Y....=EQ. |
07e0 | d8 b1 63 1d d9 e6 b9 73 e7 5a 7e c8 e9 ba de 91 b2 01 00 00 00 00 00 00 f4 46 18 b1 c5 7e 14 89 | ..c....s.Z~..............F...~.. |
0800 | 44 1c df ff e7 3f ff d9 e3 9a 00 00 00 37 7d 9b ac 3d 7d fa 74 cb 7b 2b 2b 2b 2d c9 d3 54 2a e5 | D....?.......7}..=}.t.{+++-..T*. |
0820 | fa a3 63 27 de 79 e7 9d 8e 95 05 00 00 00 00 00 00 a0 f7 c2 8a 2d f6 9b 7a bd 1e 76 15 00 00 80 | ..c'.y...............-..z..v.... |
0840 | 8f be 4d d6 46 a3 51 51 55 d5 77 bd 93 27 4f 76 74 bb a3 a3 a3 8e cf 72 00 00 00 00 00 00 00 b0 | ..M.F.QQU.w..'Ovt......r........ |
0860 | 37 84 15 5b ec 37 ef bf ff be e3 fb f7 df 7f 7f 8f 6b 02 00 00 dc f4 6d b2 56 44 e4 b9 e7 9e f3 | 7..[.7...........k.....m.VD..... |
0880 | fc 3c 16 8b c9 e8 e8 68 c7 b7 fb da 6b af 89 a2 28 1d 2f 17 00 00 00 00 00 00 40 6f 84 15 5b ec | .<.....h....k...(./.......@o..[. |
08a0 | 07 d5 6a 55 72 b9 9c 4c 4d 4d b5 7c 16 8f c7 f7 f5 68 62 00 00 f6 9a be 4e d6 fa 3d 2f e2 cc 99 | ..jUr..LMM.|.....hb.....N..=/... |
08c0 | 33 5d d9 6e 24 12 91 37 de 78 a3 23 65 4d 4f 4f cb c0 c0 40 db 7f 89 44 a2 23 db 07 00 00 00 00 | 3].n$..7.x.#eMOO...@...D.#...... |
08e0 | 00 00 ee 44 dd 8e 2d 86 19 ef f3 db d6 a1 43 87 64 7a 7a da f1 bb af bc f2 4a c7 ea 01 00 00 76 | ...D..-.......C.dzz......J.....v |
0900 | af af 93 b5 d1 68 54 92 c9 a4 eb e7 c7 8f 1f ef da b6 27 27 27 25 1e 8f 77 ad 7c 00 00 00 00 00 | .....hT...........'''%..w.|..... |
0920 | 00 00 dd 13 66 6c b1 5f cd cc cc ec db d1 c4 00 00 ec 55 7d 9d ac 15 11 79 e2 89 27 1c df 8f c7 | ....fl._..........U}....y..'.... |
0940 | e3 12 8d 46 bb ba ed 6c 36 db d5 f2 01 00 00 00 00 00 00 74 4f 98 b1 c5 7e 93 cd 66 65 6e 6e 2e | ...F...l6..........tO...~..fenn. |
0960 | ec 6a 00 00 00 9b ef 84 5d 01 3f 6e d3 95 9c 3a 75 aa eb db 1e 1e 1e 96 99 99 19 99 9f 9f ef fa | .j......].?n...:u............... |
0980 | b6 00 00 00 00 00 00 00 74 56 98 b1 c5 b0 a9 aa 2a 91 48 44 1e 7b ec 31 39 7e fc f8 1d 97 9c 06 | ........tV......*.HD.{.19~...... |
@media only all and (prefers-color-scheme: dark) {
.highlight .hll { background-color: #49483e }
.highlight .c { color: #75715e } /* Comment */
.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
.highlight .k { color: #66d9ef } /* Keyword */
.highlight .l { color: #ae81ff } /* Literal */
.highlight .n { color: #f8f8f2 } /* Name */
.highlight .o { color: #f92672 } /* Operator */
.highlight .p { color: #f8f8f2 } /* Punctuation */
.highlight .ch { color: #75715e } /* Comment.Hashbang */
.highlight .cm { color: #75715e } /* Comment.Multiline */
.highlight .cp { color: #75715e } /* Comment.Preproc */
.highlight .cpf { color: #75715e } /* Comment.PreprocFile */
.highlight .c1 { color: #75715e } /* Comment.Single */
.highlight .cs { color: #75715e } /* Comment.Special */
.highlight .gd { color: #f92672 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gi { color: #a6e22e } /* Generic.Inserted */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #75715e } /* Generic.Subheading */
.highlight .kc { color: #66d9ef } /* Keyword.Constant */
.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
.highlight .kn { color: #f92672 } /* Keyword.Namespace */
.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
.highlight .kt { color: #66d9ef } /* Keyword.Type */
.highlight .ld { color: #e6db74 } /* Literal.Date */
.highlight .m { color: #ae81ff } /* Literal.Number */
.highlight .s { color: #e6db74 } /* Literal.String */
.highlight .na { color: #a6e22e } /* Name.Attribute */
.highlight .nb { color: #f8f8f2 } /* Name.Builtin */
.highlight .nc { color: #a6e22e } /* Name.Class */
.highlight .no { color: #66d9ef } /* Name.Constant */
.highlight .nd { color: #a6e22e } /* Name.Decorator */
.highlight .ni { color: #f8f8f2 } /* Name.Entity */
.highlight .ne { color: #a6e22e } /* Name.Exception */
.highlight .nf { color: #a6e22e } /* Name.Function */
.highlight .nl { color: #f8f8f2 } /* Name.Label */
.highlight .nn { color: #f8f8f2 } /* Name.Namespace */
.highlight .nx { color: #a6e22e } /* Name.Other */
.highlight .py { color: #f8f8f2 } /* Name.Property */
.highlight .nt { color: #f92672 } /* Name.Tag */
.highlight .nv { color: #f8f8f2 } /* Name.Variable */
.highlight .ow { color: #f92672 } /* Operator.Word */
.highlight .w { color: #f8f8f2 } /* Text.Whitespace */
.highlight .mb { color: #ae81ff } /* Literal.Number.Bin */
.highlight .mf { color: #ae81ff } /* Literal.Number.Float */
.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
.highlight .sa { color: #e6db74 } /* Literal.String.Affix */
.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
.highlight .sc { color: #e6db74 } /* Literal.String.Char */
.highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */
.highlight .sd { color: #e6db74 } /* Literal.String.Doc */
.highlight .s2 { color: #e6db74 } /* Literal.String.Double */
.highlight .se { color: #ae81ff } /* Literal.String.Escape */
.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
.highlight .si { color: #e6db74 } /* Literal.String.Interpol */
.highlight .sx { color: #e6db74 } /* Literal.String.Other */
.highlight .sr { color: #e6db74 } /* Literal.String.Regex */
.highlight .s1 { color: #e6db74 } /* Literal.String.Single */
.highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
.highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #a6e22e } /* Name.Function.Magic */
.highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
.highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
.highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
.highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */
.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
}
@media (prefers-color-scheme: light) {
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
}
/*
* Copyright (c) 2016 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <vnet/mpls/mpls.h>
#include <vnet/dpo/mpls_label_dpo.h>
#include <vnet/dpo/load_balance.h>
#include <vnet/dpo/drop_dpo.h>
#include <vnet/fib/fib_path_ext.h>
#include <vnet/fib/fib_entry_src.h>
#include <vnet/fib/fib_path.h>
#include <vnet/fib/fib_path_list.h>
#include <vnet/fib/fib_internal.h>
const char *fib_path_ext_adj_flags_names[] = FIB_PATH_EXT_ADJ_ATTR_NAMES;
const char *fib_path_ext_mpls_flags_names[] = FIB_PATH_EXT_MPLS_ATTR_NAMES;
u8 *
format_fib_path_ext (u8 * s, va_list * args)
{
fib_path_ext_t *path_ext;
u32 ii;
path_ext = va_arg (*args, fib_path_ext_t *);
s = format(s, "path:%d ", path_ext->fpe_path_index);
switch (path_ext->fpe_type)
{
case FIB_PATH_EXT_MPLS: {
fib_path_ext_mpls_attr_t attr;
if (path_ext->fpe_mpls_flags)
{
s = format(s, "mpls-flags:[");
FOR_EACH_PATH_EXT_MPLS_ATTR(attr)
{
if ((1<<attr) & path_ext->fpe_mpls_flags) {
s = format(s, "%s", fib_path_ext_mpls_flags_names[attr]);
}
}
s = format(s, "]");
}
s = format(s, " labels:[");
for (ii = 0; ii < vec_len(path_ext->fpe_path.frp_label_stack); ii++)
{
s = format(s, "[%U]",
format_fib_mpls_label,
&path_ext->fpe_path.frp_label_stack[ii]);
}
s = format(s, "]");
break;
}
case FIB_PATH_EXT_ADJ: {
fib_path_ext_adj_attr_t attr;
if (path_ext->fpe_adj_flags)
{
s = format(s, "adj-flags:[");
FOR_EACH_PATH_EXT_ADJ_ATTR(attr)
{
if ((1<<attr) & path_ext->fpe_adj_flags)
{
s = format(s, "%s", fib_path_ext_adj_flags_names[attr]);
}
}
s = format(s, "]");
}
break;
}
}
return (s);
}
int
fib_path_ext_cmp (fib_path_ext_t *path_ext,
const fib_route_path_t *rpath)
{
return (fib_route_path_cmp(&path_ext->fpe_path, rpath));
}
static fib_path_list_walk_rc_t
fib_path_ext_match (fib_node_index_t pl_index,
fib_node_index_t path_index,
void *ctx)
{
fib_path_ext_t *path_ext = ctx;
if (!fib_path_cmp_w_route_path(path_index,
&path_ext->fpe_path))
{
path_ext->fpe_path_index = path_index;
return (FIB_PATH_LIST_WALK_STOP);
}
return (FIB_PATH_LIST_WALK_CONTINUE);
}
void
fib_path_ext_resolve (fib_path_ext_t *path_ext,
fib_node_index_t path_list_index)
{
/*
* Find the path on the path list that this is an extension for
*/
path_ext->fpe_path_index = FIB_NODE_INDEX_INVALID;
fib_path_list_walk(path_list_index,
fib_path_ext_match,
path_ext);
}
static void
fib_path_ext_init (fib_path_ext_t *path_ext,
fib_node_index_t path_list_index,
fib_path_ext_type_t ext_type,
const fib_route_path_t *rpath)
{
path_ext->fpe_path = *rpath;
path_ext->fpe_path_index = FIB_NODE_INDEX_INVALID;
path_ext->fpe_adj_flags = FIB_PATH_EXT_ADJ_FLAG_NONE;
path_ext->fpe_type = ext_type;
fib_path_ext_resolve(path_ext, path_list_index);
}
/**
* @brief Return true if the label stack is implicit null
* imp-null and pop equate to the same this as this level -
* the label is coming off.
*/
static int
fib_path_ext_is_imp_null (fib_path_ext_t *path_ext)
{
return ((1 == vec_len(path_ext->fpe_label_stack)) &&
((MPLS_IETF_IMPLICIT_NULL_LABEL == path_ext->fpe_label_stack[0].fml_value) ||
(MPLS_LABEL_POP == path_ext->fpe_label_stack[0].fml_value)));
}
mpls_label_dpo_flags_t
fib_path_ext_mpls_flags_to_mpls_label (fib_path_ext_mpls_flags_t fpe_flags)
{
mpls_label_dpo_flags_t ml_flags = MPLS_LABEL_DPO_FLAG_NONE;
if (fpe_flags &FIB_PATH_EXT_MPLS_FLAG_NO_IP_TTL_DECR)
{
ml_flags |= MPLS_LABEL_DPO_FLAG_NO_IP_TTL_DECR;
}
return (ml_flags);
}
load_balance_path_t *
fib_path_ext_stack (fib_path_ext_t *path_ext,
fib_forward_chain_type_t child_fct,
fib_forward_chain_type_t imp_null_fct,
load_balance_path_t *nhs)
{
fib_forward_chain_type_t parent_fct;
load_balance_path_t *nh;
if (!fib_path_is_resolved(path_ext->fpe_path_index))
return (nhs);
/*
* Since we are stacking this path-extension, it must have a valid out
* label. From the chain type request by the child, determine what
* chain type we will request from the parent.
*/
switch (child_fct)
{
case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
{
/*
* The EOS chain is a tricky since, when the path has an imp NULL one cannot know
* the adjacency to link to without knowing what the packets payload protocol
* will be once the label is popped.
*/
if (fib_path_ext_is_imp_null(path_ext))
{
parent_fct = imp_null_fct;
}
else
{
/*
* we have a label to stack. packets will thus be labelled when
* they encounter the child, ergo, non-eos.
*/
parent_fct = FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS;
}
break;
}
case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
if (fib_path_ext_is_imp_null(path_ext))
{
/*
* implicit-null label for the eos or IP chain, need to pick up
* the IP adj
*/
parent_fct = child_fct;
}
else
{
/*
* we have a label to stack. packets will thus be labelled when
* they encounter the child, ergo, non-eos.
*/
parent_fct = FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS;
}
break;
case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
parent_fct = child_fct;
break;
case FIB_FORW_CHAIN_TYPE_ETHERNET:
parent_fct = FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS;
break;
default:
return (nhs);
break;
}
dpo_id_t via_dpo = DPO_INVALID;
/*
* The next object in the graph after the imposition of the label
* will be the DPO contributed by the path through which the packets
* are to be sent. We stack the MPLS Label DPO on this path DPO
*/
fib_path_contribute_forwarding(path_ext->fpe_path_index,
parent_fct,
&via_dpo);
if (dpo_is_drop(&via_dpo) ||
load_balance_is_drop(&via_dpo))
{
/*
* don't stack a path extension on a drop. doing so will create
* a LB bucket entry on drop, and we will lose a percentage of traffic.
*/
}
else
{
vec_add2(nhs, nh, 1);
nh->path_weight = fib_path_get_weight(path_ext->fpe_path_index);
nh->path_index = path_ext->fpe_path_index;
dpo_copy(&nh->path_dpo, &via_dpo);
/*
* The label is stackable for this chain type
* construct the mpls header that will be imposed in the data-path
*/
if (!fib_path_ext_is_imp_null(path_ext))
{
/*
* we use the parent protocol for the label so that
* we pickup the correct MPLS imposition nodes to do
* ip[46] processing.
*/
dpo_id_t parent = DPO_INVALID;
dpo_proto_t chain_proto;
mpls_eos_bit_t eos;
eos = (child_fct == FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS ?
MPLS_NON_EOS :
MPLS_EOS);
chain_proto = fib_forw_chain_type_to_dpo_proto(child_fct);
dpo_copy(&parent, &nh->path_dpo);
mpls_label_dpo_create(path_ext->fpe_label_stack,
eos,
chain_proto,
fib_path_ext_mpls_flags_to_mpls_label(
path_ext->fpe_mpls_flags),
&parent,
&nh->path_dpo);
dpo_reset(&parent);
}
else if (child_fct == FIB_FORW_CHAIN_TYPE_MPLS_EOS)
{
/*
* MPLS EOS packets using an imp-null. Insert the disposition.
*/
fib_path_stack_mpls_disp(nh->path_index,
fib_forw_chain_type_to_dpo_proto(parent_fct),
path_ext->fpe_label_stack[0].fml_mode,
&nh->path_dpo);
}
}
dpo_reset(&via_dpo);
return (nhs);
}
fib_path_ext_t *
fib_path_ext_list_find (const fib_path_ext_list_t *list,
fib_path_ext_type_t ext_type,
const fib_route_path_t *rpath)
{
fib_path_ext_t *path_ext;
vec_foreach(path_ext, list->fpel_exts)
{
if ((path_ext->fpe_type == ext_type) &&
!fib_path_ext_cmp(path_ext, rpath) )
{
return (path_ext);
}
}
return (NULL);
}
fib_path_ext_t *
fib_path_ext_list_find_by_path_index (const fib_path_ext_list_t *list,
fib_node_index_t path_index)
{
fib_path_ext_t *path_ext;
if (NULL != list)
{
vec_foreach(path_ext, list->fpel_exts)
{
if (path_ext->fpe_path_index == path_index)
{
return (path_ext);
}
}
}
return (NULL);
}
fib_path_ext_t *
fib_path_ext_list_push_back (fib_path_ext_list_t *list,
fib_node_index_t path_list_index,
fib_path_ext_type_t ext_type,
const fib_route_path_t *rpath)
{
fib_path_ext_t *path_ext;
path_ext = fib_path_ext_list_find(list, ext_type, rpath);
if (NULL == path_ext)
{
vec_add2(list->fpel_exts, path_ext, 1);
fib_path_ext_init(path_ext, path_list_index, ext_type, rpath);
}
return (path_ext);
}
/*
* insert, sorted, a path extension to the entry's list.
* It's not strictly necessary to sort the path extensions, since each
* extension has the path index to which it resolves. However, by being
* sorted the load-balance produced has a deterministic order, not an order
* based on the sequence of extension additions. this is a considerable benefit.
*/
fib_path_ext_t *
fib_path_ext_list_insert (fib_path_ext_list_t *list,
fib_node_index_t path_list_index,
fib_path_ext_type_t ext_type,
const fib_route_path_t *rpath)
{
fib_path_ext_t new_path_ext, *path_ext;
int i = 0;
if (0 == fib_path_ext_list_length(list))
{
return (fib_path_ext_list_push_back(list, path_list_index,
ext_type, rpath));
}
fib_path_ext_init(&new_path_ext, path_list_index, ext_type, rpath);
vec_foreach(path_ext, list->fpel_exts)
{
int res = fib_path_ext_cmp(path_ext, rpath);
if (0 == res)
{
/*
* don't add duplicate extensions. modify instead
*/
vec_free(path_ext->fpe_label_stack);
*path_ext = new_path_ext;
goto done;
}
else if (res < 0)
{
i++;
}
else
{
break;
}
}
vec_insert_elts(list->fpel_exts, &new_path_ext, 1, i);
done:
return (&(list->fpel_exts[i]));
}
void
fib_path_ext_list_resolve (fib_path_ext_list_t *list,
fib_node_index_t path_list_index)
{
fib_path_ext_t *path_ext;
vec_foreach(path_ext, list->fpel_exts)
{
fib_path_ext_resolve(path_ext, path_list_index);
};
}
void
fib_path_ext_list_remove (fib_path_ext_list_t *list,
fib_path_ext_type_t ext_type,
const fib_route_path_t *rpath)
{
fib_path_ext_t *path_ext;
path_ext = fib_path_ext_list_find(list, ext_type, rpath);
if (NULL != path_ext)
{
/*
* delete the element moving the remaining elements down 1 position.
* this preserves the sorted order.
*/
vec_free(path_ext->fpe_label_stack);
vec_delete(list->fpel_exts, 1, (path_ext - list->fpel_exts));
}
}
void
fib_path_ext_list_flush (fib_path_ext_list_t *list)
{
fib_path_ext_t *path_ext;
vec_foreach(path_ext, list->fpel_exts)
{
vec_free(path_ext->fpe_label_stack);
};
vec_free(list->fpel_exts);
list->fpel_exts = NULL;
}
u8*
format_fib_path_ext_list (u8 * s, va_list * args)
{
fib_path_ext_list_t *list;
fib_path_ext_t *path_ext;
list = va_arg (*args, fib_path_ext_list_t *);
if (fib_path_ext_list_length(list))
{
s = format(s, " Extensions:");
vec_foreach(path_ext, list->fpel_exts)
{
s = format(s, "\n %U", format_fib_path_ext, path_ext);
};
}
return (s);
}
int
fib_path_ext_list_length (const fib_path_ext_list_t *list)
{
return (vec_len(list->fpel_exts));
}