Commit ef36edad by Иван Кубота

clean out and refactor

parent 72c40ff0
номер карточки,ингредиент,молочка,мясо,крупа,яйцо,овощ,углевод,всякое
1,Блины,1,,,1,,,
1,бекон с/к,,1,,,,,
1,ветчина куриная,,1,,,,,
1,сливки питьевые,1,,,,,,
1,куриная грудка су-вид,,1,,,,,
1,сыр твердый «Пармезан»,1,,,,,,
2,блины,,,1,1,,,
2,филе грудки куриное,,1,,,,,
2,лук репчатый свежий,,,,,1,,
2,шампиньоны свежие,,,,,1,,
2,соус «Бешамель»,1,,,,1,,
2,масло подсолнечное,,,,,1,,
2,"сыр""Чечил""",1,,,,,,
3,блины,1,,,1,,,
3,ветчина,,1,,,,,
3,сыр,1,,,,,,
4,Блины,1,,,1,,,
4,свиной фарш,,1,,,,,
4,говяжьий фарш,,1,,,,,
5,Блины,1,,,1,,,
5,картофель отварной,,,,,1,,
5,шампиньоны жареные,,,,,1,,
5,масло подсолнечное,,,,,1,,
6,вишня быстрозамороженная,,,,,1,,
6,сахар,,,,,,1,
6,загуститель — пектин,,,,,1,,
6,лимонная кислота,,,,,,,1
7,малина замороженная,,,,,1,,
7,сахар,,,,,,1,
8,сахар,,,,,,1,
8,слива свежая или быстрозамороженная,,,,,1,,
8,лимоны свежие,,,,,1,,
8,имбирь свежий,,,,,1,,
8,загуститель — пектин,,,,,1,,
9,черника свежая или быстрозамороженная,,,,,1,,
9,сахар,,,,,,1,
10,клубника свежая,,,,,1,,
10,листья мяты свежие,,,,,1,,
10,сахар,,,,,,1,
11,Филе куриное замороженное,,1,,,,,
11,капуста белокачанная свежая,,,,,1,,
11,крупа рисовая шлифованная,,,1,,,,
11,яйцо куриное пищевое,,,,1,,,
11,мука пшеничная,,,,,,,
11,масло подсолнечное,,,,,,,
12,«молоко» кокосовое,,,,,,,
12,тыква свежая,,,,,,,
12,чеснок свежий,,,,,,,
12,масло подсолнечное,,,,,,,
12,тимьян свежий,,,,,,,
12,перец Кочукару молотый,,,,,,,
12,бадья сушеный молотый,,,,,,,
13,фарш из минтая пищевой мороженый,,,,,,,
13,масло подсолнечное,,,,,,,
13,белок яичный,,,,,,,
13,сливки,,,,,,,
13,хлеб из муки пшеничной,,,,,,,
13,запечённые овощи,,,,,,,
14,Макаронные изделия Спагетти,,,,,,,
14,филе лососевых рыб,,,,,,,
14,лук репчатый свежий,,,,,,,
14,помидоры в собственном соку,,,,,,,
15,капуста свежая белокочанная,,,,,,,
15,филе куриного окорочка,,,,,,,
15,филе куриной грудки,,,,,,,
15,крупа рисовая,,,,,,,
15,соус,,,,,,,
16,мука пшеничная,,,,,,,
16,"масло сливочное м. д. ж. 82,5%",,,,,,,
16,сахар,,,,,,,
16,солод ржаной сухой неферментированный,,,,,,,
16,дрожжи хлебопекарные прессованные,,,,,,,
16,соль пищевая,,,,,,,
16,семена кунжута черного,,,,,,,
17,мука ржаная,,,,,,,
17,«заварка»,,,,,,,
17,закваска ржаная,,,,,,,
17,сахар,,,,,,,
17,кориандр молотый,,,,,,,
17,кориандр цельный,,,,,,,
18,мука пшеничная в/с,,,,,,,
18,"закваска (мука пшеничная в/с, вода)",,,,,,,
18,масло оливковое Extra Vergin,,,,,,,
19,мука пшеничная,,,,,,,
19,мука пшеничная свежесмолотая грубого помола,,,,,,,
19,семя льна коричневое и белое,,,,,,,
20,мука пшеничная хлебопекарная,,,,,,,
20,"масло сливочное массовая доля жира 82,5%",,,,,,,
20,сахар,,,,,,,
20,дрожжи хлебопекарные прессованные,,,,,,,
20,меланж,,,,,,,
21,Мидии мясо варено-мороженное,,,,,,,
22,Кальмар,,,,,,,
23,Креветка,,,,,,,
24,Кальмар,,,,,,,
25,Кальмар,,,,,,,
26,листья шпината резаные,,,,,,,
27,рис,,,,,,,
27,зерна кукурузы,,,,,,,
27,зеленый горошек,,,,,,,
27,перец,,,,,,,
28,морковь,,,,,,,
28,зеленый горошек,,,,,,,
28,перец сладкий,,,,,,,
28,кукуруза зерно,,,,,,,
28,фасоль резаная,,,,,,,
29,морковь,,,,,,,
29,картофель,,,,,,,
29,лук,,,,,,,
29,зеленый горошек,,,,,,,
29,зеленая фасоль,,,,,,,
30,Перец сладкий свежий,,,,,,,
30,морковь столовая свежая,,,,,,,
30,"лук репчатый свежий,",,,,,,,
30,лук порей свежий,,,,,,,
30,сельдерей свежий,,,,,,,
31,свинина,,,,,,,
31,шпик,,,,,,,
31,чеснок свежий,,,,,,,
31,коньяк,,,,,,,
31,перец черный и душистый,,,,,,,
32,мясо индейки,,,,,,,
32,сухое молоко,,,,,,,
32,экстракты специй,,,,,,,
33,филе грудки и бедра индейки,,,,,,,
33,продукт яичный (меланж),,,,,,,
33,чеснок свежий,,,,,,,
33,пряности натуральные молотые,,,,,,,
34,говядина,,,,,,,
34,шпик,,,,,,,
34,свинина,,,,,,,
34,пряности,,,,,,,
34,стартовая культура микроорганизмов,,,,,,,
35,свинина,,,,,,,
35,кровь пищевая сырая говяжья,,,,,,,
35,крупа гречневая,,,,,,,
35,лук репчатый свежий,,,,,,,
35,лук репчатый жареный,,,,,,,
35,перец черный и душистый,,,,,,,
41,персики свежие,,,,,,,
42,яблоки,,,,,,,
43,яблоки свежие,,,,,,,
43,сахар,,,,,,,
43,белок яйца куриного,,,,,,,
43,сок лимонный прямого отжима,,,,,,,
44,яблоки свежие,,,,,,,
44,вишня свежая или свежемороженая,,,,,,,
44,сахар,,,,,,,
44,белок яйца куриного,,,,,,,
44,лимонный сок прямого отжима,,,,,,,
45,сахар,,,,,,,
45,пюре яблочное,,,,,,,
45,ягоды облепихи замороженные,,,,,,,
45,желирующий агент — пектин яблочный,,,,,,,
45,лимонная кислота,,,,,,,
46,булгур,,,,,,,
47,кускус,,,,,,,
48,киноа,,,,,,,
49,рис,,,,,,,
50,рис,,,,,,,
51,молоко обезжиренное,,,,,,,
51,молоко цельное с использованием йогуртовой закваски,,,,,,,
52,нормализованное молоко,,,,,,,
52,сироп шиповника,,,,,,,
52,сахар,,,,,,,
52,термофильный молочнокислый стрептококк,,,,,,,
52,молочнокислая болгарская палочка,,,,,,,
52,молочнокислая палочка,,,,,,,
53,молоко нормализованное,,,,,,,
53,закваска на чистых культурах термофильного молочнокислого стрептококка и болгарской молочнокислой палочки,,,,,,,
53,молочные дрожжи,,,,,,,
54,молоко нормализованное,,,,,,,
54,закваска Icelandic SKYR,,,,,,,
55,молоко обезжиренное,,,,,,,
55,молоко цельное,,,,,,,
55,заквасочные молочнокислые культуры,,,,,,,
56,мясо говядина,,,,,,,
56,экстракты специй,,,,,,,
56,специи,,,,,,,
56,ягоды можжевельника,,,,,,,
56,стартовая культура микроорганизмов,,,,,,,
57,мясо индейки,,,,,,,
57,"экстракт черного, душистого перца",,,,,,,
57,экстракт мускатного ореха,,,,,,,
57,культура стартовая бактериальная Фермаром,,,,,,,
58,свинина,,,,,,,
58,соль морская пищевая,,,,,,,
58,сахар,,,,,,,
59,Филе грудки индейки,,,,,,,
59,подсолнечное масло,,,,,,,
59,овощи,,,,,,,
59,"специи и их экстракты: чеснок, паприка, томат, перец черный, горчица, кориандр, перец красный, перец белый, орегано",,,,,,,
59,крахмал картофельный,,,,,,,
60,говядина,,,,,,,
61,свинина,,,,,,,
62,кролик,,,,,,,
63,индейка,,,,,,,
64,курица,,,,,,,
65,сахар,,,,,,,
65,настой чая черного,,,,,,,
65,настой лимона,,,,,,,
65,сок лимона концентрированный,,,,,,,
65,консервант — сорбиновая кислота,,,,,,,
65,ароматизатор натуральный «Масло эфирное лимонное»,,,,,,,
66,вода питьевая,,,,,,,
66,зерна овса,,,,,,,
66,чай черный и зеленый,,,,,,,
66,чистая культура чайного гриба,,,,,,,
66,экстракт стевии,,,,,,,
67,вода питьевая подготовленная,,,,,,,
67,растительный экстракт лимона,,,,,,,
67,растительный экстракт имбиря,,,,,,,
69,вода кокосовая,,,,,,,
69,масло кокосовое природное холодного отжима,,,,,,,
69,патока крахмальная,,,,,,,
69,"загустители (крахмал тапиоковый природный, пектин яблочный)",,,,,,,
69,бактериальная закваска,,,,,,,
70,свинина,,,,,,,
70,печень куриная,,,,,,,
70,гранатовый сок,,,,,,,
70,морковь сушеная,,,,,,,
70,молоко сухое,,,,,,,
70,желатин,,,,,,,
71, «сыр» тофу,,,,,,,
71,масло подсолнечное нерафинированное,,,,,,,
71,масло оливковое нерафинированное,,,,,,,
71,перец сладкий сушеный,,,,,,,
71,томаты сушеные,,,,,,,
71,зеленый базилик сушеный,,,,,,,
71,майоран сушеный,,,,,,,
72,горбуша,,,,,,,
72,масло подсолнечное рафинированное,,,,,,,
72,творог м. д. ж. 9%,,,,,,,
72,ядро миндаля сушёное,,,,,,,
72,"молоко сухое м. д. ж. 1,5%",,,,,,,
72,луковый порошок,,,,,,,
72,крахмал картофельный,,,,,,,
72,крупа манная,,,,,,,
72,соль пищевая,,,,,,,
72,сахар,,,,,,,
72,перец чёрный молотый,,,,,,,
73,печень индейки,,,,,,,
73,свинина,,,,,,,
73,шпик,,,,,,,
73,яичный продукт (меланж),,,,,,,
73,груша вяленая,,,,,,,
73,соль,,,,,,,
73,комплексная пищевая добавка,,,,,,,
73,лук сушеный,,,,,,,
74,печень кролика,,,,,,,
74,шампиньоны свежие,,,,,,,
74,шпик свиной,,,,,,,
74,свинина,,,,,,,
74,лук репчатый,,,,,,,
75,бульон говяжий натуральный,,,,,,,
75,лук репчатый,,,,,,,
75,морковь,,,,,,,
75,томат-паста,,,,,,,
75,говядина,,,,,,,
75,рис длиннозерный пропаренный,,,,,,,
76,Борщ,,,,,,,
77,бульон куриный натуральный,,,,,,,
77,"филе куриное, лапша",,,,,,,
77,лук репчатый свежий,,,,,,,
77,морковь свежая,,,,,,,
77,соль поваренная пищевая,,,,,,,
77,петрушка свежая,,,,,,,
78,рыбный бульон из семги,,,,,,,
78,запеченные овощи,,,,,,,
78,картофель свежий,,,,,,,
78,лосось атлантический (семга),,,,,,,
78,сливки,,,,,,,
78,укроп свежий,,,,,,,
78,черный перец горошком,,,,,,,
79,рыбный бульон из лосося семги,,,,,,,
79,запеченные овощи,,,,,,,
79,картофель свежий,,,,,,,
79,морковь столовая свежая,,,,,,,
79,филе семги,,,,,,,
79,укроп свежий,,,,,,,
79,черный перец горошком,,,,,,,
80,омуль,,,,,,,
80,мускун,,,,,,,
80,чир,,,,,,,
81,скумбрия атлантическая,,,,,,,
81,горбуша дальневосточная,,,,,,,
82,горбуша,,,,,,,
82,скумбрия,,,,,,,
82,саворин,,,,,,,
83,"корюшка (непотрошеная, с головой)",,,,,,,
83,соль поваренная пищевая,,,,,,,
84,Муксун,,,,,,,
84,соль поваренная пищевая,,,,,,,
85,Яблоко Гренни Смит,,,,,,,
85,свекла столовая свежая,,,,,,,
85,соус мятный,,,,,,,
85,чернослив сушеный,,,,,,,
85,ядра арахиса жареные,,,,,,,
86,яйцо,,,,,,,
86,майонез,,,,,,,
86,филе горбуши отварное су-вид,,,,,,,
86,картофель отварной,,,,,,,
86,морковь столовая отварная,,,,,,,
86,сыр Гауда,,,,,,,
87,салат «Айсберг»,,,,,,,
87,грудка куриная,,,,,,,
87,шампиньоны,,,,,,,
87,яйцо куриное,,,,,,,
87,маслины,,,,,,,
87,зеленый лук,,,,,,,
87,кинза,,,,,,,
87,кунжут,,,,,,,
87,масло растительное,,,,,,,
87,соевый соус,,,,,,,
87,мед,,,,,,,
88,Ветчина отварная,,,,,,,
88,картофель отварной,,,,,,,
88,"морковь продовольственная отварная,",,,,,,,
88,огурцы соленые,,,,,,,
88,зеленый горошек быстрозамороженный,,,,,,,
88,яйцо куриное пищевое отварное,,,,,,,
88,Соус: домашний майонез,,,,,,,
88,горчица столовая,,,,,,,
88,сок лимона прямого отжима,,,,,,,
89,"свекла столовая отварная,",,,,,,,
89,картофель отварной,,,,,,,
89,морковь столовая отварная,,,,,,,
89,огурцы консервированные,,,,,,,
89,капуста маринованная,,,,,,,
89,горошек зелёный консервированный,,,,,,,
89,масло подсолнечное нерафинированно,,,,,,,
90,молоко пастеризованное,,,,,,,
90,бактериальная закваска мезофильных молочнокислых микроорганизмов,,,,,,,
90,соль пищевая,,,,,,,
91,пастеризованное козье молоко,,,,,,,
91,ягоды брусники свежие,,,,,,,
91,яблоко свежее,,,,,,,
91,закваска - мезофильные молочнокислые микроорганизмы,,,,,,,
92,молоко коровье пастеризованное,,,,,,,
92,соль поваренная пищевая,,,,,,,
92,закваска молочнокислых бактерий,,,,,,,
93,молоко нормализованное пастеризованное,,,,,,,
93,бактериальная закваска мезофильных молочнокислых микроорганизмов,,,,,,,
94,молоко пастеризованное,,,,,,,
94,бактериальная закваска мезофильных и термофильных молочнокислых микроорганизмов,,,,,,,
95,Целлюлоза,,,,,,,
96,сливки,,,,,,,
96,сметана,,,,,,,
96,повидло яблочное стерилизованное,,,,,,,
96,шоколад,,,,,,,
96,мука пшеничная,,,,,,,
96,сахарная пудра,,,,,,,
96,сахар,,,,,,,
96,молоко цельное сгущенное с сахаром,,,,,,,
96,масло сладкосливочное,,,,,,,
96,какао-порошок,,,,,,,
96,яйцо куриное столовое пищевое,,,,,,,
96,разрыхлитель,,,,,,,
97,молоко коровье,,,,,,,
97,сливки пастеризованные,,,,,,,
97,сахар,,,,,,,
97,желатин пищевой,,,,,,,
97,манго мороженое,,,,,,,
97,маракуйя мороженая,,,,,,,
97,натуральный ароматизатор — французская ваниль,,,,,,,
97,апельсин свежий,,,,,,,
98,молоко кокосовое,,,,,,,
98,темный шоколад,,,,,,,
98,"мука пшеничная,",,,,,,,
98,сахар,,,,,,,
98,масло подсолнечное,,,,,,,
98,ядро фундука дробленое,,,,,,,
98,какао-порошок,,,,,,,
98,разрыхлитель,,,,,,,
98,пюре черной смородины,,,,,,,
99,"масло «Крестьянское» 72,5%",,,,,,,
99,яйцо куриное,,,,,,,
99,сгущенное молоко с сахаром,,,,,,,
99,мука пшеничная в/с,,,,,,,
99,сахар-песок,,,,,,,
99,ванилин,,,,,,,
100,кокосовое молоко,,,,,,,
100,"смесь для выпечки,",,,,,,,
100,ядро миндаля сладкого,,,,,,,
100,масло кокосовое холодного отжима,,,,,,,
100,сироп тапинамбура,,,,,,,
100,малина свежезамороженная,,,,,,,
100,крахмал кукурузный,,,,,,,
101,мята,,,,,,,
102,чабрец,,,,,,,
103,чай,,,,,,,
103,мята,,,,,,,
104,чай,,,,,,,
105,гречиха татарская,,,,,,,
\ No newline at end of file
[
{
"cid": 1,
"type": 0,
"eid": 16,
"tag": 1
},
{
"cid": 2,
"type": 0,
"eid": 3,
"tag": 1
},
{
"cid": 3,
"type": 0,
"eid": 3,
"tag": 2
},
{
"cid": 4,
"type": 0,
"eid": 4,
"tag": 1
},
{
"cid": 5,
"type": 0,
"eid": 4,
"tag": 2
},
{
"cid": 6,
"type": 0,
"eid": 21,
"tag": 2
},
{
"cid": 7,
"type": 0,
"eid": 32,
"tag": 2
},
{
"cid": 8,
"type": 0,
"eid": 56,
"tag": 2
},
{
"cid": 9,
"type": 0,
"eid": 57,
"tag": 2
},
{
"cid": 10,
"type": 0,
"eid": 70,
"tag": 2
},
{
"cid": 11,
"type": 0,
"eid": 73,
"tag": 2
},
{
"cid": 12,
"type": 0,
"eid": 1,
"tag": 1
},
{
"cid": 13,
"type": 0,
"eid": 2,
"tag": 1
},
{
"cid": 14,
"type": 0,
"eid": 5,
"tag": 1
},
{
"cid": 15,
"type": 0,
"eid": 3,
"tag": 3
},
{
"cid": 16,
"type": 0,
"eid": 31,
"tag": 2
},
{
"cid": 17,
"type": 0,
"eid": 33,
"tag": 2
},
{
"cid": 18,
"type": 0,
"eid": 34,
"tag": 2
},
{
"cid": 19,
"type": 0,
"eid": 35,
"tag": 2
},
{
"cid": 20,
"type": 0,
"eid": 6,
"tag": 4
},
{
"cid": 21,
"type": 0,
"eid": 8,
"tag": 4
},
{
"cid": 22,
"type": 0,
"eid": 9,
"tag": 4
},
{
"cid": 23,
"type": 0,
"eid": 10,
"tag": 4
},
{
"cid": 24,
"type": 0,
"eid": 6,
"tag": 5
},
{
"cid": 25,
"type": 0,
"eid": 8,
"tag": 5
},
{
"cid": 26,
"type": 0,
"eid": 9,
"tag": 5
},
{
"cid": 27,
"type": 0,
"eid": 10,
"tag": 5
},
{
"cid": 28,
"type": 0,
"eid": 7,
"tag": 4
},
{
"cid": 29,
"type": 0,
"eid": 100,
"tag": 4
},
{
"cid": 30,
"type": 0,
"eid": 98,
"tag": 6
},
{
"cid": 31,
"type": 0,
"eid": 100,
"tag": 6
},
{
"cid": 32,
"type": 0,
"eid": 98,
"tag": 4
},
{
"cid": 33,
"type": 0,
"eid": 96,
"tag": 4
},
{
"cid": 34,
"type": 0,
"eid": 96,
"tag": 7
},
{
"cid": 35,
"type": 0,
"eid": 98,
"tag": 7
},
{
"cid": 36,
"type": 0,
"eid": 96,
"tag": 6
},
{
"cid": 37,
"type": 0,
"eid": 11,
"tag": 2
},
{
"cid": 38,
"type": 0,
"eid": 15,
"tag": 2
},
{
"cid": 39,
"type": 0,
"eid": 12,
"tag": 2
},
{
"cid": 40,
"type": 0,
"eid": 23,
"tag": 2
},
{
"cid": 41,
"type": 0,
"eid": 12,
"tag": 8
},
{
"cid": 42,
"type": 0,
"eid": 23,
"tag": 8
},
{
"cid": 43,
"type": 0,
"eid": 14,
"tag": 8
},
{
"cid": 44,
"type": 0,
"eid": 78,
"tag": 8
},
{
"cid": 45,
"type": 0,
"eid": 79,
"tag": 8
},
{
"cid": 47,
"type": 0,
"eid": 17,
"tag": 1
},
{
"cid": 48,
"type": 0,
"eid": 19,
"tag": 1
},
{
"cid": 49,
"type": 0,
"eid": 20,
"tag": 1
},
{
"cid": 50,
"type": 0,
"eid": 18,
"tag": 1
},
{
"cid": 51,
"type": 0,
"eid": 22,
"tag": 2
},
{
"cid": 52,
"type": 0,
"eid": 24,
"tag": 2
},
{
"cid": 53,
"type": 0,
"eid": 25,
"tag": 2
},
{
"cid": 54,
"type": 0,
"eid": 22,
"tag": 8
},
{
"cid": 55,
"type": 0,
"eid": 24,
"tag": 8
},
{
"cid": 56,
"type": 0,
"eid": 25,
"tag": 8
},
{
"cid": 57,
"type": 0,
"eid": 27,
"tag": 9
},
{
"cid": 58,
"type": 0,
"eid": 28,
"tag": 9
},
{
"cid": 59,
"type": 0,
"eid": 29,
"tag": 9
},
{
"cid": 60,
"type": 0,
"eid": 30,
"tag": 9
},
{
"cid": 61,
"type": 0,
"eid": 26,
"tag": 9
},
{
"cid": 62,
"type": 0,
"eid": 36,
"tag": 10
},
{
"cid": 63,
"type": 0,
"eid": 37,
"tag": 10
},
{
"cid": 64,
"type": 0,
"eid": 38,
"tag": 10
},
{
"cid": 65,
"type": 0,
"eid": 40,
"tag": 10
},
{
"cid": 66,
"type": 0,
"eid": 36,
"tag": 11
},
{
"cid": 67,
"type": 0,
"eid": 37,
"tag": 11
},
{
"cid": 68,
"type": 0,
"eid": 38,
"tag": 11
},
{
"cid": 69,
"type": 0,
"eid": 40,
"tag": 11
},
{
"cid": 70,
"type": 0,
"eid": 41,
"tag": 6
},
{
"cid": 71,
"type": 0,
"eid": 42,
"tag": 6
},
{
"cid": 72,
"type": 0,
"eid": 43,
"tag": 6
},
{
"cid": 73,
"type": 0,
"eid": 44,
"tag": 6
},
{
"cid": 74,
"type": 0,
"eid": 65,
"tag": 12
},
{
"cid": 75,
"type": 0,
"eid": 66,
"tag": 12
},
{
"cid": 76,
"type": 0,
"eid": 103,
"tag": 12
},
{
"cid": 77,
"type": 0,
"eid": 104,
"tag": 12
},
{
"cid": 78,
"type": 0,
"eid": 105,
"tag": 12
},
{
"cid": 79,
"type": 0,
"eid": 46,
"tag": 13
},
{
"cid": 80,
"type": 0,
"eid": 46,
"tag": 14
},
{
"cid": 81,
"type": 0,
"eid": 48,
"tag": 15
},
{
"cid": 82,
"type": 0,
"eid": 48,
"tag": 13
},
{
"cid": 83,
"type": 0,
"eid": 11,
"tag": 16
},
{
"cid": 84,
"type": 0,
"eid": 15,
"tag": 16
},
{
"cid": 85,
"type": 0,
"eid": 27,
"tag": 16
},
{
"cid": 86,
"type": 0,
"eid": 49,
"tag": 16
},
{
"cid": 87,
"type": 0,
"eid": 50,
"tag": 16
},
{
"cid": 88,
"type": 0,
"eid": 75,
"tag": 16
},
{
"cid": 89,
"type": 0,
"eid": 53,
"tag": 17
},
{
"cid": 90,
"type": 0,
"eid": 96,
"tag": 18
},
{
"cid": 91,
"type": 0,
"eid": 53,
"tag": 18
},
{
"cid": 92,
"type": 0,
"eid": 55,
"tag": 18
},
{
"cid": 93,
"type": 0,
"eid": 72,
"tag": 19
},
{
"cid": 94,
"type": 0,
"eid": 72,
"tag": 8
},
{
"cid": 95,
"type": 0,
"eid": 2,
"tag": 2
},
{
"cid": 96,
"type": 0,
"eid": 14,
"tag": 2
},
{
"cid": 97,
"type": 0,
"eid": 59,
"tag": 2
},
{
"cid": 98,
"type": 0,
"eid": 64,
"tag": 2
},
{
"cid": 99,
"type": 0,
"eid": 77,
"tag": 2
},
{
"cid": 101,
"type": 0,
"eid": 86,
"tag": 2
},
{
"cid": 102,
"type": 0,
"eid": 63,
"tag": 2
},
{
"cid": 103,
"type": 0,
"eid": 60,
"tag": 2
},
{
"cid": 104,
"type": 0,
"eid": 61,
"tag": 2
},
{
"cid": 105,
"type": 0,
"eid": 61,
"tag": 20
},
{
"cid": 106,
"type": 0,
"eid": 47,
"tag": 13
},
{
"cid": 107,
"type": 0,
"eid": 47,
"tag": 21
},
{
"cid": 108,
"type": 0,
"eid": 51,
"tag": 17
},
{
"cid": 109,
"type": 0,
"eid": 51,
"tag": 18
},
{
"cid": 110,
"type": 0,
"eid": 1,
"tag": 2
},
{
"cid": 111,
"type": 0,
"eid": 99,
"tag": 6
},
{
"cid": 112,
"type": 0,
"eid": 99,
"tag": 4
},
{
"cid": 113,
"type": 0,
"eid": 65,
"tag": 22
},
{
"cid": 114,
"type": 0,
"eid": 66,
"tag": 22
},
{
"cid": 115,
"type": 0,
"eid": 67,
"tag": 22
},
{
"cid": 116,
"type": 0,
"eid": 69,
"tag": 22
},
{
"cid": 117,
"type": 0,
"eid": 68,
"tag": 22
},
{
"cid": 118,
"type": 0,
"eid": 68,
"tag": 23
},
{
"cid": 119,
"type": 0,
"eid": 71,
"tag": 2
},
{
"cid": 120,
"type": 0,
"eid": 74,
"tag": 2
},
{
"cid": 121,
"type": 0,
"eid": 70,
"tag": 24
},
{
"cid": 122,
"type": 0,
"eid": 71,
"tag": 24
},
{
"cid": 123,
"type": 0,
"eid": 73,
"tag": 24
},
{
"cid": 124,
"type": 0,
"eid": 74,
"tag": 24
},
{
"cid": 125,
"type": 0,
"eid": 52,
"tag": 17
},
{
"cid": 126,
"type": 0,
"eid": 52,
"tag": 18
},
{
"cid": 127,
"type": 0,
"eid": 92,
"tag": 18
},
{
"cid": 128,
"type": 0,
"eid": 92,
"tag": 3
},
{
"cid": 129,
"type": 0,
"eid": 91,
"tag": 3
},
{
"cid": 130,
"type": 0,
"eid": 91,
"tag": 18
},
{
"cid": 131,
"type": 0,
"eid": 90,
"tag": 3
},
{
"cid": 132,
"type": 0,
"eid": 90,
"tag": 17
},
{
"cid": 133,
"type": 0,
"eid": 93,
"tag": 3
},
{
"cid": 134,
"type": 0,
"eid": 94,
"tag": 3
},
{
"cid": 135,
"type": 0,
"eid": 93,
"tag": 17
},
{
"cid": 136,
"type": 0,
"eid": 94,
"tag": 17
},
{
"cid": 137,
"type": 0,
"eid": 54,
"tag": 18
},
{
"cid": 138,
"type": 0,
"eid": 54,
"tag": 22
},
{
"cid": 139,
"type": 0,
"eid": 62,
"tag": 2
},
{
"cid": 140,
"type": 0,
"eid": 85,
"tag": 25
},
{
"cid": 141,
"type": 0,
"eid": 86,
"tag": 25
},
{
"cid": 142,
"type": 0,
"eid": 87,
"tag": 25
},
{
"cid": 143,
"type": 0,
"eid": 88,
"tag": 25
},
{
"cid": 144,
"type": 0,
"eid": 89,
"tag": 25
},
{
"cid": 145,
"type": 0,
"eid": 58,
"tag": 2
},
{
"cid": 146,
"type": 0,
"eid": 58,
"tag": 20
},
{
"cid": 147,
"type": 0,
"eid": 3,
"tag": 20
},
{
"cid": 148,
"type": 0,
"eid": 4,
"tag": 20
},
{
"cid": 149,
"type": 0,
"eid": 31,
"tag": 20
},
{
"cid": 150,
"type": 0,
"eid": 34,
"tag": 20
},
{
"cid": 151,
"type": 0,
"eid": 35,
"tag": 20
},
{
"cid": 152,
"type": 0,
"eid": 70,
"tag": 20
},
{
"cid": 153,
"type": 0,
"eid": 73,
"tag": 20
},
{
"cid": 154,
"type": 0,
"eid": 74,
"tag": 20
},
{
"cid": 155,
"type": 0,
"eid": 81,
"tag": 26
},
{
"cid": 156,
"type": 0,
"eid": 82,
"tag": 26
},
{
"cid": 157,
"type": 0,
"eid": 81,
"tag": 8
},
{
"cid": 158,
"type": 0,
"eid": 82,
"tag": 8
},
{
"cid": 159,
"type": 0,
"eid": 83,
"tag": 26
},
{
"cid": 160,
"type": 0,
"eid": 84,
"tag": 26
},
{
"cid": 161,
"type": 0,
"eid": 83,
"tag": 8
},
{
"cid": 162,
"type": 0,
"eid": 84,
"tag": 8
},
{
"cid": 163,
"type": 0,
"eid": 80,
"tag": 8
},
{
"cid": 164,
"type": 0,
"eid": 80,
"tag": 26
},
{
"cid": 165,
"type": 0,
"eid": 101,
"tag": 27
},
{
"cid": 166,
"type": 0,
"eid": 103,
"tag": 27
},
{
"cid": 167,
"type": 0,
"eid": 102,
"tag": 27
},
{
"cid": 168,
"type": 0,
"eid": 102,
"tag": 12
},
{
"cid": 169,
"type": 0,
"eid": 95,
"tag": 28
},
{
"cid": 170,
"type": 0,
"eid": 75,
"tag": 29
},
{
"cid": 171,
"type": 0,
"eid": 77,
"tag": 29
},
{
"cid": 172,
"type": 0,
"eid": 78,
"tag": 29
},
{
"cid": 173,
"type": 0,
"eid": 1,
"tag": 30
},
{
"cid": 174,
"type": 0,
"eid": 2,
"tag": 30
},
{
"cid": 175,
"type": 0,
"eid": 3,
"tag": 30
},
{
"cid": 176,
"type": 0,
"eid": 4,
"tag": 30
},
{
"cid": 177,
"type": 0,
"eid": 5,
"tag": 30
},
{
"cid": 178,
"type": 0,
"eid": 1,
"tag": 31
},
{
"cid": 179,
"type": 0,
"eid": 3,
"tag": 31
},
{
"cid": 180,
"type": 0,
"eid": 3,
"tag": 32
},
{
"cid": 181,
"type": 0,
"eid": 31,
"tag": 32
},
{
"cid": 182,
"type": 0,
"eid": 34,
"tag": 32
},
{
"cid": 183,
"type": 0,
"eid": 35,
"tag": 32
},
{
"cid": 184,
"type": 0,
"eid": 58,
"tag": 32
},
{
"cid": 185,
"type": 0,
"eid": 61,
"tag": 32
},
{
"cid": 186,
"type": 0,
"eid": 70,
"tag": 32
},
{
"cid": 187,
"type": 0,
"eid": 73,
"tag": 32
},
{
"cid": 188,
"type": 0,
"eid": 74,
"tag": 32
},
{
"cid": 189,
"type": 0,
"eid": 1,
"tag": 33
},
{
"cid": 190,
"type": 0,
"eid": 2,
"tag": 33
},
{
"cid": 191,
"type": 0,
"eid": 11,
"tag": 33
},
{
"cid": 192,
"type": 0,
"eid": 15,
"tag": 33
},
{
"cid": 193,
"type": 0,
"eid": 43,
"tag": 33
},
{
"cid": 195,
"type": 0,
"eid": 64,
"tag": 33
},
{
"cid": 196,
"type": 0,
"eid": 70,
"tag": 33
},
{
"cid": 197,
"type": 0,
"eid": 77,
"tag": 33
},
{
"cid": 198,
"type": 0,
"eid": 87,
"tag": 33
},
{
"cid": 199,
"type": 0,
"eid": 11,
"tag": 34
},
{
"cid": 200,
"type": 0,
"eid": 86,
"tag": 34
},
{
"cid": 201,
"type": 0,
"eid": 87,
"tag": 34
},
{
"cid": 202,
"type": 0,
"eid": 88,
"tag": 34
},
{
"cid": 203,
"type": 0,
"eid": 96,
"tag": 34
},
{
"cid": 204,
"type": 0,
"eid": 99,
"tag": 34
},
{
"cid": 205,
"type": 0,
"eid": 6,
"tag": 6
},
{
"cid": 206,
"type": 0,
"eid": 8,
"tag": 6
},
{
"cid": 207,
"type": 0,
"eid": 9,
"tag": 6
},
{
"cid": 208,
"type": 0,
"eid": 10,
"tag": 6
},
{
"cid": 209,
"type": 0,
"eid": 7,
"tag": 35
},
{
"cid": 210,
"type": 0,
"eid": 100,
"tag": 35
},
{
"cid": 211,
"type": 0,
"eid": 9,
"tag": 36
},
{
"cid": 212,
"type": 0,
"eid": 6,
"tag": 37
},
{
"cid": 213,
"type": 0,
"eid": 44,
"tag": 37
},
{
"cid": 214,
"type": 0,
"eid": 44,
"tag": 34
},
{
"cid": 215,
"type": 0,
"eid": 98,
"tag": 38
},
{
"cid": 216,
"type": 0,
"eid": 5,
"tag": 39
},
{
"cid": 217,
"type": 0,
"eid": 98,
"tag": 39
},
{
"cid": 218,
"type": 0,
"eid": 8,
"tag": 40
},
{
"cid": 219,
"type": 0,
"eid": 85,
"tag": 41
},
{
"cid": 220,
"type": 0,
"eid": 85,
"tag": 42
},
{
"cid": 221,
"type": 0,
"eid": 85,
"tag": 43
},
{
"cid": 222,
"type": 0,
"eid": 85,
"tag": 44
},
{
"cid": 223,
"type": 0,
"eid": 85,
"tag": 45
},
{
"cid": 224,
"type": 0,
"eid": 13,
"tag": 8
},
{
"cid": 225,
"type": 0,
"eid": 13,
"tag": 26
},
{
"cid": 226,
"type": 0,
"eid": 13,
"tag": 46
},
{
"cid": 227,
"type": 0,
"eid": 13,
"tag": 9
},
{
"cid": 228,
"type": 0,
"eid": 7,
"tag": 6
},
{
"cid": 229,
"type": 0,
"eid": 12,
"tag": 47
},
{
"cid": 230,
"type": 0,
"eid": 12,
"tag": 48
},
{
"cid": 231,
"type": 0,
"eid": 11,
"tag": 49
},
{
"cid": 232,
"type": 0,
"eid": 15,
"tag": 49
},
{
"cid": 233,
"type": 0,
"eid": 17,
"tag": 50
},
{
"cid": 234,
"type": 0,
"eid": 19,
"tag": 50
},
{
"cid": 235,
"type": 0,
"eid": 76,
"tag": 51
},
{
"cid": 236,
"type": 0,
"eid": 76,
"tag": 52
},
{
"cid": 237,
"type": 0,
"eid": 76,
"tag": 53
},
{
"cid": 238,
"type": 0,
"eid": 14,
"tag": 48
},
{
"cid": 239,
"type": 0,
"eid": 14,
"tag": 53
},
{
"cid": 240,
"type": 0,
"eid": 16,
"tag": 54
},
{
"cid": 241,
"type": 0,
"eid": 16,
"tag": 50
},
{
"cid": 242,
"type": 0,
"eid": 18,
"tag": 50
},
{
"cid": 243,
"type": 0,
"eid": 20,
"tag": 6
},
{
"cid": 244,
"type": 0,
"eid": 22,
"tag": 55
},
{
"cid": 245,
"type": 0,
"eid": 24,
"tag": 55
},
{
"cid": 246,
"type": 0,
"eid": 25,
"tag": 55
},
{
"cid": 247,
"type": 0,
"eid": 23,
"tag": 47
},
{
"cid": 248,
"type": 0,
"eid": 14,
"tag": 56
},
{
"cid": 249,
"type": 0,
"eid": 32,
"tag": 57
},
{
"cid": 250,
"type": 0,
"eid": 33,
"tag": 57
},
{
"cid": 251,
"type": 0,
"eid": 57,
"tag": 57
},
{
"cid": 252,
"type": 0,
"eid": 59,
"tag": 57
},
{
"cid": 253,
"type": 0,
"eid": 63,
"tag": 57
},
{
"cid": 254,
"type": 0,
"eid": 73,
"tag": 57
},
{
"cid": 255,
"type": 0,
"eid": 31,
"tag": 58
},
{
"cid": 256,
"type": 0,
"eid": 32,
"tag": 58
},
{
"cid": 257,
"type": 0,
"eid": 33,
"tag": 58
},
{
"cid": 258,
"type": 0,
"eid": 34,
"tag": 58
},
{
"cid": 259,
"type": 0,
"eid": 35,
"tag": 58
},
{
"cid": 260,
"type": 0,
"eid": 26,
"tag": 59
},
{
"cid": 261,
"type": 0,
"eid": 27,
"tag": 60
},
{
"cid": 262,
"type": 0,
"eid": 28,
"tag": 60
},
{
"cid": 263,
"type": 0,
"eid": 27,
"tag": 61
},
{
"cid": 264,
"type": 0,
"eid": 28,
"tag": 61
},
{
"cid": 265,
"type": 0,
"eid": 100,
"tag": 61
},
{
"cid": 266,
"type": 0,
"eid": 30,
"tag": 62
},
{
"cid": 267,
"type": 0,
"eid": 30,
"tag": 63
},
{
"cid": 268,
"type": 0,
"eid": 30,
"tag": 64
}
]
\ No newline at end of file
[
{
"id": 1,
"image": "https://vkusvill.ru/upload/resize/161031/161031_530x300x85_c.jpg"
},
{
"id": 2,
"image": "https://vkusvill.ru/upload/resize/93710/93710_530x300x85_c.jpg"
},
{
"id": 3,
"image": "https://vkusvill.ru/upload/resize/93352/93352_530x300x85_c.jpg"
},
{
"id": 4,
"image": "https://vkusvill.ru/upload/resize/95146/95146_530x300x85_c.jpg"
},
{
"id": 5,
"image": "https://vkusvill.ru/upload/resize/96634/96634_530x300x85_c.jpg"
},
{
"id": 7,
"image": "https://vkusvill.ru/upload/resize/113263/113263_530x300x85_c.jpg"
},
{
"id": 8,
"image": "https://vkusvill.ru/upload/resize/95818/95818_530x300x85_c.jpg"
},
{
"id": 9,
"image": "https://vkusvill.ru/upload/resize/93853/93853_530x300x85_c.jpg"
},
{
"id": 10,
"image": "https://vkusvill.ru/upload/resize/94377/94377_530x300x85_c.jpg"
},
{
"id": 12,
"image": "https://vkusvill.ru/upload/resize/94017/94017_530x300x85_c.jpg"
},
{
"id": 13,
"image": "https://vkusvill.ru/upload/resize/157871/157871_530x300x85_c.jpg"
},
{
"id": 14,
"image": "https://vkusvill.ru/upload/resize/162506/162506_530x300x85_c.jpg"
},
{
"id": 15,
"image": "https://vkusvill.ru/upload/resize/154668/154668_530x300x85_c.jpg"
},
{
"id": 16,
"image": "https://vkusvill.ru/upload/resize/161019/161019_530x300x85_c.jpg"
},
{
"id": 17,
"image": "https://vkusvill.ru/upload/resize/113263/113263_530x300x85_c.jpg"
},
{
"id": 18,
"image": "https://vkusvill.ru/upload/resize/96735/96735_530x300x85_c.jpg"
},
{
"id": 19,
"image": "https://vkusvill.ru/upload/resize/94387/94387_530x300x85_c.jpg"
},
{
"id": 20,
"image": "https://vkusvill.ru/upload/resize/157888/157888_530x300x85_c.jpg"
},
{
"id": 21,
"image": "https://vkusvill.ru/upload/resize/96601/96601_530x300x85_c.jpg"
},
{
"id": 22,
"image": "https://vkusvill.ru/upload/resize/93260/93260_530x300x85_c.jpg"
},
{
"id": 23,
"image": "https://vkusvill.ru/upload/resize/95442/95442_530x300x85_c.jpg"
},
{
"id": 24,
"image": "https://vkusvill.ru/upload/resize/93248/93248_530x300x85_c.jpg"
},
{
"id": 25,
"image": "https://vkusvill.ru/upload/resize/158195/158195_530x300x85_c.jpg"
},
{
"id": 26,
"image": "https://vkusvill.ru/upload/resize/96005/96005_530x300x85_c.jpg"
},
{
"id": 27,
"image": "https://vkusvill.ru/upload/resize/95103/95103_530x300x85_c.jpg"
},
{
"id": 28,
"image": "https://vkusvill.ru/upload/resize/95101/95101_530x300x85_c.jpg"
},
{
"id": 29,
"image": "https://vkusvill.ru/upload/resize/95099/95099_530x300x85_c.jpg"
},
{
"id": 30,
"image": "https://vkusvill.ru/upload/resize/157890/157890_530x300x85_c.jpg"
},
{
"id": 31,
"image": "https://vkusvill.ru/upload/resize/94937/94937_530x300x85_c.jpg"
},
{
"id": 32,
"image": "https://vkusvill.ru/upload/resize/93938/93938_530x300x85_c.jpg"
},
{
"id": 33,
"image": "https://vkusvill.ru/upload/resize/93844/93844_530x300x85_c.jpg"
},
{
"id": 34,
"image": "https://vkusvill.ru/upload/resize/95596/95596_530x300x85_c.jpg"
},
{
"id": 36,
"image": "https://vkusvill.ru/upload/resize/95618/95618_530x300x85_c.jpg"
},
{
"id": 37,
"image": "https://vkusvill.ru/upload/resize/93625/93625_530x300x85_c.jpg"
},
{
"id": 38,
"image": "https://vkusvill.ru/upload/resize/95620/95620_530x300x85_c.jpg"
},
{
"id": 39,
"image": "https://vkusvill.ru/upload/resize/93749/93749_530x300x85_c.jpg"
},
{
"id": 40,
"image": "https://vkusvill.ru/upload/resize/157311/157311_530x300x85_c.jpg"
},
{
"id": 41,
"image": "https://vkusvill.ru/upload/resize/153082/153082_530x300x85_c.jpg"
},
{
"id": 42,
"image": "https://vkusvill.ru/upload/resize/99730/99730_530x300x85_c.jpg"
},
{
"id": 43,
"image": "https://vkusvill.ru/upload/resize/96081/96081_530x300x85_c.jpg"
},
{
"id": 44,
"image": "https://vkusvill.ru/upload/resize/95513/95513_530x300x85_c.jpg"
},
{
"id": 45,
"image": "https://vkusvill.ru/upload/resize/162524/162524_530x300x85_c.jpg"
},
{
"id": 46,
"image": "https://vkusvill.ru/upload/resize/94357/94357_530x300x85_c.jpg"
},
{
"id": 47,
"image": "https://vkusvill.ru/upload/resize/96042/96042_530x300x85_c.jpg"
},
{
"id": 48,
"image": "https://vkusvill.ru/upload/resize/96046/96046_530x300x85_c.jpg"
},
{
"id": 49,
"image": "https://vkusvill.ru/upload/resize/96040/96040_530x300x85_c.jpg"
},
{
"id": 50,
"image": "https://vkusvill.ru/upload/resize/157295/157295_530x300x85_c.jpg"
},
{
"id": 51,
"image": "https://vkusvill.ru/upload/resize/93247/93247_530x300x85_c.jpg"
},
{
"id": 52,
"image": "https://vkusvill.ru/upload/resize/93481/93481_530x300x85_c.jpg"
},
{
"id": 53,
"image": "https://vkusvill.ru/upload/resize/95610/95610_530x300x85_c.jpg"
},
{
"id": 54,
"image": "https://vkusvill.ru/upload/resize/162486/162486_530x300x85_c.jpg"
},
{
"id": 55,
"image": "https://vkusvill.ru/upload/resize/162528/162528_530x300x85_c.jpg"
},
{
"id": 56,
"image": "https://vkusvill.ru/upload/resize/94876/94876_530x300x85_c.jpg"
},
{
"id": 57,
"image": "https://vkusvill.ru/upload/resize/96643/96643_530x300x85_c.jpg"
},
{
"id": 58,
"image": "https://vkusvill.ru/upload/resize/94257/94257_530x300x85_c.jpg"
},
{
"id": 59,
"image": "https://vkusvill.ru/upload/resize/161126/161126_530x300x85_c.jpg"
},
{
"id": 60,
"image": "https://vkusvill.ru/upload/resize/151246/151246_530x300x85_c.jpg"
},
{
"id": 61,
"image": "https://vkusvill.ru/upload/resize/93373/93373_530x300x85_c.jpg"
},
{
"id": 62,
"image": "https://vkusvill.ru/upload/resize/36233/36233_530x300x85_c.jpg"
},
{
"id": 63,
"image": "https://vkusvill.ru/upload/resize/94623/94623_530x300x85_c.jpg"
},
{
"id": 64,
"image": "https://vkusvill.ru/upload/resize/93376/93376_530x300x85_c.jpg"
},
{
"id": 65,
"image": "https://vkusvill.ru/upload/resize/94097/94097_530x300x85_c.jpg"
},
{
"id": 66,
"image": "https://vkusvill.ru/upload/resize/94756/94756_530x300x85_c.jpg"
},
{
"id": 67,
"image": "https://vkusvill.ru/upload/resize/93810/93810_530x300x85_c.jpg"
},
{
"id": 68,
"image": "https://vkusvill.ru/upload/resize/141107/141107_530x300x85_c.jpg"
},
{
"id": 69,
"image": "https://vkusvill.ru/upload/resize/155586/155586_530x300x85_c.jpg"
},
{
"id": 70,
"image": "https://vkusvill.ru/upload/resize/94249/94249_530x300x85_c.jpg"
},
{
"id": 71,
"image": "https://vkusvill.ru/upload/resize/95069/95069_530x300x85_c.jpg"
},
{
"id": 72,
"image": "https://vkusvill.ru/upload/resize/157319/157319_530x300x85_c.jpg"
},
{
"id": 73,
"image": "https://vkusvill.ru/upload/resize/96449/96449_530x300x85_c.jpg"
},
{
"id": 74,
"image": "https://vkusvill.ru/upload/resize/157301/157301_530x300x85_c.jpg"
},
{
"id": 75,
"image": "https://vkusvill.ru/upload/resize/36472/36472_530x300x85_c.jpg"
},
{
"id": 76,
"image": "https://vkusvill.ru/upload/resize/95379/95379_530x300x85_c.jpg"
},
{
"id": 77,
"image": "https://vkusvill.ru/upload/resize/93384/93384_530x300x85_c.jpg"
},
{
"id": 78,
"image": "https://vkusvill.ru/upload/resize/154670/154670_530x300x85_c.jpg"
},
{
"id": 79,
"image": "https://vkusvill.ru/upload/resize/151259/151259_530x300x85_c.jpg"
},
{
"id": 80,
"image": "https://vkusvill.ru/upload/resize/161017/161017_530x300x85_c.jpg"
},
{
"id": 81,
"image": "https://vkusvill.ru/upload/resize/157291/157291_530x300x85_c.jpg"
},
{
"id": 82,
"image": "https://vkusvill.ru/upload/resize/93193/93193_530x300x85_c.jpg"
},
{
"id": 83,
"image": "https://vkusvill.ru/upload/resize/94935/94935_530x300x85_c.jpg"
},
{
"id": 84,
"image": "https://vkusvill.ru/upload/resize/96307/96307_530x300x85_c.jpg"
},
{
"id": 85,
"image": "https://vkusvill.ru/upload/resize/149089/149089_530x300x85_c.jpg"
},
{
"id": 86,
"image": "https://vkusvill.ru/upload/resize/96318/96318_530x300x85_c.jpg"
},
{
"id": 87,
"image": "https://vkusvill.ru/upload/resize/95216/95216_530x300x85_c.jpg"
},
{
"id": 88,
"image": "https://vkusvill.ru/upload/resize/93367/93367_530x300x85_c.jpg"
},
{
"id": 89,
"image": "https://vkusvill.ru/upload/resize/95948/95948_530x300x85_c.jpg"
},
{
"id": 90,
"image": "https://vkusvill.ru/upload/resize/162484/162484_530x300x85_c.jpg"
},
{
"id": 91,
"image": "https://vkusvill.ru/upload/resize/154664/154664_530x300x85_c.jpg"
},
{
"id": 92,
"image": "https://vkusvill.ru/upload/resize/93323/93323_530x300x85_c.jpg"
},
{
"id": 93,
"image": "https://vkusvill.ru/upload/resize/96491/96491_530x300x85_c.jpg"
},
{
"id": 94,
"image": "https://vkusvill.ru/upload/resize/96247/96247_530x300x85_c.jpg"
},
{
"id": 95,
"image": "https://vkusvill.ru/upload/resize/157293/157293_530x300x85_c.jpg"
},
{
"id": 96,
"image": "https://vkusvill.ru/upload/resize/156148/156148_530x300x85_c.jpg"
},
{
"id": 97,
"image": "https://vkusvill.ru/upload/resize/96593/96593_530x300x85_c.jpg"
},
{
"id": 98,
"image": "https://vkusvill.ru/upload/resize/96391/96391_530x300x85_c.jpg"
},
{
"id": 99,
"image": "https://vkusvill.ru/upload/resize/94957/94957_530x300x85_c.jpg"
},
{
"id": 100,
"image": "https://vkusvill.ru/upload/resize/157898/157898_530x300x85_c.jpg"
},
{
"id": 101,
"image": "https://vkusvill.ru/upload/resize/143429/143429_530x300x85_c.jpg"
},
{
"id": 102,
"image": "https://vkusvill.ru/upload/resize/95864/95864_530x300x85_c.jpg"
},
{
"id": 103,
"image": "https://vkusvill.ru/upload/resize/94555/94555_530x300x85_c.jpg"
},
{
"id": 104,
"image": "https://vkusvill.ru/upload/resize/95751/95751_530x300x85_c.jpg"
}
]
\ No newline at end of file
,название,описание,категория,подкатегория,подподкатегория,участвует в тесте
1,"Блины ""Карбонара""","Начинка состоит из бекона с куриной ветчиной и куриной грудкой, приготовленной по технологии су-вид (продукты в вакуумной упаковке готовятся на водяной бане), отлично дополняют сливки и твердый сыр ""Пармезан"". Рекомендуется подогреть перед употреблением",продукты,блюда ТОП 35,Блины,1
2,Блины с начинкой жюльен,Блины с французской куриной закуской с сыром и соусом «Бешамель».,продукты,блюда ТОП 35,Блины,0
3,Блины с ветчиной (из свинины) и с сыром,Готовые охлажденные блины с начинкой из наших сыра Гауда и ветчины по-Ленинградски.,продукты,блюда ТОП 35,Блины,0
4,Блины с мясом,"Блины из пшеничной муки с сочной мясной начинкой из свиного и говяжьего фарша. В составе только свежие и качественные ингредиенты, без консервантов и усилителей вкуса.",продукты,блюда ТОП 35,Блины,0
5,Блины постные с картофелем и грибами,Постные блины с постной начинкой,продукты,блюда ТОП 35,Блины,0
6,"Варенье вишневое, 50 г","Маленькая баночка сладкого топпинга из ягод вишни. Удобно взять с собой на работу в дополнении к блинам, сырникам или просто в качестве сладости к чаю.",продукты,блюда ТОП 35,Варенье,1
7,Малина дроблёная с сахаром,"Свежая ягода, протертая с сахаром. Вкусный и полезный перекус, или даже легкий десерт. Малина обладает жаропонижающим и противовоспалительным эффектом.",продукты,блюда ТОП 35,Варенье,0
8,Варенье из слив с лимоном и имбирем,"Варенье из свежей или замороженной сливы, лимона, имбиря, сахара и пектина. В составе нашего варенья только фрукты и сахар. Хотя ГОСТ разрешает добавлять в варенье лимонную, аскорбиновую и винную пищевую кислоту, в нашем продукте вы ничего этого не увидите.",продукты,блюда ТОП 35,Варенье,0
9,Варенье черничное,"Варенье приготовлено из свежей или быстрозамороженной черники и сахара. Всем известно, что черника полезна для зрения, она способствует его сохранению и улучшению.",продукты,блюда ТОП 35,Варенье,0
10,Варенье из клубники с мятой,Приготовлено из свежих ягод с добавлением свежих листев мяты. Новый взгляд на привычный вкус. Варенье изготовлено в солнечной Армении.,продукты,блюда ТОП 35,Варенье,0
11,Голубцы ленивые в сметанном соусе,"Нежное блюдо на основе куриного филе и капусты белокочанной с добавлением риса, муки и сливочного масла. Все это дополняет ароматный сливочный соус на основе сметаны и тушеных овощей.",продукты,блюда ТОП 35,Вторые блюда,1
12,Лингвини с креветками и с соусом с тыквой,"Лингвини - это паста из твердых сортов пшеницы. Приготовлена""альденте"" с добавлением креветок и тыквенного соуса на основе растительных масел. Это блюдо можно разогреть, но истинные гурманы оценят его и в холодном виде.",продукты,блюда ТОП 35,Вторые блюда,0
13,Котлетки рыбные с запечёнными овощами,Сытные рыбные котлетки из минтая с добавлением запеченных овощей. Отличный вариант для диетического обеда.,продукты,блюда ТОП 35,Вторые блюда,1
14,Паста с лососем в сливочном соусе,"Спагетти из твердых сортов пшеницы приготовленные «аль денте» дополнены нежным филе лосося холодного копчения. Соус на основе сливок добавляет этому блюду мягкость во вкусе, а сыр пармезан - пикантные нотки.",продукты,блюда ТОП 35,Вторые блюда,1
15,Голубцы с курицей в томатном соусе,Нежные конвертики из капустных листьев плотно набитые начинкой из куриного филе с добавлением лука и рисовой крупы. Яркий соус на основе куриного бульона и томатов в собственном соку идеально дополняет блюдо.,продукты,блюда ТОП 35,Вторые блюда,1
16,Бейгл с кунжутом,"Румяная сдоба с черно-белым кунжутом в качестве присыпки, разрезаная пополам, подходит для наполнения различными начинками, к примеру творожным сыром и помидором или джемом.",продукты,блюда ТОП 35,Выпечка и хлеб,1
17,Хлеб бородинский бездрожжевой,"Хлеб на ржаной муке, приготовленный без добавления дрожжей. Зерна кориандра, посыпанные сверху, дополняют вкус и придают яркий аромат.",продукты,блюда ТОП 35,Выпечка и хлеб,1
18,Чиабатта,"Классический итальянский хлеб на основе пшеничной муки с добавлением дрожжей. Отличная основа как для изысканных перекусов, так и для обычных бутербродов с маслом и сыром",продукты,блюда ТОП 35,Выпечка и хлеб,0
19,Хлеб Печерский масличный,"Бездрожжевой пшеничный хлеб с семенами льна, которые способствуют очищению организма от шлаков и улучшают работу ЖКТ",продукты,блюда ТОП 35,Выпечка и хлеб,0
20,Слойка Свердловская,Ароматная воздушная булочка со вкусом из детства. Слойка изготовлена из пшеничной муки с добавлением сливочного масла.,продукты,блюда ТОП 35,Выпечка и хлеб,1
21,Мидии мясо варено-мороженное,"Вылавлены в Тихом океане. Покрыты тоненьким слоем глазури, в продукте ее не больше 7%. Хорошо очищены от раковин.",продукты,блюда ТОП 35,Замороженные морепродукты,0
22,Кальмар филе очищенный зам.,"Район вылова — Дальний восток. Очищены от кожи, можно жарить, варить, фаршировать, добавлять в различные салаты.",продукты,блюда ТОП 35,Замороженные морепродукты,0
23,Креветка северная варено-мороженая,"Район вылова- Гренландия. Они не искусственно выращенные, а дикие. Поэтому их мясо качественно отличается от искусственных аналогов. Сразу после вылова на корабле продукт подвергают шоковой заморозке",продукты,блюда ТОП 35,Замороженные морепродукты,0
24,Кальмар кольца зам.,"Продукт нарезан на колечки. Удобный вариант для приготовления закусок, салатов и вторых блюд. Район вылова — Дальний восток.",продукты,блюда ТОП 35,Замороженные морепродукты,0
25,Кальмар тушка зам.,"Продукт богат белком и быстро готовится, достаточно на 2 минуты опустить в кипящую воду. Если мясо переварить, оно станет резиновым на вкус.",продукты,блюда ТОП 35,Замороженные морепродукты,1
26,Шпинат свежезамороженный,"Резаные листья используют для приготовления закусок, салатов, гарниров, в качестве начинки для пирогов и для приготовления самых разных вторых блюд. На производстве используется уникальная японская технология заморозки CAS. Ее особенность в том, что заморозка происходит равномерно по всей толще овощей.",продукты,блюда ТОП 35,"Замороженные овощи, грибы, ягоды и фрукты",0
27,Смесь Гавайская с/м,"Замороженная смесь из риса, кукурузы, зеленого горошка и перца. Изготовлено из отечественных овощей. Гавайская смесь отлично сочетается с мясом и рыбой в качестве гарнира",продукты,блюда ТОП 35,"Замороженные овощи, грибы, ягоды и фрукты",0
28,Смесь мексиканская с/м,"Замороженная смесь из кукурузы, зеленого горошка, моркови, зеленой фасоли и перца. Изготовлено из отечественных овощей. Можно использовать в качестве гарнира, как основу для салата, для приготовления различных мясных и овощных блюд",продукты,блюда ТОП 35,"Замороженные овощи, грибы, ягоды и фрукты",0
29,Весенние овощи с/м,"Замороженная смесь из моркови, картофеля, зеленого горошка, зеленой фасоли и лука. Изготовлено из отечественных овощей. Эта смесь универсальна. Ее можно использовать для приготовления первых блюд, как основу для салатов, в качестве гарнира",продукты,блюда ТОП 35,"Замороженные овощи, грибы, ягоды и фрукты",0
30,Смесь овощная для вок с/м,"Готовая свежемороженая смесь из сладкого перца, свежей моркови, репчатого лука, а также лука порея и свежего сельдерея. Такой набор идеален для приготовления лапши вок с тофу и овощами, рецепт которой указан на упаковке. Не нужно мыть,чистить, а потом еще и нарезать овощи, эта смесь помогает отлично сэкономить время на готовке.",продукты,блюда ТОП 35,"Замороженные овощи, грибы, ягоды и фрукты",1
31,Колбаса «Сервелат Коньячный» в/к,"Варено-копченая колбаса из свинины, говядины и свиного шпика с добавлением чеснока, черного и душистого перца. В составе натуральный коньяк, а не ароматизатор. Он наделяет сервелат благородным ароматом. Обладает мягким несильно соленым вкусом.",продукты,блюда ТОП 35,Колбасы. Ветчина,0
32,Колбаса «Особенная» из индейки варёная,"Колбаса из индейки с вкраплениями цельных кусочков мяса. Вкус и аромат колбасы подчеркивают черный перец, мускатный орех, зеленый перец и лимон. Мясо индейки диетическое.",продукты,блюда ТОП 35,Колбасы. Ветчина,0
33,Колбаса запеченная из индейки,"Запеченная колбаса из филе грудки и бедра индейки с добавлением свежего чеснока, черного и душистого перца и мускатного ореха.",продукты,блюда ТОП 35,Колбасы. Ветчина,0
34,Колбаса «Брауншвейг. полусухая» с/к в/у,"приготовлена из говядины и свиного шпика с добавлением пряностей. Фарш маринуют в рассоле и коптят ольховым, буковым и дубовым дымом в течение 5 суток. Затем колбаса проходит стадию созревания.",продукты,блюда ТОП 35,Колбасы. Ветчина,0
35,Колбаса кровяная с гречкой,"Такую колбасу еще называют домашней, поскольку она достаточно проста в приготовлении при наличии необходимых ингредиентов. У славян была традиция, подавать такую колбасу на праздничный стол в Рождество. Колбаса обладает насыщенным вкусом и легким ароматом специй.",продукты,блюда ТОП 35,Колбасы. Ветчина,1
36,Шампунь Яичный,"Шампунь для нормальных, поврежденных и сухих волос. Запечатывает секущиеся кончики, обеспечивает комплексное восстановление структуры волоса, делает волосы шелковистыми.",продукты,блюда ТОП 35,"Косметика, средства гигиены",0
37,Шампунь мужской,"Подходит для всех типов волос. Шампунь обеспечивает комплексное восстановление структуры волос, возвращает им здоровье и ухоженный вид. Комплекс мягких ПАВ растительного происхождения очищает волосы, не раздражая кожу головы.",продукты,блюда ТОП 35,"Косметика, средства гигиены",0
38,Шампунь молочный Миндаль,"Шампунь молочный с экстрактом миндаля предназначен для ухода за волосами всех типов, превосходно очищает жирные волосы, мягко и бережно ухаживает за сухими и ломкими волосами, возвращая им здоровье и ухоженный вид.",продукты,блюда ТОП 35,"Косметика, средства гигиены",0
39,Маска для волос Сладкий миндаль,Восстанавливает и питает волосы. Обеспечивает легкое расчесывние и здоровый блеск волос. Имеет очень нежный сладковатый аромат миндаля,продукты,блюда ТОП 35,"Косметика, средства гигиены",0
40,"Шампунь твёрдый ""Крапивный""","Твердый шампунь для волос с экстрактом крапивы. Небольшой брусочек крапивного шампуня отлично пенится и хорошо смывается водой. Этот шампунь питает, увлажняет и улучшает структуру волос, сохраняя яркость цвета. Придает волосам объем и шелковистый блеск.",продукты,блюда ТОП 35,"Косметика, средства гигиены",1
41,Пастила фруктовая из персика,"Продукт изготовлен исключительно из свежих плодов, без добавления сахара. Сладость у продукта естественная, природная. Лёгкий снек для правильного перекуса.",продукты,блюда ТОП 35,Леденцы. Мармелад. Халва. Зефир,1
42,Пастила яблочная натуральная,"Полезное лакомство в составе которого только яблоки. Приготовлено методом бережной сушки. Эта технология позволяет сохранить максимальное количество витаминов и полезных веществ, содержащихся в яблоках",продукты,блюда ТОП 35,Леденцы. Мармелад. Халва. Зефир,0
43,Пастила яблочная хрустящая,"Вкусное и хрустящее лакомство, в составе которого только свежие яблоки, сахар, яичный белок и лимонный сок прямого отжима. Приготовлено методом сушки. Эта технология позволяет сохранить максимальное количество витаминов и полезных веществ, содержащихся в яблоках.",продукты,блюда ТОП 35,Леденцы. Мармелад. Халва. Зефир,0
44,Пастила яблоко-вишня хрустящая,"Вкусное и хрустящее лакомство, в составе которого только свежие яблоки, вишня, яичный белок и сахар. Приготовлено при низкой температуре с сохранением полезных витаминов и микроэлементах.",продукты,блюда ТОП 35,Леденцы. Мармелад. Халва. Зефир,0
45,"Мармелад ""Облепиха""","Легкий ягодный аромат и сладкий, но не приторный вкус. В основе яблочное пюре, сахар и ягоды облепихи",продукты,блюда ТОП 35,Леденцы. Мармелад. Халва. Зефир,1
46,Булгур,"популярен в турецкой, ливанской и сицилийской кухнях. Для его получения цельные зерна пшеницы замачивают, пропаривают, высушивают, удаляют оболочку и дробят. Таким образом крупа приобретает приятный ореховый вкус.",продукты,блюда ТОП 35,"Макароны, крупы, бобовые",0
47,Кускус,Дробленая крупа из твердых сортов пшеницы. Традиционное блюдо в Марокко и Тунисе. Традиционно готовится на пару или достаточно залить кипятком,продукты,блюда ТОП 35,"Макароны, крупы, бобовые",0
48,Киноа,"Крупа народов инков. За ее богатый состав прозвали «божественным зерном» и «матерью всех злаков». Помимо комплекса витаминов и минералов, имеет идеальный баланс протеинов. Способна полностью компенсировать отсутствие мяса в рационе.",продукты,блюда ТОП 35,"Макароны, крупы, бобовые",0
49,Рис для плова Басмати экстрадлинный,Идеально подходит для приготовления плова. При варке увеличивающееся в 2 раза. Обладает способностью хорошо поглощать жир и остается рассыпчатым после приготовления.,продукты,блюда ТОП 35,"Макароны, крупы, бобовые",0
50,"Рис ""Жасмин""","Универсальный продукт из которого можно приготовить множество блюд. Идеально подходит как для приготовления плова, так и для молочных каш, гарниров или супов.",продукты,блюда ТОП 35,"Макароны, крупы, бобовые",1
51,Йогурт греческий,Продукт приготовлен из натурального коровьего молока с использованием йогуртовой закваски. Богат белком и кальцием; - укрепляет костную ткань; - ускоряет обменные процессы в организме; - нормализует пищеварительные процессы; - укрепляет иммунитет.,продукты,блюда ТОП 35,Молочные продукты,0
52,Иммуноцея с сиропом шиповника,"Кисломолочный продукт, приготовленный из коровьего молока и закваски с добавлением сиропа шиповника. Способствует укреплению иммунитета, помогает ему в борьбе с простудой. Особенно такой продукт актуален осенью, когда наш организм подвержен простудным заболеваниям.",продукты,блюда ТОП 35,Молочные продукты,0
53,Мацони,"необычный кисломолочный продукт. Он напоминает сразу и простоквашу, и кефир, и даже йогурт. Готовят его традиционного из кипяченого коровьего молока и закваски, содержащей молочнокислые бактерии и болгарскую палочку.",продукты,блюда ТОП 35,Молочные продукты,0
54,"Скир ""Исландский"" 1,5%","Продукт на основе нормализованного коровьего молока и закваски. Нечто среднее между сметаной и творожной массой. По вкусу напоминает греческий йогурт. Можно кушать как самостоятельное блюдо, а можно с фруктами или овощами, в качестве соуса, а также в качестве заправки в салат.",продукты,блюда ТОП 35,Молочные продукты,1
55,"Творог 5%, 180 г",Продукт из свежего коровьего молока и закваски в компактной упаковке. Подходит для приготовления сырников.,продукты,блюда ТОП 35,Молочные продукты,1
56,Балык «Королевский» с/к,"Деликатес из говядины с толстого края. Отличительная часть мяса с этой части туши в том, что в нем встречаются нежные прожилки, как в мраморной говядине. Мясо посыпают солью и сахаром, выдерживают 7 дней. Затем коптят холодным дымом (температура до 32 градусов) на буковых и дубовых щепах.",продукты,блюда ТОП 35,Мясная гастрономия,0
57,Карпаччо из индейки с/к,"Тонкие ломтики нежного сырокопченного мяса индейки. Не содержат влагоудерживающих компонентов и консервантов. Советуем попробовать со свежим багетом и
ягодным соусом, например, черносмородиновым.",продукты,блюда ТОП 35,Мясная гастрономия,0
58,"Шпек сыровяленый нарезка, 50 г","Похожая на прошутто ветчина, с более насыщенным вкусом. Коптят продукт холодным способом. После того как мясо прокоптилось, оно 6−8 месяцев дозревает в специальных климатических камерах, в условиях максимально приближенных к средиземноморскому климату",продукты,блюда ТОП 35,Мясная гастрономия,0
59,"Филе грудки индейки ""Су-вид"" в маринаде Корридо","Продукт замаринован в смеси сушеных овощей и специй и приготовлен по технологии «су-вид». ( мясо помещают в вакумный пакет и медленно готовят при сравнительно низкой и точно контролируемой температуре, обычно в водяной бане) Такой процесс позволяет сохранить максимальное количество полезных свойства продукта.",продукты,блюда ТОП 35,Мясная гастрономия,1
60,"Ребрышки говяжьи, 400 г","Готовятся быстро. Идеально подойдут как для приготовления наваристого бульона, так и для жаркого, солянки, плова и других видов мясных блюд. А можно их просто поджарить с добавлением соли и специй и подать с овощами.",продукты,блюда ТОП 35,"Мясо, птица",1
61,Вырезка из свинины,"Самая нежная часть туши. Можно жарить, тушить, запекать, в любом случае будет вкусно. Мясо более плотное, обладает насыщенным вкусом и приятным ароматом",продукты,блюда ТОП 35,"Мясо, птица",0
62,Половина тушки кролика,"Мясо считается диетическим. Усваивается намного лучше, чем другие виды мяса. Гипоаллергенно, потому его рекомендуют детям, беременным и кормящим женщинам.",продукты,блюда ТОП 35,"Мясо, птица",0
63,Стейк из индейки,"Мясо нарезанно на удобные стейки. Отличный вариант для жарки. Диетическое, в нем мало холестерина. Легко усваивается и легко переваривается.",продукты,блюда ТОП 35,"Мясо, птица",0
64,Филе бедра куриное бескостное,"Диетический продукт питания, обладает более высокими вкусовыми и питательными свойствами по сравнению с мясом взрослой птицы. Достаточно промыть продукт и замариновать по вкусу, в духовке, на сковороде, на пару или на гриле, независимо от того как вы готовите курицу, получится вкусно и сочно",продукты,блюда ТОП 35,"Мясо, птица",1
65,Напиток Чай с лимоном,"Освежающий напиток на основе настоя черного чая и лимона. Не содержит искусственных ароматизаторов. Этот напиток поможет утолить жажду, взбодрит и придаст сил.",продукты,блюда ТОП 35,Напитки,0
66,Напиток «Чайный гриб» со стевией,"Непастеризованный нефильтрованный и безалкогольный напиток.
Производится из пророщенных злаков без сахара посредством брожения с помощью чистой культуры чайного гриба с последующим добавлением медовой травы — стевии.",продукты,блюда ТОП 35,Напитки,0
67,Напиток «Лимон-Имбирь»,"Освежающий детокс-напиток, приводящий в чувство, к бодрости. Среднегазированный.",продукты,блюда ТОП 35,Напитки,0
68,Вода минеральная Псыж 1л,"Газированная минеральная природная вода из скважины номер 1А Псыжского участка минеральных вод Карачаево-Черкесской республики. Вода применяется в профилактических целях, а также при лечении гастрита, болезней пищевода и кишечника.",продукты,блюда ТОП 35,Напитки,0
69,"Напиток ""Кокосовый"" на бактериальной закваске",Напиток на основе кокосовой воды и кокосового масла с добавлением закваски. Обладает легкой кислинкой во вкусе.,продукты,блюда ТОП 35,Напитки,1
70,Паштет мясной запеченный,"Паштет приготовлен из свинины, куриной печени, сливочного масла, моркови, репчатого лука.",продукты,блюда ТОП 35,"Паштеты, холодцы",0
71,Паштет из тофу «По-испански»,"Постный паштет с добавлением подсолнечного и оливкового масла, сладкого перца, томатов и сушеного базилика. Вкусное и сытное наполнение для бутербродов и хлебцев.",продукты,блюда ТОП 35,"Паштеты, холодцы",0
72,Риет из горбуши с миндалем,"Риет- метод приготовления мяса, похожий на паштет. В основе филе горбуши с добавлением подсолнечного масла, 9%-го творога и ядер миндаля. Консистенция плотная, нежирная, хорошо размазывается по тосту.",продукты,блюда ТОП 35,"Паштеты, холодцы",1
73,Паштет мясной с печенью индейки и грушей,"Продукт украшен тончайшей корочкой из сахарного сиропа с добавлением экстракта натурального чернослива, вяленой вишней и тыквенными семечками. Груша в паштет добавлена маленькими кусочками, что только оттеняет нежность паштета.",продукты,блюда ТОП 35,"Паштеты, холодцы",0
74,Паштет из печени кролика с шампиньонами,"Паштет на основе печени кролика и свинины, с добавлением шампиньонов, свиного шпика, репчатого лука и пряностей. Рекомендуется разогреть перед употреблением, благодаря нагреванию все ингредиенты раскрывают свой вкус.",продукты,блюда ТОП 35,"Паштеты, холодцы",1
75,Суп Харчо,"Классический рецепт этого блюда пришел к нам из грузинской кухни. Приготовлен суп из говяжьего бульона, говядины, риса, томатной пасты и пряностей. В составе только свежие и качественные ингредиенты, без консервантов и усилителей вкуса.",продукты,блюда ТОП 35,Первые блюда,0
76,Борщ вегетарианский,"Традиционное блюдо, которое можно в пост, вегетарианцам и веганам. Вкусно со сметаной, соевым майонезом и хлебцами.",продукты,блюда ТОП 35,Первые блюда,0
77,Суп куриный с домашней лапшой,"Наваристый домашний суп из куриного бульона, куриного филе и лапши. Блюдо приготовлено из свежих и качественных ингредиентов, без консервантов и усилителей вкуса.",продукты,блюда ТОП 35,Первые блюда,0
78,Суп-пюре норвежский с сёмгой,"Нежный и ароматный суп-пюре из семги, запеченных моркови и лука, свежего картофеля с добавлением сливок и специй. Цельные кусочки норвежской семги делают это блюдо сытным.",продукты,блюда ТОП 35,Первые блюда,1
79,Уха русская с сёмгой,"Легкий супчик на бульоне из семги атлантической с добавлением овощей, укропа и специй. Идеально для здорового питания",продукты,блюда ТОП 35,Первые блюда,1
80,"Ассорти из омуля, муксуна, чира",Необычная подборка подкопченных рыбных деликатесов семейства лососевых в одной упаковке.,продукты,блюда ТОП 35,Рыбная гастрономия,1
81,Ассорти рыбное х/к из скумбрии и горбуши,"Рыба с легким ароматом копчения не нужно чистить и удалять косточки, все уже готово к употреблению.",продукты,блюда ТОП 35,Рыбная гастрономия,1
82,Ассорти рыбное х/к ломтики,Рыбная нарезка из дальневосточной горбуши и атлантической скумбрии и саворина. Имеет самый простой состав — рыба и соль.,продукты,блюда ТОП 35,Рыбная гастрономия,0
83,Корюшка горячего копчения,"Выловлена в Санкт-Петербурге. Одна из отличительных особенностей этой рыбы — ее запах свежих огурцов, из-за чего ее прозвали «огуречником»",продукты,блюда ТОП 35,Рыбная гастрономия,0
84,Муксун ломтики холодного копчения,Деликатесная рыба с белым жирным и очень нежным мясом. Выловлена в Якутии.,продукты,блюда ТОП 35,Рыбная гастрономия,0
85,"Салат с яблоком, свеклой и черносливом","Хрустящий салат богатый витаминами и клетчаткой. Заправка на основе лимонного сока, мёда и мяты отлично раскрывает вкус всех ингредиентов. Идеально для тех, кто следит за фигурой.",продукты,блюда ТОП 35,Салаты и закуски,1
86,Салат Мимоза,"Рыбный салат из отварного филе горбуши, куриных яиц, картофеля, моркови и сыра. Заправлен майонезом. Все ингредиенты аккуратно выложены слоями.",продукты,блюда ТОП 35,Салаты и закуски,0
87,Салат «Грин Энерджи»,"Сочетание салата «Айсберг», куриной грудки, шампиньонов, куриного яйца, маслин, зеленого лука, кинзы и кунжута. Заправка приготовлена из растительного масла, соевого соуса и меда. Этот салат очень питательный, при этом обладает низкой калорийностью.",продукты,блюда ТОП 35,Салаты и закуски,0
88,Салат «Оливье»,"Классический салат с куриной ветчиной, отварной куриной грудкой и отварной говядиной. Заправлен натуральным майонезом.",продукты,блюда ТОП 35,Салаты и закуски,0
89,Салат винегрет с маринованной капустой,"Готовый салат. В качестве заправки нерафинированное подсолнечное масло. Не смотря на всю простоту этого салата, его приготовление даже у опытной хозяйки займет немало времени. Мы предлагаем вам готовый вариант.",продукты,блюда ТОП 35,Салаты и закуски,0
90,"Сыр ""Российский"" тёртый","Сыр в удобном формате. Желтоватый цвет сыру придает натуральный пищевой краситель – аннато. В натертом виде такой сыр отлично подойдет для приготовления любых видов блюд, начиная от пасты и заканчивая пиццей.",продукты,блюда ТОП 35,Сыры,1
91,"Сыр козий ""Кремчиз с брусникой и яблоком""","Нежный сливочный сыр с прослойкой кисло-сладкого соуса. Отлично подойдет как в качестве сытного перекуса, так и в качестве десерта к чаю.",продукты,блюда ТОП 35,Сыры,1
92,Сыр твердый «Грюнбергер»,"Сыр, который по праву можно считать аналогом известного швейцарского сыра «Грюйер».Это твердый желтый сыр без дырок, имеющий острый пикантный аромат и слегка ореховый вкус.",продукты,блюда ТОП 35,Сыры,0
93,Сыр «Эдам»,"Знаменитый полутвердый сыр из коровьего молока, относится к голландским сортам. Не содержит растительных жиров и консервантов. Этот сыр обладает слегка сладковатым сливочным вкусом с пикантными нотками.",продукты,блюда ТОП 35,Сыры,0
94,Сыр «Алтайский» полутвёрдый,Сыр можно назвать нашим аналогом популярного голландского сыра «Маасдам». Он обладает слегка сладковатым пикантным вкусом.,продукты,блюда ТОП 35,Сыры,0
95,"Тетрадь в линейку, 48 л",Плотная тетрадь в линейку с оригинальным цветом страниц и обложки.,продукты,блюда ТОП 35,Товары для дома и кухни,1
96,"Десерт молочный ""Ночь в Брюгге""",Нежный шоколадный десерт со вкусом горького шоколада и легкой кислинки яблочного повидла с нежный кремом.,продукты,блюда ТОП 35,Торты. Пирожные. Муссы. Суфле,1
97,Панна-котта «Манго-маракуйя-апельсин»,"Нежный десерт из молока, сливок, манго, маракуйи и апельсина, в основе приготовления которого итальянская рецептура.",продукты,блюда ТОП 35,Торты. Пирожные. Муссы. Суфле,0
98,Пирожное постное «Трюфельное»,"Шоколадное пирожное без молока и яиц. Приготовлено из кокосового молока, темного шоколада с добавлением муки, фундука и черной смородины. Пирожное по вкусу очень напоминает трюфель, отсюда и название.",продукты,блюда ТОП 35,Торты. Пирожные. Муссы. Суфле,0
99,Рулет бисквитный,"Бисквит с нежной кремовой прослойкой. В составе сливочное масло и сгущенное молоко «Избёнка». Десерт максимально похож на десерт, продававшийся в советские годы.",продукты,блюда ТОП 35,Торты. Пирожные. Муссы. Суфле,0
100,"Пирожное ""Малиновое"" на кокосовом молоке","Десерт приготовлен на коксовом молоке и рисовой муке, без добавления сахара. Подходит вегетарианцам и людям избегающим глютеносодержащие продукты. Сладость десерту придает сироп топинамбура и ягоды малины.",продукты,блюда ТОП 35,Торты. Пирожные. Муссы. Суфле,1
101,Мята душистая,"Чай освежает, помогает быстро снять признаки усталости, улучшает пищеварение и помогает избавиться от головной боли.",продукты,блюда ТОП 35,Чай. Травы. Кофе. Какао,0
102,Горный чабрец,"Обладает насыщенным пряным ароматом и ярким вкусом. Чай с чабрецом поможет снять усталость, взбодрит и придаст сил. Рекомендуется при частых стрессах и бессоннице.",продукты,блюда ТОП 35,Чай. Травы. Кофе. Какао,0
103,Чай с мятой и календулой в пакетиках,"Используются крымские травы, выращенные на горных экологически чистых участках.",продукты,блюда ТОП 35,Чай. Травы. Кофе. Какао,0
104,Чай зеленый байховый в пакетиках,"Чай выращивают в Мацестинской долине, расположенной вблизи города Сочи в уникальной субтропической зоне. Это самый северный чай в мире. Благодаря такому происхождению в нем накапливается больше полезных веществ, чем в чаях, выращенных в более южных регионах",продукты,блюда ТОП 35,Чай. Травы. Кофе. Какао,0
105,"Чай гречишный, в пирамидках","В составе только гречиха татарская, никаких добавок и искусственных ароматизаторов. Гречишный чай - это напиток имеющий золотистый цвет, ореховый аромат и сладко - ореховый вкус, похожий на карамель. Приятная альтернатива привычному чаю.",продукты,блюда ТОП 35,Чай. Травы. Кофе. Какао,1
\ No newline at end of file
id,question_id,text,correct,,
1,1,Наша молочная продукция с короткими сроками реализации.,0,,1
,1,"Чтобы молоко хорошо хранилось, мы используем сухое молоко",1,,0
,1,"Мы не используем растительные жиры, загустители и добавки",0,,
,1,Все наше молоко проходит тщательный процесс стерилизации,1,,
,2,"Конечно, ведь наши производители используют только натуральное отборное сырье . Молоко не стерилизуют, а только лишь пастеризуют,убивая вредные бактерии, но сохраняя полезные. У детской продукции короткие сроки хранения, всего 5-7 суток.",1,,
,2,"Конечно, ведь наши производители используют только натуральное отборное сырье . Молоко не пастеризуют, а только лишь стерилизуют,убивая вредные бактерии, но сохраняя полезные. У детской продукции короткие сроки хранения, всего 5-7 суток.",0,,
,2,"Конечно, ведь наши производители используют только натуральное отборное сырье . Молоко не стерилизуют, а только лишь пастеризуют,убивая вредные бактерии, но сохраняя полезные. У детской продукции короткие сроки хранения, всего 2-3 суток.",0,,
,2,"Конечно, ведь наши производители используют только отборное непастеризованное молоко. У детской продукции короткие сроки хранения, всего 5-7 суток. И нежный приятный деткам вкус.",0,,
,3,"Козье молоко легче усваивается, чем коровье, не вызывает аллергии. Продукты из козьего молока рекомендуются людям с лактозной недостаточностью.",1,,
,3,"Козье молоко подходит людям, которым надоело коровье молоко и они хотят попробовать что -то новенькое.",0,,
,3,"Козье молоко легче усваивается, чем коровье, не вызывает аллергии. Продукты из козьего молока рекомендуются людям с лактозной недостаточностью. Но абсолютно не подходит маленьким детям, поскольку в нем отсутствуют казеины, необходимые растущему организму.",0,,
,4,"Не применяют при выращивании скота гормоны роста, а применение антибиотиков не превышает допустимые требования по безопасности. Мясо регулярно проходит проверку на инъецирование, наличие гормонов и антибиотиков.",1,,
,4,"Не применяют при выращивании скота гормоны роста, а применение антибиотиков вообще не допустимо. Мясо регулярно проходит проверку на инъецирование, наличие гормонов и антибиотиков.",0,,
,4,"Отдают предпочтение мясным, а не мясомолочным, породам коров, когда речь идет о говядине. И свиньям только определенных пород, если речь идет о свинине.",0,,
,5,"Содержание глазури на нашей замороженной рыбе не превышает 2%, мы не увеличиваем вес продукта, за счет льда.",0,,
,5,"Содержание глазури на нашей замороженной рыбе не превышает 5%, мы не увеличиваем вес продукта, за счет льда.",1,,
,5,"Рыбу взвешивают в охлажденном виде, а лишь потом замораживают, таким образом покупатели не переплачивают за ""лед""",0,,
,6,Изготовлены из высококачественной дикой рыбы.,0,,
,6,"Изготовлены из высококачественного сырья, в основном из дикой рыбы, исключение составляет форель и семга. В Пресервах используются только натуральные специи и никаких искусственных консервантов.",1,,
,6,Изготовлены из высококачественной дикой рыбы. В Пресервах используются только натуральные специи и никаких искусственных консервантов.,0,,
,7,"Высококачественный продукт, прошедший все необходимые проверки и цельные кусочки рыбы.",1,,
,7,Хороший качественный продукт приятного цвета и запаха,0,,
,7,Рыбу готовую к употреблению,0,,
,8,В магазинах Вкусвилл реализуются овощи и фрукты лишь Российского происхождения.,0,,
,8,"В магазинах Вкусвилл продаются овощи и фрукты которые произрастают на территории России и стран СНГ. Импортные овощи и фрукты появляются в наших магазинах только, когда речь идет об экзотических плодах или когда в нашей стране и странах СНГ заканчивается сезон.",1,,
,8,"В магазинах Вкусвилл продаются овощи и фрукты которые произрастают на территории России и стран СНГ. Импортные овощи и фрукты появляются в наших магазинах только, когда речь идет об экзотических плодах.",0,,
,9,Бездрожжевые хлеба без улучшителей вкуса,0,,
,9,Хлеба выпекаемые на дрожжах,0,,
,9,Хлеба богатые клетчаткой из цельнозерновой муки,0,,
,9,Хлебцы приготовленные с использованием нерафинированного масла полученного путем первого холодного отжима семян подсолнечника,1,,
,10,Маргарина и кокосового масла,0,,
,10,Сливочного и пальмового масла,0,,
,10,Подсолнечного и кокосового масла,0,,
,10,Маргарина и пальмового масла,1,,
,11,Очищенная родниковая природная вода с сохраненным минеральным балансом.,1,,
,11,"Чистая вода, прошедшая фильтрацию",0,,
,11,Обладает омолаживающим эффектом,0,,
,12,"Мы не продаем восстановленные соки, все соки прямого отжима. В составе только фрукты.",1,,
,12,"Мы продаем качественные восстановленные соки, в составе которых только фрукты.",0,,
,12,"У наших соков предельно простой состав: вода и фруктовое пюре без ароматизаторов, красителей и консервантов.",0,,
,13,Производители наших морсов используют отечественные ягоды для производства морсов.,1,,
,13,"Производители наших морсов используют натуральные пюре без ароматизаторов, красителей и консервантов.",0,,
,13,Производители наших морсов используют отечественные ягоды для производства морсов и иностранные в не сезон.,0,,
,14,Сидр,0,,
,14,Вино,1,,
,14,Пиво,0,,
,14,Медовуха,0,,
,15,"Легкие блюда, предназначенные для полезного перекуса, приготовленные из ягод, фруктов, орехов, шоколада без термообработки и добавления сахара.",1,,
,15,"Легкие блюда, предназначенные для полезного перекуса :сушеные ягоды, фрукты, овощи обжаренные без добавления масла",0,,
,15,Миксы из сушеных ягод и фруктов,0,,
,16,Из твердых сортов пшеницы,1,,
,16,Из мягких сортов пшеницы,0,,
,16,Из смешанных сортов пшеницы,0,,
,16,Из всех вышеперечисленных сортов пшеницы,0,,
,17,"Мясные полуфабрикаты делаются из качественного охлажденного сырья, без добавления сои, разрыхлителей, усилителей вкуса. Для придания пикантности используются только натуральные специи и маринады.",1,,
,17,Мясные полуфабрикаты делаются из качественного охлажденного или замороженного сырья. Для придания пикантности используются только натуральные специи и маринады.,0,,
,17,"Мясные полуфабрикаты делаются из качественного замороженного сырья по старинным русским рецептам, что помогает добиться ""домашнего вкуса""",0,,
,18,Так как наши производители одни из не многих не добавляют в колбасу нитрата натрия.,1,,
,18,Все дело в особой технологии приготовления,0,,
,18,"Наши колбасы сделаны из отборного охлажденного мяса без консервантов, заменителей и стабилизаторов.",0,,
,19,Булгур,1,,
,19,Чечевица,1,,
,19,Киноа,1,,
,19,Кускус,1,,
,20,в России,1,,
,20,в России и странах СНГ,0,,
,20,в Индии,0,,
,21,Курага,0,,
,21,Цукаты,1,,
,21,Хлопья ячменные,0,,
,21,Хлопья гречневые,0,,
,22,температура,1,,
,22,относительная влажность,1,,
,22,световой режим,1,,
,22,срок годности,0,,
,23,прибор предназначен для измерения относительной влажности и температуры воздуха внутри помещений,1,,
,23,прибор предназначен для поддержания необходимой относительной влажности и температуры воздуха внутри помещений,0,,
,23,"прибор предназначен для измерения температуры, относительной влажности воздуха, освещенности внутри помещений",0,,
,24,Полностью соответствовать предъявляемым к ней требованиям безопасности,1,,
,24,Сохранять свои потребительские свойства,1,,
,24,Быть пригодна для использования по назначению,1,,
,25,От нуля часов указанной даты,1,,
,25,От часа утра указанной даты,0,,
,25,От 23.00 указанной даты,0,,
,26,От даты производства,1,,
,26,От даты фасовки/розлива/упаковки.,0,,
,27,Не помыла руки перед началом работы,0,,
,27,Не подобрала волосы под шапочку,0,,
,27,Пришла на работу с признаками кишечной дисфункции,0,,
,27,Пообедала в неположенном месте,0,,
,27,Пришла в ярких ювелирных украшениях,0,,
,27,"Лена все сделала правильно, ни каких санитарных норм не нарушила",1,,
,28,2009,1,,
,28,2012,0,,
,28,2008,0,,
,28,2000,0,,
,29,2009,0,,
,29,2012,1,,
,29,2008,0,,
,29,2000,0,,
,30,Андрей Кривенко,1,,
,30,Артем Кривенко,0,,
,30,Евгений Щепин,0,,
,30,Валерий Разгуляев,0,,
,31,Сайт www.vkusvill.ru,1,,
,31,"Социальные сети (группы Избёнка ""ВКонтакте"", ""Facebook"", ""Одноклассниках""),",1,,
,31,Горячая линия,1,,
,31,почта info@izbenka.msk.ru,1,,
,31,"Бот ""ВкусВилл"" в Telegram",1,,
,31,"Письмо г. Москва, ул Щепкина, д 42, стр. 2А.",0,,
,32,Дарится бесплатно,1,,
,32,Дает возможность покупать товары по спец. ценникам желтого цвета.,1,,
,32,Дает возможность назначать Любимый продукт,1,,
,32,Дает возможность покупать товары по спец. ценникам оранжевого цвета.,0,,
,32,"Дает дополнительные преимущества, подключившись к боту и мобильному приложению",1,,
,32,Дает возможность накапливать бонусы на карту за любые продукты,0,,
,33,Подарить бесплатно и рассказать о ее преимуществах,1,,
,33,"Подарить карту, если клиент пробивает чек на любую сумму",0,,
,33,"Подарить карту, если клиент приобрел продуктов более чем на 500рублей",0,,
,33,Подарить бесплатно,0,,
,33,Предложить преобрести карту и рассказать о ее преимуществах,0,,
,33,Положить карту клиенту в пакет с покупками,0,,
,34,Количество бонусов от 30 рублей,1,,
,34,Любимый продукт (если есть),1,,
,34,"Адрес магазина, где находится клиент",0,,
,34,Имя владельца карты,1,,
,35,Сумма покупки,1,,
,35,Сумма полученных денег от покупателя,1,,
,35,Сумма сдачи,1,,
,35,В какой валюте принята оплата,0,,
,36,"Положить чек в пакет, а сдачу на монетницу",0,,
,36,Отдать чек и сдачу в руки,0,,
,36,"Положить сдачу на монетницу,а сверху чек",1,,
,37,Ноль на весах,0,,
,37,"Один раз ""минус 20 гр"" после того, как положили товар на весы",0,,
,37,"2 раза ""минус 20 грамм"", после того, как положили товар на весы",1,,
,37,Подбор товара,0,,
,38,Ноль на весах,0,,
,38,"Один раз ""минус 20 гр"" после того, как положили товар на весы",1,,
,38,"2 раза ""минус 20 грамм"", после того, как положили товар на весы",0,,
,38,Подбор товара,0,,
,39,Ноль на весах,1,,
,39,"Один раз ""минус 20 гр""",0,,
,39,"2 раза ""минус 20 грамм""",0,,
,39,Подбор товара,0,,
,40,Нужно обязательно позвать старшего продавца.,1,,
,40,"Самостоятельно, нажав нужную клавишу",0,,
,40,"Попросить помочь коллегу, который умеет это делать",0,,
,40,"Нужно позвать Галю, у нее ключ",0,,
,41,Позвать старшего продавца,1,,
,41,Забрать товар и отдать деньги клиенту из кассы,0,,
,41,Мы делаем возвраты только при наличии чека,0,,
,42,Совершить покупку свыше 500 руб за два дня подряд,1,,
,42,Совершить покупку свыше 500 рублей за один день,1,,
,43,Ежедневно без ограничений в течение 6 дней (сегодня на завтра),1,,
,43,Любимый продукт менять нельзя,0,,
,44,В день назначения,0,,
,44,"После назначения, на следующий день",1,,
,44,При повторной покупке свыше 500 рублей,0,,
,45,Неограниченное количество.,1,,
,45,Не более 5 штук,0,,
,45,Один,0,,
,46,"Выбираем товар в чеке, на который покупатель хочет сделать скидку на сегодня, заходим в """"Прочие операции"" и выбираем ""Любимый продукт на сегодня""",1,,
,46,"Сообщить покупателю, что мы не обещаем делать делать скидку сегодня на сегодня.",0,,
,47,Позвать старшего продавца. С его разрешения можно заменить ЛП на один день,1,,
,47,"Заменить любимый продукт самостоятельно ,нажав повторно на ""Прочие операции"" и выбрать ""ЛП на сегодня"", далее ""Вернуться в окно регистрации",0,,
,47,"Если есть на остатках, но клиент не нашел его в зале, заменить ЛП на один день не возможно",0,,
,48,"Если ЛП стоит товар, которого на данный момент уже нет на остатках во всех магазинах ВкусВилл.",1,,
,48,Если товар выведен и его уже нет в конкретном магазине,1,,
,48,Если товар отсутствует в магазине более 14 дней.,1,,
,49,Паспорт РФ,1,,
,49,Загранпаспорт,1,,
,49,Временное удостоверение личности гражданина РФ,1,,
,49,Удостоверение личности моряка,1,,
,49,Водительские права,1,,
,49,Служебный паспорт,1,,
,49,Дипломатический паспорт,1,,
,49,Военный билет,1,,
,49,Вид на жительство,1,,
,49,Разрешение на временное проживание лица без гражданства РФ,1,,
,49,Удостоверение беженца и свидетельство о предоставление временного убежища на территории РФ,1,,
,49,Студенческий билет,0,,
,49,Пропуск на работу,0,,
,49,Свидетельство о браке,0,,
,50,"За реализацию спиртного несовершеннолетним - продавцам, кассирам и лицам, отпускающим товар, может грозить административная ответственность.",1,,
,50,Так положено по стандартам компании,0,,
,50,"В соответствии с Федеральным законом - продажа алкогольной продукции, разрешена, только при предъявлении удостоверении личности.",0,,
,51,да,0,,
,51,нет,1,,
,52,Предложить пакет,1,,
,52,Поприветствовать,1,,
,52,Предложить новинку,0,,
,53,"Товар оформляется старшим продавцом и отдается курьеру, который специально за ним приезжает!Если не приезжает в течение 3х дней -выбрасываем",1,,
,53,Товар оформляется и фотографируется старшим продавцом. Вся информация отправляется технологам. В магазине товар утилизируется.,0,,
,54,Сниженная цена по карте магазина,1,,
,54,"Сниженная цена при покупки от 2-х или 3-х одинаковых наименований , наличие карты не имеет значения",0,,
,54,Скидка 40 % на товар с подходящим сроком реализации,0,,
,54,Новинка,0,,
,55,Сниженная цена по карте магазина,0,,
,55,"Сниженная цена при покупки от 2-х или 3-х одинаковых наименований , наличие карты не имеет значения",1,,
,55,Скидка 40 % на товар с подходящим сроком реализации,0,,
,55,Новинка,0,,
,56,Сниженная цена по карте магазина,0,,
,56,"Сниженная цена при покупки от 2-х или 3-х одинаковых наименований , наличие карты не имеет значения",0,,
,56,Скидка 40 % на товар с подходящим сроком реализации,1,,
,56,Новинка,0,,
,57,Сниженная цена по карте магазина,0,,
,57,"Сниженная цена при покупки от 2-х или 3-х одинаковых наименований , наличие карты не имеет значения",0,,
,57,Скидка 40 % на товар с подходящим сроком реализации,0,,
,57,Новинка,1,,
,58,"честность, доверие, ответственность, хорошие взаимоотношения и взаимопомощь",1,,
,58,"доверие, партнерство, развитие",0,,
,58,"трудолюбие, открытость, взаимопомощь",0,,
,59,"Зарплату нам платит не начальник, а довольные покупатели!",1,,
,59,Довольный клиент- довольный сотрудник.,0,,
,59,Здоровое питание -во все семьи,0,,
,60,Отсутствие просроченных продуктов на кассе.,1,,
,60,"Делать скидку 40% на товар с самым старым сроком годности, если в магазине оказывается три разных срока годности данного товара.",1,,
,60,"Никогда не проявлять грубость, непрофессионализм, чёрствость.",1,,
,60,Не обсуждать клиентов в торговом зале.,1,,
,60,"Из двух задач, выбирать ту, которая важнее для покупателей, находящихся в магазине",1,,
,60,Пускать в магазин с животными и создавать места для привязи рядом с магазином,0,,
,60,Продавать алкоголь без предъявления документа.,0,,
,60,"Подсказывать покупателю, что он может получить скидку по любимому продукту, поменяв на другой - из-за отсутствия текущего ЛП на остатках магазина",0,,
,60,Поставлять в магазин товар определённого производителя,0,,
,61,Пускать в магазин с животными и создавать места для привязи рядом с магазином,1,,
,61,Продавать алкоголь без предъявления документа.,1,,
,61,Поставлять в магазин товар определённого производителя,1,,
,62,Заказ собран к открытию магазина,1,,
,62,Самые свежие сроки,1,,
,62,Обратная связь с покупателем,1,,
,62,Заказ собран к закрытию магазина,0,,
,62,Заказ собран и слава Богу,0,,
,62,"Если нет того, что указано в заказе, собираем аналоги",0,,
,63,Температура,1,,
,63,Относительная влажность,1,,
,63,Световой режим,1,,
,63,Срок годности,0,,
,64,Прибор предназначен для измерения относительной влажности и температуры воздуха внутри помещений,1,,
,64,Прибор предназначен для поддержания необходимой относительной влажности и температуры воздуха внутри помещений,0,,
,64,"Прибор предназначен для измерения температуры, относительной влажности воздуха, освещенности внутри помещений",0,,
,65,Полностью соответствовать предъявляемым к ней требованиям безопасности,1,,
,65,Сохранять свои потребительские свойства,1,,
,65,Быть пригодна для использования по назначению,1,,
,66,От нуля часов указанной даты,1,,
,66,От часа утра указанной даты,0,,
,66,От 23.00 указанной даты,0,,
,67,От даты производства,1,,
,67,От даты фасовки/розлива/упаковки.,0,,
,68,Не помыла руки перед началом работы,0,,
,68,Не подобрала волосы под шапочку,0,,
,68,Пришла на работу с признаками кишечной дисфункции,0,,
,68,Пообедала в неположенном месте,0,,
,68,Пришла в ярких ювелирных украшениях ,0,,
,68,"Лена все сделала правильно, ни каких санитарных норм не нарушила",1,,
\ No newline at end of file
id,card_info_id,text,image,type
1,1,"Выберите утверждение , которое НЕ относится к нашей молочной продукции:",,checkbox
2,1,Порекомендуете ли вы наши детские кисломолочные продукты покупателям с детьми? ,,radio
3,1,Кому подходит козье молоко?,,radio
4,1,Закончите фразу: Наши производители мясной продукции:,,radio
5,1,"Клиент хочет купить замороженную рыбу, но не хочет переплачивать за вес льда, ваш комментарий:",,radio
6,1,"Закончите фразу: все товары из категории ""рыбная гастрономия"":",,radio
7,1,"Какое из описаний подходит наиболее точно: Открыв банку с рыбной консервой, клиент увидит:",,radio
8,1,Какое из ниже ниже представленных утверждений верно:,,radio
9,1,Какой продукт покупатель НЕ найдет на полках наших магазинов?,,radio
10,1,"При изготовлении наших десертов не используют консерванты, улучшители и стабилизаторы, а также никакого:",,radio
11,1,В чем уникальность нашей воды?,,radio
12,1,Что можете сказать о наших соках?,,radio
13,1,Какое из ниже представленных выражений верное:,,radio
14,1,Какого из ниже представленных напитков нет в ассортименте магазинов Вкусвилл?,,radio
15,1,Что такое полезные снеки ВкусВилл?,,radio
16,1,На полках наших магазинов можно найти макаронные изделия:,,radio
17,1,"Покупатели хвалят наши продукты из мяса и птицы за их ""домашний вкус"" и качество, как производителям удается добится таких отзывов?",,radio
18,1,Почему у нашей колбасы не привлекательный цвет?,,radio
19,1,Какие редкие крупы можно найти в магазинах ВкусВилл?,,checkbox
20,1,Чаи ВкусВилл выращивают:,,radio
21,1,"Мюсли Ягодные. Состав: хлопья пшеничные, хлопья овсяные, клюква, клубника вяленая, курага, цукаты, хлопья ячменные,;хлопья ржаные, хлопья из пророщенной пшеницы;семена тыквы, ядро миндаля, хлопья гречневые, ядро фисташки, отруби пшеничные. Назовите лишний ингредиент в составе, который поставщики Вкусвилл никогда не используют при приготовлении мюсли.",,radio
22,1,Что относится к условиям хранения пищевых продуктов?,,checkbox
23,1,Что такое гигрометр психрометрический?,,radio
24,1,"В течение срока годности, пищева продукция должна:",,checkbox
25,1,"Если время изготовления продукта не указанно, от какого времени исчесляется срок годности?",,radio
26,1,"От какой даты, считается срок годности, если на упаковке указаны дата производства и дата фасовки (розлива, упаковки)?",,radio
27,1,"Лена пришла на работу в 08.00, переоделась в рабочую форму , помыла руки, собрала волосы в хвост, одела козырек и вышла в торговый зал. Коллеге Ире она рассказала, что вчера муж подарил ей шикарные гранатовые бусы и массивные серьги, в перерыв обязательно покажет фото. Во время обеда Лена взяла Питу Бургер и вышла на улицу -перекусить и насладиться теплым осенним деньком. После перекура тщательно помыла руки и продезинфицировала. В 20.00 Лена закончила паботу и побежала на маникюр. Какое правило санитарной безопасности нарушила Лена?",,radio
28,1,"С какого года на рынке компания ""Избёнка""?",,radio
29,1,"В каком году открылся первый магазин ""ВкусВилл""",,radio
30,1,"Кто основатель проекта ""ВкусВилл""",,radio
31,1,Где покупатель может оставить отзыв или предложение?,,checkbox
32,1,Каковы преимущества карты во ВкусВилл?,,checkbox
33,1,Покупатель не является держателем карты. Ваши действия?,,radio
34,1,Что необходимо сообщить клиенту после прокатки карты на кассе,,checkbox
35,1,"Если клиент расплачивается наличными, что необходимо озвучить на кассе?",,checkbox
36,1,Как правильно выдать чек покупателю?,,radio
37,1,"Какую клавишу необходимо нажать на кассе после взвешивания, если вы собираетесь пробить 3 яблока, сложенных в зеленый контейнер",,radio
38,1,"Какую клавишу необходимо нажать на кассе после взвешивания, если вы собираетесь пробить 3 яблока, сложенных в прозрачный контейнер",,radio
39,1,"Какую клавишу необходимо нажать на кассе в первую очередь, если вы собираетесь пробить 3 яблока, сложенных в пакет",,radio
40,1,Как осуществить отказ от позиции или отмену чека?,,radio
41,1,Как сделать возврат?,,radio
42,1,Каковы условия назначения Любимого продукта?,,checkbox
43,1,Как часто можно менять Любимый продукт ?,,radio
44,1,Когда начинает действовать скидка на Любимый продукт?,,radio
45,1,Какое количество любимого продукта можно купить за 1 раз?,,radio
46,1,"Что делать, если ЛП отсутствует и покупатель хочет назначить скидку на другой товар только на сегодня?",,radio
47,1,"Что делать, если ЛП у покупателя отсутствует в зале, но есть на остатках?",,radio
48,1,В каком случае замена ЛП на 1 день приведет к его установке на весь срок действия?,,checkbox
49,1,Какие документы могут считаться удостоверением личности при продаже алкогольной продукции?,,checkbox
50,1,"Почему необходимо спрашивать документы, при продаже алкогольной продукции",,radio
51,1,Нужно ли спрашивать документы при продаже безалкогольного пива?,,radio
52,1,Что обязательно перед пробитием товара на кассе?,,checkbox
53,1,"Как правильно поступать с возвратом товара, в котором есть посторонний предмет?",,radio
54,1,Желтый ценник это-,,radio
55,1,Оранжевый ценник это-,,radio
56,1,Зеленый ценник это-,,radio
57,1,Синий ценник это-,,radio
58,1,Наши ценности,,radio
59,1,Наш девиз,,radio
60,1,Что обещают наши консультанты,,checkbox
61,1,Что НЕ обещают наши консультанты,,checkbox
62,1,"Назовите 3 принципа сервиса ""Закажи и забери"". ",,checkbox
63,2,Что относится к условиям хранения пищевых продуктов?,,checkbox
64,3,Что такое гигрометр психрометрический?,,radio
65,4,"В течение срока годности, пищевая продукция должна:",,checkbox
66,6,"Если время изготовления продукта не указанно, от какого времени исчесляется срок годности?",,radio
67,7,"От какой даты, считается срок годности, если на упаковке указаны дата производства и дата фасовки (розлива, упаковки)?",,radio
68,8,"Лена пришла на работу в 08.00, переоделась в рабочую форму , помыла руки, собрала волосы в хвост, одела козырек и вышла в торговый зал. Коллеге Ире она рассказала, что вчера муж подарил ей шикарные гранатовые бусы и массивные серьги, в перерыв обязательно покажет фото. Во время обеда Лена взяла Питу Бургер и вышла на улицу -перекусить и насладиться теплым осенним деньком. После перекура тщательно помыла руки и продезинфицировала. В 20.00 Лена закончила паботу и побежала на маникюр. Какое правило санитарной безопасности нарушила Лена?",,radio
\ No newline at end of file
[
{
"id": 1,
"name": "мучное"
},
{
"id": 2,
"name": "мясо"
},
{
"id": 3,
"name": "сыр"
},
{
"id": 4,
"name": "сахар"
},
{
"id": 5,
"name": "варенье"
},
{
"id": 6,
"name": "сладкое"
},
{
"id": 7,
"name": "шоколад"
},
{
"id": 8,
"name": "морепродукты"
},
{
"id": 9,
"name": "овощи"
},
{
"id": 10,
"name": "шампунь"
},
{
"id": 11,
"name": "гигиена"
},
{
"id": 12,
"name": "чай"
},
{
"id": 13,
"name": "крупа"
},
{
"id": 14,
"name": "булгур"
},
{
"id": 15,
"name": "киноа"
},
{
"id": 16,
"name": "рис"
},
{
"id": 17,
"name": "молочный продукт"
},
{
"id": 18,
"name": "молочное"
},
{
"id": 19,
"name": "риет"
},
{
"id": 20,
"name": "харам"
},
{
"id": 21,
"name": "кускус"
},
{
"id": 22,
"name": "напиток"
},
{
"id": 23,
"name": "вода"
},
{
"id": 24,
"name": "паштет"
},
{
"id": 25,
"name": "салат"
},
{
"id": 26,
"name": "рыба"
},
{
"id": 27,
"name": "травы"
},
{
"id": 28,
"name": "канцтовары"
},
{
"id": 29,
"name": "суп"
},
{
"id": 30,
"name": "блины"
},
{
"id": 31,
"name": "ветчина"
},
{
"id": 32,
"name": "свинина"
},
{
"id": 33,
"name": "курица"
},
{
"id": 34,
"name": "яйцо"
},
{
"id": 35,
"name": "малина"
},
{
"id": 36,
"name": "черника"
},
{
"id": 38,
"name": "смородина"
},
{
"id": 39,
"name": "постное"
},
{
"id": 40,
"name": "слива"
},
{
"id": 41,
"name": "сернослив"
},
{
"id": 42,
"name": "свекла"
},
{
"id": 43,
"name": "яблоко"
},
{
"id": 44,
"name": "арахис"
},
{
"id": 45,
"name": "мята"
},
{
"id": 46,
"name": "котлеты"
},
{
"id": 47,
"name": "креветки"
},
{
"id": 48,
"name": "макароны"
},
{
"id": 49,
"name": "капуста"
},
{
"id": 50,
"name": "хлеб"
},
{
"id": 51,
"name": "борщ"
},
{
"id": 52,
"name": "первое"
},
{
"id": 53,
"name": "готовая еда"
},
{
"id": 54,
"name": "кунжут"
},
{
"id": 55,
"name": "кальмар"
},
{
"id": 56,
"name": "лосось"
},
{
"id": 57,
"name": "индейка"
},
{
"id": 58,
"name": "колбаса"
},
{
"id": 59,
"name": "зелень"
},
{
"id": 60,
"name": "зеленый горошек"
},
{
"id": 61,
"name": "кукуруза"
},
{
"id": 62,
"name": "лук"
},
{
"id": 63,
"name": "перец"
},
{
"id": 64,
"name": "сельдерей"
}
]
\ No newline at end of file
const csv = require('csv-parser'),
fs = require('fs'),
path = require('path');
const readCSV = async function(scope) {
const {fileName, types, keys, index} = scope,
postProcess = scope.postProcess || (a => a);
const trash = Symbol('Trash')
const hash = {};
return await new Promise(function(resolve, reject) {
let id = 1;
const inc = ()=>id++;
fs.createReadStream(fileName)
.pipe(csv({
mapHeaders: ({header}) => keys[header] || trash,
mapValues: ({header, value}) => header in types ? types[header](value) : null
}))
.on('data', (obj) => {
postProcess(obj, inc);
hash[obj[index]] = obj;
})
.on('end', () => {
resolve(hash);
console.log('CSV parsed: '+ fileName)
});
});
};
const base = process.env.KUS_DATA_DIR || './data';
const connections = JSON.parse(fs.readFileSync(path.join(base,'connections.json'))+'');
const tags = JSON.parse(fs.readFileSync(path.join(base,'tags.json'))+'');
data = {tags, connections};
(async()=>{
data.components = await readCSV({
fileName: path.join(base,'components.csv'),
keys: {
'номер карточки': 'id',
'ингредиент': 'name'
},
types: {
id: Number,
name: String
},
postProcess: (a, inc) => a.iID = inc(),
index: 'iID'
});
data.standardQuestions = await readCSV({
fileName: path.join(base,'standard_questions.csv'),
keys: {
'id': 'qID',
'card_info_id': 'cardInfoID',
'text': 'title',
'image': 'image',
'type': 'multiple'
},
types: {
qID: Number,
cardInfoID: Number,
title: String,
image: String,
multiple: String,
},
postProcess: (a) => {
a.answers = [];
a.multiple = a.multiple === 'checkbox';
},
index: 'qID'
});
const standardAnswers = await readCSV({
fileName: path.join(base,'standard_answers.csv'),
keys: {
'question_id': 'qID',
'text': 'title',
'correct': 'correct',
},
types: {
qID: Number,
title: String,
correct: Number
},
postProcess: (a, inc) => {
a.id = inc();
a.answers = [];
a.correct = a.correct === 1;
},
index: 'id'
});
Object.values(standardAnswers).forEach(a=>{
data.standardQuestions[a.qID].answers.push(a);
});
data.products = await readCSV({
fileName: path.join(base,'products.csv'),
keys: {
'': 'id',
'название': 'title',
'описание': 'description',
'категория': 'cat',
'подкатегория': 'subcat',
'подподкатегория': 'subsubcat',
'участвует в тесте': 'use'
},
types: {
id: Number,
title: String,
description: String,
cat: String,
subcat: String,
subsubcat: String,
use: a=>Boolean(Number(a))
},
index: 'id'
});
var dumped = [{"id":1,"title":"Блины \"Карбонара\"","image":"/upload/resize/161031/161031_530x300x85_c.jpg"},{"id":2,"title":"Блины с начинкой жюльен","image":"/upload/resize/93710/93710_530x300x85_c.jpg"},{"id":3,"title":"Блины с ветчиной (из свинины) и с сыром","image":"/upload/resize/93352/93352_530x300x85_c.jpg"},{"id":4,"title":"Блины с мясом","image":"/upload/resize/95146/95146_530x300x85_c.jpg"},{"id":5,"title":"Блины постные с картофелем и грибами","image":"/upload/resize/96634/96634_530x300x85_c.jpg"},{"id":6,"title":"Варенье вишневое, 50 г"},{"id":7,"title":"Малина дроблёная с сахаром","image":"/upload/resize/113263/113263_530x300x85_c.jpg"},{"id":8,"title":"Варенье из слив с лимоном и имбирем","image":"/upload/resize/95818/95818_530x300x85_c.jpg"},{"id":9,"title":"Варенье черничное","image":"/upload/resize/93853/93853_530x300x85_c.jpg"},{"id":10,"title":"Варенье из клубники с мятой","image":"/upload/resize/94377/94377_530x300x85_c.jpg"},{"id":11,"title":"Голубцы ленивые в сметанном соусе"},{"id":12,"title":"Лингвини с креветками и с соусом с тыквой","image":"/upload/resize/94017/94017_530x300x85_c.jpg"},{"id":13,"title":"Котлетки рыбные с запечёнными овощами","image":"/upload/resize/157871/157871_530x300x85_c.jpg"},{"id":14,"title":"Паста с лососем в сливочном соусе","image":"/upload/resize/162506/162506_530x300x85_c.jpg"},{"id":15,"title":"Голубцы с курицей в томатном соусе","image":"/upload/resize/154668/154668_530x300x85_c.jpg"},{"id":16,"title":"Бейгл с кунжутом","image":"/upload/resize/161019/161019_530x300x85_c.jpg"},{"id":17,"title":"Хлеб бородинский бездрожжевой","image":"/upload/resize/113263/113263_530x300x85_c.jpg"},{"id":18,"title":"Чиабатта","image":"/upload/resize/96735/96735_530x300x85_c.jpg"},{"id":19,"title":"Хлеб Печерский масличный","image":"/upload/resize/94387/94387_530x300x85_c.jpg"},{"id":20,"title":"Слойка Свердловская","image":"/upload/resize/157888/157888_530x300x85_c.jpg"},{"id":21,"title":"Мидии мясо варено-мороженное","image":"/upload/resize/96601/96601_530x300x85_c.jpg"},{"id":22,"title":"Кальмар филе очищенный зам.","image":"/upload/resize/93260/93260_530x300x85_c.jpg"},{"id":23,"title":"Креветка северная варено-мороженая","image":"/upload/resize/95442/95442_530x300x85_c.jpg"},{"id":24,"title":"Кальмар кольца зам.","image":"/upload/resize/93248/93248_530x300x85_c.jpg"},{"id":25,"title":"Кальмар тушка зам.","image":"/upload/resize/158195/158195_530x300x85_c.jpg"},{"id":26,"title":"Шпинат свежезамороженный","image":"/upload/resize/96005/96005_530x300x85_c.jpg"},{"id":27,"title":"Смесь Гавайская с/м","image":"/upload/resize/95103/95103_530x300x85_c.jpg"},{"id":28,"title":"Смесь мексиканская с/м","image":"/upload/resize/95101/95101_530x300x85_c.jpg"},{"id":29,"title":"Весенние овощи с/м","image":"/upload/resize/95099/95099_530x300x85_c.jpg"},{"id":30,"title":"Смесь овощная для вок с/м","image":"/upload/resize/157890/157890_530x300x85_c.jpg"},{"id":31,"title":"Колбаса «Сервелат Коньячный» в/к","image":"/upload/resize/94937/94937_530x300x85_c.jpg"},{"id":32,"title":"Колбаса «Особенная» из индейки варёная","image":"/upload/resize/93938/93938_530x300x85_c.jpg"},{"id":33,"title":"Колбаса запеченная из индейки","image":"/upload/resize/93844/93844_530x300x85_c.jpg"},{"id":34,"title":"Колбаса «Брауншвейг. полусухая» с/к в/у","image":"/upload/resize/95596/95596_530x300x85_c.jpg"},{"id":35,"title":"Колбаса кровяная с гречкой"},{"id":36,"title":"Шампунь Яичный","image":"/upload/resize/95618/95618_530x300x85_c.jpg"},{"id":37,"title":"Шампунь мужской","image":"/upload/resize/93625/93625_530x300x85_c.jpg"},{"id":38,"title":"Шампунь молочный Миндаль","image":"/upload/resize/95620/95620_530x300x85_c.jpg"},{"id":39,"title":"Маска для волос Сладкий миндаль","image":"/upload/resize/93749/93749_530x300x85_c.jpg"},{"id":40,"title":"Шампунь твёрдый \"Крапивный\"","image":"/upload/resize/157311/157311_530x300x85_c.jpg"},{"id":41,"title":"Пастила фруктовая из персика","image":"/upload/resize/153082/153082_530x300x85_c.jpg"},{"id":42,"title":"Пастила яблочная натуральная","image":"/upload/resize/99730/99730_530x300x85_c.jpg"},{"id":43,"title":"Пастила яблочная хрустящая","image":"/upload/resize/96081/96081_530x300x85_c.jpg"},{"id":44,"title":"Пастила яблоко-вишня хрустящая","image":"/upload/resize/95513/95513_530x300x85_c.jpg"},{"id":45,"title":"Мармелад \"Облепиха\"","image":"/upload/resize/162524/162524_530x300x85_c.jpg"},{"id":46,"title":"Булгур","image":"/upload/resize/94357/94357_530x300x85_c.jpg"},{"id":47,"title":"Кускус","image":"/upload/resize/96042/96042_530x300x85_c.jpg"},{"id":48,"title":"Киноа","image":"/upload/resize/96046/96046_530x300x85_c.jpg"},{"id":49,"title":"Рис для плова Басмати экстрадлинный","image":"/upload/resize/96040/96040_530x300x85_c.jpg"},{"id":50,"title":"Рис \"Жасмин\"","image":"/upload/resize/157295/157295_530x300x85_c.jpg"},{"id":51,"title":"Йогурт греческий","image":"/upload/resize/93247/93247_530x300x85_c.jpg"},{"id":52,"title":"Иммуноцея с сиропом шиповника","image":"/upload/resize/93481/93481_530x300x85_c.jpg"},{"id":53,"title":"Мацони","image":"/upload/resize/95610/95610_530x300x85_c.jpg"},{"id":54,"title":"Скир \"Исландский\" 1,5%","image":"/upload/resize/162486/162486_530x300x85_c.jpg"},{"id":55,"title":"Творог 5%, 180 г","image":"/upload/resize/162528/162528_530x300x85_c.jpg"},{"id":56,"title":"Балык «Королевский» с/к","image":"/upload/resize/94876/94876_530x300x85_c.jpg"},{"id":57,"title":"Карпаччо из индейки с/к","image":"/upload/resize/96643/96643_530x300x85_c.jpg"},{"id":58,"title":"Шпек сыровяленый нарезка, 50 г","image":"/upload/resize/94257/94257_530x300x85_c.jpg"},{"id":59,"title":"Филе грудки индейки \"Су-вид\" в маринаде Корридо","image":"/upload/resize/161126/161126_530x300x85_c.jpg"},{"id":60,"title":"Ребрышки говяжьи, 400 г","image":"/upload/resize/151246/151246_530x300x85_c.jpg"},{"id":61,"title":"Вырезка из свинины","image":"/upload/resize/93373/93373_530x300x85_c.jpg"},{"id":62,"title":"Половина тушки кролика","image":"/upload/resize/36233/36233_530x300x85_c.jpg"},{"id":63,"title":"Стейк из индейки","image":"/upload/resize/94623/94623_530x300x85_c.jpg"},{"id":64,"title":"Филе бедра куриное бескостное","image":"/upload/resize/93376/93376_530x300x85_c.jpg"},{"id":65,"title":"Напиток Чай с лимоном","image":"/upload/resize/94097/94097_530x300x85_c.jpg"},{"id":66,"title":"Напиток «Чайный гриб» со стевией","image":"/upload/resize/94756/94756_530x300x85_c.jpg"},{"id":67,"title":"Напиток «Лимон-Имбирь»","image":"/upload/resize/93810/93810_530x300x85_c.jpg"},{"id":68,"title":"Вода минеральная Псыж 1л","image":"/upload/resize/141107/141107_530x300x85_c.jpg"},{"id":69,"title":"Напиток \"Кокосовый\" на бактериальной закваске","image":"/upload/resize/155586/155586_530x300x85_c.jpg"},{"id":70,"title":"Паштет мясной запеченный","image":"/upload/resize/94249/94249_530x300x85_c.jpg"},{"id":71,"title":"Паштет из тофу «По-испански»","image":"/upload/resize/95069/95069_530x300x85_c.jpg"},{"id":72,"title":"Риет из горбуши с миндалем","image":"/upload/resize/157319/157319_530x300x85_c.jpg"},{"id":73,"title":"Паштет мясной с печенью индейки и грушей","image":"/upload/resize/96449/96449_530x300x85_c.jpg"},{"id":74,"title":"Паштет из печени кролика с шампиньонами","image":"/upload/resize/157301/157301_530x300x85_c.jpg"},{"id":75,"title":"Суп Харчо","image":"/upload/resize/36472/36472_530x300x85_c.jpg"},{"id":76,"title":"Борщ вегетарианский","image":"/upload/resize/95379/95379_530x300x85_c.jpg"},{"id":77,"title":"Суп куриный с домашней лапшой","image":"/upload/resize/93384/93384_530x300x85_c.jpg"},{"id":78,"title":"Суп-пюре норвежский с сёмгой","image":"/upload/resize/154670/154670_530x300x85_c.jpg"},{"id":79,"title":"Уха русская с сёмгой","image":"/upload/resize/151259/151259_530x300x85_c.jpg"},{"id":80,"title":"Ассорти из омуля, муксуна, чира","image":"/upload/resize/161017/161017_530x300x85_c.jpg"},{"id":81,"title":"Ассорти рыбное х/к из скумбрии и горбуши","image":"/upload/resize/157291/157291_530x300x85_c.jpg"},{"id":82,"title":"Ассорти рыбное х/к ломтики","image":"/upload/resize/93193/93193_530x300x85_c.jpg"},{"id":83,"title":"Корюшка горячего копчения","image":"/upload/resize/94935/94935_530x300x85_c.jpg"},{"id":84,"title":"Муксун ломтики холодного копчения","image":"/upload/resize/96307/96307_530x300x85_c.jpg"},{"id":85,"title":"Салат с яблоком, свеклой и черносливом","image":"/upload/resize/149089/149089_530x300x85_c.jpg"},{"id":86,"title":"Салат Мимоза","image":"/upload/resize/96318/96318_530x300x85_c.jpg"},{"id":87,"title":"Салат «Грин Энерджи»","image":"/upload/resize/95216/95216_530x300x85_c.jpg"},{"id":88,"title":"Салат «Оливье»","image":"/upload/resize/93367/93367_530x300x85_c.jpg"},{"id":89,"title":"Салат винегрет с маринованной капустой","image":"/upload/resize/95948/95948_530x300x85_c.jpg"},{"id":90,"title":"Сыр \"Российский\" тёртый","image":"/upload/resize/162484/162484_530x300x85_c.jpg"},{"id":91,"title":"Сыр козий \"Кремчиз с брусникой и яблоком\"","image":"/upload/resize/154664/154664_530x300x85_c.jpg"},{"id":92,"title":"Сыр твердый «Грюнбергер»","image":"/upload/resize/93323/93323_530x300x85_c.jpg"},{"id":93,"title":"Сыр «Эдам»","image":"/upload/resize/96491/96491_530x300x85_c.jpg"},{"id":94,"title":"Сыр «Алтайский» полутвёрдый","image":"/upload/resize/96247/96247_530x300x85_c.jpg"},{"id":95,"title":"Тетрадь в линейку, 48 л","image":"/upload/resize/157293/157293_530x300x85_c.jpg"},{"id":96,"title":"Десерт молочный \"Ночь в Брюгге\"","image":"/upload/resize/156148/156148_530x300x85_c.jpg"},{"id":97,"title":"Панна-котта «Манго-маракуйя-апельсин»","image":"/upload/resize/96593/96593_530x300x85_c.jpg"},{"id":98,"title":"Пирожное постное «Трюфельное»","image":"/upload/resize/96391/96391_530x300x85_c.jpg"},{"id":99,"title":"Рулет бисквитный","image":"/upload/resize/94957/94957_530x300x85_c.jpg"},{"id":100,"title":"Пирожное \"Малиновое\" на кокосовом молоке","image":"/upload/resize/157898/157898_530x300x85_c.jpg"},{"id":101,"title":"Мята душистая","image":"/upload/resize/143429/143429_530x300x85_c.jpg"},{"id":102,"title":"Горный чабрец","image":"/upload/resize/95864/95864_530x300x85_c.jpg"},{"id":103,"title":"Чай с мятой и календулой в пакетиках","image":"/upload/resize/94555/94555_530x300x85_c.jpg"},{"id":104,"title":"Чай зеленый байховый в пакетиках","image":"/upload/resize/95751/95751_530x300x85_c.jpg"},{"id":105,"title":"Чай гречишный, в пирамидках"}];
dumped.filter(a=>a.image).forEach(a=>data.products[a.id].image = 'https://vkusvill.ru'+a.image)
fs.writeFileSync('tmp.json',JSON.stringify(Object.values(data.products).map(({id, title})=>({id, title}))))
data.after && data.after(data);
})();
const keys = {
'номер карточки': 'id',
'ингредиент': 'name'
};
const mapper = {
id: Number,
name: String
};
module.exports = data;
\ No newline at end of file
{"type":"https:\/\/tools.ietf.org\/html\/rfc2616#section-10","title":"An error occurred","detail":"Not Found Quiz","trace":[{"namespace":"","short_class":"","class":"","type":"","function":"","file":"\/home\/forge\/api.local.vkusvill.testin.ru\/src\/Controller\/CreateQuizAttempt.php","line":53,"args":[]},{"namespace":"App\\Controller","short_class":"CreateQuizAttempt","class":"App\\Controller\\CreateQuizAttempt","type":"-\u003E","function":"__invoke","file":"\/home\/forge\/api.local.vkusvill.testin.ru\/vendor\/symfony\/http-kernel\/HttpKernel.php","line":151,"args":[]},{"namespace":"Symfony\\Component\\HttpKernel","short_class":"HttpKernel","class":"Symfony\\Component\\HttpKernel\\HttpKernel","type":"-\u003E","function":"handleRaw","file":"\/home\/forge\/api.local.vkusvill.testin.ru\/vendor\/symfony\/http-kernel\/HttpKernel.php","line":68,"args":[]},{"namespace":"Symfony\\Component\\HttpKernel","short_class":"HttpKernel","class":"Symfony\\Component\\HttpKernel\\HttpKernel","type":"-\u003E","function":"handle","file":"\/home\/forge\/api.local.vkusvill.testin.ru\/vendor\/symfony\/http-kernel\/Kernel.php","line":198,"args":[]},{"namespace":"Symfony\\Component\\HttpKernel","short_class":"Kernel","class":"Symfony\\Component\\HttpKernel\\Kernel","type":"-\u003E","function":"handle","file":"\/home\/forge\/api.local.vkusvill.testin.ru\/public\/index.php","line":32,"args":[]}]}
\ No newline at end of file
cd /home/forge/kus-quizard
node . -r -n
\ No newline at end of file
......@@ -4,7 +4,6 @@ const APP_HOST = env.APP_HOST || "127.0.0.1";
const APP_PORT = env.APP_PORT || 4000;
const DB_PATH = env.DB_PATH || "./db/users.json";
const data = require("./db.js");
const App = require('express');
const Router = require('node-async-router');
......@@ -32,7 +31,7 @@ const serveBundle = async function(tpl, res){
}
const cacheEntry = posixName;//+new Date()+'_'+Math.random().toString(36).substr(2)
res.end(tpl
.replace('$DATA$', JSON.stringify(data))
//.replace('$DATA$', JSON.stringify(data))
.replace('$BUNDLE$',
'<script src="'+cacheEntry+'"></script>')
);
......@@ -99,7 +98,7 @@ var transformServe = function(dir) {
if (req.url.substr(-5) === '.scss') {
// not secure
console.log('scss', dir, req.url, __dirname)
//console.log('scss', dir, req.url, __dirname)
fs.readFile(path.join(__dirname,dir,req.url), function(err, data){
if( err ){
next();
......@@ -108,7 +107,7 @@ var transformServe = function(dir) {
file: path.join(__dirname,dir,req.url),
sourceMap: true,
importer: function(url, prev, done) {
console.log(url, prev, done)
//console.log(url, prev, done)
// url is the path in import as is, which LibSass encountered.
// prev is the previously resolved path.
// done is an optional callback, either consume it or return value synchronously.
......@@ -122,7 +121,7 @@ var transformServe = function(dir) {
contents: fs.readFileSync(name)+''
});
console.log({name, __dirname, dir, url, prev})
//console.log({name, __dirname, dir, url, prev})
},10);
// OR
//var result = someSyncFunction(url, prev);
......@@ -135,7 +134,7 @@ var transformServe = function(dir) {
}
res.header('Content-Type', 'text/css');
res.end(result.css)
debugger
//debugger
/*...*/ });
}
});
......@@ -143,7 +142,6 @@ var transformServe = function(dir) {
console.log('Serve jsx', dir, req.url)
fs.readFile(path.join(dir, req.url), function(err, data){
if( err ){
console.log('No jsx', err)
next();
}else{
......@@ -157,7 +155,6 @@ var transformServe = function(dir) {
cache[ req.url + '.map' ] = JSON.stringify( result.map );
res.set( 'SourceMap', req.url + '.map' );
res.end( result.code );
debugger;
}
})
}
......@@ -172,30 +169,29 @@ var transformServe = function(dir) {
app.use(transformServe('public'));
app.use(transformServe('src'));
var lives = [];
app.use('/', function(req, res, next) {
console.log(req.originalUrl)
if(req.originalUrl === '/'){
fs.readFile(dir(pack.src, pack.entry.html), function(err, data) {
if(err){
res.end(JSON.stringify(err, null, 2 ));
app.use('/', function(req, res, next){
console.log( req.originalUrl )
if( req.originalUrl === '/' ){
fs.readFile( dir( pack.src, pack.entry.html ), function( err, data ){
if( err ){
res.end( JSON.stringify( err, null, 2 ) );
}else{
serveBundle(data+'', res);
serveBundle( data + '', res );
}
});
} );
}else if(req.originalUrl === '/[live]'){
lives.push(res);
}else if( req.originalUrl === '/[live]' ){
lives.push( res );
}else if( req.originalUrl in cache ){
res( cache[ req.originalUrl ] );
}else{
if(req.originalUrl in cache){
res( cache[ req.originalUrl ] );
}else{
next();
}
next();
}
});
app.use(App.static(dir(pack.public)))
//app.use(App.static(dir(pack.src)))
app.use(App.static(dir(pack.public)));
app.use(App.static(dir(pack.src)))
......@@ -236,7 +232,7 @@ let debounceUpdate = function(filename){
}
};
var watch = require('recursive-watch');
watch('./public', function(filename){
watch('./src', function(filename){
if(filename.indexOf('_tmp_')>-1)
return;
......
var fs = require('fs')
var xx =require("@babel/core").transform(
fs.readFileSync('./public/js/view/page/export.jsx'),
{
"plugins": [
["@babel/plugin-transform-react-jsx", {
"pragma": "D.h", // default pragma is React.createElement
"pragmaFrag": "D.f", // default is React.Fragment
"throwIfNamespace": false // defaults to true
}]
]
}, function(c,d,e) {
console.log(d.code.replace(/\\u([\d\w]{4})/gi, (m, g) => String.fromCharCode(parseInt(g, 16))))
debugger
});
/*
,
"pragma": "Zrx.h",
"pragmaFrag": "Zrx.Fragment",
"throwIfNamespace": false
*/
\ No newline at end of file
{
"question": "Выберите лишний ингредиент, НЕ входящий в продукт \"Салат винегрет с маринованной капустой\"",
"answers": [
{
"correct": false,
"text": "горошек зелёный консервированный"
},
{
"correct": true,
"text": "шампиньоны"
},
{
"correct": false,
"text": "масло подсолнечное нерафинированно"
},
{
"correct": false,
"text": "капуста маринованная"
},
{
"correct": false,
"text": "огурцы консервированные"
},
{
"correct": false,
"text": "свекла столовая отварная,"
}
],
"log": [
"Random seed: bxa9uo",
"Quiz generate radio „Do not contain“",
"Have >= 2 components: 75",
"Matched product: Салат винегрет с маринованной капустой",
"Have 7 components. Took 5:",
" > огурцы консервированные",
" > горошек зелёный консервированный",
" > масло подсолнечное нерафинированно",
" > капуста маринованная",
" > свекла столовая отварная,",
"\nTags: Салаты и закуски",
"Matched 4 component donors.",
"Nearest candidate have got 1 similar tag.",
"Filtered candidates with [1] similar tags.",
"Use Салат «Грин Энерджи» as donor.",
"Because it has 1 similar tags: Салаты и закуски",
"\n << шампиньоны"
],
"type": "radio",
"image": "",
"category": 1
}
\ No newline at end of file
......@@ -3,8 +3,6 @@
"version": "0.1.0",
"main": "bin/index.js",
"dependencies": {
"@babel/plugin-transform-modules-commonjs": "^7.8.3",
"csv-parser": "^2.3.2",
"express": "^4.17.1",
"node-async-router": "^0.0.2",
"node-sass": "^4.13.1",
......@@ -20,6 +18,7 @@
"devDependencies": {
"@babel/core": "^7.8.3",
"@babel/plugin-transform-modules-amd": "^7.8.3",
"@babel/plugin-transform-modules-commonjs": "^7.8.3",
"@babel/plugin-transform-react-jsx": "^7.8.3"
},
"plugins": [
......
;(function(Path) {
'use strict';
var log = console.log;
/*var log = function() {
console.log.apply(console, ['Define'].concat([].slice.call(arguments)));
};*/
var head = document.getElementsByTagName('head')[0];
var cssLoader = function(fileName) {
var link = document.createElement('link');
link.setAttribute('rel', 'stylesheet');
link.setAttribute('type', 'text/css');
link.setAttribute('href', fileName);
head.appendChild(link);
return true;
};
var jsLoader = function(fileName) {
fileName = fileName.replace(/src\//,'');
var script = document.createElement('script');
script.setAttribute('type', script.type = 'text/javascript');
script.onload = function(){
};
script.setAttribute('src', script.src = fileName);
head.appendChild(script);
};
var InstantLoaders = [
{name: '.scss', loader: cssLoader},
{name: '.css', loader: cssLoader},
{name: '.jsx', loader: jsLoader},
{name: '.js', loader: jsLoader},
];
var Ready = function() {}; Ready.prototype = {ready: true};
var Wait = function(fileName) {this.fileName = fileName; this.wait = [];};
Wait.prototype = {
fileName: '',
ready: false,
resolving: 0,
checkInstantLoad: function() {
for( var i = 0, _i = InstantLoaders.length; i < _i; i++ ){
const instantLoader = InstantLoaders[ i ];
if(this.fileName.substr(-instantLoader.name.length).toLowerCase()===instantLoader.name){
if(instantLoader.loader(this.fileName)) {
return true;
}
break;
}
}
return false;
}
};
var wait = {
exports: Ready()
};
var defined = {
};
var resolve = function(base, file) {
return Path.resolve(Path.dirname(base), file);
};
var exec = function(def) {
var exports = {};
def.fn.apply(null, def.deps.map(function(dep) {
if(dep === 'exports'){
return exports;
}
return defined[resolve(def.fileName, dep)];
}));
defined[def.fileName] = exports;
var waiters = wait[def.fileName].wait;
if(wait[def.fileName] instanceof Wait){
wait[ def.fileName ] = new Ready();
for( var i = 0, _i = waiters.length; i < _i; i++ ){
var waitElement = waiters[ i ];
if( waitElement instanceof Wait ){
waitElement.resolving--;
}
}
for( var i = 0, _i = waiters.length; i < _i; i++ ){
var waitElement = waiters[ i ];
if( waitElement.resolving === 0 ){
exec( waitElement.def )
}
}
}
};
window.define = function(fileName, deps, fn) {
fileName = Path.trim(fileName);
defined[fileName] = {fileName:fileName, deps: deps, fn:fn};
deps = deps.map(function(dep) {
return dep === 'exports' ? 'exports': resolve(fileName, dep);
});
var unresolved = deps.filter(function(dep) {
if(dep === 'exports'){
return false;
}
var resolvedName = dep;
var waiter = wait[resolvedName];
if(!wait[resolvedName]){
waiter = wait[resolvedName] = new Wait(resolvedName)
}
if(!waiter.ready){
waiter.wait.push( fileName );
if( waiter.checkInstantLoad() ){
wait[ resolvedName ] = new Ready();
}
}
return !wait[resolvedName].ready;
});
if(!(fileName in wait)){
wait[fileName] = new Wait(fileName);
}
var waiter = wait[fileName];
if(unresolved.length === 0){
log(fileName, 'deps fullfilled');
exec(defined[fileName])
}else{
log(fileName, 'is waiting for', unresolved);
for( var i = 0, _i = unresolved.length; i < _i; i++ ){
var unresolvedElement = unresolved[ i ];
waiter.wait.push(resolve(fileName, unresolvedElement));
waiter.resolving++;
}
}
};
window.define.wait = wait;
window.define.defined = defined;
})(window.__Path);
\ No newline at end of file
function sqlEscape(str) {
return (str+'').replace(/[\0\x08\x09\x1a\n\r"'\\\%]/g, function (char) {
switch (char) {
case "\0":
return "\\0";
case "\x08":
return "\\b";
case "\x09":
return "\\t";
case "\x1a":
return "\\z";
case "\n":
return "\\n";
case "\r":
return "\\r";
case "\"":
case "'":
case "\\":
case "%":
return "\\"+char; // prepends a backslash to backslash, percent,
// and double/single quotes
default:
return char;
}
});
}
const indexKey = {
connections: 'cid',
tags: 'id'//'iID'
},
yamlEscape = function(a) {
return typeof a === 'number'? a : '\''+(a+'').replace(/'/,'\'\'')+'\''
};
const formatters = {
json: function(data) {
return JSON.stringify(data, null, 2);
},
csv: toCSV,
sql: function(data) {
if(data.length){
const item = data[0], header = [];
for(let key in item){
header.push(key);
}
const rows = data.map(item=>header.map(key=>item[key]));
return [ 'INSERT INTO `' + store.get( 'exportTableName' ) + '` (' + header.map( sqlEscape ).map( a => '`' + a + '`' ).join( ', ' ) + ') VALUES' ].concat(
rows.map( row => '(' + row.map( sqlEscape ).map( a => '\'' + a + '\'' ).join( ', ' ) + ')' ).join( ',\n' )
).join( '\n' ) + ';';
}else{
return ';'
}
},
yaml: function(data, exportData) {
const index = indexKey[exportData]
return data
.map(item=>
[exportData.substr(0,exportData.length-1)+item[index]+':'].concat(
Object.keys(item)
.filter(key=>key !== index)
.map(key=>' '+key+': '+ yamlEscape(item[key]))
).join('\n')
).join('\n')
}
};
const exportLogic = function(exportEl) {
store.sub(['exportData', 'exportFormat', 'lastUpdate'], function(exportData, exportFormat) {
var arr = [];
var fullData = dP[exportData];
for(var k in fullData){
arr.push(fullData[k]);
}
exportEl.value = exportFormat in formatters ? formatters[exportFormat](arr, exportData): 'Create formatter '+exportFormat;
});
return exportEl;
};
\ No newline at end of file
let ComponentsOfProduct;
quizTypes.checkbox = [ ComponentsOfProduct = {
probability: 10,
correct: {min: 2, max: 4},
wrong: {min: 1, max: 4},
answers: {min: 3, max: 6},
doNotLogUnique: true,
questionCmpAmount: 2,
type: 'Select components of product',
products: {from: 3, to: 7},
minSimilarTags: 1,
from: qB.prebuild.similarTaggedProducts.fn,
question(income, log){
return `Какие ингредиенты входят в продукт ${lapk(income.correct.title)}`
},
answer(income, log){
const correct = shuffle(income.allUniq)
.slice(0, rand(this.correct.min, this.correct.max))
.map(i=>new Answer.Correct(textFormat(i.name))),
componentsNotInCorrect = qB.getComponentsNotInCorrect(income),
maxWrongs = Math.min(this.wrong.max, this.answers.max-correct.length),
wrongCount = rand(this.wrong.min, maxWrongs),
wrongs = componentsNotInCorrect
.slice(0, wrongCount)
.map(i=>new Answer.Wrong(textFormat(i.name)));
log.push('');
log.push(`Took ${correct.length} correct:`);
correct.forEach(a=>log.push(` > ${a.text}`))
log.push('');
log.push(`And ${wrongs.length} wrong:`);
wrongs.forEach(a=>log.push(` > ${a.text}`))
return shuffle(correct.concat(wrongs));
}
},
Object.assign({}, ComponentsOfProduct, {
probability: 4,
correct: {min: 2, max: 4},
wrong: {min: 2, max: 4},
answers: {min: 4, max: 8},
realMaxAnswers: 6,
question(income, log){
return `Какие ингредиенты НЕ входят в продукт ${lapk(income.correct.title)}`
},
answer(income, log){
log.push('Generate Answers by `Select components of product` subroutine');
const result = ComponentsOfProduct.answer.call(this, income, log);
log.push('Reversing');
const reversed = result
.map(a=>a instanceof Answer.Correct ? new Answer.Wrong(a.text) : new Answer.Correct(a.text));
const right = reversed.filter(a=>a instanceof Answer.Correct),
wrong = reversed.filter(a=>a instanceof Answer.Wrong);
return shuffle(right.concat(wrong.slice(0, Math.min(this.wrong.max, this.realMaxAnswers - right.length))));
}
}),
{
probability: 10,
correct: {min: 2, max: 4},
wrong: {min: 1, max: 3},
answers: {min: 4, max: 6},
doNotLogUnique: true,
questionCmpAmount: 2,
type: 'Select components of product',
products: {from: 2, to: 4},
minSimilarTags: 1,
from(log){
const products = qB.randomProduct({
minComponents: 1,
amount: this.products,
connectedByTags: true,
minSimilarTags: this.minSimilarTags,
doNotTrim: true
}, log),
componentsWithProducts = qB.getComponentsWithSharedProducts(products, 2);
log.push('Shared products count: '+componentsWithProducts.length);
if(componentsWithProducts.length === 0)
return false;
const bounded = componentsWithProducts.filter(cp=>
cp.products.length >= this.correct.min &&
products.length - cp.products.length >= this.wrong.min
);
log.push('After bounding by correct/wrong/full count '+bounded.length+' left');
if(bounded.length === 0){
log.push('Does not meet count criteria');
return false;
}
const chosen = rand(bounded);
log.push('Chosen component: '+chosen.component.name);
return {
baseProduct: chosen.products[0],
component: chosen.component,
correct: chosen.products,
wrong: products.filter(p=>chosen.products.indexOf(p)===-1)
};
},
question(income, log){
return `В какие продукты входит следующий ингредиент ${lapk(textFormat(income.component.name))}`
},
answer(income, log){
const correct = income.correct
.slice(0, rand(this.correct))
.map(p=>new Answer.Correct(p.title)),
wrong = income.wrong
.slice(0, Math.min(rand(this.wrong), this.answers.max - correct.length))
.map(p=>new Answer.Wrong(p.title));
log.push('');
log.push(`Get ${correct.length} correct products:`);
correct.map(c=>log.push(` > ${c.text}`));
log.push('');
log.push(`Get ${correct.length} wrong products:`);
wrong.map(c=>log.push(` > ${c.text}`));
return shuffle(correct.concat(wrong));
}
}
];
\ No newline at end of file
quizTypes.checkboxPhoto = [
{
questionMinComponentsCount: 2,
probability: 8,
type: 'What components are in it',
answers: {min: 3, max: 6},
correct: {min: 2, max: 4},
wrong: {min: 1, max: 4},
from: qB.prebuild.similarTaggedProductWithPhotoAndComponents.fn,
question(income, log){
return 'Какие ингредиенты входят в продукт, изображенный на картинке?'
},
answer( income, log ){
let corrects = income.allCorrect
.slice(0, rand(this.correct))
.map(a=>new Answer.Correct(textFormat(a.name))),
wrongs = income.allWrong
.slice(0, rand(this.wrong))
.map(a=>new Answer.Wrong(textFormat(a.name)));
return shuffle(
corrects
.concat(wrongs)
.slice(
0,
Math.min(
this.answers.max,
corrects.length+wrongs.length)));
}
},
{
questionMinComponentsCount: 2,
probability: 3,
type: 'What components are NOT in it',
answers: {min: 3, max: 6},
correct: {min: 2, max: 4},
wrong: {min: 1, max: 4},
from: qB.prebuild.similarTaggedProductWithPhotoAndComponents.fn,
question(income, log){
return 'Какие ингредиенты НЕ входят в продукт, изображенный на картинке?'
},
answer( income, log ){
let corrects = income.allWrong
.slice(0, rand(this.correct))
.map(a=>new Answer.Correct(textFormat(a.name))),
wrongs = income.allCorrect
.slice(0, rand(this.wrong))
.map(a=>new Answer.Wrong(textFormat(a.name)));
return shuffle(
corrects
.concat(wrongs)
.slice(
0,
Math.min(
this.answers.max,
corrects.length+wrongs.length)));
}
}
];
\ No newline at end of file
const qB = {
randomProduct: function({
minComponents,
amount,
single,
connectedByTags,
minSimilarTags,
doNotTrim,
withPhoto
}, log) {
let filtered = Object.values(dP.products);
filtered = filtered
.filter((p)=>p.getComponents().length >= minComponents);
log.push(`Have >= ${minComponents} components: `+filtered.length);
if(!filtered.length)
return;
if(single){
amount = 1;
}
let minAmount, maxAmount;
if(typeof amount !== 'number'){
minAmount = amount.from;
maxAmount = amount.to;
}else{
minAmount = maxAmount = amount;
}
let similarClusters = [];
if(connectedByTags){
let tagsHash = {};
filtered.forEach(p => {
p.getTags().forEach(({id})=>
(tagsHash[id] || (tagsHash[id] = [])).push(p)
);
});
let similarTags = {};
filtered.forEach(p => {
const tags = p.getTags(),
tagsStr = tags.map(({id})=>id).sort().join(',');
if(tagsStr in similarTags)
return;
let similar = filtered
.map(subP =>
({
similar: subP.getTags().filter(subT => tags.indexOf(subT)>-1).length,
p: subP
})
)
.filter(i=>i.similar>0)
.sort((a, b)=>b.similar - a.similar);
if(similar.length){
let maxCount = similar[ 0 ].similar;
let minCount = minSimilarTags || Math.round( maxCount - maxCount / 4 );
similarTags[ tagsStr ] = similar
.filter( s => s.similar >= minCount )
.map(s=>s.p)
}
});
similarClusters = Object.keys(similarTags)
.map(k=>({k, v:similarTags[k]}))
.filter( a => a.v.length >= minAmount);
log.push(`Clusters that have >= ${minSimilarTags} similar tags: `+Object.values(similarClusters).length);
let randed = rand(similarClusters);
log.push(`Used cluster tags: ${randed.k.split(',').map(id=>dP.tagsHash[id].name).join(', ')}`);
filtered = randed.v;
}
let result;
if(single){
result = rand(filtered);
log.push('Matched product: '+result.title);
}else{
if(filtered.length < minAmount){
log.push(`Not enough components meeting criteria`);
return false;
}
result = shuffle(filtered).slice(0, doNotTrim?filtered.length:rand(minAmount, maxAmount));
log.push('Base products:');
result.forEach(p => log.push(` > ${p.title}`))
log.push('');
}
return result;
},
subdivideComponents: function(from, sub) {
const hash = {};
from.forEach(c=>hash[normalizeText(c.name)] = c);
sub.forEach(c=>delete hash[normalizeText(c.name)]);
return Object.values(hash);
},
getUniqComponents: function(products) {
return Object.values(qB.getUniqComponentsHash(products));
},
getUniqComponentsHash: function(products) {
const hash = {};
products.forEach(
p=>
p
.getComponents()
.forEach(c=>
hash[normalizeText(c.name)] = c
)
);
return hash;
},
getComponentsWithSharedProducts: function(
products,
minSharedProductCount,
maxSharedProductCount
) {
const hash = {};
minSharedProductCount = minSharedProductCount || 0;
maxSharedProductCount = maxSharedProductCount || Infinity;
products.forEach(
p=>
p
.getComponents()
.forEach(c=> {
const name = normalizeText( c.name );
(hash[ name ] || (hash[name] = [])).push({c, p});
})
);
return Object
.values(hash)
.filter(i =>
i.length >= minSharedProductCount &&
i.length <= maxSharedProductCount
)
.map(i=>({component: i[0].c, products: i.map(({p})=>p)}));
},
getComponentsNotInCorrect: function(income) {
return shuffle(
qB.subdivideComponents(
qB.getUniqComponents(income.wrong),
income.correct.getComponents()
)
);
},
getProductsWithTags: function({
products,
tags,
minMatch
}){
if(minMatch === void 0){
minMatch = tags.length;
}
const tHash = tags.reduce((s, t)=>{s[t.id] = t; return s;}, {});
products = products || Object.values( dP.products );
return products
.filter(
p => p.getTags()
.filter(t=>t.id in tHash).length >= minMatch
);
},
prebuild: {
similarTaggedProductWithPhotoAndComponents: {
fn: function(log) {
this.getEmAll = true;
this.products = {min: 2};
const possibilities = shuffle(
qB.prebuild.similarTaggedProductWithPhoto.fn.call(this, log)
);
if(!possibilities || !possibilities.length)
return false;
for( let i = 0, _i = possibilities.length; i < _i; i++ ){
const possibility = possibilities[ i ];
const components = possibility.correct.getComponents();
const other = qB.getUniqComponentsHash(possibility.all.filter( sP => sP !== possibility.correct ))
components.forEach(c=>delete other[normalizeText(c.name)]);
if(Object.keys(other).length >= this.answers.min){
log.push('Take '+possibility.baseProduct.title+' with uniq components:');
components.forEach(c=>
log.push(` > ${c.name}`)
);
log.push('');
log.push('Other components in group tagged as '+
possibility.baseProduct.getTags().map(t=>t.name).join(', ')+':'
);
Object.values( other ).forEach(c=>
log.push(` > ${c.name}`)
);
const c = rand( components )
return {
allCorrect: components,
baseProduct: possibility.baseProduct,
correct: c,
wrong: shuffle( Object.values( other ) ).slice( 0, rand( this.answers.min - 1, this.answers.max - 1 ) ),
allWrong: Object.values( other )
};
}
}
return false;
}
},
similarTaggedProductWithPhoto: {
questionMinComponentsCount: Number,
products: {min: Number, max: Number},
fn: function(log) {
let allProducts = Object.values(dP.products);
let products = Object.values(dP.products)
.filter(p=>p.image)
.filter(p=>p.getComponents().length>=this.questionMinComponentsCount)
log.push( `Products with image and >= ${this.questionMinComponentsCount} components count: ${products.length}` );
if(products.length === 0){
rand(Object.values(dP.products)).image = 'https://robohash.org/'+Math.random().toString(36)
return false;
}
const possibility = products.map(p=>{
const similar = qB.getProductsWithTags({
products: allProducts,
tags: p.getTags(),
minMatch: 1
});
if(similar.length+1 >= this.products.min ){
return {
correct: p,
baseProduct: p,
wrong: similar.filter( sP => sP !== p ).slice(0,rand( this.products.min - 1,this.products.max - 1)),
all: similar
};
}else{
return false;
}
})
.filter(Boolean);
log.push( `Possible count: ${possibility.length}` );
return this.getEmAll ? possibility : rand(possibility);
}
},
similarTaggedProducts: {
// minimal components in product
questionCmpAmount: 4,
// amount of matched products
products: {from: 4, to: 8},
// product similarity (minimal matched tags count)
minSimilarTags: 2,
fn(log){
let products = qB.randomProduct({
minComponents: this.questionCmpAmount,
amount: this.products,
connectedByTags: true,
minSimilarTags: this.minSimilarTags
}, log);
for( let i = 0, _i = products.length; i < _i; i++ ){
const product = products[ i ];
/* if(this.withPhoto && !product.image)
continue;*/
const cmps = product
.getComponents()
.filter(cmp => products.filter(p=>p.containsComponent(cmp)).length === 1)
if(cmps.length>=this.questionCmpAmount){
if(this.doNotLogUnique){
log.push( `Product ${lapk( product.title )} have ${cmps.length} uniq components:` );
}else{
log.push( `Product ${lapk( product.title )} have >= ${this.questionCmpAmount} uniq components (${cmps.length}):` );
}
const shuffled = shuffle(cmps.slice()),
used = shuffled.slice(0, this.questionCmpAmount);
cmps.forEach(c=>log.push(`${!this.doNotLogUnique && used.indexOf(c)>-1?'+':' '} > ${c.name}`));
let wrong = products.slice();
wrong.splice(i,1);
return {
baseProduct: product,
correct: product,
wrong: wrong,
uniq: used,
allUniq: shuffled
}
}
}
return false;
}
}
}
};
\ No newline at end of file
quizTypes.radio = [
{
questionCmpAmount: 4,
probability: 10,
type: 'Product contains 4 components',
products: {from: 4, to: 8},
minSimilarTags: 1,
from: qB.prebuild.similarTaggedProducts.fn,
question(income, log){
return 'В какой из продуктов входят данные ингредиенты: '+income.uniq.map(a=> textFormat(a.name)).join(', ');//products.map(p=>p.title)
},
answer( income, log ){
return shuffle(
[new Answer.Correct(textFormat(income.correct.title))]
.concat(income.wrong.map(p=>new Answer.Wrong(textFormat(p.title)))))
}
},
{
questionCmpAmount: 2,
probability: 8,
type: 'Component in product',
products: {from: 4, to: 6},
minSimilarTags: 1,
from: qB.prebuild.similarTaggedProducts.fn,
question(income, log){
return `Выберите один ингредиент, который входит в продукт ${lapk(income.correct.title)}`
},
answer( income, log ){
return shuffle(
[new Answer.Correct(textFormat(shuffle(income.uniq)[0].name))]
.concat(
shuffle(
qB.subdivideComponents( qB.getUniqComponents(income.wrong), income.correct.getComponents() )
)
.slice(0, rand(this.products.from-1, this.products.to-1))
.map(c=>new Answer.Wrong(textFormat(c.name)))
)
)
}
},
{
questionCmpAmount: 0,
probability: 8,
type: 'Select product description',
products: {from: 3, to: 5},
minSimilarTags: 1,
from: qB.prebuild.similarTaggedProducts.fn,
question(income, log){
return `Какое из этих описаний относится к продукту ${lapk(income.correct.title)}`
},
answer( income, log ){
return shuffle(
[new Answer.Correct(textFormat(income.correct.description))]
.concat(
income.wrong.map(
p => new Answer.Wrong(textFormat(p.description))
)
))
}
},
{
questionCmpAmount: 0,
probability: 8,
type: 'Select product that matches description',
products: {from: 4, to: 6},
minSimilarTags: 1,
from: qB.prebuild.similarTaggedProducts.fn,
question(income, log){
return `К какому из продуктов относится это описание:\n${textFormat(income.correct.description)}`
},
answer( income, log ){
return shuffle(
[new Answer.Correct(textFormat(income.correct.title))]
.concat(
income.wrong.map(
p => new Answer.Wrong(textFormat(p.title))
)
))
}
},
{
probability: 10,
answers: {from: 3, to: 6},
question: ({product})=> `Выберите лишний ингредиент, НЕ входящий в продукт "${product.title}"`,
type: 'Do not contain',
from: (log)=>{
const product = qB.randomProduct({ minComponents: 2, single: true }, log);
return {baseProduct: product, product}
},
answer( {product}, log ){
const out =
shuffle(
dP.Product.getComponents(product)
.map(i=>({correct: false, text: i.name}))
)
.slice(0, rand(this.answers.from - 1, this.answers.to - 1)),
// get tags
tags = product.tags,
donors = [];
log.push(`Have ${dP.Product.getComponents(product).length} components. Took ${out.length}:`);
out.forEach(function(a) {
log.push(' > '+ a.text)
});
log.push('\nTags: '+dP.Product.getTags(product).map(t=>t.name).join(', '));
Object.keys(dP.products)
.map(k=>dP.products[k])
.forEach(item => {
if(item.id === product.id)
return;
const matchedCount = tags.filter(tid=>item.tags.indexOf(tid)>-1).length;
if(matchedCount>0){
donors.push({
count: matchedCount,
item,
title: item.title,
component: dP.Product.getComponents(item).map(a=>a.name)
});
}
});
log.push('Matched '+donors.length+' component donors.');
donors.sort((a,b)=>b.count-a.count);
if(!donors.length){
log.push('Not enough');
return false;
}
const maxCount = donors[0].count;
const minCount = Math.round(maxCount - maxCount/4);
const alreadyExist = out.reduce((store, i)=>{
store[normalizeText(i.text)] = true;
return store;
}, {'соль': true,'сольпощово': true, 'сохор': true});
log.push('Nearest candidate have got '+ maxCount +' similar tag.');
const may = ([].concat.apply(
[],
donors
.filter(i=>i.count > 0 && i.count >= minCount)
.map(i=>
i.component
.filter(c=>{
if(!c.trim())
return false;
const normalized = normalizeText(c);
if(normalized in alreadyExist)
return false;
alreadyExist[normalized] = true;
return true;
})
.map(x => ({count: i.count, item: i.item, text: x}))
)
));
log.push('Filtered candidates with ['+ (minCount===maxCount? minCount : minCount+' - '+ maxCount) +'] similar tags.');
if(may.length<2)
return false;
const answer = rand(may);
log.push('Use '+ answer.item.title +' as donor.');
log.push('Because it has '+ answer.count +' similar tags: '+ dP.Product.getTags(answer.item).map(t=>t.name).join(', '));
out.push({correct: true, text: answer.text});
log.push('\n << '+ answer.text);
return out;
}
}];
\ No newline at end of file
quizTypes.radioPhoto = [
{
questionMinComponentsCount: 0,
probability: 10,
type: 'What is it',
products: {min: 4, max: 6},
from: qB.prebuild.similarTaggedProductWithPhoto.fn,
question(income, log){
return 'Какой продукт изображен на картинке?'
},
answer( income, log ){
return shuffle(
[new Answer.Correct(textFormat(income.correct.title))]
.concat(income.wrong.map(p=>new Answer.Wrong(textFormat(p.title)))))
}
},
{
questionMinComponentsCount: 0,
probability: 8,
type: 'What describes it better',
products: {min: 3, max: 5},
from: qB.prebuild.similarTaggedProductWithPhoto.fn,
question(income, log){
return 'Какое из этих описаний относится к продукту, изображенному на картинке?'
},
answer( income, log ){
return shuffle(
[new Answer.Correct(textFormat(income.correct.description))]
.concat(income.wrong.map(p=>new Answer.Wrong(textFormat(p.description)))))
}
},
{
questionMinComponentsCount: 2,
probability: 3,
type: 'What component is in it',
answers: {min: 4, max: 6},
from: qB.prebuild.similarTaggedProductWithPhotoAndComponents.fn,
question(income, log){
return 'Выберите один ингредиент, который входит в продукт, изображенный на картинке'
},
answer( income, log ){
return shuffle(
[new Answer.Correct(textFormat(income.correct.name))]
.concat(income.wrong.map(p=>new Answer.Wrong(textFormat(p.name)))))
}
}
];
\ No newline at end of file
const lapk = (text)=>`„${text}“`;
const rand = function(a, b){
if(Array.isArray(a)){
return a[Math.random.seeded()*a.length|0];
}
if(typeof a === 'object' && 'max' in a){
b = a.max;
a = a.min || 0;
}
a = Math.ceil(a);
b = Math.floor(b);
return Math.floor(Math.random.seeded() * (b - a + 1)) + a;
return (r-a)*(b-a)|0;
},
probabilityRand = function(items) {
let sum = 0;
for( let i = 0, _i = items.length; i < _i; i++ ){
const item = items[ i ];
sum += item.probability |0;
}
const theRandom = Math.random.seeded();
let total = 0;
for( let i = 0, _i = items.length; i < _i; i++ ){
const item = items[ i ];
total += item.probability/sum;
if(theRandom < total)
return item;
}
};
const normalizeText = function(text) {
return text.trim().toLowerCase().replace(/[^а-я]/g,'').replace(/[аоуеэюёиыя]+/g,'о')
};
const quizTypes = {
checkbox: [],
checkboxPhoto: {
},
radio: [],
radioPhoto: {
}
};
const shuffle = function (a) {
for (let i = a.length - 1; i > 0; i--) {
const j = Math.floor(Math.random.seeded() * (i + 1));
[a[i], a[j]] = [a[j], a[i]];
}
return a;
};
const standardGenerator = function(random) {
const initialSeed = Math.random.seeded.getStringSeed();
const log = quizGenerator.log = ['Random seed: '+initialSeed];
const questionID = random(Object.values(dP.standardQuestions)),
q = dP.standardQuestions[questionID];
log.push('Creating standard question.');
log.push('It would be question number '+questionID);
log.push('');
log.push('Title '+q.title);
q.answers.forEach(
a =>
log.push((a.correct?'+':' ')+` > ${a.title}`));
return {
type: q.multiple ? 'checkbox': 'radio',
categoryId: 2,
productId: q.cardInfoID,
question: textFormat(q.title),
answers: shuffle(q.answers.map(a =>
a.correct ?
new Answer.Correct(a.title) :
new Answer.Wrong(a.title))),
image: !q.image?null:q.image,
log
};
};
const quizGenerator = function(type, photo, subType) {
return _quizGenerator(type, photo, subType);
},
_quizGenerator = function(type, photo, subType, attempt) {
attempt = attempt || 0;
const initialSeed = Math.random.seeded.getStringSeed();
let log;
if(attempt === 0){
const types = quizTypes[type+(photo?'Photo':'')];
subType = probabilityRand(types);
log = quizGenerator.log = ['Random seed: '+initialSeed,'Quiz generate '+type+(photo ? ' with photo':'') +' '+(subType?`${lapk(subType.type)}`:'. FAIL')];
}else if(attempt<30){
log = quizGenerator.log;
log.push('\nATTEMPT FAILED!\n\n'+
'------------------------\n' +
' ATTEMPT '+ (attempt+1)+'\n'+
'------------------------\n\n'
)
}else{
throw new Error('Too much errors')
}
const cfg = subType;
if(!cfg)
return {answers: [], log};
const source = cfg.from.call(cfg, log);
if(source === false){
// давай по новой
return _quizGenerator( type, photo, subType, attempt + 1 );
}
let answers = shuffle(cfg.answer.call(cfg, source, log));
if(answers === false){
// давай по новой
return _quizGenerator( type, photo, subType, attempt + 1 );
}
return {
seed: initialSeed,
type,
categoryId: 1,
productId: source.baseProduct.id,
question: cfg.question.call(cfg, source, log),
answers,
image: !photo?null:source.baseProduct.image,
log,
}
};
const Answer = {
Correct: function(val) {
this.correct = true;
this.text = val;
},
Wrong: function(val) {
this.correct = false;
this.text = val;
}
};
\ No newline at end of file
dP.Product = {
getByID: function(id) {
return dP.products[id];
},
getComponents: function(product) {
return dP.componentsListHashByProduct[ product.id ] || [];
},
getTags: function(product) {
return product.tags.map(dP.Tag.getByID);
},
get: function() {
},
ctor: function(data) {
this.tags = [];
Object.assign(this, data);
}
};
dP.Product.ctor.prototype = {
getComponents(){return dP.Product.getComponents(this);},
getTags(){return dP.Product.getTags(this);},
containsComponent(cmp, fuzzy){
if(!fuzzy)
return this.getComponents().indexOf(cmp)>-1;
const normalized = normalizeText(cmp.name);
return this.getComponents().filter(sCmp=>normalized === normalizeText(sCmp.name) ).length > 0;
}
};
\ No newline at end of file
const useSubSub = true;
const dataProvider = {
maxConnection: 0,
maxTagID: 0,
slice: {},
standardQuestions: {},
tags: [],
connections: {},
products: {}
},
dP = dataProvider,
initDataProvider = function(data) {
Object.assign(dP, data);
let key;
for(key in data.products){
data.products[key] = new dP.Product.ctor(data.products[key])
}
Object.assign(dP, {
componentsList: [],
componentsListHashByProduct: {}
});
for(key in data.components){
const cmp = data.components[key];
cmp.tags = [];
dP.componentsList.push(cmp);
(dP.componentsListHashByProduct[cmp.id] || (dP.componentsListHashByProduct[cmp.id] = [])).push(cmp);
}
if(useSubSub){
data.tags = [];
data.connections = [];
dP.tagsHash = {};
Object.values( data.products ).forEach( function( item ){
const tag = dP.Tag.getOrCreate( item.subsubcat );
dP.Tag.connectToProduct( dP.Product.getByID( item.id ), tag );
} );
}else{
dP.tagsHash = data.tags.reduce( ( store, item ) => {
dP.maxTagID = Math.max( dP.maxTagID, item.id );
store[ item.id ] = item;
return store
}, {} );
data.connections.forEach( ( connection ) => {
dP.maxConnection = Math.max( dP.maxConnection, connection.cid );
if( connection.type === 0 ){
data.products[ connection.eid ].tags.push( connection.tag )
}
} );
}
};
dP.slice.productTable = {
getItems: function() {
return Object.keys(dP.products)
.map(k=>dP.products[k])
.map(item=>{
dP.slice.productTable.updateFilterCache(item);
return item;
})
},
updateFilterCache: function(item) {
item._titleFilter = item.title.toLowerCase();
item._componentsFilter = (dP.componentsListHashByProduct[item.id] || []).map(a=>a.name).join(' ');
item._tagsFilter = (item.tags || []).map(t=>dP.tagsHash[t].name).join(' ');
}
};
\ No newline at end of file
dP.Tag = {
getOrCreate: function(val) {
const matched = dP.Tag.getByName(val);
if(matched)
return matched;
// create
const tagID = ++dP.maxTagID,
item = {
id: tagID,
name: val
};
dP.tagsHash[tagID] = item;
dP.tags.push(item);
return item;
},
remove: function(tagID) {
dP.tags.splice(dP.tags.indexOf(dP.tagsHash[tagID]), 1);
delete dP.tagsHash[tagID];
},
getByID: function(tagID) {
return dP.tagsHash[tagID]
},
getByName: function(name) {
return dP.tags.filter(a=>a.name === name)[0];
},
disconnectFromProduct: function(product, tag) {
const tagID = tag.id;
if(product.tags.indexOf(tagID) > -1){
product.tags.splice( product.tags.indexOf(tagID), 1 );
const connection = dP.connections
.filter(connection =>
connection.tag === tagID &&
connection.type === 0 &&
connection.eid === product.id
)[0];
if(!connection)
return;
if(connection.cid === dP.maxConnection-1)
dP.maxConnection--;
dP.connections.splice(
dP.connections.indexOf(
connection
) ,1);
dP.Tag.removeIfNoConnections(tag);
dP.slice.productTable.updateFilterCache(product);
}
},
connectToProduct: function(product, tag) {
const tagID = tag.id;
if(product.tags.indexOf(tagID) === -1){
product.tags.push( tagID );
dP.connections.push({
cid: ++dP.maxConnection,
type: 0,
eid: product.id,
tag: tagID
});
dP.slice.productTable.updateFilterCache(product);
}
},
removeIfNoConnections: function({tagID}) {
if(dP.connections.filter(connection=>connection.tag === tagID).length === 0){
dP.Tag.remove(tagID)
}
}
};
\ No newline at end of file
// Pico pico graph!
var PCG = window['PCG'] = function(cfg) {
if(cfg.consts){
this.consts = PCG.apply(PCG.apply({}, this.consts), cfg.consts);
delete cfg.consts;
}
PCG.apply(this, cfg);
this._update = this._update.bind(this);
this.resize = this.resize.bind(this);
this.init();
};
PCG.apply = function(a,b) {
for(var k in b){
a[k] = b[k];
}
return a;
};
PCG.ZOOM = {
PIE: 1,
CUSTOM: 2,
LOAD: 3
};
\ No newline at end of file
const D = PCG.D;
const {div, span} = D;
const view = {
page: {},
cmp: {}
};
\ No newline at end of file
D.declare('view.cmp.Menu',({title, id, key, cls}) =>
<div cls={_ => store.equal(key, id,active => _( 'main-menu-item', cls,
'main-menu-item__'+D.escapeCls(id),
{'main-menu-item__active': active}
))}
onclick={()=> store.set(key, id)}>{title}</div>
);
\ No newline at end of file
view.page.Components = function(){
let componentTable;
this.dom = div( { cls: 'content-component' },
div({cls: 'product-filter__area title-gradient'},
div({cls: 'product-filter'},
div({cls: 'product-filter__title'},'Фильтр'),
D.input({
attr: {
value: (update)=>store.sub('componentFilterText', (val)=>update(val))},
cls: 'product-filter__input',
on: {input: (e)=>store.set('componentFilterText', e.target.value)}})
)
),
componentTable = new view.cmp.Table( {
sorters: [ { id: 'title', type: String } ],
sort: [ { name: 'asc' } ],
filterFn: function( text, me ){
return !text || textFilterMatched( this.name, text )
},
afterFilter: ( items ) => store.set( 'componentFilteredCount', items.length ),
itemTpl: ( item, me, bonus ) => {
const dom = div( { cls: 'table-item table-item__component' },
span( {
cls: 'component-title',
on: { click: tableAction },
attr: { 'data-action': 'toggle:' + item.id }
}, me.highlight( item.name ), ' ≡' )
);
return dom;
},
items: dP.componentsList
} )
);
const tableAction = componentTable.getActionDelegate();
store.sub([
'componentFilterText'
], function(text) {
componentTable.filter(text.trim().toLowerCase());
componentTable.updateChildren();
});
};
\ No newline at end of file
//import f from './exp.js';
//console.log(f)
D.declare('view.page.Export', function(){
return <div cls="export-panel">
<div cls="title-gradient">
<div cls="export-sub-menu">
<div cls={_=>_("export-sub-menu", 'olo')}>
<view.cmp.Menu title='Тэги' id='tags' key='exportData'/>
<view.cmp.Menu title='Связи' id='connections' key='exportData'/>
</div>
<div cls="export-sub-menu">
{view.cmp.Menu( { title: 'CSV', id: 'csv', key: 'exportFormat' } )}
{view.cmp.Menu( { title: 'JSON', id: 'json', key: 'exportFormat' } )}
{view.cmp.Menu( { title: 'YAML', id: 'yaml', key: 'exportFormat' } )}
{view.cmp.Menu( { title: 'SQL', id: 'sql', key: 'exportFormat' } )}
</div>
</div>
</div>
{exportLogic( <textarea cls='export-data'/>)}
<div cls="export-comment">Connetction type{'<Enum>'}: 0 — продукт, 1 — компонент`</div>
<button onclick={e => console.log( e )}>btn1</button>
</div>
});
view.page.Export = function() {
this.dom =
div({cls: 'export-panel'},
div({cls: 'title-gradient'},
div({cls: 'export-sub-menu'},
div({cls: 'export-sub-menu'},
view.cmp.Menu({title: 'Тэги', id: 'tags', key: 'exportData'}),
view.cmp.Menu({title: 'Связи', id: 'connections', key: 'exportData'})
),
div({cls: 'export-sub-menu'},
view.cmp.Menu({title: 'CSV', id: 'csv', key: 'exportFormat'}),
view.cmp.Menu({title: 'JSON', id: 'json', key: 'exportFormat'}),
view.cmp.Menu({title: 'YAML', id: 'yaml', key: 'exportFormat'}),
view.cmp.Menu({title: 'SQL', id: 'sql', key: 'exportFormat'}),
)
)
),
exportLogic(D.textarea({cls: 'export-data'})),
div({cls: 'export-comment'}, `Connetction type<Enum>: 0 — продукт, 1 — компонент`)
);
};
\ No newline at end of file
view.cmp.Answer = function(answer, type) {
return (
<label cls={D.cls('quiz-answer-label', 'quiz-answer-label__'+type)}>
<input type={type} checked={answer.correct}/>{answer.text}
</label>
)
};
view.page.Generate = function() {
const update = function() {
const photo = store.get('generatePhoto') === 'photo',
type = store.get('generateType'),
category = store.get('generateCategory');
try{
seedInput.value = Math.random.seeded.getStringSeed();
const result = category === 'product' ? quizGenerator( type, photo ) : standardGenerator(({length})=>rand(0,length-1));
title.innerHTML = textFormat( result.question, true );
image.innerHTML = result.image ? `<img src="${result.image}" alt="img"/>` : '';
image.style.display = result.image ? 'block': 'none';
debug.value = result.log.join( '\n' )
D.removeChildren( answers );
D.appendChild( answers, result.answers.map( ( a ) => view.cmp.Answer( a, type ) ) );
}catch( e ){
debug.value = quizGenerator.log.join( '\n' )
console.error(e)
}
};
let title, answers, debug, seedInput, image;
this.dom =
<div cls='generate-panel'>
<div cls='title-gradient'>
<div cls='generate-sub-menu'>
<div cls='generate-sub-menu'>
{view.cmp.Menu({title: 'Продукты', id: 'product', key: 'generateCategory'})}
{view.cmp.Menu({title: 'Стандарты', id: 'standard', key: 'generateCategory'})}
</div>
{view.cmp.Switch({key: 'generateCategory'}, {
product: <div cls='generate-sub-menu'>
<div cls='generate-sub-menu'>
{view.cmp.Menu({title: 'Единственный', id: 'radio', key: 'generateType'})}
{view.cmp.Menu({title: 'Множественный', id: 'checkbox', key: 'generateType'})}
</div>
<div cls='generate-sub-menu'>
{view.cmp.Menu({title: 'С фото', id: 'photo', key: 'generatePhoto'})}
{view.cmp.Menu({title: 'Без фото', id: 'noPhoto', key: 'generatePhoto'})}
</div>
</div>
})}
</div>
</div>
<div cls='generate-controls'>
<input type='button' value='F5' onclick={update}/>
<span cls='generate-seed-label'>Seed:</span>
{seedInput = <input
cls='seed'
type='input' value='' placeholder='seed'
oninput={function() {
var val = seedInput.value;
Math.random.seeded.setStringSeed(val);
update()
}}/>
}
</div>
<div cls='generate-example'>
{title = <div cls='generate-title'/>}
{image = <div cls='generate-image'/>}
{answers = <div cls='generate-answers'/>}
{debug = <textarea cls='generate-debug'/>}
</div>
</div>;
store.sub(['generateType', 'generatePhoto', 'generateCategory'], update);
};
\ No newline at end of file
view.cmp.Answer = function(answer, type) {
return D.label({cls: D.cls('quiz-answer-label', 'quiz-answer-label__'+type)},
D.input({
attr: {type, checked: answer.correct}
}),
answer.text
)
};
view.page.Generate = function() {
const update = function() {
const photo = store.get('generatePhoto') === 'photo',
type = store.get('generateType'),
category = store.get('generateCategory');
try{
seedInput.value = Math.random.seeded.getStringSeed();
const result = category === 'product' ? quizGenerator( type, photo ) : standardGenerator(({length})=>rand(0,length-1));
title.innerHTML = textFormat( result.question, true );
image.innerHTML = result.image ? `<img src="${result.image}" alt="img"/>` : '';
image.style.display = result.image ? 'block': 'none';
debug.value = result.log.join( '\n' )
D.removeChildren( answers );
D.appendChild( answers, result.answers.map( ( a ) => view.cmp.Answer( a, type ) ) );
}catch( e ){
debug.value = quizGenerator.log.join( '\n' )
console.error(e)
}
};
let title, answers, debug, seedInput, image;
this.dom =
div({cls: 'generate-panel'},
div({cls: 'title-gradient'},
div({cls: 'generate-sub-menu'},
div({cls: 'generate-sub-menu'},
view.cmp.Menu({title: 'Продукты', id: 'product', key: 'generateCategory'}),
view.cmp.Menu({title: 'Стандарты', id: 'standard', key: 'generateCategory'})
),
view.cmp.Switch({key: 'generateCategory'}, {
product: div({cls: 'generate-sub-menu'},
div({cls: 'generate-sub-menu'},
view.cmp.Menu({title: 'Единственный', id: 'radio', key: 'generateType'}),
view.cmp.Menu({title: 'Множественный', id: 'checkbox', key: 'generateType'})
),
div({cls: 'generate-sub-menu'},
view.cmp.Menu({title: 'С фото', id: 'photo', key: 'generatePhoto'}),
view.cmp.Menu({title: 'Без фото', id: 'noPhoto', key: 'generatePhoto'})
)
)
})
)
),
div({cls: 'generate-controls'},
D.input({
attr: {type: 'button', value: 'F5'},
on: {click: update}}),
span({cls: 'generate-seed-label'}, 'Seed:'),
seedInput = D.input({
cls: 'seed',
attr: {type: 'input', value: '', placeholder: 'seed'},
on: {input: function() {
var val = seedInput.value
Math.random.seeded.setStringSeed(val);
update()
//Math.random.seeded.setStringSeed(val);
}}}),
),
div({cls: 'generate-example'},
title = div({cls: 'generate-title'}),
image = div({cls: 'generate-image'}),
answers = div({cls: 'generate-answers'}),
debug = D.textarea({cls: 'generate-debug'})
)
);
store.sub(['generateType', 'generatePhoto', 'generateCategory'], update);
};
\ No newline at end of file
view.page.Products = function() {
let productTable, productFilterByTitle, productFilterByComponent, productFilterByTag, productFilterText,
tagField;
this.dom = div({cls: 'content-products'},
div({cls: 'product-filter__area title-gradient'},
div({cls: 'product-filter'},
div({cls: 'product-filter__title'},'Фильтр'),
D.input({
attr: {
value: (update)=>store.sub('productFilterText', (val)=>update(val))},
cls: 'product-filter__input',
on: {input: (e)=>store.set('productFilterText', e.target.value)}})
),
div({cls: 'product-filter'},
span({cls: 'product-filter__hint'},'Область фильтрации:'),
D.label({cls: 'product-filter__label'},
D.input({
attr:{
type: 'checkbox',
checked: (update)=>store.sub('productFilterByTitle', (val)=>update(val))},
on: {change: (e)=>{store.set('productFilterByTitle', e.target.checked)}}
}), 'Название'
),
D.label({cls: 'product-filter__label'},
D.input({
attr:{
type: 'checkbox',
checked: (update)=>store.sub('productFilterByComponent', (val)=>update(val))},
on: {change: (e)=>{store.set('productFilterByComponent', e.target.checked)}}
}), 'Ингредиенты'
),
D.label({cls: 'product-filter__label'},
D.input({
attr:{
type: 'checkbox',
checked: (update)=>store.sub('productFilterByTag', (val)=>update(val))},
on: {change: (e)=>{store.set('productFilterByTag', e.target.checked)}}
}), 'Тэги'
)
)
),
div({cls: 'tag-manipulations'},
D.input({attr:{type: 'button', value: 'Удалить тэг'}, on: {
click: ()=> {
var val = tagField.getValue().trim();
if(val!==''){
var tag = dP.Tag.getByName(val);
if(!tag)
return;
productTable.getSelected().forEach(function(item) {
dP.Tag.disconnectFromProduct(dP.Product.getByID(item.id), tag);
productTable.updateChildByData(item);
});
store.set('lastUpdate', +new Date())
}
}}}),
tagField = new view.cmp.TagField(),
D.input({
cls: update =>
store.sub('productFilteredCount', count =>
update(D.cls('tag-manipulations-add-tag', {
'tag-manipulations__not-active': count === 0 || count > 30}))),
attr:{type: 'button', value: 'Добавить тэг'},
on: {
click: ()=> {
var val = tagField.getValue().trim();
if(val==='')
return;
const tag = dP.Tag.getOrCreate(val);
productTable.getSelected().forEach(function(item) {
dP.Tag.connectToProduct(dP.Product.getByID(item.id), tag);
productTable.updateChildByData(item);
});
store.set('lastUpdate', +new Date())
}
}
}),
D.span({cls: 'tag-manipulations-add-tag__comment'},
_=> store.sub('productFilteredCount', count =>
_(
'Найдено: '+count,
count === 0 ? D.span({}, 'Надо больше результатов!') : (count > 30 ? D.span({}, 'Не цепляй тэг на всё сразу!') : null)
)))
),
productTable = new view.cmp.Table({
sorters: [{id: 'title', type: String}],
sort: [{title: 'asc'}],
filterBy: {title: true, tag: true, component: true},
filterFn: function(text, me) {
return !text ||
(me.filterBy.title && textFilterMatched(this._titleFilter, text)) ||
(me.filterBy.tag && textFilterMatched(this._tagsFilter,text)) ||
(me.filterBy.component && textFilterMatched(this._componentsFilter,text))
},
afterFilter: (items)=>store.set('productFilteredCount', items.length),
itemTpl: (item, me, bonus) => {
const dom = div({cls: 'table-item table-item__product'},
div( {
cls: 'table-item-action table-item-collapse',
attr: { title: 'Скрыть', 'data-action': 'hide:' + item.id },
on: { click: tableAction }
}, '←' ),
span( {
cls: 'product-title',
on: { click: tableAction },
attr:{ 'data-action': 'toggle:'+ item.id}
}, me.highlight( item.title ),' ≡' ),
( item.tags || [] ).map( t => me.highlight( dP.tagsHash[ t ].name ) ).map( view.cmp.Tag ),
bonus.full && D.html( { cls: 'product-description' }, textFormat(item.description, true) ),
div(
{ cls: 'table-item__product-components' },
D.join( ( dP.componentsListHashByProduct[ item.id ] || [] ).map( a => D.span( { cls: 'product-cmp' }, me.highlight( a.name ) ) ), ', ' )
)
);
if(bonus.hidden){
if(bonus.hiddenFull){
dom.classList.add( 'table-item__hidden-full' );
}else{
setTimeout( () => {
dom.classList.add( 'table-item__hidden' );
}, 1 )
setTimeout( () => {
bonus.hiddenFull = true;
dom.classList.add( 'table-item__hidden-full' );
}, 300 )
}
}
return dom;
},
items: dP.slice.productTable.getItems()
})
);
const tableAction = productTable.getActionDelegate();
store.sub([
'productFilterText',
'productFilterByTitle',
'productFilterByComponent',
'productFilterByTag'
], function(text, title, component, tag) {
Object.assign(productTable.filterBy, {title, component, tag});
productTable.filter(text.trim().toLowerCase());
productTable.updateChildren();
});
};
\ No newline at end of file
(function(PCG, glob){
var svgNS = 'http://www.w3.org/2000/svg';
// I am too lazy to do DOM manually / anyway this solution is optimal enough
var setters = {
cls: function(el) {
return function(cls) {
if( el.tagName.toLowerCase() === 'svg' ){
el.setAttribute( 'class', cls );
}else{
el.className = D.cls.apply(D, arguments);
}
}
},
attr: function(el, attrName) {
return function(val) {
if(val !== void 0 && val !== false){
el.setAttribute( attrName, val );
}else{
el.removeAttribute(attrName)
}
}
}
};
var used = {
cls: true, className: true, 'class': true,
attr: true, style: true, renderTo: true,
prop: true,
on: true
};
// ~jsx h function
var domEl = function( type, cfg ){
if(typeof type === 'function'){
return type(cfg);
}
cfg = cfg || {};
var cls = cfg.cls || cfg['class'] || cfg.className,
style = cfg.style,
attr = cfg.attr || {},
prop = cfg.prop,
on = cfg.on || {},
renderTo = cfg.renderTo,
el = cfg.el || document.createElement( type ),
classList = el.classList;
var i, _i, name;
for(i in cfg)
if( cfg.hasOwnProperty(i)){
name = i.toLowerCase();
if(name in used)
continue;
if(name.substr(0, 2) === 'on'){
on[ name.substr( 2 ) ] = cfg[ i ];
}else{
attr[i] = cfg[i];
}
}
if( cls ){
if(typeof cls === 'function'){
cls(setters.cls(el));
}else{
setters.cls(el)(cls);
}
//if(el.className !== cls)debugger
//cls.split( ' ' ).forEach( function( clsItem ){ classList.add( clsItem ); });
}
if( style ){
PCG.apply( el.style, style );
}
for( i in attr ){
if(attr.hasOwnProperty( i )){
if( typeof attr[ i ] === 'function' ){
attr[ i ]( setters.attr( el, i ) );
}else{
setters.attr( el, i )( attr[ i ] );
}
}
}
for( i in prop ){
prop.hasOwnProperty( i ) && ( el[ i ] = prop[ i ] );
}
for( i in on ){
on.hasOwnProperty( i ) && el.addEventListener( i, on[ i ] );
}
for( i = 2, _i = arguments.length; i < _i; i++ ){
var child = arguments[ i ];
D.appendChild( el, child );
}
if( renderTo ){
D.appendChild( renderTo, el );
}
return el;
};
var D = PCG.D = {
svg: null,
label: null,
div: null,
span: null,
path: null,
canvas: null,
input: null,
textarea: null,
tBody: null,
tHead: null,
th: null,
td: null,
tr: null,
Text: function( val ){ return document.createTextNode( val );}
};
'div,span,input,label,canvas,span,textarea,table,tr,td,th,tBody,tHead'.split( ',' ).forEach( function( name ){
D[ name ] = function(){
return domEl.apply( null, [ name ].concat([].slice.call(arguments)))
};
} );
'svg,path,circle'.split( ',' ).forEach( function( name ){
D[ name ] = function( cfg){
if( !cfg ){
cfg = {};
}
cfg.el = document.createElementNS( svgNS, name );
cfg.el.setAttribute( 'xmlns', svgNS );
return domEl.apply( null, [ null ].concat([].slice.call(arguments)))
};
} );
D.html = function(cfg){
var el = domEl('div', cfg);
el.innerHTML = [].slice.call(arguments,1).join('\n');
return el;
};
D.h = domEl;
D.removeChildren = function(el){
var subEl;
while((subEl = el.lastChild)){
el.removeChild(subEl);
}
};
D.appendChild = function(el, subEl){
var type = typeof subEl;
if(subEl === null){
return ;
}
if( type !== 'object' ){
if( type === 'function' ){
var tmp = D.span( {} );
el.appendChild( tmp );
subEl( function(){
D.removeChildren( tmp );
D.appendChild( tmp, [].slice.call( arguments ) )
} )
}else if( subEl !== void 0 && subEl !== false && subEl !== null ){
el.appendChild( D.Text( subEl ) );
}
}else if('dom' in subEl){
el.appendChild( subEl.dom );
}else if( Array.isArray(subEl) ){
subEl.forEach(subEl => D.appendChild( el, subEl ) );
}else{
el.appendChild( subEl );
}
};
D.join = function(arr, delimiter){
var out = [], isFn = typeof delimiter === 'function';
for( var i = 0, _i = arr.length - 1; i < _i; i++ ){
out.push(arr[i], isFn?delimiter(i):delimiter);
}
if(i < _i+1)
out.push(arr[i]);
return out;
};
D.cls = function() {
var out = [], i = 0, _i = arguments.length, token, tmp, key;
for(;i<_i;i++){
token = arguments[i];
if(typeof token === 'string'&& token){
out.push( token );
}else if(typeof token === 'object'){
if(Array.isArray(token)){
tmp = D.cls.apply(null, token);
tmp && out.push( token );
}else{
for(key in token){
token[key] && out.push( key );
}
}
}else if(typeof token === 'function'){
}
}
return out.join(' ');
};
D.escapeCls = function(cls) {
return (cls+'').replace(/[^a-zA-Z0-9\-_]/g,'');
};
var _construct = function(ctor, cfg) {
//if it is not an arrow function
if('prototype' in ctor && ctor.prototype.constructor === ctor){
var cls = new ctor(cfg);
return 'dom' in cls ? cls.dom : cls;
}else{
return ctor(cfg);
}
};
var usage = {};
var populate = function(name, construct) {
var tokens = name.split('.'),
last = tokens.pop(),
first = tokens.shift();
// ES 6 consts are not in global scope. So we can not just add vars to window
var pointer = first?
new Function('glob', 'return typeof '+first+' !== "undefined"?'+first+':(glob["'+first+'"] = {})')(glob)
:glob;
tokens.reduce(function(pointer, token, i, full) {
return pointer[token] || (pointer[token] = {});
}, pointer)[last] = construct;
return construct;
};
D.declare = function(name, ctor) {
var uses;
if(name in usage){
console.log(`${name} declaration updated. Usage count: ${usage[name].instances.length}`)
usage[ name ].ctor = ctor;
uses = usage[ name ].instances;
for( var i = 0, _i = uses.length; i < _i; i++ ){
var u = uses[ i ], d = u.dom;
u.dom = _construct(ctor, u.cfg);
if(d.parentNode){
d.parentNode.replaceChild( u.dom, d )
}
}
}else{
console.log(`${name} declared`)
uses = (usage[ name ] = {ctor: ctor, instances: []}).instances;
}
return populate(name, function construct (cfg) {
var dom = _construct(ctor, cfg);
uses.push({dom: dom, cfg: cfg});
return dom;
});
}
})(window['PCG'], typeof window !== "undefined" ? window :
typeof WorkerGlobalScope !== "undefined" ? self :
typeof global !== "undefined" ? global :
typeof GLOBAL !== "undefined" ? GLOBAL :
Function("return this;")());
\ No newline at end of file
var NS = window['NS'] = function(cfg) {
if(cfg.consts){
this.consts = NS.apply(NS.apply({}, this.consts), cfg.consts);
delete cfg.consts;
}
NS.apply(this, cfg);
this._update = this._update.bind(this);
this.resize = this.resize.bind(this);
this.init();
};
NS.apply = function(a,b) {
for(var k in b){
a[k] = b[k];
}
return a;
};
(function(NS, glob){
var svgNS = 'http://www.w3.org/2000/svg';
var setters = {
cls: function(el) {
return function(cls) {
if( el.tagName.toLowerCase() === 'svg' ){
el.setAttribute( 'class', cls );
}else{
el.className = D.cls.apply(D, arguments);
}
}
},
attr: function(el, attrName) {
return function(val) {
if(val !== void 0 && val !== false){
el.setAttribute( attrName, val );
}else{
el.removeAttribute(attrName)
}
}
}
};
var used = {
cls: true, className: true, 'class': true,
attr: true, style: true, renderTo: true,
prop: true,
on: true
};
// ~jsx h function
var domEl = function( type, cfg ){
if(typeof type === 'function'){
return type(cfg);
}
cfg = cfg || {};
var cls = cfg.cls || cfg['class'] || cfg.className,
style = cfg.style,
attr = cfg.attr || {},
prop = cfg.prop,
on = cfg.on || {},
renderTo = cfg.renderTo,
el = cfg.el || document.createElement( type ),
classList = el.classList;
var i, _i, name;
for(i in cfg)
if( cfg.hasOwnProperty(i)){
name = i.toLowerCase();
if(name in used)
continue;
if(name.substr(0, 2) === 'on'){
on[ name.substr( 2 ) ] = cfg[ i ];
}else{
attr[i] = cfg[i];
}
}
if( cls ){
if(typeof cls === 'function'){
cls(setters.cls(el));
}else{
setters.cls(el)(cls);
}
}
if( style ){
NS.apply( el.style, style );
}
for( i in attr ){
if(attr.hasOwnProperty( i )){
if( typeof attr[ i ] === 'function' ){
attr[ i ]( setters.attr( el, i ) );
}else{
setters.attr( el, i )( attr[ i ] );
}
}
}
for( i in prop ){
prop.hasOwnProperty( i ) && ( el[ i ] = prop[ i ] );
}
for( i in on ){
on.hasOwnProperty( i ) && el.addEventListener( i, on[ i ] );
}
for( i = 2, _i = arguments.length; i < _i; i++ ){
var child = arguments[ i ];
D.appendChild( el, child );
}
if( renderTo ){
D.appendChild( renderTo, el );
}
return el;
};
var D = NS.D = {
svg: null,
label: null,
div: null,
span: null,
path: null,
canvas: null,
input: null,
textarea: null,
tBody: null,
tHead: null,
th: null,
td: null,
tr: null,
Text: function( val ){ return document.createTextNode( val );}
};
'div,span,input,label,canvas,span,textarea,table,tr,td,th,tBody,tHead'.split( ',' ).forEach( function( name ){
D[ name ] = function(){
return domEl.apply( null, [ name ].concat([].slice.call(arguments)))
};
} );
'svg,path,circle'.split( ',' ).forEach( function( name ){
D[ name ] = function( cfg){
if( !cfg ){
cfg = {};
}
cfg.el = document.createElementNS( svgNS, name );
cfg.el.setAttribute( 'xmlns', svgNS );
return domEl.apply( null, [ null ].concat([].slice.call(arguments)))
};
} );
D.html = function(cfg){
var el = domEl('div', cfg);
el.innerHTML = [].slice.call(arguments,1).join('\n');
return el;
};
D.h = domEl;
D.removeChildren = function(el){
var subEl;
while((subEl = el.lastChild)){
el.removeChild(subEl);
}
};
D.appendChild = function(el, subEl){
var type = typeof subEl;
if(subEl === null){
return ;
}
if( type !== 'object' ){
if( type === 'function' ){
var tmp = D.span( {} );
el.appendChild( tmp );
subEl( function(){
D.removeChildren( tmp );
D.appendChild( tmp, [].slice.call( arguments ) )
} )
}else if( subEl !== void 0 && subEl !== false && subEl !== null ){
el.appendChild( D.Text( subEl ) );
}
}else if('dom' in subEl){
el.appendChild( subEl.dom );
}else if( Array.isArray(subEl) ){
subEl.forEach(subEl => D.appendChild( el, subEl ) );
}else{
el.appendChild( subEl );
}
};
D.join = function(arr, delimiter){
var out = [], isFn = typeof delimiter === 'function';
for( var i = 0, _i = arr.length - 1; i < _i; i++ ){
out.push(arr[i], isFn?delimiter(i):delimiter);
}
if(i < _i+1)
out.push(arr[i]);
return out;
};
D.cls = function() {
var out = [], i = 0, _i = arguments.length, token, tmp, key;
for(;i<_i;i++){
token = arguments[i];
if(typeof token === 'string'&& token){
out.push( token );
}else if(typeof token === 'object'){
if(Array.isArray(token)){
tmp = D.cls.apply(null, token);
tmp && out.push( token );
}else{
for(key in token){
token[key] && out.push( key );
}
}
}else if(typeof token === 'function'){
}
}
return out.join(' ');
};
D.escapeCls = function(cls) {
return (cls+'').replace(/[^a-zA-Z0-9\-_]/g,'');
};
var _construct = function(ctor, cfg, p) {
//if it is not an arrow function
if('prototype' in ctor && ctor.prototype.constructor === ctor){
var cls = new ctor(cfg || {}, p);
return 'dom' in cls ? cls.dom : cls;
}else{
return ctor(cfg || {}, p);
}
};
var usage = {};
var populate = function(name, construct) {
var tokens = name.split('.'),
last = tokens.pop(),
first = tokens.shift();
// ES 6 consts are not in global scope. So we can not just add vars to window
var pointer = first?
new Function('glob', 'return typeof '+first+' !== "undefined"?'+first+':(glob["'+first+'"] = {})')(glob)
:glob;
tokens.reduce(function(pointer, token, i, full) {
return pointer[token] || (pointer[token] = {});
}, pointer)[last] = construct;
return construct;
};
D.declare = function(name, ctor) {
var uses;
if(name in usage){
console.log(`${name} declaration updated. Usage count: ${usage[name].instances.length}`)
usage[ name ].ctor = ctor;
uses = usage[ name ].instances;
for( var i = 0, _i = uses.length; i < _i; i++ ){
var u = uses[ i ], d = u.dom;
u.dom = _construct(ctor, u.cfg, u.p);
if(d.parentNode){
d.parentNode.replaceChild( u.dom, d )
}
}
}else{
console.log(`${name} declared`)
uses = (usage[ name ] = {ctor: ctor, instances: []}).instances;
}
return populate(name, function construct (cfg, p) {
var dom = _construct(ctor, cfg, p);
uses.push({dom: dom, cfg: cfg, p: p});
return dom;
});
}
})(window['NS'], typeof window !== "undefined" ? window :
typeof WorkerGlobalScope !== "undefined" ? self :
typeof global !== "undefined" ? global :
typeof GLOBAL !== "undefined" ? GLOBAL :
Function("return this;")());
var D = NS.D,
div = D.div,
span = D.span,
view = {
page: {},
cmp: {}
};
\ No newline at end of file
var Observable = function() {
this._listeners = {};
};
Observable.prototype = {
on: function(k, v) {
(this._listeners[k] || (this._listeners[k] = [])).push(v);
var _self = this;
return function ReleaseObservable() {
_self.un(k, v);
};
},
un: function(k, v) {
var list = this._listeners[k];
if(list){
var id = list.indexOf(v);
if(id > -1){
list.splice(id, 1);
}
}
},
fire: function(k) {
var listeners = this._listeners[k];
if(listeners === void 0)
return;
for( var i = 0, _i = listeners.length; i < _i; i++ ){
const listener = listeners[ i ];
listener.apply(this, [].slice.call(arguments, 1));
}
}
};
var Observable = function() {
this._listeners = {};
};
Observable.prototype = {
on: function(k, v) {
(this._listeners[k] || (this._listeners[k] = [])).push(v);
var _self = this;
return function ReleaseObservable() {
_self.un(k, v);
};
},
un: function(k, v) {
var list = this._listeners[k];
if(list){
var id = list.indexOf(v);
if(id > -1){
list.splice(id, 1);
}
}
},
fire: function(k) {
var listeners = this._listeners[k];
if(listeners === void 0)
return;
for( var i = 0, _i = listeners.length; i < _i; i++ ){
const listener = listeners[ i ];
listener.apply(this, [].slice.call(arguments, 1));
}
}
};
// It is mostly node.js posix path.
window.__Path = (function(){
var splitPathRe =
......
......@@ -4,7 +4,7 @@ function mulberry32(a) {
t = Math.imul(t ^ t >>> 15, t | 1);
t ^= t + Math.imul(t ^ t >>> 7, t | 61);
return ((t ^ t >>> 14) >>> 0) / 4294967296;
}
};
out.getSeed = function() {
return a;
......
const checkSpecialCharsAndEmpty = (value) => {
const thisValue = value.toString().toLowerCase();
let hasSpecialChars = false;
if (typeof value === 'string') {
hasSpecialChars = thisValue.includes('\n')
|| thisValue.includes('\t')
|| thisValue.includes(',')
|| thisValue.includes(';')
|| thisValue.includes('.')
|| thisValue.includes('"')
|| thisValue.includes('\'')
|| thisValue.includes('`')
|| thisValue.includes('´')
|| thisValue.includes(' ')
|| thisValue.length === 0;
}
return hasSpecialChars;
};
const separatorOrLineBreak = (length, elementIdx, separator) => (
length - 1 === elementIdx ? '\n' : separator
);
const escapeDoubleQuotesInsideElement = (element) => {
const thisElement = element.replace(/"/g, '""');
return thisElement;
};
const appendElement = (element, lineLength, elementIdx, separator) => {
const includesSpecials = checkSpecialCharsAndEmpty(element);
let thisElement = element;
if (includesSpecials) {
thisElement = escapeDoubleQuotesInsideElement(thisElement);
}
return (
includesSpecials
? `"${thisElement}"${separatorOrLineBreak(lineLength, elementIdx, separator)}`
: `${thisElement}${separatorOrLineBreak(lineLength, elementIdx, separator)}`
);
};
const toCSV = data => convertArrayOfObjectsToCSV(data, {separator: ','});
const convertArrayOfObjectsToCSV = (data, { header, separator }) => {
const array = [...data];
let csv = '';
if (header) {
header.forEach((headerEl, i) => {
const thisHeaderEl = headerEl || (headerEl === 0 ? 0 : '');
csv += appendElement(thisHeaderEl, header.length, i, separator);
});
}
array.forEach((row, idx) => {
const thisRow = Object.keys(row);
if (!header && idx === 0) {
thisRow.forEach((key, i) => {
const value = key || (key === 0 ? 0 : '');
csv += appendElement(value, thisRow.length, i, separator);
});
}
thisRow.forEach((key, i) => {
const value = row[key] || (row[key] === 0 ? 0 : '');
csv += appendElement(value, thisRow.length, i, separator);
});
});
return csv;
const checkSpecialCharsAndEmpty = (value) => {
const thisValue = value.toString().toLowerCase();
let hasSpecialChars = false;
if (typeof value === 'string') {
hasSpecialChars = thisValue.includes('\n')
|| thisValue.includes('\t')
|| thisValue.includes(',')
|| thisValue.includes(';')
|| thisValue.includes('.')
|| thisValue.includes('"')
|| thisValue.includes('\'')
|| thisValue.includes('`')
|| thisValue.includes('´')
|| thisValue.includes(' ')
|| thisValue.length === 0;
}
return hasSpecialChars;
};
const separatorOrLineBreak = (length, elementIdx, separator) => (
length - 1 === elementIdx ? '\n' : separator
);
const escapeDoubleQuotesInsideElement = (element) => {
const thisElement = element.replace(/"/g, '""');
return thisElement;
};
const appendElement = (element, lineLength, elementIdx, separator) => {
const includesSpecials = checkSpecialCharsAndEmpty(element);
let thisElement = element;
if (includesSpecials) {
thisElement = escapeDoubleQuotesInsideElement(thisElement);
}
return (
includesSpecials
? `"${thisElement}"${separatorOrLineBreak(lineLength, elementIdx, separator)}`
: `${thisElement}${separatorOrLineBreak(lineLength, elementIdx, separator)}`
);
};
const toCSV = data => convertArrayOfObjectsToCSV(data, {separator: ','});
const convertArrayOfObjectsToCSV = (data, { header, separator }) => {
const array = [...data];
let csv = '';
if (header) {
header.forEach((headerEl, i) => {
const thisHeaderEl = headerEl || (headerEl === 0 ? 0 : '');
csv += appendElement(thisHeaderEl, header.length, i, separator);
});
}
array.forEach((row, idx) => {
const thisRow = Object.keys(row);
if (!header && idx === 0) {
thisRow.forEach((key, i) => {
const value = key || (key === 0 ? 0 : '');
csv += appendElement(value, thisRow.length, i, separator);
});
}
thisRow.forEach((key, i) => {
const value = row[key] || (row[key] === 0 ? 0 : '');
csv += appendElement(value, thisRow.length, i, separator);
});
});
return csv;
};
\ No newline at end of file
const isEqual = function(original, fn) {
return function(val) {
fn(val===original);
}
};
const Store = function(cfg) {
Observable.call(this);
this._props = cfg || {};
};
Store.prototype = {
set: function(key, val) {
if(this._props[key] !== val){
this._props[ key ] = val;
this.fire( 'change', key, val );
this.fire( key, val );
}
},
get: function(key) {
return this._props[key];
},
sub: function(key, fn) {
if(Array.isArray(key)){
var wrap = () => fn.apply(this, key.map(key=>this.get(key)));
for( var i = 0, _i = key.length; i < _i; i++ ){
this.on(key[i], wrap)
}
wrap();
}else{
this.on( key, fn )
fn( this.get( key ) );
}
return this;
},
equal: function(key, val, fn) {
const wrap = isEqual(val, fn);
this.on(key, wrap);
wrap(this.get(key));
return this;
}
};
Store.prototype = Object.assign(new Observable, Store.prototype);
const isEqual = function(original, fn) {
return function(val) {
fn(val===original);
}
};
const Store = function(cfg) {
Observable.call(this);
this._props = cfg || {};
};
Store.prototype = {
set: function(key, val) {
if(this._props[key] !== val){
this._props[ key ] = val;
this.fire( 'change', key, val );
this.fire( key, val );
}
},
get: function(key) {
return this._props[key];
},
sub: function(key, fn) {
if(Array.isArray(key)){
var wrap = () => fn.apply(this, key.map(key=>this.get(key)));
for( var i = 0, _i = key.length; i < _i; i++ ){
this.on(key[i], wrap)
}
wrap();
}else{
this.on( key, fn )
fn( this.get( key ) );
}
return this;
},
equal: function(key, val, fn) {
const wrap = isEqual(val, fn);
this.on(key, wrap);
wrap(this.get(key));
return this;
}
};
Store.prototype = Object.assign(new Observable, Store.prototype);
\ No newline at end of file
......@@ -3,64 +3,28 @@
<head>
<title>Category mapper</title>
<meta charset="utf-8" />
<script src="controller/path.js"></script>
<script src="controller/require.js"></script>
<script src="livest-reloading.js"></script>
<script src="core/Path.js"></script>
<script src="core/Require.js"></script>
<script src="core/LivestReloading.js"></script>
<script src="js/releasable-observer.js"></script>
<script src="js/pcg-base.js"></script>
<script src="js/pcg-dom-util.js"></script>
<script src="core/Observer.js"></script>
<script src="core/DOM.js"></script>
<script src="js/csv.js"></script>
<script src="core/Random.Seeded.js"></script>
<script src="js/helpers/rand.js"></script>
<script src="js/model/store.js"></script>
<script src="js/model/data.js"></script>
<script src="core/data/store/Store.js"></script>
<script src="model/Store.js"></script>
<script src="js/model/provider.js"></script>
<script src="js/model/slice/productTable.js"></script>
<script src="js/model/tag.js"></script>
<script src="js/model/product.js"></script>
<script src="js/helpers/textFilter.js"></script>
<script src="js/helpers/answer.js"></script>
<script src="js/view/base.js"></script>
<script src="js/view/cmp/base.js"></script>
<script src="js/view/cmp/menu.jsx"></script>
<script src="js/view/cmp/switch.js"></script>
<script src="js/view/cmp/table.js"></script>
<script src="js/view/cmp/tag.js"></script>
<script src="js/view/cmp/tagfield.js"></script>
<script src="js/view/page/products.js"></script>
<script src="js/view/page/export.jsx"></script>
<script src="js/view/page/generate.jsx"></script>
<script src="js/view/page/components.js"></script>
<script src="js/controller/exportLogic.js"></script>
<script src="js/controller/quizBits/main.js"></script>
<script src="js/controller/quizGenerator.js"></script>
<script src="js/controller/quizBits/checkbox.js"></script>
<script src="js/controller/quizBits/checkboxPhoto.js"></script>
<script src="js/controller/quizBits/radio.js"></script>
<script src="js/controller/quizBits/radioPhoto.js"></script>
$BUNDLE$
<!--
<script src="../src/main.jsx"></script>
<link type="text/css" rel="stylesheet" href="src/main.css">-->
</head>
<body>
<script>
initDataProvider($DATA$);
define('begin', ['main.jsx'], function(main) {
define('start', ['main.jsx'], function(main) {
main.default();
});
</script>
......
import './main.scss';
import {Button} from '/view/cmp/button.jsx'
import './view/page/login/Login.jsx';
import './view/page/account/Account.jsx';
import './view/cmp/switch/Switch.jsx';
export default function() {
let tagField, exportEl;
div({
renderTo: document.body,
cls: 'content'
},
div({
cls: 'main-menu'
},
view.cmp.Menu({title: 'Продукты', id: 'products', key: 'mainMenuActive'}),
view.cmp.Menu({title: 'Ингредиенты', id: 'components', key: 'mainMenuActive'}),
view.cmp.Menu({title: 'Генерируем', id: 'generate', key: 'mainMenuActive'}),
view.cmp.Menu({title: 'Export', id: 'export', key: 'mainMenuActive', cls: 'menu-item-export'}),
),
view.cmp.Switch({cls: 'content-area', key: 'mainMenuActive'}, {
products: new view.page.Products(),
components: new view.page.Components(),
'export': <view.page.Export/>,
generate: new view.page.Generate()
})
);
let dom = <div renderTo={document.body} cls="content">
{view.cmp.Switch({cls: 'content-area', key: 'navigation.current'}, {
login: new view.page.Login(),
main: new view.page.Account(),
})}
</div>;
};
const store = new Store({
mainMenuActive: 'products',
exportFormat: 'yaml',
exportData: 'tags',
exportTableName: 'SOMETABLE',
productFilterText: '',
componentFilterText: '',
'productFilterByTitle': true,
'productFilterByComponent': true,
'productFilterByTag': true,
'generateType': 'radio',
'generatePhoto': false,
generateCategory: 'product'
});
try{
var data = JSON.parse( localStorage.getItem( 'store' ) );
window.addEventListener && console.log(data)
for(var k in data){
store.set(k, data[k]);
}
}catch( e ){}
store.on('change', function() {
localStorage.setItem('store', JSON.stringify(store._props));
});
const store = new Store({
'navigation.current': 'login'
});
try{
var data = JSON.parse( localStorage.getItem( 'store' ) );
window.addEventListener && console.log(data)
for(var k in data){
store.set(k, data[k]);
}
}catch( e ){}
store.on('change', function() {
localStorage.setItem('store', JSON.stringify(store._props));
});
var textCache = {};
const textFilterMatched = function(where, what) {
var prepared = textCache[what];
if(!prepared){
var tokens = what.split(/\s/)
textCache[what] = prepared = tokens.map(token => token[0] === '-' ? {has: false, text: token.substr(1)}: {has: true, text: token});
}
var yep = true;
for( var i = 0, _i = prepared.length; i < _i; i++ ){
var preparedElement = prepared[ i ];
if(preparedElement.text === '')
continue;
var matched = where.indexOf(preparedElement.text)>-1;
if(preparedElement.has === false && matched){
return false
}else if(preparedElement.has === true && !matched)
yep = false;
}
return yep;
};
const textFormat = function(text, html) {
if(typeof text !== 'string')
return text;
text = text.trim();
if(text[0] === ',')text = text.substr(1);
if(text[text.length-1] === ',')text = text.substr(0, text.length - 1);
const income = text;
if(text.split(/[«"»]/).length % 2 === 0){
// odd count of quotes
text = text.replace(/[«»]/,'')
}
let valids = {}, id = 1, add = (val)=>{
const uid = '_!@#'+id+'#@!_';
id++;
valids[uid] = val;
return uid;
};
text = text
.trim()
.replace(/\n\n/g,'|||||')
.replace(/\s\s+/g,' ')
.replace(/ /g,' ')
.replace(/([а-я][-–—][0-9][-–—][а-я])/g, add)
.replace(/(\d)(руб)/g,'$1 $2')
//.replace(/([а-яА-Я])[—-]([а-яА-Я])/g, (full, a, b)=>add(a+'-'+b))
.replace(/([а-яА-Я])[—-]([а-яА-Я])/g, (full, a, b)=>add(html?'<nobr>'+a+'-'+b+'</nobr>': a+'-'+b))
.replace(/([0-9])[,]([0-9])/g, (full, a, b)=>add(a+','+b))
.replace(/(ВкусВилл)/g, add)
.replace(/([^\s])[—-]/g, '$1 —')
.replace(/([,\.:])([а-яА-Я0-9\.,"])/g, '$1 $2')
.replace(/\s([,\.:])/g, '$1')
.replace(/([\(])\s/g, '$1')
.replace(/[^\s]([\(])/g, ' $1')
.replace(/[\s+]([\)])/g, '$1')
.replace(/([а-я\?\.])(\d+\.)/g, '$1 $2')
.replace(/ [-–—] /g, (html?'&nbsp;':' ')+'— ')
.replace(/-(\d)/g, '–$1')
.replace(/ (\d\. [а-яА-Я])/g, '\n$1')
.replace(/"([а-яА-Я][^"]+)\s+"([а-яА-Я\s][^"]+)"\s+([а-яА-Я][^"]+)"/g,'«$1 “$2” $3»')
.replace(/"([^"]+)"/g,'«$1»')
.replace(\s+/g,'«')
.replace(/\s+»/g,'»')
.replace(/([а-я])([А-Я])/g,(ful, a, b)=>a+' '+b.toLowerCase())
//.replace(/\. /g,'.&shy; ')
// phone
.replace(/(\+7|8)[\s\(]*(\d{3})[\s\)]*(\d{3})[\s\-—–]*(\d{2})[\s-—–]*(\d{2})/, html ?'+7&nbsp;($2)&nbsp;$3-$4-$5' : '+7 ($2) $3-$4-$5')
.replace(/свершении/g,'совершении')
[html?'replace':'trim'](/[А-Я]+/g, function(text) {
return text.length > 2 || text === 'НЕ' ? '<span class="important">'+text.toLowerCase()+'</span>': text;
})
[html?'replace':'trim'](/, ([А-Я])/g, (f, a)=>', '+a.toLowerCase())
.replace(/\|\|\|\|\|/g,'\n\n')
[html?'replace':'trim'](/\*\*([^*]+)\*\*/g,'<span class="notificate-text">$1</span>')
;
// HANGING
/*
text = text
.replace(/([«(])/g,'<span class="before-hanging-open"></span>&shy;<span class="hanging-open">$1</span>')
.replace(/([»)])/g,'<span class="hanging-close">$1</span>');
*/
//<span class="hanging-close">»</span>');
var lines = text.split('\n');
var numberStarting = 0;
var lastNumber = 0;
var remake = [];
lines.forEach(function(line) {
line.replace(/^(\d+)\.\s/, function(full, num) {
num = num-0;
if(lastNumber !== num - 1){
if(lastNumber>num){
// ok
}else{
var text = remake.pop();
while(lastNumber<num - 1){
text.replace(new RegExp('[^\\d]'+(lastNumber+1)+'[^\\d]'), function(ful, pos,a){
remake.push(text.substr(0, pos).replace(lastNumber+1, lastNumber+1+'.'))
text = text.substr(pos+(lastNumber+1+'').length)
});
lastNumber++;
}
remake.push(text.replace(lastNumber, lastNumber+'.'));
}
}
lastNumber = num;
});
remake.push(line);
});
var longSentance = 200;
if(remake.length === 1 && remake[0].length>longSentance){
remake = remake[ 0 ].split( '. ' ).map( a => a + '.' ).reduce((store, sentance)=>{
var last = (store.pop()||'');
if(last.length+sentance.length< longSentance*1.3){
store.push([ last, sentance ].join( ' ' ));
}else{
if(last)
store.push(last);
store.push(sentance);
}
return store
},[]);
remake = [].concat.apply( [], remake.map( a => [ a, '' ] ));
}
let out = remake.length === 1 ? remake[0] : remake.map(a=>html?'<p>'+a+'</p>':a).join('\n');
out = out.replace(/_!@#(\d+)#@!_/g, (f, num)=>{
return valids[f]
});
out = out.trim();
if(out.length>70)
out = out[0].toUpperCase()+out.substr(1);
/*console.log(income);
console.log(out);*/
return out;
var textCache = {};
String.Typography = function(text, cfg) {
const {html} = cfg;
if(typeof text !== 'string')
return text;
text = text.trim();
if(text[0] === ',')text = text.substr(1);
if(text[text.length-1] === ',')text = text.substr(0, text.length - 1);
const income = text;
if(text.split(/[«"»]/).length % 2 === 0){
// odd count of quotes
text = text.replace(/[«»]/,'')
}
let valids = {}, id = 1, add = (val)=>{
const uid = '_!@#'+id+'#@!_';
id++;
valids[uid] = val;
return uid;
};
text = text
.trim()
.replace(/\n\n/g,'|||||')
.replace(/\s\s+/g,' ')
.replace(/ /g,' ')
.replace(/([а-я][-–—][0-9][-–—][а-я])/g, add)
.replace(/(\d)(руб)/g,'$1 $2')
//.replace(/([а-яА-Я])[—-]([а-яА-Я])/g, (full, a, b)=>add(a+'-'+b))
.replace(/([а-яА-Я])[—-]([а-яА-Я])/g, (full, a, b)=>add(html?'<nobr>'+a+'-'+b+'</nobr>': a+'-'+b))
.replace(/([0-9])[,]([0-9])/g, (full, a, b)=>add(a+','+b))
.replace(/(ВкусВилл)/g, add)
.replace(/([^\s])[—-]/g, '$1 —')
.replace(/([,\.:])([а-яА-Я0-9\.,"])/g, '$1 $2')
.replace(/\s([,\.:])/g, '$1')
.replace(/([\(])\s/g, '$1')
.replace(/[^\s]([\(])/g, ' $1')
.replace(/[\s+]([\)])/g, '$1')
.replace(/([а-я\?\.])(\d+\.)/g, '$1 $2')
.replace(/ [-–—] /g, (html?'&nbsp;':' ')+'— ')
.replace(/-(\d)/g, '–$1')
.replace(/ (\d\. [а-яА-Я])/g, '\n$1')
.replace(/"([а-яА-Я][^"]+)\s+"([а-яА-Я\s][^"]+)"\s+([а-яА-Я][^"]+)"/g,'«$1 “$2” $3»')
.replace(/"([^"]+)"/g,'«$1»')
.replace(\s+/g,'«')
.replace(/\s+»/g,'»')
.replace(/([а-я])([А-Я])/g,(ful, a, b)=>a+' '+b.toLowerCase())
//.replace(/\. /g,'.&shy; ')
// phone
.replace(/(\+7|8)[\s\(]*(\d{3})[\s\)]*(\d{3})[\s\-—–]*(\d{2})[\s-—–]*(\d{2})/, html ?'+7&nbsp;($2)&nbsp;$3-$4-$5' : '+7 ($2) $3-$4-$5')
.replace(/свершении/g,'совершении')
[html?'replace':'trim'](/[А-Я]+/g, function(text) {
return text.length > 2 || text === 'НЕ' ? '<span class="important">'+text.toLowerCase()+'</span>': text;
})
[html?'replace':'trim'](/, ([А-Я])/g, (f, a)=>', '+a.toLowerCase())
.replace(/\|\|\|\|\|/g,'\n\n')
[html?'replace':'trim'](/\*\*([^*]+)\*\*/g,'<span class="notificate-text">$1</span>')
;
// HANGING
/*
text = text
.replace(/([«(])/g,'<span class="before-hanging-open"></span>&shy;<span class="hanging-open">$1</span>')
.replace(/([»)])/g,'<span class="hanging-close">$1</span>');
*/
//<span class="hanging-close">»</span>');
var lines = text.split('\n');
var numberStarting = 0;
var lastNumber = 0;
var remake = [];
lines.forEach(function(line) {
line.replace(/^(\d+)\.\s/, function(full, num) {
num = num-0;
if(lastNumber !== num - 1){
if(lastNumber>num){
// ok
}else{
var text = remake.pop();
while(lastNumber<num - 1){
text.replace(new RegExp('[^\\d]'+(lastNumber+1)+'[^\\d]'), function(ful, pos,a){
remake.push(text.substr(0, pos).replace(lastNumber+1, lastNumber+1+'.'))
text = text.substr(pos+(lastNumber+1+'').length)
});
lastNumber++;
}
remake.push(text.replace(lastNumber, lastNumber+'.'));
}
}
lastNumber = num;
});
remake.push(line);
});
var longSentance = 200;
if(remake.length === 1 && remake[0].length>longSentance){
remake = remake[ 0 ].split( '. ' ).map( a => a + '.' ).reduce((store, sentance)=>{
var last = (store.pop()||'');
if(last.length+sentance.length< longSentance*1.3){
store.push([ last, sentance ].join( ' ' ));
}else{
if(last)
store.push(last);
store.push(sentance);
}
return store
},[]);
remake = [].concat.apply( [], remake.map( a => [ a, '' ] ));
}
let out = remake.length === 1 ? remake[0] : remake.map(a=>html?'<p>'+a+'</p>':a).join('\n');
out = out.replace(/_!@#(\d+)#@!_/g, (f, num)=>{
return valids[f]
});
out = out.trim();
if(out.length>70)
out = out[0].toUpperCase()+out.substr(1);
/*console.log(income);
console.log(out);*/
return out;
};
String.Search = function(string, search) {
var prepared = textCache[search];
if(!prepared){
var tokens = search.split(/\s/)
textCache[search] = prepared = tokens
.map(token => token[0] === '-' ? {has: false, text: token.substr(1)}: {has: true, text: token});
}
var yep = true;
for( var i = 0, _i = prepared.length; i < _i; i++ ){
var preparedElement = prepared[ i ];
if(preparedElement.text === '')
continue;
var matched = string.indexOf(preparedElement.text)>-1;
if(preparedElement.has === false && matched){
return false
}else if(preparedElement.has === true && !matched)
yep = false;
}
return yep;
};
\ No newline at end of file
import './button.scss';
export const Button = D.declare('cmp.Button', function(cfg) {
export const Button = D.declare('view.cmp.Button', function(cfg) {
return <input type='text' {...cfg} cls='button'/>
});
\ No newline at end of file
import './LabeledField.scss';
export default D.declare('view.cmp.field.LabeledField', (cfg)=>
<div class="labeled-field">
<label><span class="labeled-field__label">{cfg.label}</span>
<input class="labeled-field__input" type={'text'}/>
</label>
</div>
)
\ No newline at end of file
.labeled-field {
display: flex;
}
.labeled-field__label {
width: 150px;
}
\ No newline at end of file
view.cmp.Table = function(cfg){
Object.assign(this, cfg);
const children = this.childrenEl = D.div({
cls: 'cmp-table__children'
});
this.dom = D.div({
cls: D.cls('cmp-table', cfg.cls)
}, children);
this.currentSlice = [];
this.childrenEls = [];
setTimeout(()=>this.updateChildren(),0);
};
view.cmp.Table.prototype = {
currentSlice: [],
childrenEls: [],
childrenEl: null,
filterText: '',
filterFn: () => true,
afterFilter: ()=>true,
filter: function(text) {
this.filterText = text;
this.filterRegExp = new RegExp(text.replace(/[\[\]\(\)\?\*\.\+]/g,'').replace(/\s+/g,'|'), 'ig')
},
fetch: function() {
const field = Object.keys(this.sort[0])[0]
this.currentSlice = this.items
.filter(item=>this.filterFn.call(item, this.filterText, this))
.sort((a,b)=>a[field] > b.field ? 1 : a[field] < b.field ? -1 : 0)
.map(data=>({data, dom: null}));
this.afterFilter(this.getSelected());
},
updateChildren: function() {
this.fetch();
D.removeChildren(this.childrenEl);
this.currentSlice.forEach((item) => {
D.appendChild(this.childrenEl, item.dom = this.itemTpl(item.data, this, item));
})
},
updateChild: function(item) {
if(item.dom){
const dom = this.itemTpl(item.data, this, item);
item.dom.parentNode.replaceChild(dom, item.dom);
item.dom = dom;
}
},
updateChildByData: function(data) {
const match = this.currentSlice.filter(i=>i.data===data),
item = match[0];
if(!item)
return;
if(item.dom){
const dom = this.itemTpl(item.data, this, item);
item.dom.parentNode.replaceChild(dom, item.dom);
item.dom = dom;
}
},
getSelected: function() {
return this.currentSlice.filter(i=>!i.hidden).map(i=>i.data)
},
highlight: function(text) {
if(!this.filterText)
return text;
const txts = [];
;
return D.join(text.replace(this.filterRegExp, function(match) {
txts.push(match);
return '|||||'
}).split('|||||'), (i)=>D.span({cls: 'highlighted'}, txts[i]))
},
getActionDelegate: function() {
var me = this;
return function(e) {
const [type, val] = this.getAttribute('data-action').split(':');
const match = me.currentSlice.filter(({data})=>data.id+'' === val+'');
if(type === 'hide'){
if(match.length){
match[0].hidden = true;
me.updateChild(match[0])
me.afterFilter(me.getSelected());
}
}
if(type === 'toggle'){
if(match.length){
match[0].full = !match[0].full;
me.updateChild(match[0])
}
}
e.stopPropagation();
}
},
};
\ No newline at end of file
const Table = function(cfg){
Object.assign(this, cfg);
const children = this.childrenEl = D.div({
cls: 'cmp-table__children'
});
this.dom = D.div({
cls: D.cls('cmp-table', cfg.cls)
}, children);
this.currentSlice = [];
this.childrenEls = [];
setTimeout(()=>this.updateChildren(),0);
};
Table.prototype = {
currentSlice: [],
childrenEls: [],
childrenEl: null,
filterText: '',
filterFn: () => true,
afterFilter: ()=>true,
filter: function(text) {
this.filterText = text;
this.filterRegExp = new RegExp(text.replace(/[\[\]\(\)\?\*\.\+]/g,'').replace(/\s+/g,'|'), 'ig')
},
fetch: function() {
const field = Object.keys(this.sort[0])[0]
this.currentSlice = this.items
.filter(item=>this.filterFn.call(item, this.filterText, this))
.sort((a,b)=>a[field] > b.field ? 1 : a[field] < b.field ? -1 : 0)
.map(data=>({data, dom: null}));
this.afterFilter(this.getSelected());
},
updateChildren: function() {
this.fetch();
D.removeChildren(this.childrenEl);
this.currentSlice.forEach((item) => {
D.appendChild(this.childrenEl, item.dom = this.itemTpl(item.data, this, item));
})
},
updateChild: function(item) {
if(item.dom){
const dom = this.itemTpl(item.data, this, item);
item.dom.parentNode.replaceChild(dom, item.dom);
item.dom = dom;
}
},
updateChildByData: function(data) {
const match = this.currentSlice.filter(i=>i.data===data),
item = match[0];
if(!item)
return;
if(item.dom){
const dom = this.itemTpl(item.data, this, item);
item.dom.parentNode.replaceChild(dom, item.dom);
item.dom = dom;
}
},
getSelected: function() {
return this.currentSlice.filter(i=>!i.hidden).map(i=>i.data)
},
highlight: function(text) {
if(!this.filterText)
return text;
const txts = [];
;
return D.join(text.replace(this.filterRegExp, function(match) {
txts.push(match);
return '|||||'
}).split('|||||'), (i)=>D.span({cls: 'highlighted'}, txts[i]))
},
getActionDelegate: function() {
var me = this;
return function(e) {
const [type, val] = this.getAttribute('data-action').split(':');
const match = me.currentSlice.filter(({data})=>data.id+'' === val+'');
if(type === 'hide'){
if(match.length){
match[0].hidden = true;
me.updateChild(match[0])
me.afterFilter(me.getSelected());
}
}
if(type === 'toggle'){
if(match.length){
match[0].full = !match[0].full;
me.updateChild(match[0])
}
}
e.stopPropagation();
}
},
};
export default D.declare('view.cmp.List', Table);
view.cmp.Switch = (cfg, contentHash) => {
const cmp = div( {
cls: update => store.sub(
cfg.key,
val => update(
D.cls(
'cmp-switch',
cfg.cls,
{ 'cmp-switch__filled': val in contentHash } ) ) ) } );
store.sub( cfg.key, (val)=> {
D.removeChildren(cmp);
if(val in contentHash)
D.appendChild( cmp, contentHash[ val ] );
});
return cmp;
};
\ No newline at end of file
export default D.declare('view.cmp.Switch', (cfg, contentHash) => {
const cmp = div( {
cls: update => store.sub(
cfg.key,
val => update(
D.cls(
'cmp-switch',
cfg.cls,
{ 'cmp-switch__filled': val in contentHash } ) ) ) } );
store.sub( cfg.key, (val)=> {
D.removeChildren(cmp);
if(val in contentHash)
D.appendChild( cmp, contentHash[ val ] );
});
return cmp;
});
\ No newline at end of file
D.declare('view.cmp.Tag', function(text) {
return D.span({cls: 'tag'}, '#', text)
D.declare('view.cmp.Tag', function(text) {
return D.span({cls: 'tag'}, '#', text)
});
\ No newline at end of file
view.cmp.TagField = (function(){
const TagField = function( data ){
Observable.call( this );
var field, isFocused = false, lastVal, dropDown;
//var cacheTagsDom = {};
var offset = 0;
var matchedItems = 0;
var neBlur = false;
var autocomplete = ( e ) => {
offset = 0;
var val = field.value.trim().toLowerCase();
if( lastVal !== val ){
var matched = val === '' ? [] : dP.tags.filter( t => t.name.toLowerCase().trim() !== val && t.name.toLowerCase().trim().indexOf( val ) > -1 ).slice( 0, 20 );
this.value = lastVal = val;
matchedItems = matched.length;
D.removeChildren( dropDown );
matched.forEach( function( match ){
D.appendChild( dropDown, div( {
cls: 'cmp-tag-dropdown-item',
on: {
click: () => {
field.value = match.name;
autocomplete();
},
mousedown: () => {
neBlur = true;
setTimeout( () => neBlur = false, 40 )
clearTimeout( blurTimeout )
}
}
},
view.cmp.Table.prototype.highlight.call( {
filterText: val,
filterRegExp: new RegExp( val, 'ig' )
}, match.name ) ) );//cacheTagsDom[match.id] || (cacheTagsDom[match.id] = );
} );
dropDownUpdateCls();
}
};
var _dropDownUpdateCls,
dropDownUpdateCls = function(){
_dropDownUpdateCls(
D.cls( 'cmp-tag-dropdown', {
'cmp-tag-dropdown__hidden': matchedItems === 0 || isFocused === false
} )
)
};
var blurTimeout;
var el = div( { cls: 'cmp-tag-field' },
field = D.input( {
cls: 'cmp-tag-input',
attr: { placeholder: 'Тэг' },
on: {
input: autocomplete,
focus: () => {
clearTimeout( blurTimeout );
isFocused = true;
dropDownUpdateCls()
},
blur: () => {
if( !neBlur ){
blurTimeout = setTimeout( function(){
isFocused = false;
dropDownUpdateCls();
}, 100 )
}
}
}
} ),
dropDown = div( {
cls: ( update ) => {
_dropDownUpdateCls = update;
dropDownUpdateCls();
}
} )
);
this.dom = el;
};
TagField.prototype = {
getValue: function(){
return this.value;
}
};
TagField.prototype = Object.assign( new Observable, TagField.prototype );
return TagField;
})();
\ No newline at end of file
export default D.declare('view.cmp.TagField', (function(){
const TagField = function( data ){
Observable.call( this );
var field, isFocused = false, lastVal, dropDown;
//var cacheTagsDom = {};
var offset = 0;
var matchedItems = 0;
var neBlur = false;
var autocomplete = ( e ) => {
offset = 0;
var val = field.value.trim().toLowerCase();
if( lastVal !== val ){
var matched = val === '' ? [] : dP.tags.filter( t => t.name.toLowerCase().trim() !== val && t.name.toLowerCase().trim().indexOf( val ) > -1 ).slice( 0, 20 );
this.value = lastVal = val;
matchedItems = matched.length;
D.removeChildren( dropDown );
matched.forEach( function( match ){
D.appendChild( dropDown, div( {
cls: 'cmp-tag-dropdown-item',
on: {
click: () => {
field.value = match.name;
autocomplete();
},
mousedown: () => {
neBlur = true;
setTimeout( () => neBlur = false, 40 )
clearTimeout( blurTimeout )
}
}
},
view.cmp.Table.prototype.highlight.call( {
filterText: val,
filterRegExp: new RegExp( val, 'ig' )
}, match.name ) ) );//cacheTagsDom[match.id] || (cacheTagsDom[match.id] = );
} );
dropDownUpdateCls();
}
};
var _dropDownUpdateCls,
dropDownUpdateCls = function(){
_dropDownUpdateCls(
D.cls( 'cmp-tag-dropdown', {
'cmp-tag-dropdown__hidden': matchedItems === 0 || isFocused === false
} )
)
};
var blurTimeout;
var el = div( { cls: 'cmp-tag-field' },
field = D.input( {
cls: 'cmp-tag-input',
attr: { placeholder: 'Тэг' },
on: {
input: autocomplete,
focus: () => {
clearTimeout( blurTimeout );
isFocused = true;
dropDownUpdateCls()
},
blur: () => {
if( !neBlur ){
blurTimeout = setTimeout( function(){
isFocused = false;
dropDownUpdateCls();
}, 100 )
}
}
}
} ),
dropDown = div( {
cls: ( update ) => {
_dropDownUpdateCls = update;
dropDownUpdateCls();
}
} )
);
this.dom = el;
};
TagField.prototype = {
getValue: function(){
return this.value;
}
};
TagField.prototype = Object.assign( new Observable, TagField.prototype );
return TagField;
})());
\ No newline at end of file
export default D.declare('view.page.Account', ()=>
<div>
Account Page
</div>
)
\ No newline at end of file
import '../../cmp/field/LabeledField.jsx'
export default D.declare('view.page.Login', ()=>
<div>
Login page
<view.cmp.field.LabeledField label={'Login'}/>
<view.cmp.field.LabeledField label={'Password'}/>
</div>
)
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment