@fui-org/fui-cli 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (212) hide show
  1. package/README.md +13 -1
  2. package/dist/fui.js +160 -43
  3. package/package.json +4 -2
  4. package/skills/fui/SKILL.md +131 -66
  5. package/skills/fui-skill/README.md +112 -0
  6. package/skills/fui-skill/SKILL.md +269 -0
  7. package/skills/fui-skill/assets/projectdefaultstyle.css +518 -0
  8. package/skills/fui-skill/design-md/airbnb/DESIGN.md +545 -0
  9. package/skills/fui-skill/design-md/airbnb/README.md +5 -0
  10. package/skills/fui-skill/design-md/airtable/DESIGN.md +554 -0
  11. package/skills/fui-skill/design-md/airtable/README.md +5 -0
  12. package/skills/fui-skill/design-md/apple/DESIGN.md +562 -0
  13. package/skills/fui-skill/design-md/apple/README.md +5 -0
  14. package/skills/fui-skill/design-md/asu/DESIGN.md +179 -0
  15. package/skills/fui-skill/design-md/asu/README.md +107 -0
  16. package/skills/fui-skill/design-md/binance/DESIGN.md +634 -0
  17. package/skills/fui-skill/design-md/binance/README.md +5 -0
  18. package/skills/fui-skill/design-md/bmw/DESIGN.md +544 -0
  19. package/skills/fui-skill/design-md/bmw/README.md +5 -0
  20. package/skills/fui-skill/design-md/bmw-m/DESIGN.md +503 -0
  21. package/skills/fui-skill/design-md/bmw-m/README.md +5 -0
  22. package/skills/fui-skill/design-md/bugatti/DESIGN.md +454 -0
  23. package/skills/fui-skill/design-md/bugatti/README.md +5 -0
  24. package/skills/fui-skill/design-md/cal/DESIGN.md +542 -0
  25. package/skills/fui-skill/design-md/cal/README.md +5 -0
  26. package/skills/fui-skill/design-md/claude/DESIGN.md +589 -0
  27. package/skills/fui-skill/design-md/claude/README.md +5 -0
  28. package/skills/fui-skill/design-md/clay/DESIGN.md +541 -0
  29. package/skills/fui-skill/design-md/clay/README.md +5 -0
  30. package/skills/fui-skill/design-md/clickhouse/DESIGN.md +544 -0
  31. package/skills/fui-skill/design-md/clickhouse/README.md +5 -0
  32. package/skills/fui-skill/design-md/cohere/DESIGN.md +451 -0
  33. package/skills/fui-skill/design-md/cohere/README.md +5 -0
  34. package/skills/fui-skill/design-md/coinbase/DESIGN.md +570 -0
  35. package/skills/fui-skill/design-md/coinbase/README.md +5 -0
  36. package/skills/fui-skill/design-md/composio/DESIGN.md +506 -0
  37. package/skills/fui-skill/design-md/composio/README.md +5 -0
  38. package/skills/fui-skill/design-md/cursor/DESIGN.md +537 -0
  39. package/skills/fui-skill/design-md/cursor/README.md +5 -0
  40. package/skills/fui-skill/design-md/elevenlabs/DESIGN.md +504 -0
  41. package/skills/fui-skill/design-md/elevenlabs/README.md +5 -0
  42. package/skills/fui-skill/design-md/expo/DESIGN.md +526 -0
  43. package/skills/fui-skill/design-md/expo/README.md +5 -0
  44. package/skills/fui-skill/design-md/ferrari/DESIGN.md +531 -0
  45. package/skills/fui-skill/design-md/ferrari/README.md +5 -0
  46. package/skills/fui-skill/design-md/figma/DESIGN.md +578 -0
  47. package/skills/fui-skill/design-md/figma/README.md +5 -0
  48. package/skills/fui-skill/design-md/framer/DESIGN.md +544 -0
  49. package/skills/fui-skill/design-md/framer/README.md +5 -0
  50. package/skills/fui-skill/design-md/fui/DESIGN.md +532 -0
  51. package/skills/fui-skill/design-md/hashicorp/DESIGN.md +575 -0
  52. package/skills/fui-skill/design-md/hashicorp/README.md +5 -0
  53. package/skills/fui-skill/design-md/ibm/DESIGN.md +550 -0
  54. package/skills/fui-skill/design-md/ibm/README.md +5 -0
  55. package/skills/fui-skill/design-md/intercom/DESIGN.md +546 -0
  56. package/skills/fui-skill/design-md/intercom/README.md +5 -0
  57. package/skills/fui-skill/design-md/kraken/DESIGN.md +125 -0
  58. package/skills/fui-skill/design-md/kraken/README.md +5 -0
  59. package/skills/fui-skill/design-md/lamborghini/DESIGN.md +288 -0
  60. package/skills/fui-skill/design-md/lamborghini/README.md +5 -0
  61. package/skills/fui-skill/design-md/linear.app/DESIGN.md +548 -0
  62. package/skills/fui-skill/design-md/linear.app/README.md +5 -0
  63. package/skills/fui-skill/design-md/lovable/DESIGN.md +298 -0
  64. package/skills/fui-skill/design-md/lovable/README.md +5 -0
  65. package/skills/fui-skill/design-md/mastercard/DESIGN.md +365 -0
  66. package/skills/fui-skill/design-md/mastercard/README.md +5 -0
  67. package/skills/fui-skill/design-md/meta/DESIGN.md +683 -0
  68. package/skills/fui-skill/design-md/meta/README.md +5 -0
  69. package/skills/fui-skill/design-md/minimax/DESIGN.md +746 -0
  70. package/skills/fui-skill/design-md/minimax/README.md +5 -0
  71. package/skills/fui-skill/design-md/mintlify/DESIGN.md +852 -0
  72. package/skills/fui-skill/design-md/mintlify/README.md +5 -0
  73. package/skills/fui-skill/design-md/miro/DESIGN.md +825 -0
  74. package/skills/fui-skill/design-md/miro/README.md +5 -0
  75. package/skills/fui-skill/design-md/mistral.ai/DESIGN.md +773 -0
  76. package/skills/fui-skill/design-md/mistral.ai/README.md +5 -0
  77. package/skills/fui-skill/design-md/mongodb/DESIGN.md +767 -0
  78. package/skills/fui-skill/design-md/mongodb/README.md +5 -0
  79. package/skills/fui-skill/design-md/nike/DESIGN.md +575 -0
  80. package/skills/fui-skill/design-md/nike/README.md +5 -0
  81. package/skills/fui-skill/design-md/notion/DESIGN.md +821 -0
  82. package/skills/fui-skill/design-md/notion/README.md +5 -0
  83. package/skills/fui-skill/design-md/nvidia/DESIGN.md +640 -0
  84. package/skills/fui-skill/design-md/nvidia/README.md +5 -0
  85. package/skills/fui-skill/design-md/ollama/DESIGN.md +539 -0
  86. package/skills/fui-skill/design-md/ollama/README.md +5 -0
  87. package/skills/fui-skill/design-md/opencode.ai/DESIGN.md +521 -0
  88. package/skills/fui-skill/design-md/opencode.ai/README.md +5 -0
  89. package/skills/fui-skill/design-md/pinterest/DESIGN.md +597 -0
  90. package/skills/fui-skill/design-md/pinterest/README.md +5 -0
  91. package/skills/fui-skill/design-md/playstation/DESIGN.md +661 -0
  92. package/skills/fui-skill/design-md/playstation/README.md +5 -0
  93. package/skills/fui-skill/design-md/posthog/DESIGN.md +690 -0
  94. package/skills/fui-skill/design-md/posthog/README.md +5 -0
  95. package/skills/fui-skill/design-md/raycast/DESIGN.md +669 -0
  96. package/skills/fui-skill/design-md/raycast/README.md +5 -0
  97. package/skills/fui-skill/design-md/renault/DESIGN.md +589 -0
  98. package/skills/fui-skill/design-md/renault/README.md +5 -0
  99. package/skills/fui-skill/design-md/replicate/DESIGN.md +616 -0
  100. package/skills/fui-skill/design-md/replicate/README.md +5 -0
  101. package/skills/fui-skill/design-md/resend/DESIGN.md +585 -0
  102. package/skills/fui-skill/design-md/resend/README.md +5 -0
  103. package/skills/fui-skill/design-md/revolut/DESIGN.md +636 -0
  104. package/skills/fui-skill/design-md/revolut/README.md +5 -0
  105. package/skills/fui-skill/design-md/runwayml/DESIGN.md +244 -0
  106. package/skills/fui-skill/design-md/runwayml/README.md +5 -0
  107. package/skills/fui-skill/design-md/sanity/DESIGN.md +357 -0
  108. package/skills/fui-skill/design-md/sanity/README.md +5 -0
  109. package/skills/fui-skill/design-md/sentry/DESIGN.md +551 -0
  110. package/skills/fui-skill/design-md/sentry/README.md +5 -0
  111. package/skills/fui-skill/design-md/shopify/DESIGN.md +516 -0
  112. package/skills/fui-skill/design-md/shopify/README.md +5 -0
  113. package/skills/fui-skill/design-md/slack/DESIGN.md +482 -0
  114. package/skills/fui-skill/design-md/spacex/DESIGN.md +363 -0
  115. package/skills/fui-skill/design-md/spacex/README.md +5 -0
  116. package/skills/fui-skill/design-md/spotify/DESIGN.md +246 -0
  117. package/skills/fui-skill/design-md/spotify/README.md +5 -0
  118. package/skills/fui-skill/design-md/starbucks/DESIGN.md +580 -0
  119. package/skills/fui-skill/design-md/starbucks/README.md +5 -0
  120. package/skills/fui-skill/design-md/stripe/DESIGN.md +487 -0
  121. package/skills/fui-skill/design-md/stripe/README.md +5 -0
  122. package/skills/fui-skill/design-md/supabase/DESIGN.md +462 -0
  123. package/skills/fui-skill/design-md/supabase/README.md +5 -0
  124. package/skills/fui-skill/design-md/superhuman/DESIGN.md +448 -0
  125. package/skills/fui-skill/design-md/superhuman/README.md +5 -0
  126. package/skills/fui-skill/design-md/tesla/DESIGN.md +286 -0
  127. package/skills/fui-skill/design-md/tesla/README.md +5 -0
  128. package/skills/fui-skill/design-md/theverge/DESIGN.md +339 -0
  129. package/skills/fui-skill/design-md/theverge/README.md +5 -0
  130. package/skills/fui-skill/design-md/together.ai/DESIGN.md +633 -0
  131. package/skills/fui-skill/design-md/together.ai/README.md +5 -0
  132. package/skills/fui-skill/design-md/uber/DESIGN.md +636 -0
  133. package/skills/fui-skill/design-md/uber/README.md +5 -0
  134. package/skills/fui-skill/design-md/vercel/DESIGN.md +736 -0
  135. package/skills/fui-skill/design-md/vercel/README.md +5 -0
  136. package/skills/fui-skill/design-md/vodafone/DESIGN.md +538 -0
  137. package/skills/fui-skill/design-md/vodafone/README.md +5 -0
  138. package/skills/fui-skill/design-md/voltagent/DESIGN.md +521 -0
  139. package/skills/fui-skill/design-md/voltagent/README.md +5 -0
  140. package/skills/fui-skill/design-md/warp/DESIGN.md +526 -0
  141. package/skills/fui-skill/design-md/warp/README.md +5 -0
  142. package/skills/fui-skill/design-md/webflow/DESIGN.md +588 -0
  143. package/skills/fui-skill/design-md/webflow/README.md +5 -0
  144. package/skills/fui-skill/design-md/wired/DESIGN.md +497 -0
  145. package/skills/fui-skill/design-md/wired/README.md +5 -0
  146. package/skills/fui-skill/design-md/wise/DESIGN.md +544 -0
  147. package/skills/fui-skill/design-md/wise/README.md +5 -0
  148. package/skills/fui-skill/design-md/x.ai/DESIGN.md +465 -0
  149. package/skills/fui-skill/design-md/x.ai/README.md +5 -0
  150. package/skills/fui-skill/design-md/zapier/DESIGN.md +537 -0
  151. package/skills/fui-skill/design-md/zapier/README.md +5 -0
  152. package/skills/fui-skill/examples/component.vue +162 -0
  153. package/skills/fui-skill/examples/f-table-patterns.json +331 -0
  154. package/skills/fui-skill/examples/module-patterns.json +973 -0
  155. package/skills/fui-skill/examples/project-patterns.json +222 -0
  156. package/skills/fui-skill/metadata.json +75 -0
  157. package/skills/fui-skill/references/INDEX.md +144 -0
  158. package/skills/fui-skill/references/advanced-techniques.md +160 -0
  159. package/skills/fui-skill/references/coding-standards.md +112 -0
  160. package/skills/fui-skill/references/component-design.md +455 -0
  161. package/skills/fui-skill/references/component-quickref.md +77 -0
  162. package/skills/fui-skill/references/component-table.md +276 -0
  163. package/skills/fui-skill/references/components-dialog.md +192 -0
  164. package/skills/fui-skill/references/components-display.md +147 -0
  165. package/skills/fui-skill/references/components-echart.md +391 -0
  166. package/skills/fui-skill/references/components-input.md +359 -0
  167. package/skills/fui-skill/references/controls-patterns.md +847 -0
  168. package/skills/fui-skill/references/controls-styling-vocabulary.md +140 -0
  169. package/skills/fui-skill/references/db-table-design.md +77 -0
  170. package/skills/fui-skill/references/db-workflow.md +504 -0
  171. package/skills/fui-skill/references/default-function.md +415 -0
  172. package/skills/fui-skill/references/design-modes.md +85 -0
  173. package/skills/fui-skill/references/echart-templates.md +481 -0
  174. package/skills/fui-skill/references/fastproject.md +97 -0
  175. package/skills/fui-skill/references/fsheet.md +218 -0
  176. package/skills/fui-skill/references/fullstack-workflow.md +351 -0
  177. package/skills/fui-skill/references/module-data-patterns.md +126 -0
  178. package/skills/fui-skill/references/module-json-anatomy.md +137 -0
  179. package/skills/fui-skill/references/module-structure.md +260 -0
  180. package/skills/fui-skill/references/new-session.md +108 -0
  181. package/skills/fui-skill/references/pdfmake.md +60 -0
  182. package/skills/fui-skill/references/permission-system.md +169 -0
  183. package/skills/fui-skill/references/platform-architecture.md +294 -0
  184. package/skills/fui-skill/references/project-config.md +335 -0
  185. package/skills/fui-skill/references/project-provisioning.md +383 -0
  186. package/skills/fui-skill/references/script-map.md +296 -0
  187. package/skills/fui-skill/references/sql-clr-functions.md +224 -0
  188. package/skills/fui-skill/references/system-design.md +116 -0
  189. package/skills/fui-skill/references/tapi-file-api.md +191 -0
  190. package/skills/fui-skill/references/tapi-permission-patterns.md +158 -0
  191. package/skills/fui-skill/references/tapi-reference.md +549 -0
  192. package/skills/fui-skill/references/tools-registry.md +460 -0
  193. package/skills/fui-skill/references/ui-crosswindow-patterns.md +317 -0
  194. package/skills/fui-skill/references/ui-dialog-patterns.md +229 -0
  195. package/skills/fui-skill/references/ui-layout-patterns.md +176 -0
  196. package/skills/fui-skill/references/ui-patterns.md +315 -0
  197. package/skills/fui-skill/references/ui-screenshot-review.md +94 -0
  198. package/skills/fui-skill/references/ui-table-cell-patterns.md +316 -0
  199. package/skills/fui-skill/references/ui-templates.md +29 -0
  200. package/skills/fui-skill/references/verification.md +246 -0
  201. package/skills/fui-skill/references/watcher-patterns.md +196 -0
  202. package/skills/fui-skill/references/websocket-realtime.md +254 -0
  203. package/skills/fui-skill/scripts/component-3.0.js +2549 -0
  204. package/skills/fui-skill/scripts/component.js +3142 -0
  205. package/skills/fui-skill/scripts/componentTable-3.0.js +909 -0
  206. package/skills/fui-skill/scripts/componentTable.js +769 -0
  207. package/skills/fui-skill/scripts/defaultfunction-3.0.js +781 -0
  208. package/skills/fui-skill/scripts/defaultfunction.js +966 -0
  209. package/skills/fui-skill/scripts/fastproject-3.0.js +870 -0
  210. package/skills/fui-skill/scripts/fastproject.js +828 -0
  211. package/skills/fui-skill/scripts/fechart.js +890 -0
  212. package/skills/fui-skill/scripts/fsheet.js +1330 -0
@@ -0,0 +1,828 @@
1
+ $awt = 'Bearer ' + getCookie('awt');
2
+ var vueData = {
3
+ p_domain: extractHostname(window.location.origin),
4
+ p_routers: [],
5
+ p_params: null,
6
+ p_urlReferrer: (typeof urlReferrer === 'undefined' ? "" : urlReferrer),
7
+ p_router: window.location.href.replace(window.location.origin, "").replace(window.location.search, ""),
8
+ v_Loading: false,
9
+ v_LoadingOverlay: [],
10
+ v_containerOn: true,
11
+ user: {
12
+ UserID: null,
13
+ UserName: null,
14
+ LastName: null,
15
+ FirstName: null,
16
+ Sex: null,
17
+ Phone: null,
18
+ Email: null,
19
+ DepartmentID: null,
20
+ GroupID: null,
21
+ SystemRight: null,
22
+ FunctionRight: null,
23
+ LastLogin: null
24
+ },
25
+ v_Set: {
26
+ title: null,
27
+ apiDomain: "",
28
+ login: false,
29
+ menu: [],
30
+ userInfo: "",
31
+ }
32
+ }
33
+ var scriptList = [];
34
+ var vm;
35
+ var vueOBJ = {
36
+ el: '#fastProjectAPP',
37
+ vuetify: null,
38
+ data: vueData,
39
+ methods: {
40
+ formvalidate() {
41
+ if (vueData.v_Set.disableValidate) return true;
42
+ return this.$refs.form.validate(true);
43
+ },
44
+ formSubmit() {
45
+ if (!vm.formvalidate()) {
46
+ showMessage({ type: "red", title: "Hãy điền đầy đủ dữ liệu bắt buộc !" });
47
+ return false;
48
+ }
49
+ return true;
50
+ }
51
+ },
52
+ };
53
+
54
+ //===========================================================================================
55
+ //===========================================================================================
56
+ $(document).ready(function () {
57
+ try {
58
+ Vue.use(VueToast);
59
+ loadModuleInfo();
60
+ } catch (ex) {
61
+ console.log("%cGet data error ", 'color: red; font-size: 30px; margin-top: 10px', ex);
62
+ }
63
+ });
64
+ //===========================================================================================
65
+ function buildParamURL() {
66
+ //-------- build param from url ----------------------------
67
+ vueData.p_routers = vueData.p_router.split('/').filter(w => w != '');
68
+
69
+ vueData.p_params = window.location.search;
70
+ const urlParams = new URLSearchParams(vueData.p_params);
71
+
72
+ for (const key of urlParams.keys()) {
73
+ vueData[key] = urlParams.get(key);
74
+ }
75
+ }
76
+ //===========================================================================================
77
+ function loadModuleInfo() {
78
+ _.templateSettings.interpolate = /{{([\s\S]+?)}}/g; // thiet lap nay là cho lodash
79
+ if (typeof $moduleUI == "undefined") $moduleUI = {};
80
+
81
+ if (typeof $projectData == "undefined") {
82
+ errorMess(1, "Chưa thiết lập cấu hình cho dự án");
83
+ return
84
+ }
85
+
86
+ if (typeof $projectGroupSetting == "undefined") $projectGroupSetting = {}
87
+
88
+ $.extend(vueData.v_Set, $projectGroupSetting, $projectData, $moduleUI.set);
89
+
90
+ if (vueData.v_Set.domainSetting) {
91
+ if (vueData.v_Set.domainSetting[vueData.p_domain]) {
92
+ $.extend(vueData.v_Set, vueData.v_Set.domainSetting[vueData.p_domain]);
93
+ }
94
+ delete vueData.v_Set.domainSetting;
95
+ }
96
+
97
+ buildParamURL();
98
+
99
+ //------- lay thong tin user nếu co ----------
100
+ if (vueData.v_Set.userInfo && vueData.v_Set.userInfo != '') {
101
+ $.ajax({
102
+ type: "POST",
103
+ headers: {
104
+ authorization: $awt
105
+ },
106
+ url: fixURL(vueData.v_Set.userInfo),
107
+ contentType: "application/json; charset=utf-8",
108
+ dataType: "json",
109
+ crossDomain: true,
110
+ success: function (d) {
111
+ vueData.user = d;
112
+ },
113
+ complete: function (data) {
114
+ createModuleDom();
115
+ }
116
+ });
117
+ } else createModuleDom();
118
+
119
+ }
120
+
121
+ //===========================================================================================
122
+ function createModuleDom() {
123
+
124
+ //===============================================
125
+ if (!$moduleUI.watch) $moduleUI.watch = {};
126
+
127
+ //========= day la moi ================
128
+ console.log(`FUI 2.6 Editor : https://fui.vn/fp/module?pid=${ProjectID}&mid=${ModuleID}&pageurl=${encodeURI(location.href)}`)
129
+
130
+ //--------------------------------------------------------------------------------
131
+ //---------- create data opject and load api data --------------------------------
132
+ //--------------------------------------------------------------------------------
133
+
134
+ runAction($moduleUI.data);
135
+
136
+ //-------------------- build DOM for VUE -----------------------------------------
137
+ var vue2MainLayout = $(`
138
+ <v-form ref="form" lazy-validation @submit.prevent="formSubmit">
139
+ <v-app>
140
+ <header-bar v-if="v_Set.menu || v_Set.menuLeft" :logo="v_Set.logo" :title="v_Set.title" :menu="v_Set.menu" :menu-left="v_Set.menuLeft" :component="v_Set.menuComponent" :user-profile="v_Set.userProfile" :menu-style="v_Set.menuStyle"></header-bar>
141
+ <v-main id="mainContainer" v-if="v_containerOn"></v-main>
142
+ </v-app>
143
+ </v-form>
144
+ `)
145
+
146
+ $("#mainContainer", vue2MainLayout).prepend(buildModuleUI($moduleUI.controls, vueData))
147
+ $("#fastProjectAPP").prepend(vue2MainLayout)
148
+ //---------------------------------------------------------------------------
149
+
150
+ createWatch_Data($moduleUI.watch)
151
+
152
+ //============ websocket ===========================
153
+ if (vueData.webSocket) {
154
+ vueData.webSocketState = { code: 0, text: "" };
155
+ if (_.isPlainObject(vueData.webSocket)) {
156
+ let objW = {}
157
+ _.forEach(vueData.webSocket, function (value, key) {
158
+ objW[bindDataToString(key, vueData)] = value;
159
+ });
160
+ vueData.webSocket = objW;
161
+ }
162
+ webSocketConnection('https://ws.fui.vn/signalr', vueData.webSocket, vueData.webSocketState);
163
+ webSocketJoinGroup(vueData.webSocket);
164
+ }
165
+ //==================================================
166
+
167
+ vueOBJ.vuetify = new Vuetify(vueData.v_Set.themeStyle);
168
+ vm = new Vue(vueOBJ);
169
+
170
+ //=========== add watch ================
171
+ createWatch($moduleUI.watch);
172
+
173
+ console.log("DATA", vueData);
174
+ moment.locale('en')
175
+ //=============== lay du lieu tu iframe ==============================================
176
+ window.onmessage = function (event) {
177
+ var evt = event || window.event;
178
+
179
+ //console.log("on message", evt.data)
180
+ switch (evt.data.cmd) {
181
+ case "setData":
182
+ setWindowData(evt.data.value.key, evt.data.value.data);
183
+ break;
184
+ case "getData":
185
+ let data = { key: evt.data.value.key, data: getWindowData(evt.data.value.val) };
186
+ windowSendMessage(evt.source, "sendData", data);
187
+ break;
188
+ case "openWindow":
189
+ openWindow(evt.data.value);
190
+ break;
191
+ case "LOGIN":
192
+ setCookie('awt', evt.data.token, 365, "." + getDomainWithoutSubdomain(location.href));
193
+ location.assign(location.href);
194
+ break;
195
+ default:
196
+ // code block
197
+ }
198
+ };
199
+
200
+ //=========== kiem tra đang nhap ================
201
+ if (_.isString(vueData.v_Set.login) && vueData.v_Set.login != "") {
202
+ if ($awt == 'Bearer ' || (vueData.v_Set.userInfo && !vueData.user.UserID)) {
203
+ loginFUN();
204
+ return
205
+ }
206
+ }
207
+ }
208
+ //===========================================================================================
209
+ //===========================================================================================
210
+ function buildModuleUI(controlsList, target) {
211
+ var container = $("<div>");
212
+ _.forEach(controlsList, function (C) {
213
+ var cont;
214
+ if (C.prop == undefined) C.prop = "";
215
+ if (_.isString(C.prop)) cont = $("<v-container " + C.prop + ">");
216
+ else cont = $("<v-container>").attr(C.prop);
217
+
218
+ _.forEach(C.rows, function (R) {
219
+ var row;
220
+ if (R.prop == undefined) R.prop = "";
221
+ if (_.isString(R.prop)) row = $("<v-layout " + R.prop + ">");
222
+ else row = $("<v-layout>").attr(R.prop);
223
+
224
+ row.append(buildControl(R.cols, true, target));
225
+ cont.append(row);
226
+ });
227
+ container.append(cont);
228
+ });
229
+
230
+ return container.children();
231
+ }
232
+ //===========================================================================================
233
+ function buildControl(controlsList, flex, target) {
234
+ var container = $("<div>");
235
+
236
+ _.forEach(controlsList, function (c) {
237
+ if (typeof (c.el) != "undefined" && c.el != "") {
238
+ if (c.el == 'layout') c.el = 'v-layout'
239
+
240
+ if (!c.attr) c.attr = {}
241
+
242
+ var defCom = defaultControlAttr[c.el];
243
+
244
+ if (defCom) {
245
+ if (defCom.attr) c.attr = $.extend(true, _.cloneDeep(defCom.attr), c.attr);
246
+ }
247
+
248
+ //---------------- chuyen doi du lieu thanh biến -------------
249
+ buildVisualValForObj(c.attr, target);
250
+
251
+ if (!c.attr[":required"]) delete c.attr[":rules"];
252
+ var ctl = $("<" + c.el + ">").attr(c.attr);
253
+
254
+ if (c.inner) {
255
+ if (_.isString(c.inner)) ctl.html(c.inner);
256
+ else if (_.isArray(c.inner)) {
257
+ if (c.el == 'v-layout') {
258
+ ctl.append(buildControl(c.inner, true, target));
259
+ } else {
260
+ ctl.append(buildControl(c.inner, false, target));
261
+ }
262
+ }
263
+ } else
264
+ if (c.innerHTML) {
265
+ if (_.isString(c.innerHTML)) ctl.html(c.innerHTML);
266
+ else if (_.isArray(c.innerHTML)) {
267
+ if (c.el == 'v-layout') {
268
+ ctl.append(buildControl(c.innerHTML, true, target));
269
+ } else {
270
+ ctl.append(buildControl(c.innerHTML, false, target));
271
+ }
272
+ }
273
+ }
274
+
275
+ if (flex) {
276
+ if (c.col == undefined) c.col = ""
277
+
278
+ if (c.el == 'v-flex') ctl.attr(stringAttrToJson(c.col));
279
+ else if (_.isString(c.col)) ctl = $(`<v-flex ${c.col}>`).append(ctl);
280
+ else ctl = $(`<v-flex>`).attr(c.col).append(ctl);
281
+
282
+ if (c.w) {
283
+ if (c.w > 12) ctl.css("flex-basis", c.w + "px");
284
+ else ctl.addClass("sm" + c.w);
285
+ }
286
+
287
+ if ($isMobile && c.w && c.w <= 12) ctl.addClass("xs12");
288
+ }
289
+
290
+ container.append(ctl);
291
+ }
292
+ });
293
+ return container.children();
294
+ }
295
+
296
+ //===========================================================================================
297
+ //===========================================================================================
298
+ //===========================================================================================
299
+ function addImport(importArr) {
300
+ if (importArr) {
301
+ _.forEach(importArr, function (val) {
302
+ if (val) {
303
+ if (_.endsWith(val, '.css')) $("<link/>", { rel: "stylesheet", type: "text/css", href: val }).appendTo("head");
304
+ else scriptList.push(val);
305
+ }
306
+ });
307
+ }
308
+ }
309
+ //===========================================================================================
310
+ function createWatch_Data(obj) {
311
+ if (obj) {
312
+ if (_.isPlainObject(obj)) {
313
+ _.forEach(obj, function (value, key) {
314
+ setValue(vueData, key, getVueData(key, vueData));
315
+ });
316
+ }
317
+ }
318
+ }
319
+ //===========================================================================================
320
+ function createWatch(obj) {
321
+ if (obj) {
322
+ if (_.isPlainObject(obj)) {
323
+ if (obj['deep-watch']) {
324
+ _.forEach(obj['deep-watch'], function (value, key) {
325
+ key = bindDataToString(key, vueData);
326
+ console.log("ADD Deep Watch : ", key);
327
+ vm.$watch(key, function (newValue, oldValue) {
328
+ runAction(value);
329
+ }, { deep: true });
330
+ });
331
+ delete obj['deep-watch'];
332
+ }
333
+ //----------------------------
334
+ _.forEach(obj, function (value, key) {
335
+ key = bindDataToString(key, vueData);
336
+ console.log("ADD Watch : ", key);
337
+ vm.$watch(key, function (newValue, oldValue) {
338
+ runAction(value);
339
+ }, { deep: false });
340
+ });
341
+ }
342
+ }
343
+ }
344
+ //===========================================================================================
345
+ function buildVisualValForObj(controlAttr, target) {
346
+ _.forEach(controlAttr, function (val, key) {
347
+ if (_.isObjectLike(val)) {
348
+ controlAttr[key] = JSON.stringify(val);
349
+ } else if (target) {
350
+ if (key == "v-model") {
351
+ if (val.indexOf('vueData.') < 0 && getVueData(val, target) == undefined) {
352
+ let mapObj = {};
353
+ mapObj[val] = undefined;
354
+
355
+ mapData(mapObj, target, {});
356
+ }
357
+ } else if (_.isString(val) && key[0] == ":") {
358
+ let regexValCheck = /^[a-zA-Z0-9$_\[\]\-\.]*$/gm;
359
+
360
+ if (val.indexOf('vueData.') < 0 && regexValCheck.test(val) && getVueData(val, target) == undefined) {
361
+ let mapObj = {};
362
+ if (key == ":items") mapObj[val] = [];
363
+ else mapObj[val] = undefined;
364
+
365
+ mapData(mapObj, target, {});
366
+ }
367
+ }
368
+
369
+ }
370
+ });
371
+ }
372
+ //===========================================================================================
373
+ function runAction(obj, includeData) {
374
+ if (!obj) return;
375
+
376
+ let dataSrc = _.assignIn({}, vueData, includeData);
377
+ if (_.isString(obj)) obj = getVueData(obj, dataSrc);
378
+
379
+ if (!obj) {
380
+ console.log("Action Undefined");
381
+ return;
382
+ }
383
+
384
+
385
+
386
+ if (!_.isArray(obj)) obj = _.castArray(obj);
387
+ //-------------------------------------------------
388
+ _.forEach(obj, function (value) {
389
+ if (value.CONFIRM) {
390
+ confirm({
391
+ title: bindDataToString(value.CONFIRM, dataSrc),
392
+ action: function () {
393
+ let action = _.cloneDeep(value);
394
+ delete action.CONFIRM;
395
+ delete action.CANCEL;
396
+ vueAction(action, includeData);
397
+ },
398
+ cancel: function () {
399
+ if (value.CANCEL) vueAction(value.CANCEL, includeData);
400
+ else if (includeData && _.isFunction(includeData.cancelConfirm)) includeData.cancelConfirm();
401
+ }
402
+ });
403
+ } else vueAction(value, includeData);
404
+ });
405
+ }
406
+ //===========================================================================================
407
+ function vueAction(objAction, includeData, callBack) {
408
+ var obj = _.cloneDeep(objAction);
409
+ var dataSrc = _.assignIn({}, vueData, includeData);
410
+
411
+ if (!obj) return;
412
+
413
+ if (obj.IN) {
414
+ if (_.isString(obj.IN)) mapData({ "IN": obj.IN }, obj, dataSrc);
415
+ else {
416
+ var objIN = {};
417
+ mapData(obj.IN, objIN, dataSrc);
418
+ obj.IN = objIN;
419
+ }
420
+ }
421
+ //--------------------------------------------------------------
422
+ if (obj.API) {
423
+ obj.API = bindDataToString(obj.API, dataSrc);
424
+
425
+ if (obj.HEADER) {
426
+ if (_.isString(obj.HEADER)) mapData({ "HEADER": obj.HEADER }, obj, dataSrc);
427
+ else mapData(obj.HEADER, obj.HEADER, dataSrc);
428
+ }
429
+
430
+ defProp(obj.OUT);
431
+ callAPI(obj, function (d) {
432
+ if (_.isFunction(callBack)) callBack(d);
433
+ runAction(obj.CALLBACK, includeData);
434
+ }, includeData);
435
+ return;
436
+ }
437
+
438
+ if (obj.CALL) {
439
+ runAction(obj.CALL, includeData);
440
+ return;
441
+ }
442
+
443
+ if (obj.EXE) {
444
+ templateCompiled(`<% ${obj.EXE} %>`, {...includeData, ...vueData})
445
+ return;
446
+ }
447
+
448
+ if (obj.FUN) {
449
+ obj.FUN = bindDataToString(obj.FUN, dataSrc);
450
+ runFunction(obj, function (d) {
451
+ mapData(obj.OUT, vueData, d);
452
+
453
+ if (_.isFunction(callBack)) callBack(d);
454
+ runAction(obj.CALLBACK, includeData);
455
+ });
456
+ return;
457
+ }
458
+
459
+ if (obj.IF) {
460
+ if (templateCompiled(`<%- ${obj.IF} %>`, {...includeData, ...vueData}) == 'true') {
461
+ if (_.isString(obj.THEN)) templateCompiled(`<% ${obj.THEN} %>`, {...includeData, ...vueData});
462
+ else runAction(obj.THEN, includeData);
463
+ } else {
464
+ if (_.isString(obj.ELSE)) templateCompiled(`<% ${obj.ELSE} %>`, {...includeData, ...vueData});
465
+ else runAction(obj.ELSE, includeData);
466
+ }
467
+ return;
468
+ }
469
+
470
+ if (obj.MESS) {
471
+ obj.MESS = bindDataToString(obj.MESS, dataSrc);
472
+ Vue.$toast.success(obj.MESS, { position: 'top' });
473
+ return;
474
+ }
475
+
476
+ if (obj.MESSBOX) {
477
+ obj.MESSBOX = bindDataToString(obj.MESSBOX, dataSrc);
478
+ showMessage({ title: obj.MESSBOX })
479
+ return;
480
+ }
481
+
482
+ mapData(obj, vueData, vueData, includeData);
483
+ }
484
+ //===========================================================================================
485
+ function mapData(map, target, src, includeData) {
486
+ if (_.isString(map)) {
487
+ setValue(target, map, src);
488
+ } else {
489
+ if (_.isPlainObject(map)) {
490
+ _.forEach(map, function (value, key) {
491
+ if (includeData) src = _.assignIn({}, vueData, includeData);
492
+ //Get data of window
493
+ key = bindDataToString(key, vueData)
494
+
495
+ if (_.isString(value) && value[0] == "#") {
496
+ let windowData;
497
+ try {
498
+ if (window != top) windowData = parent.getWindowData(value);
499
+ setValue(target, key, windowData);
500
+ }
501
+ catch (err) {
502
+ let patternBlocked = /Blocked(.*)cross-origin(.*)/g;
503
+ // Khi bi Blocked ko cho set du lieu vi khac ten mien
504
+ if (patternBlocked.test(err)) windowSendMessage('#PARENT', "getData", { key: key, val: value });
505
+ else console.log("Set value error:", key, err);
506
+ }
507
+ } else
508
+ if (key[0] == "#") {// Set data to Window
509
+ try {
510
+ if (window != top) parent.setWindowData(key, getVueData(value, src));
511
+ else setWindowData(key, getVueData(value, src));
512
+ }
513
+ catch (err) {
514
+ let patternBlocked = /Blocked(.*)cross-origin(.*)/g;
515
+ // Khi bi Blocked ko cho set du lieu vi khac ten mien
516
+ if (patternBlocked.test(err)) windowSendMessage('#PARENT', "setData", { key: key, data: getVueData(value, src) });
517
+ else console.log("Set value error:", key, err);
518
+ }
519
+ } else {
520
+ setValue(target, key, getVueData(value, src), src);
521
+ }
522
+ });
523
+ }
524
+ }
525
+ }
526
+ //===========================================================================================
527
+ function defProp(obj) {
528
+ if (_.isString(obj)) {
529
+ if (typeof vueData[obj] == "undefined") vueData[obj] = []
530
+ } else
531
+ if (_.isPlainObject(obj))
532
+ for (k in obj) {
533
+ if (typeof vueData[k] == "undefined") vueData[k] = undefined;
534
+ }
535
+ }
536
+ //===========================================================================================
537
+ function bindData(obj) {
538
+ if (_.isObjectLike(obj)) return obj;
539
+ else return getVueData(obj, vueData);
540
+ }
541
+ //===========================================================================================
542
+ function getVueData(key, src) {
543
+ if (_.isString(key)) {
544
+ if (key == "") return "";
545
+ key = _.replace(key, 'vueData.', '').trim();
546
+
547
+ if (key[0] == "`") {
548
+ return _.trim(bindDataToString(key, src), "`");
549
+ } else {
550
+ if ((/^{{.*}}$/gm).test(key)) key = key.replace(/^{{|}}$/gm, ''); // bo cap {{ }} dau va cuoi
551
+
552
+ try {
553
+ templateCompiled(`<% ReturnValue = ${key} %>`, src);
554
+ return ReturnValue;
555
+ } catch (err) {
556
+ let pattern = /Blocked(.*)cross-origin(.*)/g;
557
+ if (pattern.test(err)) throw err;
558
+ else {
559
+ if ((/({{.*}}|[ ])/gm).test(key)) return _.trim(bindDataToString(key, src), "`");
560
+ else {
561
+ if (err.name != "ReferenceError") console.log("%cGet data error ", 'color: red; font-size: 16px; margin-top: 10px', key, err);
562
+ }
563
+ }
564
+ //console.log("Error ", err);
565
+ }
566
+
567
+ return undefined;
568
+ //console.log("ERROR", key)
569
+ }
570
+
571
+ } else if (_.isPlainObject(key) && key.ARRAY && key.COL) {
572
+ return _.map(_.at(src, key.ARRAY)[0], _.property(key.COL));
573
+ }
574
+
575
+ return key;
576
+ }
577
+ //===========================================================================================
578
+ function setValue(target, key, value, srcData, index) {
579
+ if (_.isArray(key)) {
580
+ let k = key[index];
581
+ if (k[k.length - 1] == ']') {
582
+ k = k.replaceAll("]", "");
583
+ if ((/^[0-9]*$/gm).test(k)) k = parseInt(k); // kiem tra xem chuoi la number
584
+ else {
585
+ if (k[0] == "'") k = k.replaceAll("'", "");
586
+ else {
587
+ k = getVueData(k, srcData);
588
+ }
589
+ }
590
+ }
591
+
592
+ if (key.length - 1 == index) {
593
+ target[k] = value;
594
+ return;
595
+ }
596
+
597
+ if (typeof target[k] == "undefined") {
598
+ let kn = key[index + 1];
599
+ if (kn[kn.length - 1] == ']') target[k] = [];
600
+ else target[k] = {};
601
+ }
602
+ setValue(target[k], key, value, srcData, index + 1);
603
+ } else {
604
+ if (key[0] == "`" || key[0] == "'") {
605
+ key = key.replaceAll("'", "").replaceAll("`", "");
606
+ setValue(target, [key], value, srcData, 0);
607
+ }
608
+ else setValue(target, _.words(key, /[^.\[]+/g), value, srcData, 0);
609
+ }
610
+ }
611
+ //===========================================================================================
612
+ function bindDataToString(str, data) {
613
+ if (!_.isString(str)) return str;
614
+
615
+ let compiled = _.template(str);
616
+ return compiled(data);
617
+ }
618
+ //===========================================================================================
619
+ function templateCompiled(str, data) {
620
+ var compiled = _.template(str);
621
+ return compiled(data);
622
+ }
623
+ //===========================================================================================
624
+ function getWindowData(value) {
625
+ let winName = _.split(value, '.', 1)[0];
626
+ let key = _.replace(value, winName + '.', '');
627
+
628
+ if (winName == '#PARENT') return bindData(key);
629
+
630
+ let win = document.getElementById(winName.slice(1, winName.length));
631
+
632
+ if (win) return win.contentWindow.bindData(key);
633
+ else console.log("Window ID not found", winName);
634
+
635
+ return undefined;
636
+ }
637
+ //===========================================================================================
638
+ function setWindowData(key, value) {
639
+ let W = _.split(key, '.', 1)[0];
640
+ let K = _.replace(key, W + '.', '');
641
+
642
+ if (W == '#PARENT') {
643
+ if (K == W) {
644
+ runAction(value);
645
+ }
646
+ else setValue(vueData, K, value);
647
+ return
648
+ }
649
+
650
+ let win = document.getElementById(W.slice(1, W.length));
651
+
652
+ if (win) win.contentWindow.setWindowData(_.replace(key, W, '#PARENT'), value);
653
+ else console.log("Window ID not found", W);
654
+ }
655
+
656
+ //===========================================================================================
657
+ function runFunction(obj, callback) {
658
+ console.log("Run function", obj)
659
+ let fn = window[obj.FUN];
660
+ if (_.isFunction(fn)) {
661
+ callback(fn(obj.IN));
662
+ } else console.log("Func:", obj.FUN, "not found");
663
+ }
664
+ //===========================================================================================
665
+ function tableActionEvent(ctrl) {
666
+ let action = ctrl.$attrs["action"];
667
+ if (!action) action = ctrl.$attrs[":action"];
668
+
669
+ let oldValue = ctrl.$attrs['value'];
670
+ if (!_.isUndefined(ctrl.ctlValue)) ctrl.$emit('input', ctrl.ctlValue);
671
+ console.log("Table Action", action);
672
+ if (action) {
673
+ console.log("Table Action Event", ctrl.$attrs);
674
+
675
+ runAction(action, {
676
+ $row: ctrl.$attrs['item'],
677
+ item: ctrl.$attrs['item'],
678
+ index: ctrl.$attrs['index'],
679
+ cancelConfirm: function () {
680
+ if (!_.isUndefined(oldValue)) ctrl.ctlValue = oldValue;
681
+ if (!_.isUndefined(ctrl.ctlValue)) ctrl.$emit('input', ctrl.ctlValue);
682
+ }
683
+ });
684
+ }
685
+ }
686
+ //===========================================================================================
687
+ function callAPI(objApi, callBack, includeData) {
688
+ if (objApi.API) {
689
+ let loadingID = generateID();
690
+ vueData.v_LoadingOverlay.push(loadingID);
691
+ vueData.v_Loading = true;
692
+
693
+ $.ajax({
694
+ type: (objApi.METHOD ? objApi.METHOD : "POST"),
695
+ headers: (objApi.HEADER ? objApi.HEADER : {
696
+ authorization: $awt
697
+ }),
698
+ url: fixURL(objApi.API),
699
+ data: JSON.stringify(objApi.IN),
700
+ contentType: "application/json; charset=utf-8",
701
+ dataType: "json",
702
+ crossDomain: true,
703
+ success: function (d) {
704
+ //---- convert to json object ------------
705
+ json_data_parse(d, 0);
706
+ //--------------------------------
707
+ console.log("API:", _.cloneDeep(objApi.API), "IN:", objApi.IN ? _.cloneDeep(objApi.IN) : "");
708
+ console.log("OUT:", _.cloneDeep(d));
709
+ //--------------------------------------
710
+ if (objApi.OUT) {
711
+ if (_.isString(objApi.OUT) && Object.keys(d).length == 1 && d.data) d = d.data;
712
+ mapData(objApi.OUT, vueData, d);
713
+ }
714
+ if (objApi.MESS) Vue.$toast.success(bindDataToString(objApi.MESS, vueData), { position: 'top' })
715
+ if (_.isFunction(callBack)) callBack(d);
716
+ },
717
+ error: function (xhr, ajaxOptions, thrownError) {
718
+ console.log("API:", objApi.API, "IN:", objApi.IN ? objApi.IN : "");
719
+ if (objApi.ERROROUT) {
720
+ mapData(objApi.ERROROUT, vueData, xhr);
721
+ }
722
+ if (objApi.ERRORCALLBACK) {
723
+ runAction(objApi.ERRORCALLBACK, includeData);
724
+ }
725
+ if (objApi.ERROROUT) return;
726
+
727
+ if (xhr.status == 200) {
728
+ console.log("Error XHR:", xhr);
729
+ mapData(objApi.OUT, vueData, xhr.responseText);
730
+ } else {
731
+ console.log("Error XHR:", xhr);
732
+ errorMess(xhr.status, (_.isString(xhr.responseJSON) ? xhr.responseJSON : (_.isPlainObject(xhr.responseJSON) ? xhr.responseJSON.Message : "")))
733
+ }
734
+ },
735
+ complete: function (data) {
736
+ vueData.v_LoadingOverlay = _.without(vueData.v_LoadingOverlay, loadingID);
737
+ if (vueData.v_LoadingOverlay.length == 0) vueData.v_Loading = false;
738
+ }
739
+ });
740
+ }
741
+ }
742
+ //===========================================================================================
743
+ function loginFUN() {
744
+ if (!vueData.v_Set.login || vueData.v_Set.login == "") return;
745
+ if (vueData.v_Set.login.indexOf('login.fui.vn') >= 0) {
746
+ openWindow({
747
+ id: "loginWindow",
748
+ headerbar: false,
749
+ transition: 'fade-transition',
750
+ title: 'Đăng nhập',
751
+ url: vueData.v_Set.login,
752
+ onclose: function () {
753
+ location.assign(location.href);
754
+ }
755
+ });
756
+ }
757
+ else location.assign(vueData.v_Set.login);
758
+ }
759
+
760
+ //===========================================================================================
761
+ function errorMess(code, message) {
762
+ let errorText = {
763
+ "400": ["Bad Request", "The server did not understand the request"],
764
+ "401": ["Unauthorized", "The requested page needs a username and a password"],
765
+ "402": ["Payment Required", "You can not use this code yet"],
766
+ "403": ["Forbidden", "Access is forbidden to the requested page"],
767
+ "404": ["Not Found", "The server can not find the requested page"],
768
+ "405": ["Method Not Allowed", "The method specified in the request is not allowed"],
769
+ "406": ["Not Acceptable", "The server can only generate a response that is not accepted by the client"],
770
+ "407": ["Proxy Authentication Required", "You must authenticate with a proxy server before this request can be served"],
771
+ "408": ["Request Timeout", "The request took longer than the server was prepared to wait"],
772
+ "411": ["Length Required", "The 'Content-Length' is not defined. The server will not accept the request without it"],
773
+ "413": ["Request Entity Too Large", ""],
774
+ "414": ["Request-url Too Long", ""],
775
+ "415": ["Unsupported Media Type", ""],
776
+ "500": ["Internal Server Error", "The request was not completed. The server met an unexpected condition"],
777
+ "501": ["Not Implemented", "The request was not completed. The server did not support the functionality required"],
778
+ "502": ["Bad Gateway", ""],
779
+ "503": ["Service Unavailable", "The request was not completed. The server is temporarily overloading or down"],
780
+ "504": ["Gateway Timeout", "The gateway has timed out"],
781
+ };
782
+ let err = errorText[code];
783
+ let title;
784
+
785
+ if (code == "403") {
786
+ if (message == '') title = 'Bạn chưa được phân quyền tính năng này.';
787
+ else {
788
+ title = message;
789
+ message = '';
790
+ }
791
+ vueData.v_containerOn = false;
792
+ } else if (code == "401") {
793
+ if (vueData.v_Set.login && ($awt == 'Bearer ' || message.toLowerCase().indexOf('token') >= 0)) {
794
+ loginFUN();
795
+ return
796
+ } else {
797
+ if (!vueData.v_Set.login || vueData.v_Set.login == "") {
798
+ title = 'Hãy đăng nhập lại';
799
+ message = "Chứng thực của bạn không còn hiệu lực";
800
+ } else {
801
+ confirm({
802
+ title: message,
803
+ message: 'Bạn có muốn đăng nhập lại hay không ?',
804
+ action: function () {
805
+ loginFUN();
806
+ }
807
+ });
808
+ return;
809
+ }
810
+ }
811
+ } else if (!err) {
812
+ title = "Error " + code + ': Hãy kiểm tra kết nối mạng';
813
+ } else {
814
+ if (code == '400') title = '';
815
+ else title = code + ": " + err[0];
816
+
817
+ if (!message) message = err[1];
818
+ }
819
+
820
+ //---------------------------------------------------------------------------------------------------------------------------
821
+ showMessage({
822
+ icon: 'mdi mdi-alert-circle-outline',
823
+ title: title,
824
+ message: message,
825
+ type: 'red'
826
+ });
827
+ }
828
+ //===========================================================================================