普通视图

发现新文章,点击刷新页面。
昨天以前fun's Blog

Rust从没入门到放弃

作者 fun
2021年7月2日 08:00

最近业余学了大概有10来天rust了,已经手抄了好几个小项目的代码。跃跃欲试给自己找了几道题目玩玩,还挺好玩的hh

qa.rs

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
#![deny(warnings)]

fn main() {
let i = 0i64;
change_value();
assert_eq!(i, 1);
}

//
// Implement this function to run a successful `cargo run --release`.
//
// **NOTE**
// - do NOT change any existing codes except that `todo!()`
//
fn change_value() {
todo!()
}

#[cfg(test)]
mod test {
#[test]
fn test1() {
let mut a = Vec::new();
{
// fix this line to make this test pass
a[10000000] = 1;
}
assert_eq!(a[10000000], 1);
}

#[test]
fn test2() {
let a = async { "Hello World!" };
let b;
{
// fix this line to make this test pass
b = a();
}
assert_eq!(b, "Hello World!");
}
}

这道题的话就是要保证cargo run --release正常执行

大概三个问题:

  • main函数里的i变量需要在change_value修改为1,assert_eq!才能顺利执行
  • a数组第10000000个值设为1
  • 同步块里调用async函数a

第一题

1
2
3
4
5
6
7
8
9
fn main() {
let i = 0i64;
change_value();
assert_eq!(i, 1);
}

fn change_value() {
todo!()
}

按照我浅薄的理解,change_value里面是无法访问main块里作用域的,如果不把i传参进去,
要想把i改为1是不太可能的。如果只能在change_value里加逻辑的话理论上是做不到覆盖i的值。如果可以修改外面的代码话let mut = i; change_value(&mut i);即可。

复习了很多作用域的定义,还google了很多可能可以的办法,结论应该是不行…
但回到题目的要求:可以让这个程序正常运行,突然想到前几天写minigrep的时候用到的中断process::exit,既然i值理论上无法修改,但我可以在这个函数块里让进程停止运行,这样一来后面的assert_eq也就不会继续运行了hhh

第二题

1
2
3
4
5
let mut a = Vec::new();
{
// fix this line to make this test pass
a[10000000] = 1;
}

报错index out of bounds: the len is 0 but the index is 10000000
Vec的文档可以看到有个resize的方法

1
2
3
4
5
6
let mut a = Vec::new();
{
// fix this line to make this test pass
a.resize(10000001, 0);
a[10000000] = 1;
}

在前面加个resize,确保长度大于下面要赋值长度的

第三题

1
2
3
4
5
6
7
let a = async { "Hello World!" };
let b;
{
// fix this line to make this test pass
b = a();
}
assert_eq!(b, "Hello World!");

报错error[E0618]: expected function, found impl Future
这是要在同步函数里调用异步函数hh,google了下找到篇文章用了block_on

1
2
3
4
5
6
let a = async { "Hello World!" };
let b;
{
// fix this line to make this test pass
b = futures::executor::block_on(a);
}

这里引入了依赖库futures, 也试着找了下block_on最简单的实现看下能不能在不引入依赖的情况下自己实现block_on,但都看了下好复杂…

FunDB

第二道大题是个结构化的项目了里面有很多实现被抹去了,需要自己完善细节。
但实际的话这个项目相似度很高很多逻辑是重复相似的,仔细看很多实现都能在里面找到解,整体来讲都不难学习意义也挺大的。

题目:

  1. implement all todo!() in the codebase(stay relaxed, they are all very simple)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    src/helper.rs:155:        todo!()
    src/helper.rs:164: todo!()
    src/helper.rs:173: todo!()
    src/helper.rs:182: todo!()
    src/helper.rs:191: todo!()
    src/helper.rs:200: todo!()
    src/helper.rs:209: todo!()
    src/helper.rs:218: todo!()
    src/helper.rs:228: todo!()
    src/helper.rs:233: todo!()
    src/helper.rs:238: todo!()
    src/mapx/backend.rs:125: todo!()
    src/mapx/backend.rs:180: todo!()
    src/mapx/backend.rs:190: todo!()
    src/mapx/backend.rs:215: todo!()
    src/mapx/mod.rs:165: todo!()
    src/vecx/backend.rs:113: todo!()
    src/vecx/mod.rs:134: todo!()
    src/vecx/mod.rs:166: todo!()
    src/vecx/mod.rs:185: todo!()

分析

扩展了两种的支持持久化的数据结构,持久化是用rust写的sled嵌入式数据库做的

  • Mapx
  • Vecx

为了提高读取性能,会在内存中缓存一定量的数据,超出的部分需要从sled
整个代码主要是围绕实现这两个数据类型的,以及各种操作和运算+迭代器等相关操作的实现

helper.rs

Value对象的相关trait实现

Trait Deref Value

实现 Deref trait 允许我们重载 解引用运算符
详细:Rust 程序设计语言 - 通过 Deref trait 将智能指针当作常规引用处理

src/helper.rs:155: todo!() return Value reference
1
2
3
fn deref(&self) -> &Self::Target {
&self.value
}

Trait PartialEq + PartialOrd

等值比较和次序比较的运算符重载具体实现

src/helper.rs:164: todo!() other type is Value
1
2
3
fn eq(&self, other: &Value<'a, V>) -> bool {
self.value == other.value
}

另一个比对对象也是Value类型

src/helper.rs:173: todo!() other is reference V
1
2
3
fn eq(&self, other: &V) -> bool {
self.value.deref() == other
}

另一个对象是泛型

src/helper.rs:182: todo!() partial_cmp Option
1
2
3
fn partial_cmp(&self, other: &V) -> Option<Ordering> {
self.value.deref().partial_cmp(other)
}

次序比较

Trait From: convert any to Value

从任意值转换为Value对象, Value对象的value属性类型是Cow

src/helper.rs:191: todo!() v is any type
1
2
3
fn from(v: V) -> Self {
Value::new(Cow::Owned(v))
}

从任意类型

src/helper.rs:200: todo!() v type is is Cow
1
2
3
fn from(v: Cow<'a, V>) -> Self {
Value::new(v)
}

从Cow类型

src/helper.rs:209: todo!() v type is Value
1
2
3
fn from(v: Value<'a, V>) -> Self {
v.into_inner()
}

into_inner

src/helper.rs:218: todo!() v is referenece
1
2
3
fn from(v: &V) -> Self {
Value::new(Cow::Owned(v.clone()))
}

引用泛型v

sled helper function

初始化sled数据库,记录数的序列化存储读取

src/helper.rs:228: todo!() sled_open initliaze sled instance
1
2
3
4
5
6
7
8
9
pub(crate) fn sled_open(path: &str, is_tmp: bool) -> Result<sled::Db> {
let mut cf = sled::Config::default().path(path).mode(sled::Mode::HighThroughput)
.use_compression(false);

if is_tmp {
cf = cf.temporary(true);
}
cf.open().c(d!())
}

根据path 初始化seld数据库

src/helper.rs:233: todo!() read_db_len read counter
1
2
3
4
5
6
pub(crate) fn read_db_len(path: &str) -> Result<usize> {
let bytes = fs::read(path).unwrap();
let mut buffer = [0u8; 8];
buffer.copy_from_slice(&bytes[0..8]);
Ok(usize::from_le_bytes(buffer))
}

从文件读取数据长度

src/helper.rs:238: todo!() write_db_len save counter
1
2
3
pub(crate) fn write_db_len(path: &str, len: usize) -> Result<()> {
fs::write(path, usize::to_le_bytes(len)).c(d!())
}

序列化存储len到文件

mapx/backend.rs

Mapx基于sled的存储实现

Trait Iterator

迭代器

src/mapx/backend.rs:125: todo!() - create iterator
1
2
3
4
5
6
7
pub(super) fn iter(&self) -> MapxIter<K, V> {
MapxIter {
iter: self.db.iter(),
_pd0: PhantomData,
_pd1: PhantomData,
}
}

返回迭代器

src/mapx/backend.rs:180: todo!() - iterator next
1
2
3
4
5
6
7
8
9
10
11
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
.map(|v| v.ok())
.flatten()
.map(|(key, value)| {
(
pnk!(bincode::deserialize(&key)),
pnk!(serde_json::from_slice(&value)),
)
})
}

迭代器next实现,写入数据库做了序列化需要反序列化

src/mapx/backend.rs:190: todo!() - iterator next_back
1
2
3
4
5
6
7
8
9
10
11
12
fn next_back(&mut self) -> Option<Self::Item> {
self.iter
.next_back()
.map(|v| v.ok())
.flatten()
.map(|(key, value)| {
(
pnk!(bincode::deserialize(&key)),
pnk!(serde_json::from_slice(&value)),
)
})
}

迭代器next_back实现,同样写入数据库做了序列化需要反序列化

Trait PartialEq

Mapx对象的等值比较运算符重载

  • src/mapx/backend.rs:215: todo!() - compare is same
    1
    2
    3
    4
    5
    fn eq(&self, other: &Mapx<K, V>) -> bool {
    !self.iter()
    .zip(other.iter())
    .any(|(a, b)|{ a != b})
    }

迭代器对比每个值是否都一致

mapx/mod.rs

Mapx结构的具体实现

  • in_mem 存储了在内存里的数据
  • in_disk 是backend的Mapx的实例
  • in_mem_cnt 内存数据长度
src/mapx/mod.rs:165: todo!() - iter consider in mem and disk
1
2
3
4
5
6
7
8
9
10
11
pub fn iter(&self) -> Box<dyn Iterator<Item = (K, V)> + '_> {
if self.in_mem.len() == self.in_disk.len() {
Box::new(MapxIterMem {
iter: self.in_mem.iter(),
})
} else {
Box::new(MapxIter {
iter: self.in_disk.iter(),
})
}
}

如果内存里的数据长度和磁盘数据一致直接返回内存的迭代器

vecx/backend.rs

Vecx基于sled的存储实现

Trait Iterator

迭代器相关

src/vecx/backend.rs:113: todo!() create iterator
1
2
3
4
5
6
pub(super) fn iter(&self) -> VecxIter<T> {
VecxIter {
iter: self.db.iter(),
_pd: PhantomData
}
}

返回sled数据库迭代器

vecx/mod.rs

Vecx结构的具体实现

  • in_mem 存储在内存的数据 BTreeMap
  • in_disk 是backend的Vecx的实例
  • in_mem_cnt 内存数据长度

Iterator

src/vecx/mod.rs:134: todo!() create iterator: should consider in mem and disk
1
2
3
4
5
6
7
8
9
10
11
pub fn iter(&self) -> Box<dyn Iterator<Item = T> + '_> {
if self.in_mem.len() == self.in_disk.len() {
Box::new(VecxIterMem {
iter: self.in_mem.iter(),
})
} else {
Box::new(VecxIter {
iter: self.in_disk.iter(),
})
}
}

和Mapx一样优先从内存

src/vecx/mod.rs:166: todo!() VecxIter next backend iter
1
2
3
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|v| v.1)
}

数据库迭代器next实现

src/vecx/mod.rs:185: todo!() VecxIterMem next mem btree iter
1
2
3
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|v| v.1.clone())
}

内存迭代器next实现

基本上都是迭代器+运算符重载的回顾

Ant Design Vue Pro暗黑模式配置

作者 fun
2021年5月23日 08:00

Ant Design Vue Pro一直还没支持暗黑主题,主要是Ant Design Vue 1.7.x也还没支持暗黑模式。

不过我看了下2.1.2的Ant Design Vue里面是支持了暗黑主题的:

方式一:在样式文件全量引入 antd.dark.less

1
@import '~ant-design-vue/dist/antd.dark.less'; // 引入官方提供的暗色 less 样式入口文件

方式二: 是用在 webpack.config.js 使用 less-loader 按需引入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const { getThemeVariables } = require('ant-design-vue/dist/theme');
// webpack.config.js
module.exports = {
rules: [{
test: /\.less$/,
use: [{
loader: 'style-loader',
}, {
loader: 'css-loader', // translates CSS into CommonJS
}, {
loader: 'less-loader', // compiles Less to CSS
+ options: {
+ lessOptions: { // 如果使用less-loader@5,请移除 lessOptions 这一级直接配置选项。
+ modifyVars: getThemeVariables({
+ dark: true, // 开启暗黑模式
+ }),
+ javascriptEnabled: true,
+ },
+ },
}],
}],
};

看下了最新版的Ant Design Vue Pro,用的还是1.7.x的ant design vue。

其实也可以一个个重写颜色定义,但要适配的组件还是太多了,于是在想能不能把2.1.2的dark主题定义用到1.7.x,想必是可以直接用的。

看下了源码https://cdn.jsdelivr.net/npm/ant-design-vue@2.1.2/dist/theme.js

getThemeVariables里返回了一组less变量定义。

拿出里面的darkThemeSingle和darkThemeSingle新建一个dark.js

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
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005

var defaultTheme = {
// 'blue-base': '#1890ff',
'blue-base': '#5687bb',
'blue-1': "color(~`colorPalette('@{blue-6}', 1) `)",
'blue-2': "color(~`colorPalette('@{blue-6}', 2) `)",
'blue-3': "color(~`colorPalette('@{blue-6}', 3) `)",
'blue-4': "color(~`colorPalette('@{blue-6}', 4) `)",
'blue-5': "color(~`colorPalette('@{blue-6}', 5) `)",
'blue-6': '@blue-base',
'blue-7': "color(~`colorPalette('@{blue-6}', 7) `)",
'blue-8': "color(~`colorPalette('@{blue-6}', 8) `)",
'blue-9': "color(~`colorPalette('@{blue-6}', 9) `)",
'blue-10': "color(~`colorPalette('@{blue-6}', 10) `)",
'purple-base': '#722ed1',
'purple-1': "color(~`colorPalette('@{purple-6}', 1) `)",
'purple-2': "color(~`colorPalette('@{purple-6}', 2) `)",
'purple-3': "color(~`colorPalette('@{purple-6}', 3) `)",
'purple-4': "color(~`colorPalette('@{purple-6}', 4) `)",
'purple-5': "color(~`colorPalette('@{purple-6}', 5) `)",
'purple-6': '@purple-base',
'purple-7': "color(~`colorPalette('@{purple-6}', 7) `)",
'purple-8': "color(~`colorPalette('@{purple-6}', 8) `)",
'purple-9': "color(~`colorPalette('@{purple-6}', 9) `)",
'purple-10': "color(~`colorPalette('@{purple-6}', 10) `)",
'cyan-base': '#13c2c2',
'cyan-1': "color(~`colorPalette('@{cyan-6}', 1) `)",
'cyan-2': "color(~`colorPalette('@{cyan-6}', 2) `)",
'cyan-3': "color(~`colorPalette('@{cyan-6}', 3) `)",
'cyan-4': "color(~`colorPalette('@{cyan-6}', 4) `)",
'cyan-5': "color(~`colorPalette('@{cyan-6}', 5) `)",
'cyan-6': '@cyan-base',
'cyan-7': "color(~`colorPalette('@{cyan-6}', 7) `)",
'cyan-8': "color(~`colorPalette('@{cyan-6}', 8) `)",
'cyan-9': "color(~`colorPalette('@{cyan-6}', 9) `)",
'cyan-10': "color(~`colorPalette('@{cyan-6}', 10) `)",
'green-base': '#52c41a',
'green-1': "color(~`colorPalette('@{green-6}', 1) `)",
'green-2': "color(~`colorPalette('@{green-6}', 2) `)",
'green-3': "color(~`colorPalette('@{green-6}', 3) `)",
'green-4': "color(~`colorPalette('@{green-6}', 4) `)",
'green-5': "color(~`colorPalette('@{green-6}', 5) `)",
'green-6': '@green-base',
'green-7': "color(~`colorPalette('@{green-6}', 7) `)",
'green-8': "color(~`colorPalette('@{green-6}', 8) `)",
'green-9': "color(~`colorPalette('@{green-6}', 9) `)",
'green-10': "color(~`colorPalette('@{green-6}', 10) `)",
'magenta-base': '#eb2f96',
'magenta-1': "color(~`colorPalette('@{magenta-6}', 1) `)",
'magenta-2': "color(~`colorPalette('@{magenta-6}', 2) `)",
'magenta-3': "color(~`colorPalette('@{magenta-6}', 3) `)",
'magenta-4': "color(~`colorPalette('@{magenta-6}', 4) `)",
'magenta-5': "color(~`colorPalette('@{magenta-6}', 5) `)",
'magenta-6': '@magenta-base',
'magenta-7': "color(~`colorPalette('@{magenta-6}', 7) `)",
'magenta-8': "color(~`colorPalette('@{magenta-6}', 8) `)",
'magenta-9': "color(~`colorPalette('@{magenta-6}', 9) `)",
'magenta-10': "color(~`colorPalette('@{magenta-6}', 10) `)",
'pink-base': '#eb2f96',
'pink-1': "color(~`colorPalette('@{pink-6}', 1) `)",
'pink-2': "color(~`colorPalette('@{pink-6}', 2) `)",
'pink-3': "color(~`colorPalette('@{pink-6}', 3) `)",
'pink-4': "color(~`colorPalette('@{pink-6}', 4) `)",
'pink-5': "color(~`colorPalette('@{pink-6}', 5) `)",
'pink-6': '@pink-base',
'pink-7': "color(~`colorPalette('@{pink-6}', 7) `)",
'pink-8': "color(~`colorPalette('@{pink-6}', 8) `)",
'pink-9': "color(~`colorPalette('@{pink-6}', 9) `)",
'pink-10': "color(~`colorPalette('@{pink-6}', 10) `)",
'red-base': '#f5222d',
'red-1': "color(~`colorPalette('@{red-6}', 1) `)",
'red-2': "color(~`colorPalette('@{red-6}', 2) `)",
'red-3': "color(~`colorPalette('@{red-6}', 3) `)",
'red-4': "color(~`colorPalette('@{red-6}', 4) `)",
'red-5': "color(~`colorPalette('@{red-6}', 5) `)",
'red-6': '@red-base',
'red-7': "color(~`colorPalette('@{red-6}', 7) `)",
'red-8': "color(~`colorPalette('@{red-6}', 8) `)",
'red-9': "color(~`colorPalette('@{red-6}', 9) `)",
'red-10': "color(~`colorPalette('@{red-6}', 10) `)",
'orange-base': '#fa8c16',
'orange-1': "color(~`colorPalette('@{orange-6}', 1) `)",
'orange-2': "color(~`colorPalette('@{orange-6}', 2) `)",
'orange-3': "color(~`colorPalette('@{orange-6}', 3) `)",
'orange-4': "color(~`colorPalette('@{orange-6}', 4) `)",
'orange-5': "color(~`colorPalette('@{orange-6}', 5) `)",
'orange-6': '@orange-base',
'orange-7': "color(~`colorPalette('@{orange-6}', 7) `)",
'orange-8': "color(~`colorPalette('@{orange-6}', 8) `)",
'orange-9': "color(~`colorPalette('@{orange-6}', 9) `)",
'orange-10': "color(~`colorPalette('@{orange-6}', 10) `)",
'yellow-base': '#fadb14',
'yellow-1': "color(~`colorPalette('@{yellow-6}', 1) `)",
'yellow-2': "color(~`colorPalette('@{yellow-6}', 2) `)",
'yellow-3': "color(~`colorPalette('@{yellow-6}', 3) `)",
'yellow-4': "color(~`colorPalette('@{yellow-6}', 4) `)",
'yellow-5': "color(~`colorPalette('@{yellow-6}', 5) `)",
'yellow-6': '@yellow-base',
'yellow-7': "color(~`colorPalette('@{yellow-6}', 7) `)",
'yellow-8': "color(~`colorPalette('@{yellow-6}', 8) `)",
'yellow-9': "color(~`colorPalette('@{yellow-6}', 9) `)",
'yellow-10': "color(~`colorPalette('@{yellow-6}', 10) `)",
'volcano-base': '#fa541c',
'volcano-1': "color(~`colorPalette('@{volcano-6}', 1) `)",
'volcano-2': "color(~`colorPalette('@{volcano-6}', 2) `)",
'volcano-3': "color(~`colorPalette('@{volcano-6}', 3) `)",
'volcano-4': "color(~`colorPalette('@{volcano-6}', 4) `)",
'volcano-5': "color(~`colorPalette('@{volcano-6}', 5) `)",
'volcano-6': '@volcano-base',
'volcano-7': "color(~`colorPalette('@{volcano-6}', 7) `)",
'volcano-8': "color(~`colorPalette('@{volcano-6}', 8) `)",
'volcano-9': "color(~`colorPalette('@{volcano-6}', 9) `)",
'volcano-10': "color(~`colorPalette('@{volcano-6}', 10) `)",
'geekblue-base': '#2f54eb',
'geekblue-1': "color(~`colorPalette('@{geekblue-6}', 1) `)",
'geekblue-2': "color(~`colorPalette('@{geekblue-6}', 2) `)",
'geekblue-3': "color(~`colorPalette('@{geekblue-6}', 3) `)",
'geekblue-4': "color(~`colorPalette('@{geekblue-6}', 4) `)",
'geekblue-5': "color(~`colorPalette('@{geekblue-6}', 5) `)",
'geekblue-6': '@geekblue-base',
'geekblue-7': "color(~`colorPalette('@{geekblue-6}', 7) `)",
'geekblue-8': "color(~`colorPalette('@{geekblue-6}', 8) `)",
'geekblue-9': "color(~`colorPalette('@{geekblue-6}', 9) `)",
'geekblue-10': "color(~`colorPalette('@{geekblue-6}', 10) `)",
'lime-base': '#a0d911',
'lime-1': "color(~`colorPalette('@{lime-6}', 1) `)",
'lime-2': "color(~`colorPalette('@{lime-6}', 2) `)",
'lime-3': "color(~`colorPalette('@{lime-6}', 3) `)",
'lime-4': "color(~`colorPalette('@{lime-6}', 4) `)",
'lime-5': "color(~`colorPalette('@{lime-6}', 5) `)",
'lime-6': '@lime-base',
'lime-7': "color(~`colorPalette('@{lime-6}', 7) `)",
'lime-8': "color(~`colorPalette('@{lime-6}', 8) `)",
'lime-9': "color(~`colorPalette('@{lime-6}', 9) `)",
'lime-10': "color(~`colorPalette('@{lime-6}', 10) `)",
'gold-base': '#faad14',
'gold-1': "color(~`colorPalette('@{gold-6}', 1) `)",
'gold-2': "color(~`colorPalette('@{gold-6}', 2) `)",
'gold-3': "color(~`colorPalette('@{gold-6}', 3) `)",
'gold-4': "color(~`colorPalette('@{gold-6}', 4) `)",
'gold-5': "color(~`colorPalette('@{gold-6}', 5) `)",
'gold-6': '@gold-base',
'gold-7': "color(~`colorPalette('@{gold-6}', 7) `)",
'gold-8': "color(~`colorPalette('@{gold-6}', 8) `)",
'gold-9': "color(~`colorPalette('@{gold-6}', 9) `)",
'gold-10': "color(~`colorPalette('@{gold-6}', 10) `)",
'preset-colors': 'pink, magenta, red, volcano, orange, yellow, gold, cyan, lime, green, blue, geekblue,\n purple',
theme: 'default',
'ant-prefix': 'ant',
'html-selector': 'html',
'primary-color': '@blue-6',
'info-color': '@primary-color',
'success-color': '@green-6',
'processing-color': '@blue-6',
'error-color': '@red-5',
'highlight-color': '@red-5',
'warning-color': '@gold-6',
'normal-color': '#d9d9d9',
white: '#fff',
black: '#000',
'primary-1': "color(~`colorPalette('@{primary-color}', 1) `)",
'primary-2': "color(~`colorPalette('@{primary-color}', 2) `)",
'primary-3': "color(~`colorPalette('@{primary-color}', 3) `)",
'primary-4': "color(~`colorPalette('@{primary-color}', 4) `)",
'primary-5': "color(\n ~`colorPalette('@{primary-color}', 5) `\n)",
'primary-6': '@primary-color',
'primary-7': "color(~`colorPalette('@{primary-color}', 7) `)",
'primary-8': "color(~`colorPalette('@{primary-color}', 8) `)",
'primary-9': "color(~`colorPalette('@{primary-color}', 9) `)",
'primary-10': "color(~`colorPalette('@{primary-color}', 10) `)",
'body-background': '#fff',
'component-background': '#fff',
'popover-background': '@component-background',
'popover-customize-border-color': '@border-color-split',
'font-family':
"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,\n 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',\n 'Noto Color Emoji'",
'code-family': "'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace",
'text-color': 'fade(@black, 85%)',
'text-color-secondary': 'fade(@black, 45%)',
'text-color-inverse': '@white',
'icon-color': 'inherit',
'icon-color-hover': 'fade(@black, 75%)',
'heading-color': 'fade(@black, 85%)',
'text-color-dark': 'fade(@white, 85%)',
'text-color-secondary-dark': 'fade(@white, 65%)',
'text-selection-bg': '@primary-color',
'font-variant-base': 'tabular-nums',
'font-feature-settings-base': 'tnum',
'font-size-base': '14px',
'font-size-lg': '@font-size-base + 2px',
'font-size-sm': '12px',
'heading-1-size': 'ceil(@font-size-base * 2.71)',
'heading-2-size': 'ceil(@font-size-base * 2.14)',
'heading-3-size': 'ceil(@font-size-base * 1.71)',
'heading-4-size': 'ceil(@font-size-base * 1.42)',
'heading-5-size': 'ceil(@font-size-base * 1.14)',
'line-height-base': '1.5715',
'border-radius-base': '2px',
'border-radius-sm': '@border-radius-base',
'padding-lg': '24px',
'padding-md': '16px',
'padding-sm': '12px',
'padding-xs': '8px',
'padding-xss': '4px',
'control-padding-horizontal': '@padding-sm',
'control-padding-horizontal-sm': '@padding-xs',
'margin-lg': '24px',
'margin-md': '16px',
'margin-sm': '12px',
'margin-xs': '8px',
'margin-xss': '4px',
'height-base': '32px',
'height-lg': '40px',
'height-sm': '24px',
'item-active-bg': '@primary-1',
'item-hover-bg': '#f5f5f5',
'iconfont-css-prefix': 'anticon',
'link-color': '@primary-color',
'link-hover-color': "color(~`colorPalette('@{link-color}', 5) `)",
'link-active-color': "color(~`colorPalette('@{link-color}', 7) `)",
'link-decoration': 'none',
'link-hover-decoration': 'none',
'link-focus-decoration': 'none',
'link-focus-outline': '0',
'ease-base-out': 'cubic-bezier(0.7, 0.3, 0.1, 1)',
'ease-base-in': 'cubic-bezier(0.9, 0, 0.3, 0.7)',
'ease-out': 'cubic-bezier(0.215, 0.61, 0.355, 1)',
'ease-in': 'cubic-bezier(0.55, 0.055, 0.675, 0.19)',
'ease-in-out': 'cubic-bezier(0.645, 0.045, 0.355, 1)',
'ease-out-back': 'cubic-bezier(0.12, 0.4, 0.29, 1.46)',
'ease-in-back': 'cubic-bezier(0.71, -0.46, 0.88, 0.6)',
'ease-in-out-back': 'cubic-bezier(0.71, -0.46, 0.29, 1.46)',
'ease-out-circ': 'cubic-bezier(0.08, 0.82, 0.17, 1)',
'ease-in-circ': 'cubic-bezier(0.6, 0.04, 0.98, 0.34)',
'ease-in-out-circ': 'cubic-bezier(0.78, 0.14, 0.15, 0.86)',
'ease-out-quint': 'cubic-bezier(0.23, 1, 0.32, 1)',
'ease-in-quint': 'cubic-bezier(0.755, 0.05, 0.855, 0.06)',
'ease-in-out-quint': 'cubic-bezier(0.86, 0, 0.07, 1)',
'border-color-base': 'hsv(0, 0, 85%)',
'border-color-split': 'hsv(0, 0, 94%)',
'border-color-inverse': '@white',
'border-width-base': '1px',
'border-style-base': 'solid',
'outline-blur-size': '0',
'outline-width': '2px',
'outline-color': '@primary-color',
'background-color-light': 'hsv(0, 0, 98%)',
'background-color-base': 'hsv(0, 0, 96%)',
'disabled-color': 'fade(#000, 25%)',
'disabled-bg': '@background-color-base',
'disabled-color-dark': 'fade(#fff, 35%)',
'shadow-color': 'rgba(0, 0, 0, 0.15)',
'shadow-color-inverse': '@component-background',
'box-shadow-base': '@shadow-1-down',
'shadow-1-up': '0 -2px 8px @shadow-color',
'shadow-1-down': '0 2px 8px @shadow-color',
'shadow-1-left': '-2px 0 8px @shadow-color',
'shadow-1-right': '2px 0 8px @shadow-color',
'shadow-2': '0 4px 12px @shadow-color',
'btn-font-weight': '400',
'btn-border-radius-base': '@border-radius-base',
'btn-border-radius-sm': '@border-radius-base',
'btn-border-width': '@border-width-base',
'btn-border-style': '@border-style-base',
'btn-shadow': '0 2px 0 rgba(0, 0, 0, 0.015)',
'btn-primary-shadow': '0 2px 0 rgba(0, 0, 0, 0.045)',
'btn-text-shadow': '0 -1px 0 rgba(0, 0, 0, 0.12)',
'btn-primary-color': '#fff',
'btn-primary-bg': '@primary-color',
'btn-default-color': '@text-color',
'btn-default-bg': '@component-background',
'btn-default-border': '@border-color-base',
'btn-danger-color': '#fff',
'btn-danger-bg': "color(~`colorPalette('@{error-color}', 5) `)",
'btn-danger-border': "color(~`colorPalette('@{error-color}', 5) `)",
'btn-disable-color': '@disabled-color',
'btn-disable-bg': '@disabled-bg',
'btn-disable-border': '@border-color-base',
'btn-default-ghost-color': '@component-background',
'btn-default-ghost-bg': 'transparent',
'btn-default-ghost-border': '@component-background',
'btn-padding-base': '0 @padding-md - 1px',
'btn-font-size-lg': '@font-size-lg',
'btn-font-size-sm': '@font-size-base',
'btn-padding-lg': '@btn-padding-base',
'btn-padding-sm': '0 @padding-xs - 1px',
'btn-height-base': '32px',
'btn-height-lg': '40px',
'btn-height-sm': '24px',
'btn-circle-size': '@btn-height-base',
'btn-circle-size-lg': '@btn-height-lg',
'btn-circle-size-sm': '@btn-height-sm',
'btn-square-size': '@btn-height-base',
'btn-square-size-lg': '@btn-height-lg',
'btn-square-size-sm': '@btn-height-sm',
'btn-group-border': '@primary-5',
'btn-text-hover-bg': 'rgba(0, 0, 0, 0.018)',
'checkbox-size': '16px',
'checkbox-color': '@primary-color',
'checkbox-check-color': '#fff',
'checkbox-check-bg': '@checkbox-check-color',
'checkbox-border-width': '@border-width-base',
'descriptions-bg': '#fafafa',
'descriptions-title-margin-bottom': '20px',
'descriptions-default-padding': '@padding-md @padding-lg',
'descriptions-middle-padding': '@padding-sm @padding-lg',
'descriptions-small-padding': '@padding-xs @padding-md',
'descriptions-item-padding-bottom': '@padding-md',
'descriptions-item-trailing-colon': 'true',
'descriptions-item-label-colon-margin-right': '8px',
'descriptions-item-label-colon-margin-left': '2px',
'descriptions-extra-color': '@text-color',
'divider-text-padding': '1em',
'divider-orientation-margin': '5%',
'divider-color': 'rgba(0, 0, 0, 6%)',
'dropdown-selected-color': '@primary-color',
'dropdown-menu-submenu-disabled-bg': '@component-background',
'empty-font-size': '@font-size-base',
'radio-size': '16px',
'radio-top': '0px',
'radio-border-width': '1px',
'radio-dot-size': '@radio-size - 8px',
'radio-dot-color': '@primary-color',
'radio-dot-disabled-color': 'fade(@black, 20%)',
'radio-solid-checked-color': '@component-background',
'radio-button-bg': '@btn-default-bg',
'radio-button-checked-bg': '@btn-default-bg',
'radio-button-color': '@btn-default-color',
'radio-button-hover-color': '@primary-5',
'radio-button-active-color': '@primary-7',
'radio-disabled-button-checked-bg': 'tint(@black, 90%)',
'radio-disabled-button-checked-color': '@disabled-color',
'radio-wrapper-margin-right': '8px',
'screen-xs': '480px',
'screen-xs-min': '@screen-xs',
'screen-sm': '576px',
'screen-sm-min': '@screen-sm',
'screen-md': '768px',
'screen-md-min': '@screen-md',
'screen-lg': '992px',
'screen-lg-min': '@screen-lg',
'screen-xl': '1200px',
'screen-xl-min': '@screen-xl',
'screen-xxl': '1600px',
'screen-xxl-min': '@screen-xxl',
'screen-xs-max': '(@screen-sm-min - 1px)',
'screen-sm-max': '(@screen-md-min - 1px)',
'screen-md-max': '(@screen-lg-min - 1px)',
'screen-lg-max': '(@screen-xl-min - 1px)',
'screen-xl-max': '(@screen-xxl-min - 1px)',
'grid-columns': '24',
'grid-gutter-width': '0',
'layout-body-background': '#f0f2f5',
'layout-header-background': '#001529',
'layout-footer-background': '@layout-body-background',
'layout-header-height': '64px',
'layout-header-padding': '0 50px',
'layout-footer-padding': '24px 50px',
'layout-sider-background': '@layout-header-background',
'layout-trigger-height': '48px',
'layout-trigger-background': '#002140',
'layout-trigger-color': '#fff',
'layout-zero-trigger-width': '36px',
'layout-zero-trigger-height': '42px',
'layout-sider-background-light': '#fff',
'layout-trigger-background-light': '#fff',
'layout-trigger-color-light': '@text-color',
'zindex-badge': '1',
'zindex-table-fixed': '1',
'zindex-affix': '10',
'zindex-back-top': '10',
'zindex-picker-panel': '10',
'zindex-popup-close': '10',
'zindex-modal': '1000',
'zindex-modal-mask': '1000',
'zindex-message': '1010',
'zindex-notification': '1010',
'zindex-popover': '1030',
'zindex-dropdown': '1050',
'zindex-picker': '1050',
'zindex-tooltip': '1060',
'zindex-image': '1080',
'animation-duration-slow': '0.3s',
'animation-duration-base': '0.2s',
'animation-duration-fast': '0.1s',
'collapse-panel-border-radius': '@border-radius-base',
'dropdown-menu-bg': '@component-background',
'dropdown-vertical-padding': '5px',
'dropdown-edge-child-vertical-padding': '4px',
'dropdown-font-size': '@font-size-base',
'dropdown-line-height': '22px',
'label-required-color': '@highlight-color',
'label-color': '@heading-color',
'form-warning-input-bg': '@input-bg',
'form-item-margin-bottom': '24px',
'form-item-trailing-colon': 'true',
'form-vertical-label-padding': '0 0 8px',
'form-vertical-label-margin': '0',
'form-item-label-colon-margin-right': '8px',
'form-item-label-colon-margin-left': '2px',
'form-error-input-bg': '@input-bg',
'input-height-base': '32px',
'input-height-lg': '40px',
'input-height-sm': '24px',
'input-padding-horizontal': '@control-padding-horizontal - 1px',
'input-padding-horizontal-base': '@input-padding-horizontal',
'input-padding-horizontal-sm': '@control-padding-horizontal-sm - 1px',
'input-padding-horizontal-lg': '@input-padding-horizontal',
'input-padding-vertical-base': '4px',
'input-padding-vertical-sm': '0px',
'input-padding-vertical-lg': '6.5px',
'input-placeholder-color': 'hsv(0, 0, 75%)',
'input-color': '@text-color',
'input-icon-color': '@input-color',
'input-border-color': '@border-color-base',
'input-bg': '@component-background',
'input-number-hover-border-color': '@input-hover-border-color',
'input-number-handler-active-bg': '#f4f4f4',
'input-number-handler-hover-bg': '@primary-5',
'input-number-handler-bg': '@component-background',
'input-number-handler-border-color': '@border-color-base',
'input-addon-bg': '@background-color-light',
'input-hover-border-color': '@primary-5',
'input-disabled-bg': '@disabled-bg',
'input-outline-offset': '0 0',
'input-icon-hover-color': 'fade(@black, 85%)',
'mentions-dropdown-bg': '@component-background',
'mentions-dropdown-menu-item-hover-bg': '@mentions-dropdown-bg',
'select-border-color': '@border-color-base',
'select-item-selected-color': '@text-color',
'select-item-selected-font-weight': '600',
'select-dropdown-bg': '@component-background',
'select-item-selected-bg': '@primary-1',
'select-item-active-bg': '@item-hover-bg',
'select-dropdown-vertical-padding': '@dropdown-vertical-padding',
'select-dropdown-font-size': '@dropdown-font-size',
'select-dropdown-line-height': '@dropdown-line-height',
'select-dropdown-height': '32px',
'select-background': '@component-background',
'select-clear-background': '@select-background',
'select-selection-item-bg': '@background-color-base',
'select-selection-item-border-color': '@border-color-split',
'select-single-item-height-lg': '40px',
'select-multiple-item-height': '@input-height-base - @input-padding-vertical-base * 2',
'select-multiple-item-height-lg': '32px',
'select-multiple-item-spacing-half': 'ceil((@input-padding-vertical-base / 2))',
'select-multiple-disabled-background': '@input-disabled-bg',
'select-multiple-item-disabled-color': '#bfbfbf',
'select-multiple-item-disabled-border-color': '@select-border-color',
'cascader-bg': '@component-background',
'cascader-item-selected-bg': '@primary-1',
'cascader-menu-bg': '@component-background',
'cascader-menu-border-color-split': '@border-color-split',
'cascader-dropdown-vertical-padding': '@dropdown-vertical-padding',
'cascader-dropdown-edge-child-vertical-padding': '@dropdown-edge-child-vertical-padding',
'cascader-dropdown-font-size': '@dropdown-font-size',
'cascader-dropdown-line-height': '@dropdown-line-height',
'anchor-border-color': '@border-color-split',
'tooltip-max-width': '250px',
'tooltip-color': '#fff',
'tooltip-bg': 'rgba(0, 0, 0, 0.75)',
'tooltip-arrow-width': '5px',
'tooltip-distance': '@tooltip-arrow-width - 1px + 4px',
'tooltip-arrow-color': '@tooltip-bg',
'popover-bg': '@component-background',
'popover-color': '@text-color',
'popover-min-width': '177px',
'popover-arrow-width': '6px',
'popover-arrow-color': '@popover-bg',
'popover-arrow-outer-color': '@popover-bg',
'popover-distance': '@popover-arrow-width + 4px',
'modal-body-padding': '24px',
'modal-header-bg': '@component-background',
'modal-header-border-color-split': '@border-color-split',
'modal-content-bg': '@component-background',
'modal-heading-color': '@heading-color',
'modal-footer-bg': 'transparent',
'modal-footer-border-color-split': '@border-color-split',
'modal-mask-bg': 'fade(@black, 45%)',
'progress-default-color': '@processing-color',
'progress-remaining-color': '@background-color-base',
'progress-text-color': '@text-color',
'progress-radius': '100px',
'menu-inline-toplevel-item-height': '40px',
'menu-item-height': '40px',
'menu-collapsed-width': '80px',
'menu-bg': '@component-background',
'menu-popup-bg': '@component-background',
'menu-item-color': '@text-color',
'menu-highlight-color': '@primary-color',
'menu-item-active-bg': '@item-active-bg',
'menu-item-active-border-width': '3px',
'menu-item-group-title-color': '@text-color-secondary',
'menu-icon-size': '@font-size-base',
'menu-icon-size-lg': '@font-size-lg',
'menu-item-vertical-margin': '4px',
'menu-item-font-size': '@font-size-base',
'menu-item-boundary-margin': '8px',
'menu-dark-color': '@text-color-secondary-dark',
'menu-dark-bg': '@layout-header-background',
'menu-dark-arrow-color': '#fff',
'menu-dark-submenu-bg': '#000c17',
'menu-dark-highlight-color': '#fff',
'menu-dark-item-active-bg': '@primary-color',
'menu-dark-selected-item-icon-color': '@white',
'menu-dark-selected-item-text-color': '@white',
'menu-dark-item-hover-bg': 'transparent',
'spin-dot-size-sm': '14px',
'spin-dot-size': '20px',
'spin-dot-size-lg': '32px',
'table-bg': '@component-background',
'table-header-bg': '@background-color-light',
'table-header-color': '@heading-color',
'table-header-sort-bg': '@background-color-base',
'table-body-sort-bg': 'rgba(0, 0, 0, 0.01)',
'table-row-hover-bg': '@primary-1',
'table-selected-row-color': 'inherit',
'table-selected-row-bg': '@primary-1',
'table-body-selected-sort-bg': '@table-selected-row-bg',
'table-selected-row-hover-bg': 'darken(@table-selected-row-bg, 2%)',
'table-expanded-row-bg': '#fbfbfb',
'table-padding-vertical': '16px',
'table-padding-horizontal': '16px',
'table-border-radius-base': '@border-radius-base',
'table-footer-bg': '@background-color-light',
'table-footer-color': '@heading-color',
'table-header-bg-sm': 'transparent',
'table-header-sort-active-bg': 'darken(@table-header-bg, 3%)',
'table-header-filter-active-bg': 'darken(@table-header-sort-active-bg, 5%)',
'tag-default-bg': '@background-color-light',
'tag-default-color': '@text-color',
'tag-font-size': '@font-size-sm',
'tag-line-height': '20px',
'time-picker-panel-column-width': '56px',
'time-picker-panel-width': '@time-picker-panel-column-width * 3',
'time-picker-selected-bg': '@background-color-base',
'carousel-dot-width': '16px',
'carousel-dot-height': '3px',
'carousel-dot-active-width': '24px',
'badge-height': '20px',
'badge-dot-size': '6px',
'badge-font-size': '@font-size-sm',
'badge-font-weight': 'normal',
'badge-status-size': '6px',
'badge-text-color': '@component-background',
'rate-star-color': '@yellow-6',
'rate-star-bg': '@border-color-split',
'card-head-color': '@heading-color',
'card-head-background': 'transparent',
'card-head-padding': '16px',
'card-inner-head-padding': '12px',
'card-padding-base': '24px',
'card-actions-background': '@background-color-light',
'card-skeleton-bg': '#cfd8dc',
'card-background': '@component-background',
'card-shadow': '0 2px 8px rgba(0, 0, 0, 0.09)',
'card-radius': '@border-radius-sm',
'comment-bg': 'inherit',
'comment-padding-base': '16px 0',
'comment-nest-indent': '44px',
'comment-font-size-base': '@font-size-base',
'comment-font-size-sm': '@font-size-sm',
'comment-author-name-color': '@text-color-secondary',
'comment-author-time-color': '#ccc',
'comment-action-color': '@text-color-secondary',
'comment-action-hover-color': '#595959',
'tabs-card-head-background': '@background-color-light',
'tabs-card-height': '40px',
'tabs-card-active-color': '@primary-color',
'tabs-title-font-size': '@font-size-base',
'tabs-title-font-size-lg': '@font-size-lg',
'tabs-title-font-size-sm': '@font-size-base',
'tabs-ink-bar-color': '@primary-color',
'tabs-bar-margin': '0 0 16px 0',
'tabs-horizontal-margin': '0 32px 0 0',
'tabs-horizontal-padding': '12px 16px',
'tabs-horizontal-padding-lg': '16px',
'tabs-horizontal-padding-sm': '8px 16px',
'tabs-vertical-padding': '8px 24px',
'tabs-vertical-margin': '0 0 16px 0',
'tabs-scrolling-size': '32px',
'tabs-highlight-color': '@primary-color',
'tabs-hover-color': '@primary-5',
'tabs-active-color': '@primary-7',
'tabs-card-gutter': '2px',
'tabs-card-tab-active-border-top': '2px solid transparent',
'back-top-color': '#fff',
'back-top-bg': '@text-color-secondary',
'back-top-hover-bg': '@text-color',
'avatar-size-base': '32px',
'avatar-size-lg': '40px',
'avatar-size-sm': '24px',
'avatar-font-size-base': '18px',
'avatar-font-size-lg': '24px',
'avatar-font-size-sm': '14px',
'avatar-bg': '#ccc',
'avatar-color': '#fff',
'avatar-border-radius': '@border-radius-base',
'switch-height': '22px',
'switch-sm-height': '16px',
'switch-sm-checked-margin-left': '-(@switch-sm-height - 3px)',
'switch-disabled-opacity': '0.4',
'switch-color': '@primary-color',
'switch-bg': '@component-background',
'switch-shadow-color': 'fade(#00230b, 20%)',
'pagination-item-bg': '@component-background',
'pagination-item-size': '32px',
'pagination-item-size-sm': '24px',
'pagination-font-family': 'Arial',
'pagination-font-weight-active': '500',
'pagination-item-bg-active': '@component-background',
'pagination-item-link-bg': '@component-background',
'pagination-item-disabled-color-active': '@white',
'pagination-item-disabled-bg-active': 'darken(@disabled-bg, 10%)',
'pagination-item-input-bg': '@component-background',
'page-header-padding': '24px',
'page-header-padding-vertical': '16px',
'page-header-padding-breadcrumb': '12px',
'page-header-back-color': '#000',
'breadcrumb-base-color': '@text-color-secondary',
'breadcrumb-last-item-color': '@text-color',
'breadcrumb-font-size': '@font-size-base',
'breadcrumb-icon-font-size': '@font-size-base',
'breadcrumb-link-color': '@text-color-secondary',
'breadcrumb-link-color-hover': '@primary-5',
'breadcrumb-separator-color': '@text-color-secondary',
'breadcrumb-separator-margin': '0 @padding-xs',
'slider-margin': '14px 6px 10px',
'slider-rail-background-color': '@background-color-base',
'slider-rail-background-color-hover': '#e1e1e1',
'slider-track-background-color': '@primary-3',
'slider-track-background-color-hover': '@primary-4',
'slider-handle-border-width': '2px',
'slider-handle-background-color': '@component-background',
'slider-handle-color': '@primary-3',
'slider-handle-color-hover': '@primary-4',
'slider-handle-color-focus': 'tint(@primary-color, 20%)',
'slider-handle-color-focus-shadow': 'fade(@primary-color, 20%)',
'slider-handle-color-tooltip-open': '@primary-color',
'slider-handle-shadow': '0',
'slider-dot-border-color': '@border-color-split',
'slider-dot-border-color-active': 'tint(@primary-color, 50%)',
'slider-disabled-color': '@disabled-color',
'slider-disabled-background-color': '@component-background',
'tree-title-height': '24px',
'tree-child-padding': '18px',
'tree-directory-selected-color': '#fff',
'tree-directory-selected-bg': '@primary-color',
'tree-node-hover-bg': '@item-hover-bg',
'tree-node-selected-bg': '@primary-2',
'collapse-header-padding': '12px 16px',
'collapse-header-padding-extra': '40px',
'collapse-header-bg': '@background-color-light',
'collapse-content-padding': '@padding-md',
'collapse-content-bg': '@component-background',
'skeleton-color': '#f2f2f2',
'skeleton-to-color': 'shade(@skeleton-color, 5%)',
'transfer-header-height': '40px',
'transfer-disabled-bg': '@disabled-bg',
'transfer-list-height': '200px',
'transfer-item-hover-bg': '@item-hover-bg',
'message-notice-content-padding': '10px 16px',
'message-notice-content-bg': '@component-background',
'wave-animation-width': '6px',
'alert-success-border-color': "~`colorPalette('@{success-color}', 3) `",
'alert-success-bg-color': "~`colorPalette('@{success-color}', 1) `",
'alert-success-icon-color': '@success-color',
'alert-info-border-color': "~`colorPalette('@{info-color}', 3) `",
'alert-info-bg-color': "~`colorPalette('@{info-color}', 1) `",
'alert-info-icon-color': '@info-color',
'alert-warning-border-color': "~`colorPalette('@{warning-color}', 3) `",
'alert-warning-bg-color': "~`colorPalette('@{warning-color}', 1) `",
'alert-warning-icon-color': '@warning-color',
'alert-error-border-color': "~`colorPalette('@{error-color}', 3) `",
'alert-error-bg-color': "~`colorPalette('@{error-color}', 1) `",
'alert-error-icon-color': '@error-color',
'list-header-background': 'transparent',
'list-footer-background': 'transparent',
'list-empty-text-padding': '@padding-md',
'list-item-padding': '@padding-sm 0',
'list-item-meta-margin-bottom': '@padding-md',
'list-item-meta-avatar-margin-right': '@padding-md',
'list-item-meta-title-margin-bottom': '@padding-sm',
'statistic-title-font-size': '@font-size-base',
'statistic-content-font-size': '24px',
'statistic-unit-font-size': '16px',
'statistic-font-family': '@font-family',
'drawer-header-padding': '16px 24px',
'drawer-body-padding': '24px',
'drawer-bg': '@component-background',
'timeline-width': '2px',
'timeline-color': '@border-color-split',
'timeline-dot-border-width': '2px',
'timeline-dot-color': '@primary-color',
'timeline-dot-bg': '@component-background',
'typography-title-font-weight': '600',
'typography-title-margin-top': '1.2em',
'typography-title-margin-bottom': '0.5em',
'image-size-base': '48px',
'image-font-size-base': '24px',
'image-bg': '#f5f5f5',
'image-color': '#fff',
'image-preview-operation-size': '18px',
'image-preview-operation-color': '@text-color-dark',
'image-preview-operation-disabled-color': 'fade(@image-preview-operation-color, 45%)',
'steps-nav-arrow-color': 'fade(@black, 25%)',
'steps-background': '@component-background',
'notification-bg': '@component-background',
'notification-padding-vertical': '16px',
'notification-padding-horizontal': '24px'
}

var darkThemeSingle = {
theme: 'dark',
'blue-1': "mix(color(~`colorPalette('@{blue-base}', 8) `), @component-background, 15%)",
'blue-2': "mix(color(~`colorPalette('@{blue-base}', 7) `), @component-background, 25%)",
'blue-3': 'mix(@blue-base, @component-background, 30%)',
'blue-4': 'mix(@blue-base, @component-background, 45%)',
'blue-5': 'mix(@blue-base, @component-background, 65%)',
'blue-6': 'mix(@blue-base, @component-background, 85%)',
'blue-7': "mix(color(~`colorPalette('@{blue-base}', 5) `), @component-background, 90%)",
'blue-8': "mix(color(~`colorPalette('@{blue-base}', 4) `), @component-background, 95%)",
'blue-9': "mix(color(~`colorPalette('@{blue-base}', 3) `), @component-background, 97%)",
'blue-10': "mix(color(~`colorPalette('@{blue-base}', 2) `), @component-background, 98%)",
'purple-1': "mix(color(~`colorPalette('@{purple-base}', 8) `), @component-background, 15%)",
'purple-2': "mix(color(~`colorPalette('@{purple-base}', 7) `), @component-background, 25%)",
'purple-3': 'mix(@purple-base, @component-background, 30%)',
'purple-4': 'mix(@purple-base, @component-background, 45%)',
'purple-5': 'mix(@purple-base, @component-background, 65%)',
'purple-6': 'mix(@purple-base, @component-background, 85%)',
'purple-7': "mix(color(~`colorPalette('@{purple-base}', 5) `), @component-background, 90%)",
'purple-8': "mix(color(~`colorPalette('@{purple-base}', 4) `), @component-background, 95%)",
'purple-9': "mix(color(~`colorPalette('@{purple-base}', 3) `), @component-background, 97%)",
'purple-10': "mix(color(~`colorPalette('@{purple-base}', 2) `), @component-background, 98%)",
'cyan-1': "mix(color(~`colorPalette('@{cyan-base}', 8) `), @component-background, 15%)",
'cyan-2': "mix(color(~`colorPalette('@{cyan-base}', 7) `), @component-background, 25%)",
'cyan-3': 'mix(@cyan-base, @component-background, 30%)',
'cyan-4': 'mix(@cyan-base, @component-background, 45%)',
'cyan-5': 'mix(@cyan-base, @component-background, 65%)',
'cyan-6': 'mix(@cyan-base, @component-background, 85%)',
'cyan-7': "mix(color(~`colorPalette('@{cyan-base}', 5) `), @component-background, 90%)",
'cyan-8': "mix(color(~`colorPalette('@{cyan-base}', 4) `), @component-background, 95%)",
'cyan-9': "mix(color(~`colorPalette('@{cyan-base}', 3) `), @component-background, 97%)",
'cyan-10': "mix(color(~`colorPalette('@{cyan-base}', 2) `), @component-background, 98%)",
'green-1': "mix(color(~`colorPalette('@{green-base}', 8) `), @component-background, 15%)",
'green-2': "mix(color(~`colorPalette('@{green-base}', 7) `), @component-background, 25%)",
'green-3': 'mix(@green-base, @component-background, 30%)',
'green-4': 'mix(@green-base, @component-background, 45%)',
'green-5': 'mix(@green-base, @component-background, 65%)',
'green-6': 'mix(@green-base, @component-background, 85%)',
'green-7': "mix(color(~`colorPalette('@{green-base}', 5) `), @component-background, 90%)",
'green-8': "mix(color(~`colorPalette('@{green-base}', 4) `), @component-background, 95%)",
'green-9': "mix(color(~`colorPalette('@{green-base}', 3) `), @component-background, 97%)",
'green-10': "mix(color(~`colorPalette('@{green-base}', 2) `), @component-background, 98%)",
'magenta-1': "mix(color(~`colorPalette('@{magenta-base}', 8) `), @component-background, 15%)",
'magenta-2': "mix(color(~`colorPalette('@{magenta-base}', 7) `), @component-background, 25%)",
'magenta-3': 'mix(@magenta-base, @component-background, 30%)',
'magenta-4': 'mix(@magenta-base, @component-background, 45%)',
'magenta-5': 'mix(@magenta-base, @component-background, 65%)',
'magenta-6': 'mix(@magenta-base, @component-background, 85%)',
'magenta-7': "mix(color(~`colorPalette('@{magenta-base}', 5) `), @component-background, 90%)",
'magenta-8': "mix(color(~`colorPalette('@{magenta-base}', 4) `), @component-background, 95%)",
'magenta-9': "mix(color(~`colorPalette('@{magenta-base}', 3) `), @component-background, 97%)",
'magenta-10': "mix(color(~`colorPalette('@{magenta-base}', 2) `), @component-background, 98%)",
'pink-1': "mix(color(~`colorPalette('@{pink-base}', 8) `), @component-background, 15%)",
'pink-2': "mix(color(~`colorPalette('@{pink-base}', 7) `), @component-background, 25%)",
'pink-3': 'mix(@pink-base, @component-background, 30%)',
'pink-4': 'mix(@pink-base, @component-background, 45%)',
'pink-5': 'mix(@pink-base, @component-background, 65%)',
'pink-6': 'mix(@pink-base, @component-background, 85%)',
'pink-7': "mix(color(~`colorPalette('@{pink-base}', 5) `), @component-background, 90%)",
'pink-8': "mix(color(~`colorPalette('@{pink-base}', 4) `), @component-background, 95%)",
'pink-9': "mix(color(~`colorPalette('@{pink-base}', 3) `), @component-background, 97%)",
'pink-10': "mix(color(~`colorPalette('@{pink-base}', 2) `), @component-background, 98%)",
'red-1': "mix(color(~`colorPalette('@{red-base}', 8) `), @component-background, 15%)",
'red-2': "mix(color(~`colorPalette('@{red-base}', 7) `), @component-background, 25%)",
'red-3': 'mix(@red-base, @component-background, 30%)',
'red-4': 'mix(@red-base, @component-background, 45%)',
'red-5': 'mix(@red-base, @component-background, 65%)',
'red-6': 'mix(@red-base, @component-background, 85%)',
'red-7': "mix(color(~`colorPalette('@{red-base}', 5) `), @component-background, 90%)",
'red-8': "mix(color(~`colorPalette('@{red-base}', 4) `), @component-background, 95%)",
'red-9': "mix(color(~`colorPalette('@{red-base}', 3) `), @component-background, 97%)",
'red-10': "mix(color(~`colorPalette('@{red-base}', 2) `), @component-background, 98%)",
'orange-1': "mix(color(~`colorPalette('@{orange-base}', 8) `), @component-background, 15%)",
'orange-2': "mix(color(~`colorPalette('@{orange-base}', 7) `), @component-background, 25%)",
'orange-3': 'mix(@orange-base, @component-background, 30%)',
'orange-4': 'mix(@orange-base, @component-background, 45%)',
'orange-5': 'mix(@orange-base, @component-background, 65%)',
'orange-6': 'mix(@orange-base, @component-background, 85%)',
'orange-7': "mix(color(~`colorPalette('@{orange-base}', 5) `), @component-background, 90%)",
'orange-8': "mix(color(~`colorPalette('@{orange-base}', 4) `), @component-background, 95%)",
'orange-9': "mix(color(~`colorPalette('@{orange-base}', 3) `), @component-background, 97%)",
'orange-10': "mix(color(~`colorPalette('@{orange-base}', 2) `), @component-background, 98%)",
'yellow-1': "mix(color(~`colorPalette('@{yellow-base}', 8) `), @component-background, 15%)",
'yellow-2': "mix(color(~`colorPalette('@{yellow-base}', 7) `), @component-background, 25%)",
'yellow-3': 'mix(@yellow-base, @component-background, 30%)',
'yellow-4': 'mix(@yellow-base, @component-background, 45%)',
'yellow-5': 'mix(@yellow-base, @component-background, 65%)',
'yellow-6': 'mix(@yellow-base, @component-background, 85%)',
'yellow-7': "mix(color(~`colorPalette('@{yellow-base}', 5) `), @component-background, 90%)",
'yellow-8': "mix(color(~`colorPalette('@{yellow-base}', 4) `), @component-background, 95%)",
'yellow-9': "mix(color(~`colorPalette('@{yellow-base}', 3) `), @component-background, 97%)",
'yellow-10': "mix(color(~`colorPalette('@{yellow-base}', 2) `), @component-background, 98%)",
'volcano-1': "mix(color(~`colorPalette('@{volcano-base}', 8) `), @component-background, 15%)",
'volcano-2': "mix(color(~`colorPalette('@{volcano-base}', 7) `), @component-background, 25%)",
'volcano-3': 'mix(@volcano-base, @component-background, 30%)',
'volcano-4': 'mix(@volcano-base, @component-background, 45%)',
'volcano-5': 'mix(@volcano-base, @component-background, 65%)',
'volcano-6': 'mix(@volcano-base, @component-background, 85%)',
'volcano-7': "mix(color(~`colorPalette('@{volcano-base}', 5) `), @component-background, 90%)",
'volcano-8': "mix(color(~`colorPalette('@{volcano-base}', 4) `), @component-background, 95%)",
'volcano-9': "mix(color(~`colorPalette('@{volcano-base}', 3) `), @component-background, 97%)",
'volcano-10': "mix(color(~`colorPalette('@{volcano-base}', 2) `), @component-background, 98%)",
'geekblue-1': "mix(color(~`colorPalette('@{geekblue-base}', 8) `), @component-background, 15%)",
'geekblue-2': "mix(color(~`colorPalette('@{geekblue-base}', 7) `), @component-background, 25%)",
'geekblue-3': 'mix(@geekblue-base, @component-background, 30%)',
'geekblue-4': 'mix(@geekblue-base, @component-background, 45%)',
'geekblue-5': 'mix(@geekblue-base, @component-background, 65%)',
'geekblue-6': 'mix(@geekblue-base, @component-background, 85%)',
'geekblue-7': "mix(color(~`colorPalette('@{geekblue-base}', 5) `), @component-background, 90%)",
'geekblue-8': "mix(color(~`colorPalette('@{geekblue-base}', 4) `), @component-background, 95%)",
'geekblue-9': "mix(color(~`colorPalette('@{geekblue-base}', 3) `), @component-background, 97%)",
'geekblue-10': "mix(color(~`colorPalette('@{geekblue-base}', 2) `), @component-background, 98%)",
'lime-1': "mix(color(~`colorPalette('@{lime-base}', 8) `), @component-background, 15%)",
'lime-2': "mix(color(~`colorPalette('@{lime-base}', 7) `), @component-background, 25%)",
'lime-3': 'mix(@lime-base, @component-background, 30%)',
'lime-4': 'mix(@lime-base, @component-background, 45%)',
'lime-5': 'mix(@lime-base, @component-background, 65%)',
'lime-6': 'mix(@lime-base, @component-background, 85%)',
'lime-7': "mix(color(~`colorPalette('@{lime-base}', 5) `), @component-background, 90%)",
'lime-8': "mix(color(~`colorPalette('@{lime-base}', 4) `), @component-background, 95%)",
'lime-9': "mix(color(~`colorPalette('@{lime-base}', 3) `), @component-background, 97%)",
'lime-10': "mix(color(~`colorPalette('@{lime-base}', 2) `), @component-background, 98%)",
'gold-1': "mix(color(~`colorPalette('@{gold-base}', 8) `), @component-background, 15%)",
'gold-2': "mix(color(~`colorPalette('@{gold-base}', 7) `), @component-background, 25%)",
'gold-3': 'mix(@gold-base, @component-background, 30%)',
'gold-4': 'mix(@gold-base, @component-background, 45%)',
'gold-5': 'mix(@gold-base, @component-background, 65%)',
'gold-6': 'mix(@gold-base, @component-background, 85%)',
'gold-7': "mix(color(~`colorPalette('@{gold-base}', 5) `), @component-background, 90%)",
'gold-8': "mix(color(~`colorPalette('@{gold-base}', 4) `), @component-background, 95%)",
'gold-9': "mix(color(~`colorPalette('@{gold-base}', 3) `), @component-background, 97%)",
'gold-10': "mix(color(~`colorPalette('@{gold-base}', 2) `), @component-background, 98%)",
'primary-1': "mix(color(~`colorPalette('@{primary-color}', 8) `), @component-background, 15%)",
'primary-2': "mix(color(~`colorPalette('@{primary-color}', 7) `), @component-background, 25%)",
'primary-3': 'mix(@primary-color, @component-background, 30%)',
'primary-4': 'mix(@primary-color, @component-background, 45%)',
'primary-5': 'mix(@primary-color, @component-background, 65%)',
'primary-6': '@primary-color',
'primary-7': "mix(color(~`colorPalette('@{primary-color}', 5) `), @component-background, 90%)",
'primary-8': "mix(color(~`colorPalette('@{primary-color}', 4) `), @component-background, 95%)",
'primary-9': "mix(color(~`colorPalette('@{primary-color}', 3) `), @component-background, 97%)",
'primary-10': "mix(color(~`colorPalette('@{primary-color}', 2) `), @component-background, 98%)",
'popover-background': '#1f1f1f',
'popover-customize-border-color': '#3a3a3a',
'body-background': '#121924',
'component-background': '#1c2533',
'text-color': 'fade(@white, 85%)',
'text-color-secondary': 'fade(@white, 45%)',
'text-color-inverse': '@white',
'icon-color-hover': 'fade(@white, 75%)',
'heading-color': 'fade(@white, 85%)',
'item-active-bg': '@primary-1',
'item-hover-bg': 'fade(@white, 8%)',
'border-color-base': '#2e3846',
'border-color-split': '#2e3846',
'background-color-light': 'fade(@white, 4%)',
'background-color-base': 'fade(@white, 8%)',
'disabled-color': 'fade(@white, 30%)',
'disabled-bg': '@background-color-base',
'disabled-color-dark': 'fade(@white, 30%)',
'tree-bg': 'transparent',
'list-customize-card-bg': 'transparent',
'shadow-color': 'rgba(0, 0, 0, 0.45)',
'shadow-color-inverse': '@component-background',
'box-shadow-base': '@shadow-2',
'shadow-1-up':
'0 -6px 16px -8px rgba(0, 0, 0, 0.32), 0 -9px 28px 0 rgba(0, 0, 0, 0.2),\n 0 -12px 48px 16px rgba(0, 0, 0, 0.12)',
'shadow-1-down':
'0 6px 16px -8px rgba(0, 0, 0, 0.32), 0 9px 28px 0 rgba(0, 0, 0, 0.2),\n 0 12px 48px 16px rgba(0, 0, 0, 0.12)',
'shadow-1-right':
'6px 0 16px -8px rgba(0, 0, 0, 0.32), 9px 0 28px 0 rgba(0, 0, 0, 0.2),\n 12px 0 48px 16px rgba(0, 0, 0, 0.12)',
'shadow-2':
'0 3px 6px -4px rgba(0, 0, 0, 0.48), 0 6px 16px 0 rgba(0, 0, 0, 0.32),\n 0 9px 28px 8px rgba(0, 0, 0, 0.2)',
'btn-shadow': '0 2px 0 rgba(0, 0, 0, 0.015)',
'btn-primary-shadow': '0 2px 0 rgba(0, 0, 0, 0.045)',
'btn-text-shadow': '0 -1px 0 rgba(0, 0, 0, 0.12)',
'btn-default-bg': 'transparent',
'btn-default-ghost-color': '@text-color',
'btn-default-ghost-border': 'fade(@white, 25%)',
'btn-text-hover-bg': 'rgba(255, 255, 255, 0.03)',
'checkbox-check-bg': 'transparent',
'descriptions-bg': '@background-color-light',
'divider-color': 'rgba(255, 255, 255, 12%)',
'modal-header-bg': '@popover-background',
'modal-header-border-color-split': '@border-color-split',
'modal-content-bg': '@popover-background',
'modal-footer-border-color-split': '@border-color-split',
'radio-solid-checked-color': '@white',
'radio-dot-disabled-color': 'fade(@white, 20%)',
'radio-disabled-button-checked-bg': 'fade(@white, 20%)',
'radio-disabled-button-checked-color': '@disabled-color',
'layout-body-background': '@body-background',
'layout-header-background': '@popover-background',
'layout-trigger-background': '#262626',
'input-bg': 'transparent',
'input-placeholder-color': 'fade(@white, 30%)',
'input-icon-color': 'fade(@white, 30%)',
'input-number-handler-active-bg': '@item-hover-bg',
'input-icon-hover-color': 'fade(@white, 85%)',
'select-background': 'transparent',
'select-dropdown-bg': '@popover-background',
'select-clear-background': '@component-background',
'select-selection-item-bg': 'fade(@white, 8)',
'select-selection-item-border-color': '@border-color-split',
'select-multiple-disabled-background': '@component-background',
'select-multiple-item-disabled-color': '#595959',
'select-multiple-item-disabled-border-color': '@popover-background',
'cascader-bg': 'transparent',
'cascader-menu-bg': '@popover-background',
'cascader-menu-border-color-split': '@border-color-split',
'tooltip-bg': '#434343',
'menu-dark-submenu-bg': '@component-background',
'menu-dark-bg': '@popover-background',
'menu-popup-bg': '@popover-background',
'message-notice-content-bg': '@popover-background',
'notification-bg': '@popover-background',
'link-hover-color': '@primary-5',
'link-active-color': '@primary-7',
'table-header-bg': '#1d1d1d',
'table-body-sort-bg': 'fade(@white, 1%)',
'table-row-hover-bg': '#262626',
'table-header-sort-bg': '#262626',
'table-header-filter-active-bg': '#434343',
'table-header-sort-active-bg': '#303030',
'table-filter-btns-bg': '@popover-background',
'table-expanded-row-bg': '@table-header-bg',
'table-filter-dropdown-bg': '@popover-background',
'table-expand-icon-bg': 'transparent',
'picker-basic-cell-hover-with-range-color': 'darken(@primary-color, 35%)',
'picker-basic-cell-disabled-bg': '#303030',
'picker-border-color': '@border-color-split',
'picker-bg': 'transparent',
'picker-date-hover-range-border-color': 'darken(@primary-color, 20%)',
'dropdown-menu-bg': '@popover-background',
'dropdown-menu-submenu-disabled-bg': 'transparent',
'steps-nav-arrow-color': 'fade(@white, 20%)',
'steps-background': 'transparent',
'avatar-bg': 'fade(@white, 30%)',
'progress-steps-item-bg': 'fade(@white, 8%)',
'calendar-bg': '@popover-background',
'calendar-input-bg': '@calendar-bg',
'calendar-border-color': 'transparent',
'calendar-full-bg': '@component-background',
'badge-text-color': '@white',
'popover-bg': '@popover-background',
'drawer-bg': '@popover-background',
'card-actions-background': '@component-background',
'card-skeleton-bg': '#303030',
'card-shadow':
'0 1px 2px -2px rgba(0, 0, 0, 0.64), 0 3px 6px 0 rgba(0, 0, 0, 0.48),\n 0 5px 12px 4px rgba(0, 0, 0, 0.36)',
'transfer-item-hover-bg': '#262626',
'comment-bg': 'transparent',
'comment-author-time-color': 'fade(@white, 30%)',
'comment-action-hover-color': 'fade(@white, 65%)',
'rate-star-bg': 'fade(@white, 12%)',
'switch-bg': '@white',
'pagination-item-bg': 'transparent',
'pagination-item-bg-active': 'transparent',
'pagination-item-link-bg': 'transparent',
'pagination-item-disabled-bg-active': 'fade(@white, 25%)',
'pagination-item-disabled-color-active': '@black',
'pagination-item-input-bg': '@pagination-item-bg',
'page-header-back-color': '@icon-color',
'page-header-ghost-bg': 'transparent',
'slider-rail-background-color': '#262626',
'slider-rail-background-color-hover': '@border-color-base',
'slider-dot-border-color': '@border-color-split',
'slider-dot-border-color-active': '@primary-4',
'skeleton-to-color': 'fade(@white, 16%)',
'alert-success-border-color': '@green-3',
'alert-success-bg-color': '@green-1',
'alert-success-icon-color': '@success-color',
'alert-info-border-color': '@primary-3',
'alert-info-bg-color': '@primary-1',
'alert-info-icon-color': '@info-color',
'alert-warning-border-color': '@gold-3',
'alert-warning-bg-color': '@gold-1',
'alert-warning-icon-color': '@warning-color',
'alert-error-border-color': '@red-3',
'alert-error-bg-color': '@red-1',
'alert-error-icon-color': '@error-color',
'timeline-color': '@border-color-split',
'timeline-dot-color': '@primary-color',
'mentions-dropdown-bg': '@popover-background'
}

module.exports = {
darkTheme: {
hack: `true;@import "${require.resolve('ant-design-vue/lib/style/color/colorPalette.less')}";`,
...defaultTheme,
...darkThemeSingle
}
}

ant design vue pro用的是vue cli 3,打开根目录的vue.config.js

找到modifyVars引入即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const {
darkTheme
} = require('./dark.js')
loaderOptions: {
less: {
modifyVars: Object.assign(
{
// less vars,customize ant design theme
// 'primary-color': '#F5222D',
},
darkTheme
),
// DO NOT REMOVE THIS LINE
javascriptEnabled: true
}
}

大致效果:

image-20210523144037213

Vue SSR基于Coding的持续集成部署实践(CI/CD)

作者 fun
2021年4月26日 08:00

用过netlify、vercel都知道推送完就会自动触发构建和部署接着线上就更新了,这种体验能极大程度提高开发效率、减轻心智负担。

通过Coding也可以很方便的获得类似的体验,本文记录了相关的实践配置过程

准备

因为Vue做了SSR,且需要部署到内网的多个服务器上,Coding可以通过堡垒机来下发部署任务到内网的多个机器。

如果是SPA应用可以直接在构建完成后把build后的资源上传到OSS或其它什么静态服务。

打开团队配置页:
https://${团队}.coding.net/cd-deck/admin/host-server/agents

安装堡垒机

复制命令安装,安装成功后即可看到加入到的堡垒机。

主机组

选定堡垒机,加上要部署到的主机内网IP

免密登录

堡垒机生成公钥

1
ssh-keygen

复制公钥到需要控制的机器即可免密登录

1
2
ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.1.23
ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.1.24

构建任务

打开一个项目,项目设置开启持续集成和制品库,然后增加一个构建任务。

安装依赖buid成功后会把dist打包上传到制品库dist.zip

Jenkinsfile

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
pipeline {
agent any
stages {
stage('检出') {
steps {
checkout([
$class: 'GitSCM',
branches: [[name: env.GIT_BUILD_REF]],
userRemoteConfigs: [[
url: env.GIT_REPO_URL,
credentialsId: env.CREDENTIALS_ID
]]])
}
}
stage('自定义构建过程') {
steps {
echo '自定义构建过程开始'
sh 'npm install -g cnpm --registry=https://registry.npm.taobao.org'
sh 'cnpm install'
sh 'npm run build'
sh 'zip -r dist.zip dist/*'
echo '构建完成.'
}
}
stage(' 上传到 generic 仓库') {
steps {
codingArtifactsGeneric(files: 'dist.zip', repoName: "${GENERIC_REPO_NAME}")
}
}
}
}

设置构建任务的触发规则为推送新标签时触发

创建应用

打开团队持续部署页
https://${你的团队}.coding.net/cd-deck/app

新建应用 > 选择主机组部署

打开详情 > 新建部署流程

配置制品下载 > dist.zip下载到指定目录

新增一个后执行脚本 > 该脚本会重启nodejs服务

update.sh

1
2
3
4
5
6
BASE_FOLDER=$(dirname "$0")
cd $BASE_FOLDER
rm -rf ./dist
unzip dist.zip
forever stop server.js
forever start server.js

配置健康探针 > 用于检测服务是否运行正常

添加触发器 > 当制品库更新自动触发部署流程

最后整个流程

这样当推送了一个新tag后(当然也可以手动触发),就会触发构建任务,制品库dist.zip被更新后触发了部署流程。

部署流程会把dist.zip下载到主机组中机器列表上的指定存储位置,
执行update.sh重启web服务,健康检查部署流程执行成功。

缺点

目前用下来的问题有:

  • 构建速度还是有点慢
  • 构建任务有时候会失败

但整体来讲还是很好用的,比起之前的更新部署来讲,节省了很多心智负担,推送完只需等待即可,期间还能继续摸鱼hh

基于Prometheus + Grafana的服务性能、质量监控实践

作者 fun
2020年6月16日 08:00

服务的质量离不开一个监控和反馈体系,如果没有一个监控反馈体系,我们并不能知道线上的服务出现了什么,正在发生什么、可能存在什么样的问题。

这时候如果有一个可视化的表盘,可以让你直观清晰的感知整个系统的运行状况,那么你就能根据这些反馈做出调整,进入一个【行动->反馈->行动..】的过程之中。渐渐的,整个系统的服务质量在这些不断的调整中就大大提高了,极为重要的一点是我们有必要对自己开发的服务质量负责。

image-20200620084423428

搜索接口性能从一开始的混乱无序,到后续的逐渐稳定。

怎么做?

基于Prometheus,我们可以按时间间隔定义采集任务,用的方式去采集各个服务应用上的性能指标。基于Grafana我们可以对这些采集到的指标进行可视化展示,查询分析,此外Grafana还支持报警规则,再通过Webhook、我们能把这些报警推送到飞书或者叮叮群里,及时响应异常情况。

指标类型

Prometheus主要支持三种类型一种分别是Counter,Histogram,Gauge,Summary

  • Counter主要用来记录一个总数,比如说api请求总次数
  • Gauge主要记录可上可下的值,比如CPU使用率

  • Summary可以用来记录接口的响应时间

  • Histogram和Summary可以做差不多同样的事,就是多了一个bucket的概念,响应时间按范围分段统计,具体差异详见

接口准备

Prometheus主要是通过定时抓取目标{target}/metrics 接口来采集数据的,所以我们需要提供一个接口来暴露这些数据

Nodejs

express为例,安装prom-clien response-time依赖

1
require('prom-client').collectDefaultMetrics();

记录一些默认的指标比如说当前nodejs进程内存 cpu gc http request等各种系统指标。

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
var Register = require('prom-client').register;  
var Counter = require('prom-client').Counter;
var Histogram = require('prom-client').Histogram;
var Summary = require('prom-client').Summary;
var ResponseTime = require('response-time');
// var Logger = require('logger').createLogger();

/**
* A Prometheus counter that counts the invocations of the different HTTP verbs
* e.g. a GET and a POST call will be counted as 2 different calls
*/
var numOfRequests = new Counter({
name: 'numOfRequests',
help: 'Number of requests made',
labelNames: ['method']
});

/**
* A Prometheus counter that counts the invocations with different paths
* e.g. /foo and /bar will be counted as 2 different paths
*/
var pathsTaken = new Counter({
name: 'pathsTaken',
help: 'Paths taken in the app',
labelNames: ['path']
});

/**
* A Prometheus summary to record the HTTP method, path, response code and response time
*/
var responses = new Summary({
name: 'responses',
help: 'Response time in millis',
labelNames: ['method', 'path', 'status']
});

/**
* This funtion will start the collection of metrics and should be called from within in the main js file
*/
module.exports.startCollection = function () {
// Logger.info(Logger.LOG_INFO, 'Starting the collection of metrics, the metrics are available on /metrics');
require('prom-client').collectDefaultMetrics();
};

/**
* This function increments the counters that are executed on the request side of an invocation
* Currently it increments the counters for numOfPaths and pathsTaken
*/
module.exports.requestCounters = function (req, res, next) {
if (req.path != '/metrics') {
numOfRequests.inc({ method: req.method });
pathsTaken.inc({ path: req.path });
}
next();
}

/**
* This function increments the counters that are executed on the response side of an invocation
* Currently it updates the responses summary
*/
module.exports.responseCounters = ResponseTime(function (req, res, time) {
if(req.url != '/metrics') {
responses.labels(req.method, req.url, res.statusCode).observe(time);
}
})

/**
* In order to have Prometheus get the data from this app a specific URL is registered
*/
module.exports.injectMetricsRoute = function (App) {
App.get('/metrics', (req, res) => {
res.set('Content-Type', Register.contentType);
res.end(Register.metrics());
});
};

记录不同route的请求次数numOfRequests ,和响应时间responses

1
2
3
4
5
6
7
8
9
10
11
12
13

app.use(Prometheus.requestCounters);
app.use(Prometheus.responseCounters);

/**
* Enable metrics endpoint
*/
Prometheus.injectMetricsRoute(app);

/**
* Enable collection of default metrics
*/
Prometheus.startCollection();

中间件加上,注入/metrics接口

PHP

php我们要用到php-apc 或者redis也可以 因为php自己是被web server执行完了就内存释放了,计数统计还得依赖redis或者apc这样的

php7得安装php-apcu还得安装apcu_bc, php7可以用 endclothing/prometheus_client_php, 5.x可以用 jimdo/prometheus_client_php

laravel为例

我们新加一个中间件Metrics.php

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

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
use Prometheus\CollectorRegistry;

class Metrics
{

public function __construct()
{
if(function_exists('apcu_add')) {
$adapter = new \Prometheus\Storage\APC();
} else {
$adapter = new \Prometheus\Storage\InMemory();
}

$registry = new CollectorRegistry($adapter);
$this->registry = $registry;
$this->initRouteMetrics();
}

public function initRouteMetrics()
{
$namespace = "api";
$buckets = [
100.0,
200.0,
300.0,
600.0,
1000.0,
1500.0,
2500.0,
5000.0,
8000.0,
15000.0,
30000.0,
50000.0,
80000.0
];
// $buckets = null;
$labelNames = $this->getRequestCounterLabelNames();

$name = 'request_duration_milliseconds';
$help = 'duration of http_requests';
$this->requestDurationHistogram = $this->registry->getOrRegisterHistogram(
$namespace, $name, $help, $labelNames, $buckets
);
}


protected function getRequestCounterLabelNames()
{
return [
'route', 'method', 'status_code',
];
}

/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string|null $guard
* @return mixed
*/
public function handle(Request $request, Closure $next)
{

$start = $_SERVER['REQUEST_TIME_FLOAT'];
$this->request = $request;

/** @var \Illuminate\Http\Response $response */
$response = $next($request);

$route = $request->route();

if($route) {
$route_name = $route->uri() ?: 'unnamed';
$method = $request->getMethod();
$status = $response->getStatusCode();
$duration = microtime(true) - $start;
$duration_milliseconds = $duration * 1000.0;
$this->countRequest($route_name, $method, $status, $duration_milliseconds);
}

return $response;
}

public function countRequest($route, $method, $statusCode, $duration_milliseconds)
{
$labelValues = [(string)$route, (string)$method, (string) $statusCode];
$this->requestDurationHistogram->observe($duration_milliseconds, $labelValues);
}
}

route统计api的响应时间

Prometheus数据采集

docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
version: "2.2"
services:
tapi:
logging:
driver: "json-file"
options:
max-size: "50m"
image: prom/prometheus
restart: always
volumes:
- /prometheus_data:/prometheus_data:rw
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- ./targets.json:/etc/prometheus/targets.json
command:
- '--storage.tsdb.path=/prometheus_data'
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.retention=10d'
ports:
- "9090:9090"

挂载一个prometheus_data外部目录来对数据持久化,config设置保留10天的数据

prometheus.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
global:
scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.

scrape_configs:
- job_name: "node"
file_sd_configs:
- refresh_interval: 1m
files:
- "/etc/prometheus/targets.json"
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: web
static_configs:
- targets: ['192.168.1.22:8096', '192.168.1.89:8096']

file_sd会定时动态读取targets.json在不重启的情况下增加新的job

targets.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[
{
"targets": [ "192.168.1.86:8029" ],
"labels": {
"env": "prod",
"job": "api"
}
},
{
"targets": [ "192.168.1.86:8030"],
"labels": {
"env": "prod",
"job": "api"
}
}
]

数据指标可视化

启动Grafana

1
docker run -d --name=grafana -p 3000:3000 grafana/grafana
配置数据源

Configuration > Add data source 选择Prometheus,URL=http://localhost:9090

配置Dashboard

增加一个特定接口的性能监控

image-20200620100155067

5分钟内请求总时间除以总次数得到api响应时间均值

image-20200620100314353

1
2
3
rate(api_request_duration_milliseconds_sum{route="g/search", method="POST"}[5m]) 
/
rate(api_request_duration_milliseconds_count{route="g/search", method="POST"}[5m])
发现慢接口

image-20200620100837871

1
2
3
4
5
6
7
topk(20, 
sum by (route) (
rate(api_request_duration_milliseconds_sum{status_code!="500", method!="OPTIONS"}[2m])
/
rate(api_request_duration_milliseconds_count{status_code!="500", method!="OPTIONS"}[2m])
)
)

sum byroute 的响应时间 取Top20,得到响应时间慢的API

1
topk(10, sum by (route) (rate(api_request_duration_milliseconds_count{status_code!="500"}[5m])))

稍微调整下可以拿到当前时间请求频繁的接口

报警

设置Alerting > Notification channels

image-20200620101549770

由于feishu的webhook传参格式不一样,我们需要格式化一下信息格式,做个转发

所以是 grafana > webhook proxy > feishu

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
const express = require('express')
const bodyParser = require('body-parser')
const app = express()
const fetch = require('node-fetch');

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));

app.post('/webhook/feishu/bot1', async (req, res, next) => {
const body = req.body;
const matchs = body.evalMatches.length ? JSON.stringify(body.evalMatches, null, 2) : '';
const formatted = {
title: body.title,
text: `${body.message}\n\nruleName:${body.ruleName}\nstate:${body.state}\n\n${matchs}\n`
};
const proxyRes = await fetch('https://open.feishu.cn/open-apis/bot/hook/xxxx', {
method: 'post',
body: JSON.stringify(formatted),
headers: { 'Content-Type': 'application/json' }
});
console.log(await proxyRes.json());
res.send('hello');
});

app.listen(3002);
规则设置

设置一个当搜索接口响应时间高于某个值的报警通知

image-20200620101422700

收到报警提醒

image-20200620102748260

记一次前端性能调优

作者 fun
2020年3月14日 08:00

可以明显感觉到搜索结果页即使接口速度在500毫秒内返回还是有一阵卡顿感,部分电脑还会出现未响应整个Tab完全死掉的情况。

可以明显感觉到搜索结果页即使接口速度在500毫秒内返回还是有一阵卡顿感,部分电脑还会出现未响应整个Tab完全死掉的情况。


打开Chrome任务管理器可以明显看到这个Tab的CPU基本上大于30%,要知道我台式机E3都能跑50%,那么普通移动版笔记本的CPU应该是要爆炸了!通常CPU爆了表现为“Tab未响应”


打开开发者工具的Performance monitor,可以看到CPU使用一直很高,明细里Style recalcs / sec 一直高。

猜测应该是某个动画导致的!

问题排查

怎么定位具体哪个DOM呢?万能的排除大法!
肉眼可见的动画点,按钮呼吸灯动画

尝试删除监控按钮的闪烁动画DOM


CPU降至20%左右,但还是很高

尝试删除整个广告结果内容区域


CPU变化不大、Style recalcs依旧很高

尝试删除右边汇总边栏


CPU,Style recalcs显著降低!

经排查除按钮呼吸灯外,汇总边栏即使在不展开时,还有个两loading动画在运行,
这想必是问题所在!

问题处理
  • 呼吸灯效果去掉或延迟开启,避免CPU的瞬时激增
  • 汇总变栏在不展开时,关闭loading效果

看到这里你可能以为问题解决可以关机睡觉了?事实上并没有,尽管CPU降下来了,但是loading结束后的卡顿感依旧还存在的。

打开Network发现即使在接口返回400ms的情况下依旧有卡顿感。于是便尝试看了下接口调用前到loading结束一共消耗的总时间时间

即使接口在500ms返回的情况下到loading结束也是要花掉3.8s的。


打开Performence录制能看到XHR结束后有一段耗时的调用,明细都是Vue的组件创建等等..


猜测是不是瀑布流里的组件是不是太多了,看了下代码好几个按钮点击后都是Popover,和Dialog。在注释掉了一些组件之后明显是快了不少!精简到到不能再精简了还是得花上1.28s。

最后只剩下瀑布流组件vue-waterfall2了!


试着不用瀑布流只是单纯的循环输出只要570ms即可,也就是说瀑布流组件花了有大概710ms。


优化瀑布流组件,换成传统瀑布流后计算位置的方式后、整个位置计算大概耗时只要不到100ms左右。加上组件渲染的时间500ms + 200ms重设前浏览器的dom渲染+ 100ms 位置重设,一起一共大概只要800ms

经过以上轮番优化后整个渲染明显要流畅许多,基本上loading状态消失后内容很快就能展示出来了。渲染速度比起最初的3.xs整整提升了差不多快5倍

后续优化建议:
把每个卡片内几个按钮的Popover,Dialog变成整个列表只有一个组件。

总结
  • 列表内如果含有大量内容块应避免过多的Popover,Dialog组件
  • 没事多关注组件的性能,时时刻刻关注性能指标,多考虑性能差的电脑
  • 动画虽好,但是用的不好就是性能杀手。性能不好的电脑分分钟“Tab未响应”
  • 在使用上尽量避免在一个页面内几处动画同时运行。
  • 不可视区域内不应该有动画

来源:

EOS API服务哪家强?

作者 fun
2019年5月24日 08:00

前段时间终于试着复活了下EOSVotersTracker,过程艰辛

本文仅从该项目的需求来选择的,读者应按自己实际情况和应用来决定使用哪个~

EOSVotersTracker

在去年 6 月 EOS 主网刚启动,投票还未满足 15%抵押的时候,我出于对投票行为的好奇,于是想能不能提供一个工具来分析节点到底被谁投了,是什么导致了排名的变化,而且那会儿我们也在参与节点竞选。
对投票过程也很感兴趣。说干就干,大概 2 小时就写好了数据收集部分:

  • 从第 1 个block开始遍历
  • 从每个block中拿出voteproducer相关对 action
  • 根据action对执行参数在内存中构建出投票关系
  • 再提供 API 接口查询返回相应的信息

当然从现在来看,很多显然是欠缺考虑的。
比如说,与排名相关不仅仅只是投票角色的增减:

  • stake 和 untake 都会造成投票权重的变化从而导致排名的变化
  • 代理给 proxy 的投票人的 stake、untake,都会引起排名的变化
  • 有些 stake 行为是作为 inline_action 被间接调用的
  • EOS get_block 的 RPC 里是不包含 inline_action 的
  • 投票人的权重会随着时间递减,相隔时间太久,重新 stake 会导致投票权重变大

再就是后来 block 越来越多,重来一次就要遍历从头到尾的 block 找出和投票相关的 action
以上的种种问题一直都存在,技术债越积越深

voters 内存表

后来没办法只能寻求更简便的办法,早在上线没多久就知道还有个 voters 表存储了所有选民的 stake 情况 vote_weight 情况。

后面就考虑:

  • 能不能一直 dump 这个表的状态
  • 通过 diff 每条数据的差异来得到投票人行为的变化

当时在本地节点测试了下:

  • 20w 投票人,dump 出来5分钟左右

后来还没来得及继续完善,我们节点就关了,因为一直没拉到票~

eosinfra 社区代理 API

该 api 是对社区节点健康检查并进行负载均衡的一个服务。由 BlockMatrix 和 EOS ASIA 提供,此外他们还提供私有的部署服务 eosinfra.io
社区node一番测试下来,dump voters 表太慢了。。

EOSPark

提供免费key申请,测试了一下:

  • 每个 key 并发上限 5
  • 本机dump 还是蛮快
  • api 和 eos 标准 api 差不多

测试下来:

  • dump 50w voters 大概要 100 分钟
  • 多申请几个 key 做负载均衡
  • 应该能减少到 30 小时。

最后扔 aws 上才发现。。。该 api 部署的在国内阿里云。国外访问太慢了…

Dfuse

最后才看 dfuse,翻了一遍:

  • 没找到 table_rows 的 api
  • 只找到一个 websocket stream table rows 的 Api

测了一下:

  • 能实时监听表的变化
  • 但是设了 fetch:true 之后,很长时间没有返回

正当我准备放弃的时候,又扫了一遍 rest api.

  • 发现一个 state/table 的接口

抱着试试看的心态调用了下,很快就返回了 50w voters 接近 120mb 的 snapshot 数据及截止到什么位置的 block number。
那么到这里基本上:

  • 可以先 websokcket stream 监听最新的变化
  • 再用 state API 获取最新的 snapshot
  • 遍历 snapshot 之后再遍历 stream 的变化
  • 通过 stream 的变化来 diff 和之前 row 的变化来
  • 得到一个投票行为的变化

Redis

之前在 node 里用内存来存储关系,在后面看来还是很乱。
吸取教训后,决定还是用 redis 来存储。
毕竟 redis 的有序集合还是很适合来存储投票关系的。

  • 启动前清空 redis
  • 利用 snapshot 拿到的数据写入到 redis
  • 再根据 stream 拿到的变化来比对 redis 里的状态得到一个 change
  • 提供 api 查询这些 change

缺点

dfuse 虽然好用但他是一个非标的 API,倘若某天他倒闭了那么也就。。。
到时候再说吧,毕竟走 dump rows 也是可取的。只是有延迟而已!

996.ICU项目Stars构成分析

作者 fun
2019年4月1日 08:00

996这话题最近太火了,上周五早上看icu stars才4w多一点,晚上就飙到10w了。作为一个当今的社会现象(还是本行),不免对背后的数据所代表的意义感兴趣。

数据抓取

于是赶紧倒腾了脚本扔服务器准备把数据抓下来瞧瞧、能抓的数据也不多,每个用户能拿到的维度也就location,organization。


github个人信息页还有email,description, stars数,粉丝数。

具备分析意义的location和organization能大概知道中国大概哪些公司的程序员、哪些城市、对这件事的关注度比较高。email可以用来骚扰?毕竟汇集了中国的大部分程序员。。

数据分析


总数12w的star里有1.4w具备地域分析、具备组织分析意义。

主要组织


1.7w填了org的用户,主要构成是BAT,接着是浙江和交通大学、这里还能做很多拆分(数据清洗懒得弄了、文末有本报表的链接自己看吧

主要地域


1.4w包含地域,中主要地区是北京,上海,深圳,广州,接着南京。倒是很符合互联网公司的分布规律.. 地址类数据清洗太恶心了,百度地图api对英文识别很差,google map是牛逼可惜没法用。

关于996

我是很讨厌强制要求的公司。但是认为应该对自己工作产生热情。如果你没有这种热情,那是不是996对你来说都很难过!没有热情、兴趣、仅受外力的驱使的工作干起来是很难的。

报告链接:
https://datastudio.google.com/open/1wcXTplzGEZCqnmQ6yKK1FVpXW0bG5mo9

❌
❌