-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.html
983 lines (568 loc) · 46.4 KB
/
index.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
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
<!DOCTYPE HTML>
<html >
<head>
<meta charset="UTF-8">
<title>QToolKit</title>
<meta name="viewport" content="width=device-width, initial-scale=1,user-scalable=no">
<meta name="author" content="Jim">
<meta name="description" content="An GUI ToolKit for desktop & mobile applcations based on HTML5 Canvas.">
<meta property="og:type" content="website">
<meta property="og:title" content="QToolKit">
<meta property="og:url" content="https://qtoolkit.github.io/index.html">
<meta property="og:site_name" content="QToolKit">
<meta property="og:description" content="An GUI ToolKit for desktop & mobile applcations based on HTML5 Canvas.">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="QToolKit">
<meta name="twitter:description" content="An GUI ToolKit for desktop & mobile applcations based on HTML5 Canvas.">
<link rel="alternative" href="/atom.xml" title="QToolKit" type="application/atom+xml">
<link rel="icon" href="/img/favicon.ico">
<link rel="apple-touch-icon" href="/img/jacman.jpg">
<link rel="apple-touch-icon-precomposed" href="/img/jacman.jpg">
<link rel="stylesheet" href="/css/style.css">
</head>
<body>
<header>
<div>
<div id="imglogo">
<a href="/"><img src="/img/logo.png" alt="QToolKit" title="QToolKit"/></a>
</div>
<div id="textlogo">
<h1 class="site-name"><a href="/" title="QToolKit">QToolKit</a></h1>
<h2 class="blog-motto">An GUI ToolKit for desktop & mobile applcations based on HTML5 Canvas.</h2>
</div>
<div class="navbar"><a class="navbutton navmobile" href="#" title="Menu">
</a></div>
<nav class="animated">
<ul>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/archives">Archives</a></li>
<li><a href="/2016/07/31/about/">About</a></li>
<li>
<form class="search" action="//google.com/search" method="get" accept-charset="utf-8">
<label>Search</label>
<input type="search" id="search" name="q" autocomplete="off" maxlength="20" placeholder="Search" />
<input type="hidden" name="q" value="site:qtoolkit.github.io">
</form>
</li>
</ul>
</nav>
</div>
</header>
<div id="container">
<div id="main">
<article class="post-expand post" itemprop="articleBody">
<header class="article-info clearfix">
<h1 itemprop="name">
<a href="/2017/01/08/Makefile-cmake-node-gyp中区分不同平台的方法/" title="Makefile/cmake/node-gyp中区分不同平台的方法" itemprop="url">Makefile/cmake/node-gyp中区分不同平台的方法</a>
</h1>
<p class="article-author">By
<a href="/about" title="Jim" target="_blank" itemprop="author">Jim</a>
<p class="article-time">
<time datetime="2017-01-08T09:31:13.000Z" itemprop="datePublished"> Published 2017-01-08</time>
</p>
</header>
<div class="article-content">
<p>最近用<a href="https://github.com/qtoolkit/qtk" target="_blank" rel="external">QTK</a>开发一个下载(下载到开发板)工具,同时用到了Makefile/cmake和node-gyp,而且都要针对不同平台做不同的处理。这里做个记录,以备以后有需要时查阅。</p>
<h2 id="Makefile"><a href="#Makefile" class="headerlink" title="Makefile"></a>Makefile</h2><p>在Makefile中,可以用OS变量判断当前系统是否是Windows,然后用uname来判断当前系统是MacOS还是其它系统。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line">ifeq ($(OS),Windows_NT)</div><div class="line"> PLATFORM="Windows"</div><div class="line">else</div><div class="line"> ifeq ($(shell uname),Darwin)</div><div class="line"> PLATFORM="MacOS"</div><div class="line"> else</div><div class="line"> PLATFORM="Unix-Like"</div><div class="line"> endif</div><div class="line">endif</div><div class="line"></div><div class="line">all:</div><div class="line"> @echo $(PLATFORM)</div></pre></td></tr></table></figure>
<h2 id="cmake"><a href="#cmake" class="headerlink" title="cmake"></a>cmake</h2><p>在cmake中,可以通过APPLE变量判断当前系统是否是MacOS,通过UNIX变量判断当前系统是否是UNIX,其它则认为是Windows。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">if(APPLE)</div><div class="line">//APPLE</div><div class="line">elseif(UNIX)</div><div class="line">//UNIX</div><div class="line">else()</div><div class="line">//Windows</div><div class="line">endif()</div></pre></td></tr></table></figure>
<h2 id="node-gyp"><a href="#node-gyp" class="headerlink" title="node-gyp"></a>node-gyp</h2><p>在binding.gyp中,可以在conditions添加不同平台的处理。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line">'conditions': [</div><div class="line"> ['OS=="mac"', {</div><div class="line"> 'xcode_settings': {</div><div class="line"> 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES'</div><div class="line"> },</div><div class="line"> "sources": ["native/serial/src/impl/list_ports/list_ports_osx.cc","native/serial/src/impl/unix.cc"]</div><div class="line"> },</div><div class="line"> 'OS=="win"', {</div><div class="line"> "sources": ["native/serial/src/impl/list_ports/list_ports_win.cc","native/serial/src/impl/win.cc"],</div><div class="line"> 'libraries': [</div><div class="line"> '-lsetupapi.lib',</div><div class="line"> '-lws2_32.lib'</div><div class="line"> ]</div><div class="line"> }]</div><div class="line">]</div></pre></td></tr></table></figure>
<p class="article-more-link">
</p>
</div>
<footer class="article-footer clearfix">
<div class="article-catetags">
<div class="article-categories">
<span></span>
<a class="article-category-link" href="/categories/Tools/">Tools</a>
</div>
<div class="article-tags">
<span></span> <a href="/tags/Makefile/">Makefile</a><a href="/tags/cmake/">cmake</a>
</div>
</div>
<div class="comments-count">
</div>
</footer>
</article>
<article class="post-expand post" itemprop="articleBody">
<header class="article-info clearfix">
<h1 itemprop="name">
<a href="/2016/09/26/QTK-Demos/" title="QTK Demos" itemprop="url">QTK Demos</a>
</h1>
<p class="article-author">By
<a href="/about" title="Jim" target="_blank" itemprop="author">Jim</a>
<p class="article-time">
<time datetime="2016-09-26T03:32:16.000Z" itemprop="datePublished"> Published 2016-09-26</time>
</p>
</header>
<div class="article-content">
<p class="article-more-link">
</p>
</div>
<footer class="article-footer clearfix">
<div class="article-catetags">
</div>
<div class="comments-count">
</div>
</footer>
</article>
<article class="post-expand post" itemprop="articleBody">
<header class="article-info clearfix">
<h1 itemprop="name">
<a href="/2016/08/17/Main-Loop/" title="Main Loop" itemprop="url">Main Loop</a>
</h1>
<p class="article-author">By
<a href="/about" title="Jim" target="_blank" itemprop="author">Jim</a>
<p class="article-time">
<time datetime="2016-08-17T10:37:10.000Z" itemprop="datePublished"> Published 2016-08-17</time>
</p>
</header>
<div class="article-content">
<p><a href="https://github.com/qtoolkit/qtk" target="_blank" rel="external">QTK</a>中的Main Loop主要是管理QTK的渲染循环,与直接调用用requestAnimationFrame相比,它有下列好处:</p>
<p>1.多次请求重绘没有副作用。在QTK中每个控件的属性有变化时都需要重绘,控件并不需要知道别的控件有没有请求重绘,只管自己有变化时请求重绘就行了,这样势必出现重复请求重绘,MainLoop只在第一次请求重绘时才调用requestAnimationFrame,重复的请求只是增加一下计数。</p>
<p>2.把绘制分成绘制前,绘制和绘制后多个阶段。动画可以在绘制前这个阶段执行,这样参数的变化就能在本次绘制中体现出来,而一些不太重要的事情可以放到绘制后执行。</p>
<p>3.节省能源,绿色环保。控件有变化时请求重绘,没有变化时不需要重绘,只在有执行动画时才跑到最大帧率,而不是像游戏一样一直保持60FPS。</p>
<p>4.注册的回调函数会一直执行,直到注销为止。</p>
<p>使用方法如下(javascript):</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">function draw(evt) {</div><div class="line"> if(quit) {</div><div class="line"> qtk.MainLoop.off(qtk.MainLoop.DRAW, draw);</div><div class="line"> }</div><div class="line">}</div><div class="line">qtk.MainLoop.on(qtk.MainLoop.DRAW, draw);</div></pre></td></tr></table></figure>
<p class="article-more-link">
</p>
</div>
<footer class="article-footer clearfix">
<div class="article-catetags">
<div class="article-categories">
<span></span>
<a class="article-category-link" href="/categories/QToolKit/">QToolKit</a>
</div>
<div class="article-tags">
<span></span> <a href="/tags/QToolKit/">QToolKit</a><a href="/tags/MainLoop/">MainLoop</a>
</div>
</div>
<div class="comments-count">
</div>
</footer>
</article>
<article class="post-expand post" itemprop="articleBody">
<header class="article-info clearfix">
<h1 itemprop="name">
<a href="/2016/08/16/Image-Tile/" title="Image Tile" itemprop="url">Image Tile</a>
</h1>
<p class="article-author">By
<a href="/about" title="Jim" target="_blank" itemprop="author">Jim</a>
<p class="article-time">
<time datetime="2016-08-16T04:19:04.000Z" itemprop="datePublished"> Published 2016-08-16</time>
</p>
</header>
<div class="article-content">
<p><a href="https://github.com/qtoolkit/qtk" target="_blank" rel="external">QTK</a>中的ImageTile表示一个图块,它可以是一整张图片,也可以是图片中的一块区域。x和y表示图块的位置,w和h表示图块的宽度和高度。</p>
<p>ImageTile的主要功能有两个:</p>
<h4 id="加载指定URL的图片。"><a href="#加载指定URL的图片。" class="headerlink" title="加载指定URL的图片。"></a>加载指定URL的图片。</h4><p>URL通常包括两个部分,用#分隔,前面部分是大图的信息,后面是图块的信息,如果没有#,则表示整张图片。目前支持4种格式的URL:</p>
<p>1.普通图片URL。此时ImageTile表示整张图片。如:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">http://www.example.com/image.png</div></pre></td></tr></table></figure>
<p>2.普通图片URL+’#’+x{x}y{y}w{w}h{h},它表示指定位置(xy)和大小(wh)的子图。如:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">http://www.example.com/image.png#x10y10w100h100</div></pre></td></tr></table></figure>
<p>3.普通图片URL+’#’+r{行数}c{列数}i{索引},它表示把图片分成指定行数和列数等大小的图块,取其中第i块,i的取值范围为0到r*c。如:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">http://www.example.com/image.png#r3c3i0</div></pre></td></tr></table></figure>
<p>4.JSON文件URL+’#’+小图的名称,它表示TexturePacker生成的JSON Hash格式文件中的一个小图。如:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">http://www.example.com/images.json#0.png</div></pre></td></tr></table></figure>
<h4 id="将图块绘制在指定的HTML5-Canvas上。"><a href="#将图块绘制在指定的HTML5-Canvas上。" class="headerlink" title="将图块绘制在指定的HTML5 Canvas上。"></a>将图块绘制在指定的HTML5 Canvas上。</h4><p>ImageTile实现了多种绘制的方式,使用时指定绘制方式和目标区域的位置和大小,目前支持的绘制方式有:</p>
<p>1.缺省方式,将图块填满指定的区域。</p>
<p>2.居中方式,将图块按原大小绘制到指定区域的中间。</p>
<p>3.自动方式,将图块缩放显示到指定区域,保持图片的宽高不变。</p>
<p>4.特殊九宫格方式,将图块分成等大小的九块,按九宫格的方式显示。</p>
<p>5.水平三宫格方式,将图块按水平方向分成等大小的三块,左右两块分别显示在目标区域的左右两边,中间的一块缩放显示在目标区域的中间剩余部分。</p>
<p>6.垂直三宫格方式,将图块按垂直方向分成等大小的三块,上下两块分别显示在目标区域的上下两边,中间的一块缩放显示在目标区域的中间剩余部分。</p>
<p>7.水平平铺。水平方向平铺显示,垂直方向拉伸,如果想保证垂直方向不拉伸,请指定图块同样的高度。</p>
<p>8.垂直平铺。垂直方向平铺显示,水平方向拉伸,如果想保水平方向不拉伸,请指定图块同样的宽度。</p>
<p>9.平铺。水平和垂直方向均平铺显示。</p>
<p class="article-more-link">
</p>
</div>
<footer class="article-footer clearfix">
<div class="article-catetags">
<div class="article-categories">
<span></span>
<a class="article-category-link" href="/categories/QToolKit/">QToolKit</a>
</div>
<div class="article-tags">
<span></span> <a href="/tags/QToolKit/">QToolKit</a><a href="/tags/ImageTile/">ImageTile</a>
</div>
</div>
<div class="comments-count">
</div>
</footer>
</article>
<article class="post-expand post" itemprop="articleBody">
<header class="article-info clearfix">
<h1 itemprop="name">
<a href="/2016/08/07/Assets-Manager/" title="Assets Manager" itemprop="url">Assets Manager</a>
</h1>
<p class="article-author">By
<a href="/about" title="Jim" target="_blank" itemprop="author">Jim</a>
<p class="article-time">
<time datetime="2016-08-07T13:19:47.000Z" itemprop="datePublished"> Published 2016-08-07</time>
</p>
</header>
<div class="article-content">
<p><a href="https://github.com/qtoolkit/qtk" target="_blank" rel="external">QTK</a>中的Assets主要是对APP使用的资源进行管理,资源包括图片、声音、字体和其它数据。</p>
<p>1.加载指定的资源。加载指定URL的资源,返回一个Promise。如果资源已经加载,就直接从缓存中获取,如果没有加载,就从网络获取,并放入到缓存中。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">var asset = qtk.Assets.loadJSON("http://localhost:9876/base/www/not_exist.txt")</div><div class="line"> .then(json => {</div><div class="line"></div><div class="line"> }, err => {</div><div class="line"></div><div class="line"> });</div></pre></td></tr></table></figure>
<p>2.预先加载资源。通常在APP启动时,预先加载某些资源。把这些资源放到一个分组中,分组中每加载完成一个资源,就会触发加载进度事件,界面可以根据加载进度事件更新进度条,整个分组加载完成后才启动APP。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line">var items = [</div><div class="line"> {type:qtk.Assets.TEXT, src:"http://localhost:9876/base/www/test.txt"},</div><div class="line"> {type:qtk.Assets.JSON, src:"http://localhost:9876/base/www/test.json"},</div><div class="line"> {type:qtk.Assets.IMAGE, src:"http://localhost:9876/base/www/test.jpg"},</div><div class="line"> {type:qtk.Assets.BLOB, src:"http://localhost:9876/base/www/test.blob"}</div><div class="line">];</div><div class="line">var assets = new qtk.Assets.Group(items);</div><div class="line">assets.onProgress(function(info) {</div><div class="line"> if(info.total === info.loaded && info.loaded === items.length) {</div><div class="line"> done();</div><div class="line"> }</div><div class="line"> console.log(JSON.stringify(info));</div><div class="line">});</div></pre></td></tr></table></figure>
<p>3.清除缓存中的资源。一些资源在不需要时,可以从缓存中清除,以释放内存。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">qtk.Assets.clear("http://localhost:9876/base/www/test.jpg");</div></pre></td></tr></table></figure>
<p class="article-more-link">
</p>
</div>
<footer class="article-footer clearfix">
<div class="article-catetags">
<div class="article-categories">
<span></span>
<a class="article-category-link" href="/categories/QToolKit/">QToolKit</a>
</div>
<div class="article-tags">
<span></span> <a href="/tags/Assets/">Assets</a><a href="/tags/QToolKit/">QToolKit</a>
</div>
</div>
<div class="comments-count">
</div>
</footer>
</article>
<article class="post-expand post" itemprop="articleBody">
<header class="article-info clearfix">
<h1 itemprop="name">
<a href="/2016/08/06/Javascript-Test-Framework/" title="Javascript Test Framework" itemprop="url">Javascript Test Framework</a>
</h1>
<p class="article-author">By
<a href="/about" title="Jim" target="_blank" itemprop="author">Jim</a>
<p class="article-time">
<time datetime="2016-08-06T13:23:54.000Z" itemprop="datePublished"> Published 2016-08-06</time>
</p>
</header>
<div class="article-content">
<p>我决定从开始就对<a href="https://github.com/qtoolkit" target="_blank" rel="external">QToolKit</a>相关项目进行严格测试。由于对测试程序框架不熟悉,在选择测试程序框架时遇到一些问题。最初打算使用<a href="https://github.com/facebook/jest" target="_blank" rel="external">jest</a>,倒不是看中它有强大自动mock功能,而是相信facebook自己使用的东西错不了。但是我在测试程序中使用XMLHTTPRequest时,总是提示网络不可用。在网上找到的答案都是关于如何mock XMLHTTPRequest的,而我更想进行实际的网络请求测试。所以只好重新审视自己的需求,希望找一个真正合适的测试程序框架:</p>
<p>1.能够在真实浏览器中测试。除了<a href="https://github.com/karma-runner/karma" target="_blank" rel="external">karma</a>,好像没有什么可以选择。这货功能确实非常强大:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line">*.You want to test code in real browsers.</div><div class="line">*.You want to test code in multiple browsers (desktop, mobile, tablets, etc.).</div><div class="line">*.You want to execute your tests locally during development.</div><div class="line">*.You want to execute your tests on a continuous integration server.</div><div class="line">*.You want to execute your tests on every save.</div><div class="line">*.You love your terminal.</div><div class="line">*.You don't want your (testing) life to suck.</div><div class="line">*.You want to use Istanbul to automagically generate coverage reports.</div><div class="line">*.You want to use RequireJS for your source files.</div></pre></td></tr></table></figure>
<p>2.使用起来方便,支持同步和异步功能的测试。karma不是测试程序框架也不是assert库,还需要自己选择相应的插件。我开始选择的是<a href="https://github.com/jasmine/jasmine" target="_blank" rel="external">jasmine</a>,用jasmine的人很多,上手也很简单。用了两天后,发现没法测试异步函数(后来找到了相应的插件),又去研究了人气很高的<a href="https://github.com/mochajs/mocha" target="_blank" rel="external">mocha</a>,它对异步测试支持非常完美。果断选择了mocha, mocha也没有提供assert库,由使用者自己选择第三方assert库。我选择了<a href="https://github.com/tj/better-assert" target="_blank" rel="external">better-assert</a>,主要原因是它简单,而且合乎我的习惯。</p>
<p>3.能提供代码覆盖率的报表。karma也有converage相应的插件。使用起来比较方便。当然也有些小问题,一是源代码会被改得面目全非,如果有问题没法调试,所以调试版本需要关掉代码覆盖率的测试功能。二是第三方库也会被统计起来,而这些库通常没有专门的测试程序,这会拉低整体的覆盖率。为了让报表好看一点,也可以为这些库写一些测试程序。</p>
<p>4.方便集成github持续集成的功能。karma也支持第三方的持续集成系统,其中不少支持github,这一部分看起来比较简单,用到的时候再深入研究。</p>
<p><a href="https://github.com/qtoolkit" target="_blank" rel="external">QToolKit</a>是用Typescript开发的,先用tsc编译成JS,然后用webpack打包成一个文件,再使用上面的框架,整个过程还是比较流畅的:</p>
<p>1.先安装node及npm,为了避免不必要的麻烦,请安装最新的版本。</p>
<p>2.创建一个项目。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">mkdir foo</div><div class="line">cd foo</div><div class="line">npm init</div><div class="line"></div><div class="line">//test command输入下面的内容: </div><div class="line">//tsc && webpack && ./node_modules/karma/bin/karma start</div></pre></td></tr></table></figure>
<p>3.安装依赖的软件包,软件包比较多,建议使用<a href="https://npm.taobao.org/" target="_blank" rel="external">淘宝的镜像</a>。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">npm install karma karma-chrome-launcher karma-coverage karma-firefox-launcher karma-mocha mocha ts-loader typescript typings webpack --save</div></pre></td></tr></table></figure>
<p>4.初始化Typescript项目,生成tsconfig.json。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">tsc --init</div></pre></td></tr></table></figure>
<p>5.编写代码。</p>
<p>src/sum.ts</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">export = function sum(x:number, y:number) : number {</div><div class="line"> return x + y;</div><div class="line">}</div></pre></td></tr></table></figure>
<p>src/index.ts</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">export import sum = require("./sum");</div></pre></td></tr></table></figure>
<p><strong>tests</strong>/sum.test.js<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">describe('sum', function() {</div><div class="line"> it('test sum', () => {</div><div class="line"> assert(foo.sum(100, 200) === 300);;</div><div class="line"> });</div><div class="line">});</div></pre></td></tr></table></figure></p>
<p>6.创建一个webpack的配置文件webpack.config.js。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line">var webpack = require('webpack');</div><div class="line">var libraryName = 'foo';</div><div class="line"></div><div class="line">module.exports = {</div><div class="line"> cache: true,</div><div class="line"> entry: {</div><div class="line"> index : './src/index.js'</div><div class="line"> },</div><div class="line"> output: {</div><div class="line"> path: '',</div><div class="line"> filename: '[name].js',</div><div class="line"> library: libraryName</div><div class="line"> },</div><div class="line"> resolve: {</div><div class="line"> extensions: ['', '.webpack.js', '.web.js', '.js']</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>7.创建karma的配置文件,先运行下面的命令,再手工修改:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">./node_modules/karma/bin/karma init</div></pre></td></tr></table></figure>
<p>加入测试需要的JS文件:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">files: [</div><div class="line"> 'index.js',</div><div class="line"> '__tests__/assert.js',</div><div class="line"> '__tests__/*.test.js'</div><div class="line">],</div></pre></td></tr></table></figure>
<p>增加覆盖率支持:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">preprocessors: {</div><div class="line"> 'index.js': ['coverage']</div><div class="line">},</div><div class="line"></div><div class="line">reporters: ['progress', 'coverage'],</div><div class="line"></div><div class="line">overageReporter: {</div><div class="line"> type : 'html',</div><div class="line"> dir : 'coverage/'</div><div class="line">},</div></pre></td></tr></table></figure>
<p>基本功能完成了,运行测试:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">npm run test</div></pre></td></tr></table></figure>
<p>这时会自动启动浏览器进行测试,浏览器中有个Debug按钮,点击Debug按钮可以打开被测试的页面,如果有问题可以在浏览器中调试。覆盖率的数据在coverage目录下,这个是在karma的配置文件中指定的。</p>
<p>里面的配置参数很多,等用到了再去研究。</p>
<p>参考:<a href="https://github.com/qtoolkit/foo" target="_blank" rel="external">Foo</a></p>
<p class="article-more-link">
</p>
</div>
<footer class="article-footer clearfix">
<div class="article-catetags">
<div class="article-categories">
<span></span>
<a class="article-category-link" href="/categories/学习笔记/">学习笔记</a>
</div>
<div class="article-tags">
<span></span> <a href="/tags/Test/">Test</a><a href="/tags/Karma/">Karma</a><a href="/tags/Mocha/">Mocha</a>
</div>
</div>
<div class="comments-count">
</div>
</footer>
</article>
<article class="post-expand post" itemprop="articleBody">
<header class="article-info clearfix">
<h1 itemprop="name">
<a href="/2016/08/05/hello-world/" title="Hello Hexo" itemprop="url">Hello Hexo</a>
</h1>
<p class="article-author">By
<a href="/about" title="Jim" target="_blank" itemprop="author">Jim</a>
<p class="article-time">
<time datetime="2016-08-05T13:19:47.000Z" itemprop="datePublished"> Published 2016-08-05</time>
</p>
</header>
<div class="article-content">
<p>Welcome to <a href="https://hexo.io/" target="_blank" rel="external">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/" target="_blank" rel="external">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html" target="_blank" rel="external">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues" target="_blank" rel="external">GitHub</a>.</p>
<h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$ hexo new <span class="string">"My New Post"</span></div></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/writing.html" target="_blank" rel="external">Writing</a></p>
<h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$ hexo server</div></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/server.html" target="_blank" rel="external">Server</a></p>
<h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$ hexo generate</div></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/generating.html" target="_blank" rel="external">Generating</a></p>
<h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$ hexo deploy</div></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/deployment.html" target="_blank" rel="external">Deployment</a></p>
<p class="article-more-link">
</p>
</div>
<footer class="article-footer clearfix">
<div class="article-catetags">
</div>
<div class="comments-count">
</div>
</footer>
</article>
<article class="post-expand post" itemprop="articleBody">
<header class="article-info clearfix">
<h1 itemprop="name">
<a href="/2016/07/31/about/" title="About QToolKit" itemprop="url">About QToolKit</a>
</h1>
<p class="article-author">By
<a href="/about" title="Jim" target="_blank" itemprop="author">Jim</a>
<p class="article-time">
<time datetime="2016-07-31T13:01:41.000Z" itemprop="datePublished"> Published 2016-07-31</time>
</p>
</header>
<div class="article-content">
<p>QTK 是一套基于HTML5 Canvas实现的应用程序框架,和其它HTML5的框架相比,它并不适合开发网页,而是专注于应用程序开发。</p>
<p>QTK主要特色如下:</p>
<p>1.<strong>基于HTML5 Canvas实现</strong>。可以实现任何Native风格的控件,HTML5 Canvas使用硬件加速,轻松实现60FPS的动画。</p>
<p>2.<strong>高效率,低功耗</strong>。JS代码针对V8优化,执行效率高。在界面有变化时才重新绘制,支持脏矩形,只绘制变化的部分,让计算开销降到最低。</p>
<p>3.<strong>用QTK本身开发的IDE</strong>。支持在线版本和本地版本,让开发变得更简单。</p>
<p>4.<strong>即可以开发移动应用程序,又可以开发桌面应用程序</strong>。QTK内部抽象出两者的不同,在运行时自动安装相应的策略。</p>
<p>5.<strong>与传统HTML5控件良好互通</strong>。可以在QTK中使用HTML5元素,也可以在HTML5的控件中使用QTK。我们还计划支持React和WebComponent的编程方式。</p>
<p>6.<strong>完整的测试程序</strong>。QTK使用Karma + Mocha对所以组件进行测试,通过不断完善测试程序,让你没有后顾之忧。</p>
<p>7.<strong>完整的文档和示例</strong>。确保已经实现的控件,对使用者都是友好的,你可以无障碍的使用它们,请告诉我们任何让你产生挫折的地方,一定会得到优先解决。在开发的过程中我们也会在博客中写出QTK内部实现原理,以及做出某些决策的原因。</p>
<p class="article-more-link">
</p>
</div>
<footer class="article-footer clearfix">
<div class="article-catetags">
<div class="article-categories">
<span></span>
<a class="article-category-link" href="/categories/QToolKit/">QToolKit</a>
</div>
<div class="article-tags">
<span></span> <a href="/tags/QToolKit/">QToolKit</a><a href="/tags/About/">About</a>
</div>
</div>
<div class="comments-count">
</div>
</footer>
</article>
<article class="post-expand post" itemprop="articleBody">
<header class="article-info clearfix">
<h1 itemprop="name">
<a href="/2016/07/31/Use-whatwg-fetch-Typescript/" title="Use whatwg-fetch In Typescript" itemprop="url">Use whatwg-fetch In Typescript</a>
</h1>
<p class="article-author">By
<a href="/about" title="Jim" target="_blank" itemprop="author">Jim</a>
<p class="article-time">
<time datetime="2016-07-31T04:16:18.000Z" itemprop="datePublished"> Published 2016-07-31</time>
</p>
</header>
<div class="article-content">
<p>说来惭愧,最近才知道的<a href="https://fetch.spec.whatwg.org/" target="_blank" rel="external">whatwg-fetch</a>的这个标准,firefox和chrome已经支持它了,github实现了相应的<a href="https://github.com/github/fetch.git" target="_blank" rel="external">polyfill</a>,typings里也有相应的定义,所以决定在<a href="https://github.com/qtoolkit/qtk" target="_blank" rel="external">qtk</a>里直接使用,而不是再去包装XMLHttpRequest。</p>
<h4 id="安装JS包"><a href="#安装JS包" class="headerlink" title="安装JS包"></a>安装JS包</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">cnpm install es6-promise --save</div><div class="line">cnpm install whatwg-fetch --save</div></pre></td></tr></table></figure>
<h4 id="安装typings"><a href="#安装typings" class="headerlink" title="安装typings"></a>安装typings</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">typings install dt~es6-promise --save --global</div><div class="line">typings install dt~whatwg-fetch --save --global</div></pre></td></tr></table></figure>
<h4 id="引入相应的包"><a href="#引入相应的包" class="headerlink" title="引入相应的包"></a>引入相应的包</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">import Promise = require("es6-promise");</div><div class="line">import fetch = require("whatwg-fetch");</div></pre></td></tr></table></figure>
<p>却奇怪的是出现错误:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">error TS2307: Cannot find module 'whatwg-fetch'.</div></pre></td></tr></table></figure></p>
<p>查了一些资料才知道,这种polyfill,只是修改了一些全局的状态,并没有导出什么东西的包,应该用下面的方式导入:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">import 'whatwg-fetch';</div></pre></td></tr></table></figure>
<p>还是typescript不熟悉啊,得花点时间系统的学习一下。</p>
<p>参考:<a href="https://www.typescriptlang.org/docs/handbook/modules.html#import-a-module-for-side-effects-only" target="_blank" rel="external">https://www.typescriptlang.org/docs/handbook/modules.html</a></p>
<p class="article-more-link">
</p>
</div>
<footer class="article-footer clearfix">
<div class="article-catetags">
<div class="article-categories">
<span></span>
<a class="article-category-link" href="/categories/学习笔记/">学习笔记</a>
</div>
<div class="article-tags">
<span></span> <a href="/tags/Typescript/">Typescript</a><a href="/tags/whatwg-fetch/">whatwg-fetch</a>
</div>
</div>
<div class="comments-count">
</div>
</footer>
</article>
</div>
<div class="openaside"><a class="navbutton" href="#" title="Show Sidebar"></a></div>
<div id="asidepart">
<div class="closeaside"><a class="closebutton" href="#" title="Hide Sidebar"></a></div>
<aside class="clearfix">
<div class="github-card">
<p class="asidetitle">Github Card</p>
<div class="github-card" data-github="qtoolkit" data-width="220" data-height="119" data-theme="medium">
<script type="text/javascript" src="//cdn.jsdelivr.net/github-cards/latest/widget.js" ></script>
</div>
</div>
<div class="categorieslist">
<p class="asidetitle">Categories</p>
<ul>
<li><a href="/categories/QToolKit/" title="QToolKit">QToolKit<sup>4</sup></a></li>
<li><a href="/categories/Tools/" title="Tools">Tools<sup>1</sup></a></li>
<li><a href="/categories/学习笔记/" title="学习笔记">学习笔记<sup>2</sup></a></li>
</ul>
</div>
<div class="tagslist">
<p class="asidetitle">Tags</p>
<ul class="clearfix">
<li><a href="/tags/QToolKit/" title="QToolKit">QToolKit<sup>4</sup></a></li>
<li><a href="/tags/Test/" title="Test">Test<sup>1</sup></a></li>
<li><a href="/tags/Makefile/" title="Makefile">Makefile<sup>1</sup></a></li>
<li><a href="/tags/cmake/" title="cmake">cmake<sup>1</sup></a></li>
<li><a href="/tags/MainLoop/" title="MainLoop">MainLoop<sup>1</sup></a></li>
<li><a href="/tags/ImageTile/" title="ImageTile">ImageTile<sup>1</sup></a></li>
<li><a href="/tags/Assets/" title="Assets">Assets<sup>1</sup></a></li>
<li><a href="/tags/Karma/" title="Karma">Karma<sup>1</sup></a></li>
<li><a href="/tags/Mocha/" title="Mocha">Mocha<sup>1</sup></a></li>
<li><a href="/tags/Typescript/" title="Typescript">Typescript<sup>1</sup></a></li>
<li><a href="/tags/whatwg-fetch/" title="whatwg-fetch">whatwg-fetch<sup>1</sup></a></li>
<li><a href="/tags/About/" title="About">About<sup>1</sup></a></li>
</ul>
</div>
<div class="linkslist">
<p class="asidetitle">Links</p>
<ul>
<li>
<a href="https://coderq.com" target="_blank" title="一个面向程序员交流分享的新一代社区">码农圈</a>
</li>
<li>
<a href="http://wuchong.me" target="_blank" title="Jark's Blog">Jark's Blog</a>
</li>
</ul>
</div>
<div class="rsspart">
<a href="/atom.xml" target="_blank" title="rss">RSS</a>
</div>
<div class="weiboshow">
<p class="asidetitle">Weibo</p>
<iframe width="100%" height="119" class="share_self" frameborder="0" scrolling="no" src="http://widget.weibo.com/weiboshow/index.php?language=&width=0&height=119&fansRow=2&ptype=1&speed=0&skin=9&isTitle=1&noborder=1&isWeibo=0&isFans=0&uid=null&verifier=b3593ceb&dpc=1"></iframe>
</div>
</aside>
</div>
</div>
<footer><div id="footer" >
<div class="line">
<span></span>
<div class="author"></div>
</div>
<section class="info">
<p> QToolKit <br/>
An GUI ToolKit for desktop & mobile applcations based on HTML5 Canvas.</p>
</section>
<div class="social-font" class="clearfix">
<a href="http://weibo.com/xianjimli" target="_blank" class="icon-weibo" title="微博"></a>
<a href="https://github.com/qtoolkit" target="_blank" class="icon-github" title="github"></a>
</div>
<p class="copyright">
Powered by <a href="http://hexo.io" target="_blank" title="hexo">hexo</a> and Theme by <a href="https://github.com/wuchong/jacman" target="_blank" title="Jacman">Jacman</a> © 2017
<a href="/about" target="_blank" title="Jim">Jim</a>
</p>
</div>
</footer>
<script src="/js/jquery-2.0.3.min.js"></script>
<script src="/js/jquery.imagesloaded.min.js"></script>
<script src="/js/gallery.js"></script>
<script src="/js/jquery.qrcode-0.12.0.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$('.navbar').click(function(){
$('header nav').toggleClass('shownav');
});
var myWidth = 0;
function getSize(){
if( typeof( window.innerWidth ) == 'number' ) {
myWidth = window.innerWidth;
} else if( document.documentElement && document.documentElement.clientWidth) {
myWidth = document.documentElement.clientWidth;
};
};
var m = $('#main'),
a = $('#asidepart'),
c = $('.closeaside'),
o = $('.openaside');
c.click(function(){
a.addClass('fadeOut').css('display', 'none');
o.css('display', 'block').addClass('fadeIn');
m.addClass('moveMain');
});
o.click(function(){
o.css('display', 'none').removeClass('beforeFadeIn');
a.css('display', 'block').removeClass('fadeOut').addClass('fadeIn');
m.removeClass('moveMain');
});
$(window).scroll(function(){
o.css("top",Math.max(80,260-$(this).scrollTop()));
});
$(window).resize(function(){
getSize();
if (myWidth >= 1024) {
$('header nav').removeClass('shownav');
}else{
m.removeClass('moveMain');
a.css('display', 'block').removeClass('fadeOut');
o.css('display', 'none');
}
});
});
</script>
<link rel="stylesheet" href="/fancybox/jquery.fancybox.css" media="screen" type="text/css">
<script src="/fancybox/jquery.fancybox.pack.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$('.article-content').each(function(i){
$(this).find('img').each(function(){
if ($(this).parent().hasClass('fancybox')) return;
var alt = this.alt;
if (alt) $(this).after('<span class="caption">' + alt + '</span>');
$(this).wrap('<a href="' + this.src + '" title="' + alt + '" class="fancybox"></a>');
});
$(this).find('.fancybox').each(function(){
$(this).attr('rel', 'article' + i);
});
});
if($.fancybox){
$('.fancybox').fancybox();
}
});
</script>
<!-- Analytics Begin -->
<script>
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?e6d1f421bbc9962127a50488f9ed37d1";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
<!-- Analytics End -->
<!-- Totop Begin -->
<div id="totop">
<a title="Back to Top"><img src="/img/scrollup.png"/></a>
</div>
<script src="/js/totop.js"></script>
<!-- Totop End -->
<!-- MathJax Begin -->
<!-- mathjax config similar to math.stackexchange -->
<!-- MathJax End -->
<!-- Tiny_search Begin -->
<!-- Tiny_search End -->
</body>
</html>