-
Notifications
You must be signed in to change notification settings - Fork 0
/
README.md.html
521 lines (518 loc) · 44.6 KB
/
README.md.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>README</title>
<style>.markdown-preview:not([data-use-github-style]) { padding: 2em; font-size: 1.2em; color: rgb(85, 85, 85); background-color: white; overflow: auto; }
.markdown-preview:not([data-use-github-style]) > :first-child { margin-top: 0px; }
.markdown-preview:not([data-use-github-style]) h1, .markdown-preview:not([data-use-github-style]) h2, .markdown-preview:not([data-use-github-style]) h3, .markdown-preview:not([data-use-github-style]) h4, .markdown-preview:not([data-use-github-style]) h5, .markdown-preview:not([data-use-github-style]) h6 { line-height: 1.2; margin-top: 1.5em; margin-bottom: 0.5em; color: rgb(3, 3, 3); }
.markdown-preview:not([data-use-github-style]) h1 { font-size: 2.4em; font-weight: 300; }
.markdown-preview:not([data-use-github-style]) h2 { font-size: 1.8em; font-weight: 400; }
.markdown-preview:not([data-use-github-style]) h3 { font-size: 1.5em; font-weight: 500; }
.markdown-preview:not([data-use-github-style]) h4 { font-size: 1.2em; font-weight: 600; }
.markdown-preview:not([data-use-github-style]) h5 { font-size: 1.1em; font-weight: 600; }
.markdown-preview:not([data-use-github-style]) h6 { font-size: 1em; font-weight: 600; }
.markdown-preview:not([data-use-github-style]) strong { color: rgb(3, 3, 3); }
.markdown-preview:not([data-use-github-style]) del { color: rgb(126, 126, 126); }
.markdown-preview:not([data-use-github-style]) a, .markdown-preview:not([data-use-github-style]) a code { color: black; }
.markdown-preview:not([data-use-github-style]) img { max-width: 100%; }
.markdown-preview:not([data-use-github-style]) > p { margin-top: 0px; margin-bottom: 1.5em; }
.markdown-preview:not([data-use-github-style]) > ul, .markdown-preview:not([data-use-github-style]) > ol { margin-bottom: 1.5em; }
.markdown-preview:not([data-use-github-style]) blockquote { margin: 1.5em 0px; font-size: inherit; color: rgb(126, 126, 126); border-color: rgb(214, 214, 214); border-width: 4px; }
.markdown-preview:not([data-use-github-style]) hr { margin: 3em 0px; border-top: 2px dashed rgb(214, 214, 214); background: none; }
.markdown-preview:not([data-use-github-style]) table { margin: 1.5em 0px; }
.markdown-preview:not([data-use-github-style]) th { color: rgb(3, 3, 3); }
.markdown-preview:not([data-use-github-style]) th, .markdown-preview:not([data-use-github-style]) td { padding: 0.66em 1em; border: 1px solid rgb(214, 214, 214); }
.markdown-preview:not([data-use-github-style]) code { color: rgb(3, 3, 3); background-color: rgb(240, 240, 240); }
.markdown-preview:not([data-use-github-style]) pre.editor-colors { margin: 1.5em 0px; padding: 1em; font-size: 0.92em; border-radius: 3px; background-color: rgb(245, 245, 245); }
.markdown-preview:not([data-use-github-style]) kbd { color: rgb(3, 3, 3); border-width: 1px 1px 2px; border-style: solid; border-color: rgb(214, 214, 214) rgb(214, 214, 214) rgb(199, 199, 199); border-image: initial; background-color: rgb(240, 240, 240); }
.markdown-preview[data-use-github-style] { font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; line-height: 1.6; word-wrap: break-word; padding: 30px; font-size: 16px; color: rgb(51, 51, 51); background-color: rgb(255, 255, 255); overflow: scroll; }
.markdown-preview[data-use-github-style] > :first-child { margin-top: 0px !important; }
.markdown-preview[data-use-github-style] > :last-child { margin-bottom: 0px !important; }
.markdown-preview[data-use-github-style] a:not([href]) { color: inherit; text-decoration: none; }
.markdown-preview[data-use-github-style] .absent { color: rgb(204, 0, 0); }
.markdown-preview[data-use-github-style] .anchor { position: absolute; top: 0px; left: 0px; display: block; padding-right: 6px; padding-left: 30px; margin-left: -30px; }
.markdown-preview[data-use-github-style] .anchor:focus { outline: none; }
.markdown-preview[data-use-github-style] h1, .markdown-preview[data-use-github-style] h2, .markdown-preview[data-use-github-style] h3, .markdown-preview[data-use-github-style] h4, .markdown-preview[data-use-github-style] h5, .markdown-preview[data-use-github-style] h6 { position: relative; margin-top: 1em; margin-bottom: 16px; font-weight: bold; line-height: 1.4; }
.markdown-preview[data-use-github-style] h1 .octicon-link, .markdown-preview[data-use-github-style] h2 .octicon-link, .markdown-preview[data-use-github-style] h3 .octicon-link, .markdown-preview[data-use-github-style] h4 .octicon-link, .markdown-preview[data-use-github-style] h5 .octicon-link, .markdown-preview[data-use-github-style] h6 .octicon-link { display: none; color: rgb(0, 0, 0); vertical-align: middle; }
.markdown-preview[data-use-github-style] h1:hover .anchor, .markdown-preview[data-use-github-style] h2:hover .anchor, .markdown-preview[data-use-github-style] h3:hover .anchor, .markdown-preview[data-use-github-style] h4:hover .anchor, .markdown-preview[data-use-github-style] h5:hover .anchor, .markdown-preview[data-use-github-style] h6:hover .anchor { padding-left: 8px; margin-left: -30px; text-decoration: none; }
.markdown-preview[data-use-github-style] h1:hover .anchor .octicon-link, .markdown-preview[data-use-github-style] h2:hover .anchor .octicon-link, .markdown-preview[data-use-github-style] h3:hover .anchor .octicon-link, .markdown-preview[data-use-github-style] h4:hover .anchor .octicon-link, .markdown-preview[data-use-github-style] h5:hover .anchor .octicon-link, .markdown-preview[data-use-github-style] h6:hover .anchor .octicon-link { display: inline-block; }
.markdown-preview[data-use-github-style] h1 tt, .markdown-preview[data-use-github-style] h2 tt, .markdown-preview[data-use-github-style] h3 tt, .markdown-preview[data-use-github-style] h4 tt, .markdown-preview[data-use-github-style] h5 tt, .markdown-preview[data-use-github-style] h6 tt, .markdown-preview[data-use-github-style] h1 code, .markdown-preview[data-use-github-style] h2 code, .markdown-preview[data-use-github-style] h3 code, .markdown-preview[data-use-github-style] h4 code, .markdown-preview[data-use-github-style] h5 code, .markdown-preview[data-use-github-style] h6 code { font-size: inherit; }
.markdown-preview[data-use-github-style] h1 { padding-bottom: 0.3em; font-size: 2.25em; line-height: 1.2; border-bottom: 1px solid rgb(238, 238, 238); }
.markdown-preview[data-use-github-style] h1 .anchor { line-height: 1; }
.markdown-preview[data-use-github-style] h2 { padding-bottom: 0.3em; font-size: 1.75em; line-height: 1.225; border-bottom: 1px solid rgb(238, 238, 238); }
.markdown-preview[data-use-github-style] h2 .anchor { line-height: 1; }
.markdown-preview[data-use-github-style] h3 { font-size: 1.5em; line-height: 1.43; }
.markdown-preview[data-use-github-style] h3 .anchor { line-height: 1.2; }
.markdown-preview[data-use-github-style] h4 { font-size: 1.25em; }
.markdown-preview[data-use-github-style] h4 .anchor { line-height: 1.2; }
.markdown-preview[data-use-github-style] h5 { font-size: 1em; }
.markdown-preview[data-use-github-style] h5 .anchor { line-height: 1.1; }
.markdown-preview[data-use-github-style] h6 { font-size: 1em; color: rgb(119, 119, 119); }
.markdown-preview[data-use-github-style] h6 .anchor { line-height: 1.1; }
.markdown-preview[data-use-github-style] p, .markdown-preview[data-use-github-style] blockquote, .markdown-preview[data-use-github-style] ul, .markdown-preview[data-use-github-style] ol, .markdown-preview[data-use-github-style] dl, .markdown-preview[data-use-github-style] table, .markdown-preview[data-use-github-style] pre { margin-top: 0px; margin-bottom: 16px; }
.markdown-preview[data-use-github-style] hr { height: 4px; padding: 0px; margin: 16px 0px; background-color: rgb(231, 231, 231); border: 0px none; }
.markdown-preview[data-use-github-style] ul, .markdown-preview[data-use-github-style] ol { padding-left: 2em; }
.markdown-preview[data-use-github-style] ul.no-list, .markdown-preview[data-use-github-style] ol.no-list { padding: 0px; list-style-type: none; }
.markdown-preview[data-use-github-style] ul ul, .markdown-preview[data-use-github-style] ul ol, .markdown-preview[data-use-github-style] ol ol, .markdown-preview[data-use-github-style] ol ul { margin-top: 0px; margin-bottom: 0px; }
.markdown-preview[data-use-github-style] li > p { margin-top: 16px; }
.markdown-preview[data-use-github-style] dl { padding: 0px; }
.markdown-preview[data-use-github-style] dl dt { padding: 0px; margin-top: 16px; font-size: 1em; font-style: italic; font-weight: bold; }
.markdown-preview[data-use-github-style] dl dd { padding: 0px 16px; margin-bottom: 16px; }
.markdown-preview[data-use-github-style] blockquote { padding: 0px 15px; color: rgb(119, 119, 119); border-left: 4px solid rgb(221, 221, 221); }
.markdown-preview[data-use-github-style] blockquote > :first-child { margin-top: 0px; }
.markdown-preview[data-use-github-style] blockquote > :last-child { margin-bottom: 0px; }
.markdown-preview[data-use-github-style] table { display: block; width: 100%; overflow: auto; word-break: keep-all; }
.markdown-preview[data-use-github-style] table th { font-weight: bold; }
.markdown-preview[data-use-github-style] table th, .markdown-preview[data-use-github-style] table td { padding: 6px 13px; border: 1px solid rgb(221, 221, 221); }
.markdown-preview[data-use-github-style] table tr { background-color: rgb(255, 255, 255); border-top: 1px solid rgb(204, 204, 204); }
.markdown-preview[data-use-github-style] table tr:nth-child(2n) { background-color: rgb(248, 248, 248); }
.markdown-preview[data-use-github-style] img { max-width: 100%; box-sizing: border-box; }
.markdown-preview[data-use-github-style] .emoji { max-width: none; }
.markdown-preview[data-use-github-style] span.frame { display: block; overflow: hidden; }
.markdown-preview[data-use-github-style] span.frame > span { display: block; float: left; width: auto; padding: 7px; margin: 13px 0px 0px; overflow: hidden; border: 1px solid rgb(221, 221, 221); }
.markdown-preview[data-use-github-style] span.frame span img { display: block; float: left; }
.markdown-preview[data-use-github-style] span.frame span span { display: block; padding: 5px 0px 0px; clear: both; color: rgb(51, 51, 51); }
.markdown-preview[data-use-github-style] span.align-center { display: block; overflow: hidden; clear: both; }
.markdown-preview[data-use-github-style] span.align-center > span { display: block; margin: 13px auto 0px; overflow: hidden; text-align: center; }
.markdown-preview[data-use-github-style] span.align-center span img { margin: 0px auto; text-align: center; }
.markdown-preview[data-use-github-style] span.align-right { display: block; overflow: hidden; clear: both; }
.markdown-preview[data-use-github-style] span.align-right > span { display: block; margin: 13px 0px 0px; overflow: hidden; text-align: right; }
.markdown-preview[data-use-github-style] span.align-right span img { margin: 0px; text-align: right; }
.markdown-preview[data-use-github-style] span.float-left { display: block; float: left; margin-right: 13px; overflow: hidden; }
.markdown-preview[data-use-github-style] span.float-left span { margin: 13px 0px 0px; }
.markdown-preview[data-use-github-style] span.float-right { display: block; float: right; margin-left: 13px; overflow: hidden; }
.markdown-preview[data-use-github-style] span.float-right > span { display: block; margin: 13px auto 0px; overflow: hidden; text-align: right; }
.markdown-preview[data-use-github-style] code, .markdown-preview[data-use-github-style] tt { padding: 0.2em 0px; margin: 0px; font-size: 85%; background-color: rgba(0, 0, 0, 0.0392157); border-radius: 3px; }
.markdown-preview[data-use-github-style] code::before, .markdown-preview[data-use-github-style] tt::before, .markdown-preview[data-use-github-style] code::after, .markdown-preview[data-use-github-style] tt::after { letter-spacing: -0.2em; content: " "; }
.markdown-preview[data-use-github-style] code br, .markdown-preview[data-use-github-style] tt br { display: none; }
.markdown-preview[data-use-github-style] del code { text-decoration: inherit; }
.markdown-preview[data-use-github-style] pre > code { padding: 0px; margin: 0px; font-size: 100%; word-break: normal; white-space: pre; background: transparent; border: 0px; }
.markdown-preview[data-use-github-style] .highlight { margin-bottom: 16px; }
.markdown-preview[data-use-github-style] .highlight pre, .markdown-preview[data-use-github-style] pre { padding: 16px; overflow: auto; font-size: 85%; line-height: 1.45; background-color: rgb(247, 247, 247); border-radius: 3px; }
.markdown-preview[data-use-github-style] .highlight pre { margin-bottom: 0px; word-break: normal; }
.markdown-preview[data-use-github-style] pre { word-wrap: normal; }
.markdown-preview[data-use-github-style] pre code, .markdown-preview[data-use-github-style] pre tt { display: inline; max-width: initial; padding: 0px; margin: 0px; overflow: initial; line-height: inherit; word-wrap: normal; background-color: transparent; border: 0px; }
.markdown-preview[data-use-github-style] pre code::before, .markdown-preview[data-use-github-style] pre tt::before, .markdown-preview[data-use-github-style] pre code::after, .markdown-preview[data-use-github-style] pre tt::after { content: normal; }
.markdown-preview[data-use-github-style] kbd { display: inline-block; padding: 3px 5px; font-size: 11px; line-height: 10px; color: rgb(85, 85, 85); vertical-align: middle; background-color: rgb(252, 252, 252); border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204) rgb(204, 204, 204) rgb(187, 187, 187); border-image: initial; border-radius: 3px; box-shadow: rgb(187, 187, 187) 0px -1px 0px inset; }
.markdown-preview[data-use-github-style] a { color: rgb(51, 122, 183); }
.markdown-preview[data-use-github-style] code { color: inherit; }
.markdown-preview[data-use-github-style] pre.editor-colors { padding: 0.8em 1em; margin-bottom: 1em; font-size: 0.85em; border-radius: 4px; overflow: auto; }
.scrollbars-visible-always .markdown-preview pre.editor-colors .vertical-scrollbar, .scrollbars-visible-always .markdown-preview pre.editor-colors .horizontal-scrollbar { visibility: hidden; }
.scrollbars-visible-always .markdown-preview pre.editor-colors:hover .vertical-scrollbar, .scrollbars-visible-always .markdown-preview pre.editor-colors:hover .horizontal-scrollbar { visibility: visible; }
.markdown-preview .task-list-item-checkbox { position: absolute; margin: 0.25em 0px 0px -1.4em; }
.markdown-preview:not([data-use-github-style]) { padding: 2em; font-size: 1.2em; color: rgb(85, 85, 85); background-color: white; overflow: auto; }
.markdown-preview:not([data-use-github-style]) > :first-child { margin-top: 0px; }
.markdown-preview:not([data-use-github-style]) h1, .markdown-preview:not([data-use-github-style]) h2, .markdown-preview:not([data-use-github-style]) h3, .markdown-preview:not([data-use-github-style]) h4, .markdown-preview:not([data-use-github-style]) h5, .markdown-preview:not([data-use-github-style]) h6 { line-height: 1.2; margin-top: 1.5em; margin-bottom: 0.5em; color: rgb(3, 3, 3); }
.markdown-preview:not([data-use-github-style]) h1 { font-size: 2.4em; font-weight: 300; }
.markdown-preview:not([data-use-github-style]) h2 { font-size: 1.8em; font-weight: 400; }
.markdown-preview:not([data-use-github-style]) h3 { font-size: 1.5em; font-weight: 500; }
.markdown-preview:not([data-use-github-style]) h4 { font-size: 1.2em; font-weight: 600; }
.markdown-preview:not([data-use-github-style]) h5 { font-size: 1.1em; font-weight: 600; }
.markdown-preview:not([data-use-github-style]) h6 { font-size: 1em; font-weight: 600; }
.markdown-preview:not([data-use-github-style]) strong { color: rgb(3, 3, 3); }
.markdown-preview:not([data-use-github-style]) del { color: rgb(126, 126, 126); }
.markdown-preview:not([data-use-github-style]) a, .markdown-preview:not([data-use-github-style]) a code { color: black; }
.markdown-preview:not([data-use-github-style]) img { max-width: 100%; }
.markdown-preview:not([data-use-github-style]) > p { margin-top: 0px; margin-bottom: 1.5em; }
.markdown-preview:not([data-use-github-style]) > ul, .markdown-preview:not([data-use-github-style]) > ol { margin-bottom: 1.5em; }
.markdown-preview:not([data-use-github-style]) blockquote { margin: 1.5em 0px; font-size: inherit; color: rgb(126, 126, 126); border-color: rgb(214, 214, 214); border-width: 4px; }
.markdown-preview:not([data-use-github-style]) hr { margin: 3em 0px; border-top: 2px dashed rgb(214, 214, 214); background: none; }
.markdown-preview:not([data-use-github-style]) table { margin: 1.5em 0px; }
.markdown-preview:not([data-use-github-style]) th { color: rgb(3, 3, 3); }
.markdown-preview:not([data-use-github-style]) th, .markdown-preview:not([data-use-github-style]) td { padding: 0.66em 1em; border: 1px solid rgb(214, 214, 214); }
.markdown-preview:not([data-use-github-style]) pre, .markdown-preview:not([data-use-github-style]) code { color: rgb(3, 3, 3); background-color: rgb(240, 240, 240); }
.markdown-preview:not([data-use-github-style]) pre, .markdown-preview:not([data-use-github-style]) pre.editor-colors { margin: 1.5em 0px; padding: 1em; font-size: 0.92em; border-radius: 3px; background-color: rgb(245, 245, 245); }
.markdown-preview:not([data-use-github-style]) kbd { color: rgb(3, 3, 3); border-width: 1px 1px 2px; border-style: solid; border-color: rgb(214, 214, 214) rgb(214, 214, 214) rgb(199, 199, 199); border-image: initial; background-color: rgb(240, 240, 240); }
.markdown-preview[data-use-github-style] { font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; line-height: 1.6; word-wrap: break-word; padding: 30px; font-size: 16px; color: rgb(51, 51, 51); background-color: rgb(255, 255, 255); overflow: scroll; }
.markdown-preview[data-use-github-style] > :first-child { margin-top: 0px !important; }
.markdown-preview[data-use-github-style] > :last-child { margin-bottom: 0px !important; }
.markdown-preview[data-use-github-style] a:not([href]) { color: inherit; text-decoration: none; }
.markdown-preview[data-use-github-style] .absent { color: rgb(204, 0, 0); }
.markdown-preview[data-use-github-style] .anchor { position: absolute; top: 0px; left: 0px; display: block; padding-right: 6px; padding-left: 30px; margin-left: -30px; }
.markdown-preview[data-use-github-style] .anchor:focus { outline: none; }
.markdown-preview[data-use-github-style] h1, .markdown-preview[data-use-github-style] h2, .markdown-preview[data-use-github-style] h3, .markdown-preview[data-use-github-style] h4, .markdown-preview[data-use-github-style] h5, .markdown-preview[data-use-github-style] h6 { position: relative; margin-top: 1em; margin-bottom: 16px; font-weight: bold; line-height: 1.4; }
.markdown-preview[data-use-github-style] h1 .octicon-link, .markdown-preview[data-use-github-style] h2 .octicon-link, .markdown-preview[data-use-github-style] h3 .octicon-link, .markdown-preview[data-use-github-style] h4 .octicon-link, .markdown-preview[data-use-github-style] h5 .octicon-link, .markdown-preview[data-use-github-style] h6 .octicon-link { display: none; color: rgb(0, 0, 0); vertical-align: middle; }
.markdown-preview[data-use-github-style] h1:hover .anchor, .markdown-preview[data-use-github-style] h2:hover .anchor, .markdown-preview[data-use-github-style] h3:hover .anchor, .markdown-preview[data-use-github-style] h4:hover .anchor, .markdown-preview[data-use-github-style] h5:hover .anchor, .markdown-preview[data-use-github-style] h6:hover .anchor { padding-left: 8px; margin-left: -30px; text-decoration: none; }
.markdown-preview[data-use-github-style] h1:hover .anchor .octicon-link, .markdown-preview[data-use-github-style] h2:hover .anchor .octicon-link, .markdown-preview[data-use-github-style] h3:hover .anchor .octicon-link, .markdown-preview[data-use-github-style] h4:hover .anchor .octicon-link, .markdown-preview[data-use-github-style] h5:hover .anchor .octicon-link, .markdown-preview[data-use-github-style] h6:hover .anchor .octicon-link { display: inline-block; }
.markdown-preview[data-use-github-style] h1 tt, .markdown-preview[data-use-github-style] h2 tt, .markdown-preview[data-use-github-style] h3 tt, .markdown-preview[data-use-github-style] h4 tt, .markdown-preview[data-use-github-style] h5 tt, .markdown-preview[data-use-github-style] h6 tt, .markdown-preview[data-use-github-style] h1 code, .markdown-preview[data-use-github-style] h2 code, .markdown-preview[data-use-github-style] h3 code, .markdown-preview[data-use-github-style] h4 code, .markdown-preview[data-use-github-style] h5 code, .markdown-preview[data-use-github-style] h6 code { font-size: inherit; }
.markdown-preview[data-use-github-style] h1 { padding-bottom: 0.3em; font-size: 2.25em; line-height: 1.2; border-bottom: 1px solid rgb(238, 238, 238); }
.markdown-preview[data-use-github-style] h1 .anchor { line-height: 1; }
.markdown-preview[data-use-github-style] h2 { padding-bottom: 0.3em; font-size: 1.75em; line-height: 1.225; border-bottom: 1px solid rgb(238, 238, 238); }
.markdown-preview[data-use-github-style] h2 .anchor { line-height: 1; }
.markdown-preview[data-use-github-style] h3 { font-size: 1.5em; line-height: 1.43; }
.markdown-preview[data-use-github-style] h3 .anchor { line-height: 1.2; }
.markdown-preview[data-use-github-style] h4 { font-size: 1.25em; }
.markdown-preview[data-use-github-style] h4 .anchor { line-height: 1.2; }
.markdown-preview[data-use-github-style] h5 { font-size: 1em; }
.markdown-preview[data-use-github-style] h5 .anchor { line-height: 1.1; }
.markdown-preview[data-use-github-style] h6 { font-size: 1em; color: rgb(119, 119, 119); }
.markdown-preview[data-use-github-style] h6 .anchor { line-height: 1.1; }
.markdown-preview[data-use-github-style] p, .markdown-preview[data-use-github-style] blockquote, .markdown-preview[data-use-github-style] ul, .markdown-preview[data-use-github-style] ol, .markdown-preview[data-use-github-style] dl, .markdown-preview[data-use-github-style] table, .markdown-preview[data-use-github-style] pre { margin-top: 0px; margin-bottom: 16px; }
.markdown-preview[data-use-github-style] hr { height: 4px; padding: 0px; margin: 16px 0px; background-color: rgb(231, 231, 231); border: 0px none; }
.markdown-preview[data-use-github-style] ul, .markdown-preview[data-use-github-style] ol { padding-left: 2em; }
.markdown-preview[data-use-github-style] ul.no-list, .markdown-preview[data-use-github-style] ol.no-list { padding: 0px; list-style-type: none; }
.markdown-preview[data-use-github-style] ul ul, .markdown-preview[data-use-github-style] ul ol, .markdown-preview[data-use-github-style] ol ol, .markdown-preview[data-use-github-style] ol ul { margin-top: 0px; margin-bottom: 0px; }
.markdown-preview[data-use-github-style] li > p { margin-top: 16px; }
.markdown-preview[data-use-github-style] dl { padding: 0px; }
.markdown-preview[data-use-github-style] dl dt { padding: 0px; margin-top: 16px; font-size: 1em; font-style: italic; font-weight: bold; }
.markdown-preview[data-use-github-style] dl dd { padding: 0px 16px; margin-bottom: 16px; }
.markdown-preview[data-use-github-style] blockquote { padding: 0px 15px; color: rgb(119, 119, 119); border-left: 4px solid rgb(221, 221, 221); }
.markdown-preview[data-use-github-style] blockquote > :first-child { margin-top: 0px; }
.markdown-preview[data-use-github-style] blockquote > :last-child { margin-bottom: 0px; }
.markdown-preview[data-use-github-style] table { display: block; width: 100%; overflow: auto; word-break: keep-all; }
.markdown-preview[data-use-github-style] table th { font-weight: bold; }
.markdown-preview[data-use-github-style] table th, .markdown-preview[data-use-github-style] table td { padding: 6px 13px; border: 1px solid rgb(221, 221, 221); }
.markdown-preview[data-use-github-style] table tr { background-color: rgb(255, 255, 255); border-top: 1px solid rgb(204, 204, 204); }
.markdown-preview[data-use-github-style] table tr:nth-child(2n) { background-color: rgb(248, 248, 248); }
.markdown-preview[data-use-github-style] img { max-width: 100%; box-sizing: border-box; }
.markdown-preview[data-use-github-style] .emoji { max-width: none; }
.markdown-preview[data-use-github-style] span.frame { display: block; overflow: hidden; }
.markdown-preview[data-use-github-style] span.frame > span { display: block; float: left; width: auto; padding: 7px; margin: 13px 0px 0px; overflow: hidden; border: 1px solid rgb(221, 221, 221); }
.markdown-preview[data-use-github-style] span.frame span img { display: block; float: left; }
.markdown-preview[data-use-github-style] span.frame span span { display: block; padding: 5px 0px 0px; clear: both; color: rgb(51, 51, 51); }
.markdown-preview[data-use-github-style] span.align-center { display: block; overflow: hidden; clear: both; }
.markdown-preview[data-use-github-style] span.align-center > span { display: block; margin: 13px auto 0px; overflow: hidden; text-align: center; }
.markdown-preview[data-use-github-style] span.align-center span img { margin: 0px auto; text-align: center; }
.markdown-preview[data-use-github-style] span.align-right { display: block; overflow: hidden; clear: both; }
.markdown-preview[data-use-github-style] span.align-right > span { display: block; margin: 13px 0px 0px; overflow: hidden; text-align: right; }
.markdown-preview[data-use-github-style] span.align-right span img { margin: 0px; text-align: right; }
.markdown-preview[data-use-github-style] span.float-left { display: block; float: left; margin-right: 13px; overflow: hidden; }
.markdown-preview[data-use-github-style] span.float-left span { margin: 13px 0px 0px; }
.markdown-preview[data-use-github-style] span.float-right { display: block; float: right; margin-left: 13px; overflow: hidden; }
.markdown-preview[data-use-github-style] span.float-right > span { display: block; margin: 13px auto 0px; overflow: hidden; text-align: right; }
.markdown-preview[data-use-github-style] code, .markdown-preview[data-use-github-style] tt { padding: 0.2em 0px; margin: 0px; font-size: 85%; background-color: rgba(0, 0, 0, 0.0392157); border-radius: 3px; }
.markdown-preview[data-use-github-style] code::before, .markdown-preview[data-use-github-style] tt::before, .markdown-preview[data-use-github-style] code::after, .markdown-preview[data-use-github-style] tt::after { letter-spacing: -0.2em; content: " "; }
.markdown-preview[data-use-github-style] code br, .markdown-preview[data-use-github-style] tt br { display: none; }
.markdown-preview[data-use-github-style] del code { text-decoration: inherit; }
.markdown-preview[data-use-github-style] pre > code { padding: 0px; margin: 0px; font-size: 100%; word-break: normal; white-space: pre; background: transparent; border: 0px; }
.markdown-preview[data-use-github-style] .highlight { margin-bottom: 16px; }
.markdown-preview[data-use-github-style] .highlight pre, .markdown-preview[data-use-github-style] pre { padding: 16px; overflow: auto; font-size: 85%; line-height: 1.45; background-color: rgb(247, 247, 247); border-radius: 3px; }
.markdown-preview[data-use-github-style] .highlight pre { margin-bottom: 0px; word-break: normal; }
.markdown-preview[data-use-github-style] pre { word-wrap: normal; }
.markdown-preview[data-use-github-style] pre code, .markdown-preview[data-use-github-style] pre tt { display: inline; max-width: initial; padding: 0px; margin: 0px; overflow: initial; line-height: inherit; word-wrap: normal; background-color: transparent; border: 0px; }
.markdown-preview[data-use-github-style] pre code::before, .markdown-preview[data-use-github-style] pre tt::before, .markdown-preview[data-use-github-style] pre code::after, .markdown-preview[data-use-github-style] pre tt::after { content: normal; }
.markdown-preview[data-use-github-style] kbd { display: inline-block; padding: 3px 5px; font-size: 11px; line-height: 10px; color: rgb(85, 85, 85); vertical-align: middle; background-color: rgb(252, 252, 252); border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204) rgb(204, 204, 204) rgb(187, 187, 187); border-image: initial; border-radius: 3px; box-shadow: rgb(187, 187, 187) 0px -1px 0px inset; }
.markdown-preview[data-use-github-style] a { color: rgb(51, 122, 183); }
.markdown-preview[data-use-github-style] pre, .markdown-preview[data-use-github-style] code { color: inherit; }
.markdown-preview[data-use-github-style] pre, .markdown-preview[data-use-github-style] pre.editor-colors { padding: 0.8em 1em; margin-bottom: 1em; font-size: 0.85em; border-radius: 4px; overflow: auto; }
.scrollbars-visible-always .markdown-preview pre.editor-colors .vertical-scrollbar, .scrollbars-visible-always .markdown-preview pre.editor-colors .horizontal-scrollbar { visibility: hidden; }
.scrollbars-visible-always .markdown-preview pre.editor-colors:hover .vertical-scrollbar, .scrollbars-visible-always .markdown-preview pre.editor-colors:hover .horizontal-scrollbar { visibility: visible; }
.markdown-preview del { text-decoration: none; position: relative; }
.markdown-preview del::after { border-bottom: 1px solid black; content: ""; left: 0px; position: absolute; right: 0px; top: 50%; }
.markdown-preview .flash { animation: flash 1s ease-out 1; outline: rgba(255, 0, 0, 0) solid 1px; }
.markdown-preview .flash:not(li) { display: block; }
.bracket-matcher .region {
border-bottom: 1px dotted lime;
position: absolute;
}
.line-number.bracket-matcher {
background-color: #777;
}
.markdown-themeable-pdf-page-break {
border-top: 2px dotted #0098ff;
}
.markdown-themeable-pdf-page-break span {
opacity: .35;
}
.spell-check-misspelling .region {
border-bottom: 2px dotted rgba(255, 51, 51, 0.75);
}
.spell-check-corrections {
width: 25em !important;
}
pre.editor-colors {
background-color: white;
color: #555;
}
pre.editor-colors .invisible-character {
color: rgba(85, 85, 85, 0.2);
}
pre.editor-colors .indent-guide {
color: rgba(85, 85, 85, 0.2);
}
pre.editor-colors .wrap-guide {
background-color: rgba(85, 85, 85, 0.2);
}
pre.editor-colors .gutter {
color: #555;
background: white;
}
pre.editor-colors .gutter .line-number.folded,
pre.editor-colors .gutter .line-number:after,
pre.editor-colors .fold-marker:after {
color: #e87b00;
}
pre.editor-colors .invisible {
color: #555;
}
pre.editor-colors .selection .region {
background-color: #e1e1e1;
}
pre.editor-colors .bracket-matcher .region {
background-color: #C9C9C9;
opacity: .7;
border-bottom: 0 none;
}
pre.editor-colors.is-focused .cursor {
border-color: black;
}
pre.editor-colors.is-focused .selection .region {
background-color: #afc4da;
}
pre.editor-colors.is-focused .line-number.cursor-line-no-selection,
pre.editor-colors.is-focused .line.cursor-line {
background-color: rgba(255, 255, 134, 0.34);
}
pre.editor-colors .syntax--source.syntax--gfm {
color: #444;
}
pre.editor-colors .syntax--gfm .syntax--markup.syntax--heading {
color: #111;
}
pre.editor-colors .syntax--gfm .syntax--link {
color: #888;
}
pre.editor-colors .syntax--gfm .syntax--variable.syntax--list {
color: #888;
}
pre.editor-colors .syntax--markdown .syntax--paragraph {
color: #444;
}
pre.editor-colors .syntax--markdown .syntax--heading {
color: #111;
}
pre.editor-colors .syntax--markdown .syntax--link {
color: #888;
}
pre.editor-colors .syntax--markdown .syntax--link .syntax--string {
color: #888;
}
.syntax--comment {
color: #999988;
font-style: italic;
}
.syntax--string {
color: #D14;
}
.syntax--string .syntax--source,
.syntax--string .syntax--meta.syntax--embedded.syntax--line {
color: #5A5A5A;
}
.syntax--string .syntax--punctuation.syntax--section.syntax--embedded {
color: #920B2D;
}
.syntax--string .syntax--punctuation.syntax--section.syntax--embedded .syntax--source {
color: #920B2D;
}
.syntax--constant.syntax--numeric {
color: #D14;
}
.syntax--constant.syntax--language {
color: #606aa1;
}
.syntax--constant.syntax--character,
.syntax--constant.syntax--other {
color: #606aa1;
}
.syntax--constant.syntax--symbol {
color: #990073;
}
.syntax--constant.syntax--numeric.syntax--line-number.syntax--find-in-files .syntax--match {
color: rgba(143, 190, 0, 0.63);
}
.syntax--variable {
color: #008080;
}
.syntax--variable.syntax--parameter {
color: #606aa1;
}
.syntax--keyword {
color: #222;
font-weight: bold;
}
.syntax--keyword.syntax--unit {
color: #445588;
}
.syntax--keyword.syntax--special-method {
color: #0086B3;
}
.syntax--storage {
color: #222;
}
.syntax--storage.syntax--type {
color: #222;
}
.syntax--entity.syntax--name.syntax--class {
text-decoration: underline;
color: #606aa1;
}
.syntax--entity.syntax--other.syntax--inherited-class {
text-decoration: underline;
color: #606aa1;
}
.syntax--entity.syntax--name.syntax--function {
color: #900;
}
.syntax--entity.syntax--name.syntax--tag {
color: #008080;
}
.syntax--entity.syntax--other.syntax--attribute-name {
color: #458;
font-weight: bold;
}
.syntax--entity.syntax--name.syntax--filename.syntax--find-in-files {
color: #E6DB74;
}
.syntax--support.syntax--constant,
.syntax--support.syntax--function,
.syntax--support.syntax--type {
color: #458;
}
.syntax--support.syntax--class {
color: #008080;
}
.syntax--invalid {
color: #F8F8F0;
background-color: #00A8C6;
}
.syntax--invalid.syntax--deprecated {
color: #F8F8F0;
background-color: #8FBE00;
}
.syntax--meta.syntax--structure.syntax--dictionary.syntax--json > .syntax--string.syntax--quoted.syntax--double.syntax--json,
.syntax--meta.syntax--structure.syntax--dictionary.syntax--json > .syntax--string.syntax--quoted.syntax--double.syntax--json .syntax--punctuation.syntax--string {
color: #000080;
}
.syntax--meta.syntax--structure.syntax--dictionary.syntax--value.syntax--json > .syntax--string.syntax--quoted.syntax--double.syntax--json {
color: #d14;
}
.syntax--meta.syntax--diff,
.syntax--meta.syntax--diff.syntax--header {
color: #75715E;
}
.syntax--css.syntax--support.syntax--property-name {
font-weight: bold;
color: #333;
}
.syntax--css.syntax--constant {
color: #099;
}
</style>
</head>
<body class='markdown-preview'><p><img src="C:\_wk\dds-launchpad-iot\docs\dover-iiot-logo-02.jpg?v=1514539943262" alt="Overview"></p>
<h1>DDS Launchpad IoT Proof Of Concept</h1>
<p>This sample project demonstrates the basics of the DDS Launchpad concepts. It will include the fundamental components of an IoT solution using Azure IoT Hub for device message ingress and Azure Service Fabric for device message access and processing.</p>
<h2>Setup</h2>
<ol>
<li><a href="https://www.visualstudio.com/">Install Visual Studio 2017</a>. Any version will do. Make sure you have the following workloads installed
<ul>
<li>Azure development</li>
<li>.NET Core cross-platform development</li>
</ul>
</li>
<li><a href="https://azure.microsoft.com/documentation/articles/service-fabric-get-started/">Set up your Service Fabric development environment</a>.</li>
<li><a href="https://azure.microsoft.com/documentation/articles/iot-hub-csharp-csharp-getstarted/#create-an-iot-hub">Create an IoT Hub in Azure</a> or use an
existing IoT Hub in your Azure subscription that is not currently being used in a production application. The sample application will run without IoT Hub, but you won’t be able to send devices messages through without it. If you’re creating a new IoT Hub to run the sample, you can simply use the <strong>F1 - Free</strong> tier under <strong>pricing and scale tier</strong> in the Azure portal.</li>
<li>While in Azure IoT Hub make sure to collect the IoT Hub Connection string for later use when configuring the Launchpad applications (…/Shared access policies/iothubowner/Connection string - primary key.)</li>
</ol>
<h2>Deploy</h2>
<ol>
<li>Make sure you have a local cluster running</li>
<li>Open a PowerShell window and CD to <code>service-fabric-dotnet-iot\build</code></li>
<li>Connect to your cluster using <code>Connect-ServiceFabricCluster</code>.</li>
<li>Run <code>.\deploy.ps1</code>
<ul>
<li>The deployment command defaults to a local 5-node cluster. If you’re running a different configuration, pass in the name of the publish profile you want to use. For example, for a one-node cluster, use <code>.\deploy.ps1 -PublishProfileName Local.1Node</code>.</li>
</ul>
</li>
</ol>
<h2>View application traces</h2>
<ol>
<li>Open the solution in Visual Studio.</li>
<li>Open the Diagnostics Event viewer: View -> Other Windows -> Diagnostic events</li>
<li>In the Diagnostics Event viewer, click the Configuration button with the gear icon, and replace the existing ETW providers with the following ETW providers, then click “Apply.”</li>
</ol>
<pre class="editor-colors"><div class="line"><span class="syntax--text syntax--plain syntax--null-grammar"><span>Microsoft-ServiceFabric-Services</span></span>
</div><div class="line"><span class="syntax--text syntax--plain syntax--null-grammar"><span>Microsoft-Launchpad.Iot.Admin.Application</span></span>
</div><div class="line"><span class="syntax--text syntax--plain syntax--null-grammar"><span>Microsoft-Launchpad.IoT.Admin.WebService</span></span>
</div><div class="line"><span class="syntax--text syntax--plain syntax--null-grammar"><span>Microsoft-Launchpad.IoT.EventsProcessor.Application</span></span>
</div><div class="line"><span class="syntax--text syntax--plain syntax--null-grammar"><span>Microsoft-Launchpad.IoT.EventsProcessor.RouterService</span></span>
</div><div class="line"><span class="syntax--text syntax--plain syntax--null-grammar"><span>Microsoft.Launchpad.IoT.Insight.Application</span></span>
</div><div class="line"><span class="syntax--text syntax--plain syntax--null-grammar"><span>Microsoft.Launchpad.IoT.Insigth.DataService</span></span>
</div><div class="line"><span class="syntax--text syntax--plain syntax--null-grammar"><span>Microsoft.Launchpad.IoT.Insigth.WebService</span></span>
</div></pre>
<h2>Have fun</h2>
<ol>
<li>Once the application deployment has completed, go to <code>http://localhost:8081/launchpad/iot</code> in a web browser to access the admin web UI.</li>
<li>Using the admin UI, create an Event Processor application. Give it any name, add the [IoT Hub connection string] collected earlier when doing the setup of the IoT Hub, and click "Add.</li>
<li>Using the admin UI, create an Insight application. Give it any name, any number of data service partitions, 1 web service instance if running locally, or -1 if running it Azure, and click “Add.”</li>
<li>Once the tenant application is created, click the “Web portal” link to see the application’s main page. <em>Note:</em> It may take a minute for the web portal to become available.</li>
<li>Run the simple device emulator that’s included with the sample under <code>dds-launchpad-iot\src\Iot.DeviceEmulator</code>.
<ol>
<li>Open then Insighton in Visual Studio 2015.</li>
<li>Set the Iot.DeviceEmulator project as the start-up project and press F5 or ctrl+F5 to run it.</li>
<li>Follow the instructions in the command prompt to register devices with IoT Hub and send messages to the Insight application created in step 3.</li>
</ol>
</li>
</ol>
<h2>Clean up</h2>
<ol>
<li>Open a PowerShell window and CD to <code>dds-launchpad-iot\build</code></li>
<li>To completely remove the sample from a cluster, run <code>.\obliterate.ps1</code></li>
<li>To clean all build output, run <code>.\clean.cmd</code>.</li>
</ol>
<h2>Conceptual overview</h2>
<p>In this example, the system allows an administrator to add any number of “insight” applications to the solution to consume messages from device field gateways through any number of IoT Hub instances. Customers (tenants) can view their devices and device messages through a Web UI. Messages sent from devices are expected to include a tenant name and device ID for the message ingestion application (Event Processor) to determine which tenant to send the message to.</p>
<p><img src="C:\_wk\dds-launchpad-iot\docs\architecture-01-page06.jpg?v=1514571123909" alt="Conceptual"></p>
<h3>Patterns demonstrated in this sample</h3>
<ul>
<li>Reading messages from IoT Hub with <a href="https://msdn.microsoft.com/library/microsoft.servicebus.messaging.eventhubreceiver.aspx">EventHubReceiver</a>. A partitioned stateful Service Fabric service provides a simple and intuitive way to read from IoT Hub partitions by simply mapping stateful service partitions to IoT Hub partitions one-to-one. This approach does not require any addition coordination or leasing between IoT Hub readers. Service Fabric manages creation, placement, availability, and scaling of the stateful service partitions. A Reliable Collection is used in each partition to keep track of the position, or <em>offset</em> in the IoT Hub event stream.</li>
<li>Multi-solution support using dynamically-created named application instances. An administrative application uses the Service Fabric management APIs to create a new named application instance for each new insight application, so that each application gets their own instance of the message storing and processing service, isolated from other applications.</li>
<li>Service-to-service communication using HTTP with <a href="http://ASP.NET">ASP.NET</a> Core. Services expose HTTP endpoints to communicate with other services.</li>
</ul>
<h2>Architectural overview</h2>
<p>This example makes use of several Azure products:</p>
<ul>
<li><strong>IoT Hub</strong> for device management and device message ingress.</li>
<li><strong>Service Fabric</strong> hosts the message processing applications.</li>
<li><strong>Azure Storage (optional)</strong> can optionally be used for long-term message storage, but is not shown in this example.</li>
</ul>
<p><img src="C:\_wk\dds-launchpad-iot\docs\architecture-01-page08.jpg?v=1514571129875" alt="Overview"></p>
<h3>Structure</h3>
<p>The solution is composed of three separate Service Fabric applications, each with their own set of services:</p>
<h4>Admin Application</h4>
<p>Used by an adminstrator to create instances of the Event Processor Application and Insight Application.</p>
<ul>
<li><strong>Web Service</strong>: The only service in this application, the web service is a stateless <a href="http://ASP.NET">ASP.NET</a> Core service that presents a management UI. API controllers perform Service Fabric management operations using <code>FabricClient</code>.</li>
</ul>
<h4>Events Processor Application</h4>
<p>An instance of this application connects to an IoT Hub, reads device events, and forwards data to the tenant application identified in the device event message.</p>
<ul>
<li><strong>Router Service</strong>: The only service in this application, the router service is the stateful partitioned service that connects to IoT Hub and forwards device messages to the appropriate tenant application.</li>
</ul>
<h4>Insight Application</h4>
<p>A customer (tenant) is the solution owner and will provide “insight” applications to satisfy specific domain related requirements. The solution will have a main customer (tenant), but it would support extending the solution to support additional related organizations such as clients, partners and even consumers. Event data flows from the edge devices into the insight applications for viewing and processing.</p>
<ul>
<li><strong>Data Service</strong>: This is a stateful service that holds the most recent device message for an insight application. This service is partitioned so that solutions with a large number of devices can scale horizontally to meet their requirements.</li>
<li><strong>Web Service</strong>: A stateless <a href="http://ASP.NET">ASP.NET</a> Core service that presents a UI for the tenant to see devices and their most recent messages.</li>
</ul>
<h3>Deployment</h3>
<p>This sample project <strong>does not</strong> create instances of each application during deployment time. The project is designed to create new application instances at runtime through the Admin UI. In order to create application instances at runtime, the application types must be registered at deployment time. A fresh deployment of this sample looks like this:</p>
<ul>
<li>LaunchpadIotAdminApplicationType</li>
<li>LaunchpadIotEventsProcessorApplicationType</li>
<li>LaunchpadIotInsightApplicationType</li>
</ul>
<p>Note that only the LaunchpadIoTAdminApplicationType has a named instance running. The other two application types are registered, but no named application instances are created by default. The web UI in the admin application is used to dynamically create named instances of the other two applications.</p>
<h3>Where we go from here</h3>
<p>The main purpose of this project is to demonstrate the fundamental patterns we expect to implement as part of the DDS iIoT Launchpad project.
The following diagram will give some idea of the scope of the project.
<img src="C:\_wk\dds-launchpad-iot\docs\architecture-01-page07.jpg?v=1514571580530" alt="Level 1 Solution - Basic">
The idea is to use the current POC project as the base for the implementation of the Phase I of the IoT Platform.
The phase I should create the artifacts that should support Basic IoT solutions.
In the following diagram we have a first exposure to the concept of IoT solution levels.
<img src="C:\_wk\dds-launchpad-iot\docs\architecture-01-page09.jpg?v=1514571776421" alt="iIoT Solution Levels Matrix">
The concepts behind each of one of those levels is beyond the scope of this document. It suffices to indicate that the “Basic” level escalates well in the dimension of data volumes but is very “economical” in the complexity axis. The idea is provide the basic foundations for the platforms and support the most common use cases.</p>
<!--Image references--></body>
</html>