src/Builder4/RooProjectSettings.bjs
[roobuilder] / src / Builder4 / RooProjectSettings.bjs
1 {
2  "name" : "RooProjectSettings",
3  "parent" : "",
4  "title" : "",
5  "path" : "/home/alan/gitlive/roobuilder/src/Builder4/RooProjectSettings.bjs",
6  "permname" : "",
7  "modOrder" : "",
8  "build_module" : "builder",
9  "items" : [
10   {
11    "@ void buttonPressed" : "(string btn)",
12    "id" : "RooProjectSettings",
13    "| void show" : " (Gtk.Widget btn, Project.Project project) {\n    _this.project = project;\n    _this.path.el.label = project.firstPath();\n    // get the active project.\n     var lm = Gtk.SourceLanguageManager.get_default();\n                \n    ((Gtk.SourceBuffer)(_this.view.el.get_buffer())) .set_language(\n        lm.get_language(\"html\")\n    );\n  \n    //print (project.fn);\n    //project.runhtml = project.runhtml || '';\n    _this.view.el.get_buffer().set_text(project.runhtml);\n    \n       \n    _this.rootURL.el.set_text( _this.project.rootURL );\n    \n\n    _this.base_template_model.loadData();\n    \n     var js = _this.project;\n    _this.database_DBTYPE.el.set_text(     js.get_string_member(\"DBTYPE\") );\n    _this.database_DBNAME.el.set_text(    js.get_string_member(\"DBNAME\") );\n    _this.database_DBUSERNAME.el.set_text(    js.get_string_member(\"DBUSERNAME\") );\n    _this.database_DBPASSWORD.el.set_text(    js.get_string_member(\"DBPASSWORD\") );\n    \n    \t//console.log('show all');\n\tthis.el.set_modal(true);\n\tthis.el.set_relative_to(btn);\n\n\tthis.el.set_position(Gtk.PositionType.RIGHT);\n\n\t// window + header?\n\t print(\"SHOWALL - POPIP\\n\");\n\tthis.el.show_all();\n\tthis.el.set_size_request(800,500);\n\tthis.view.el.grab_focus();\n\t\n    \n    //this.el.show_all();\n}\n",
14    "xtype" : "Popover",
15    "Gtk.PositionType position" : "Gtk.PositionType.RIGHT",
16    "| void save" : "() {\n   var buf =    _this.view.el.get_buffer();\n   Gtk.TextIter s;\n     Gtk.TextIter e;\n    buf.get_start_iter(out s);\n    buf.get_end_iter(out e);\n      _this.project.runhtml = buf.get_text(s,e,true);\n      \n    _this.project.rootURL = _this.rootURL.el.get_text();\n    // set by event changed...\n    //_this.project.base_template = _this.base_template.el.get_text();    \n    \n    var js = _this.project.json_project_data;\n    js.set_string_member(\"DBTYPE\", _this.database_DBTYPE.el.get_text());\n   js.set_string_member(\"DBNAME\", _this.database_DBNAME.el.get_text());\n    js.set_string_member(\"DBUSERNAME\", _this.database_DBUSERNAME.el.get_text());\n    js.set_string_member(\"DBPASSWORD\", _this.database_DBPASSWORD.el.get_text());\n//    _this.project.set_string_member(\"DBHOST\", _this.DBTYPE.el.get_text());    \n    \n    // need to re-init the database \n    \n    _this.project.initRooDatabase();\n     \n    \n}",
17    "$ xns" : "Gtk",
18    "Project.Project project" : "",
19    "bool modal" : true,
20    "uint border_width" : 0,
21    "items" : [
22     {
23      "xtype" : "Box",
24      "* pack" : "add",
25      "$ xns" : "Gtk",
26      "Gtk.Orientation orientation" : "Gtk.Orientation.VERTICAL",
27      "border_width" : 5,
28      "$ homogeneous" : false,
29      "items" : [
30       {
31        "* pack" : "pack_start,true,true,0",
32        "xtype" : "Notebook",
33        "$ xns" : "Gtk",
34        "items" : [
35         {
36          "id" : "label_global",
37          "* pack" : false,
38          "xtype" : "Label",
39          "$ xns" : "Gtk",
40          "utf8 label" : "Global"
41         },
42         {
43          "id" : "label_database",
44          "xtype" : "Label",
45          "* pack" : false,
46          "$ xns" : "Gtk",
47          "utf8 label" : "Database"
48         },
49         {
50          "* pack" : "append_page,_this.label_global.el",
51          "xtype" : "Box",
52          "gboolean homogeneous" : false,
53          "$ xns" : "Gtk",
54          "Gtk.Orientation orientation" : "Gtk.Orientation.VERTICAL",
55          "items" : [
56           {
57            "* pack" : "pack_start,false,false,0",
58            "xtype" : "Box",
59            "gboolean expand" : false,
60            "$ xns" : "Gtk",
61            "Gtk.Orientation orientation" : "Gtk.Orientation.HORIZONTAL",
62            "$ homogeneous" : false,
63            "items" : [
64             {
65              "label" : "HTML template file",
66              "* pack" : "pack_start,false,false,0",
67              "xtype" : "Label",
68              "gint margin" : 3,
69              "$ xns" : "Gtk"
70             },
71             {
72              "listeners" : {
73               "changed" : "() => {\n\tGtk.TreeIter iter;\n \n\t// this get's called when we are filling in the data... ???\n\tif (this.loading) {\n\t\treturn;\n\t}\n\t\n \n\tif (this.el.get_active_iter(out iter)) {\n\t\tValue vfname;\n\t\t_this.base_template_model.el.get_value (iter, 0, out vfname);\n\t\t_this.project.base_template = ((string)vfname) ;\n\t\t\n\t\t print(\"\\nSET base template to %s\\n\", _this.project.base_template );\n\t\t// is_bjs = ((string)vfname) == \"bjs\";\n\t}\n    \n  \n    // directory is only available for non-bjs \n \n\n\n}\n"
74              },
75              "id" : "base_template",
76              "bool loading" : false,
77              "* init" : "this.el.add_attribute(_this.base_template_cellrenderer.el , \"markup\", 0 );",
78              "* pack" : "add",
79              "xtype" : "ComboBox",
80              "$ xns" : "Gtk",
81              "items" : [
82               {
83                "id" : "base_template_cellrenderer",
84                "xtype" : "CellRendererText",
85                "* pack" : "pack_start,true",
86                "$ xns" : "Gtk"
87               },
88               {
89                "id" : "base_template_model",
90                "xtype" : "ListStore",
91                "* pack" : "set_model",
92                "$ columns" : "typeof(string)",
93                "n_columns" : 1,
94                "$ xns" : "Gtk",
95                "| void loadData" : "  () {\n\t_this.base_template.loading = true;\n  \n    this.el.clear();                                    \n    Gtk.TreeIter iter;\n    var el = this.el;\n    \n   /// el.append(out iter);\n    \n   \n    el.append(out iter);\n    el.set_value(iter, 0, \"roo.builder.html\");\n    _this.base_template.el.set_active_iter(iter);\n\tif (_this.project.base_template == \"roo.builder.html\") {\n\t   _this.base_template.el.set_active_iter(iter);\n    }\n\n    el.append(out iter);\n    el.set_value(iter, 0, \"bootstrap.builder.html\");\n \n\tprint(\"\\ncur template = %s\\n\", _this.project.base_template);\n \n    if (_this.project.base_template == \"bootstrap.builder.html\") {\n\t   _this.base_template.el.set_active_iter(iter);\n    }\n\n\tel.append(out iter);\n    el.set_value(iter, 0, \"mailer.builder.html\");\n\n\tif (_this.project.base_template == \"mailer.builder.html\") {\n\t    _this.base_template.el.set_active_iter(iter);\n    }\n\t_this.base_template.loading = false;\n                                     \n}\n"
96               }
97              ]
98             }
99            ]
100           },
101           {
102            "* pack" : "pack_start,false,false,0",
103            "xtype" : "Box",
104            "gboolean expand" : false,
105            "$ xns" : "Gtk",
106            "Gtk.Orientation orientation" : "Gtk.Orientation.HORIZONTAL",
107            "$ homogeneous" : false,
108            "items" : [
109             {
110              "label" : "root URL",
111              "* pack" : "pack_start,false,false,0",
112              "xtype" : "Label",
113              "gint margin" : 3,
114              "$ xns" : "Gtk"
115             },
116             {
117              "id" : "rootURL",
118              "* pack" : "add",
119              "xtype" : "Entry",
120              "$ xns" : "Gtk"
121             }
122            ]
123           },
124           {
125            "label" : "HTML To insert at end of <HEAD>",
126            "* pack" : "pack_start,false,false,0",
127            "xtype" : "Label",
128            "$ xns" : "Gtk"
129           },
130           {
131            "id" : "grid",
132            "int margin_right" : 4,
133            "* pack" : "pack_start,false,false,4",
134            "xtype" : "Grid",
135            "uint row_spacing" : 2,
136            "n_columns" : 2,
137            "$ xns" : "Gtk",
138            "n_rows" : 7,
139            "$ homogeneous" : true,
140            "int margin_left" : 4,
141            "items" : [
142             {
143              "label" : "File type",
144              "id" : "filetypelbl",
145              "xalign" : 0.90000000000000002,
146              "* pack" : "attach,0,0,1,1",
147              "xtype" : "Label",
148              "$ justify" : "Gtk.Justification.RIGHT",
149              "x_options" : 4,
150              "$ xns" : "Gtk"
151             },
152             {
153              "listeners" : {
154               "changed" : "() => {\n\tGtk.TreeIter iter;\n\tbool is_bjs = true;\n\tif (this.el.get_active_iter(out iter)) {\n\t\tValue vfname;\n\t\t_this.ftdbmodel.el.get_value (iter, 0, out vfname);\n\t\t is_bjs = ((string)vfname) == \"bjs\";\n\t}\n    \n  \n    // directory is only available for non-bjs \n    this.showhide(is_bjs);\n\n\n}\n"
155              },
156              "id" : "filetype",
157              "* init" : "this.el.add_attribute(_this.ftdbcellrenderer.el , \"markup\", 1 );",
158              "* pack" : "attach,1,0,1,1",
159              "xtype" : "ComboBox",
160              "| void showhide" : "(bool is_bjs) {\n\tfor (var i = 2; i < 9;i++) {\n\t\tvar el = _this.grid.el.get_child_at(0,i);\n\t\t\n\t\tvar showhide= is_bjs;\n\t\tif (i> 7) {\n\t\t\tshowhide = !showhide;\n\t\t}\n\t\t\n\t\tif (showhide) {\n\t\t   el.show();\n\t\t} else {\n\t\t\tel.hide();\n\t\t}\n\t\t el = _this.grid.el.get_child_at(1,i);\n\t\tif (showhide) {\n\t\t   el.show();\n\t\t} else {\n\t\t\tel.hide();\n\t\t}     \n    }\n    // load up the directories\n    //??? why can we not create bjs files in other directories??\n\tif (!is_bjs && _this.file.path.length < 1) {\n\t\t_this.dirmodel.loadData();\n\t\t\n\t\t\n\t}\n   \n    \n}\n",
161              "$ xns" : "Gtk",
162              "items" : [
163               {
164                "id" : "ftdbcellrenderer",
165                "xtype" : "CellRendererText",
166                "* pack" : "pack_start,true",
167                "$ xns" : "Gtk"
168               },
169               {
170                "id" : "ftdbmodel",
171                "xtype" : "ListStore",
172                "* pack" : "set_model",
173                "$ columns" : "typeof(string),typeof(string)",
174                "n_columns" : 2,
175                "$ xns" : "Gtk",
176                "| void loadData" : "  (string cur) {\n    this.el.clear();                                    \n    Gtk.TreeIter iter;\n    var el = this.el;\n    \n   /// el.append(out iter);\n    \n     \n   // el.set_value(iter, 0, \"\");\n   // el.set_value(iter, 1, \"aaa  - Just add Element - aaa\");\n\n    el.append(out iter);\n\n    \n    el.set_value(iter, 0, \"bjs\");\n    el.set_value(iter, 1, \"User Interface File (bjs)\");\n    _this.filetype.el.set_active_iter(iter);\n\n    el.append(out iter);\n    \n    el.set_value(iter, 0, \"vala\");\n    el.set_value(iter, 1, \"Vala\");\n\tif (cur == \"vala\") {\n\t    _this.filetype.el.set_active_iter(iter);\n    }\n\n\n\n    el.append(out iter);\n    \n    el.set_value(iter, 0, \"js\");\n    el.set_value(iter, 1, \"Javascript\");\n\n\tif (cur == \"js\") {\n\t    _this.filetype.el.set_active_iter(iter);\n    }\n\n    el.append(out iter);\n    \n    el.set_value(iter, 0, \"css\");\n    el.set_value(iter, 1, \"CSS\");\n\n\tif (cur == \"css\") {\n\t    _this.filetype.el.set_active_iter(iter);\n    }\n                                     \n}\n"
177               }
178              ]
179             },
180             {
181              "label" : "Directory",
182              "$ visible" : true,
183              "xalign" : 0.90000000000000002,
184              "* pack" : "attach,0,8,1,1",
185              "xtype" : "Label",
186              "$ justify" : "Gtk.Justification.RIGHT",
187              "x_options" : 4,
188              "$ xns" : "Gtk"
189             },
190             {
191              "id" : "dir",
192              "* init" : "this.el.add_attribute(_this.dircellrenderer.el , \"markup\", 1 );",
193              "* pack" : "attach,1,8,1,1",
194              "xtype" : "ComboBox",
195              "$ xns" : "Gtk",
196              "items" : [
197               {
198                "id" : "dircellrenderer",
199                "xtype" : "CellRendererText",
200                "* pack" : "pack_start,true",
201                "$ xns" : "Gtk"
202               },
203               {
204                "id" : "dirmodel",
205                "xtype" : "ListStore",
206                "* pack" : "set_model",
207                "$ columns" : "typeof(string),typeof(string)",
208                "n_columns" : 2,
209                "$ xns" : "Gtk",
210                "| void loadData" : "  () {\n\t\n\t\n  \n    this.el.clear();                                    \n    \n    if (!(_this.project is Project.Gtk)) {\n\t\treturn;\n\t}\n    var sd = ((Project.Gtk)_this.project).sourcedirs();\n    \n    Gtk.TreeIter iter;\n    var el = this.el;\n    \n   /// el.append(out iter);\n    \n     \n   // el.set_value(iter, 0, \"\");\n   // el.set_value(iter, 1, \"aaa  - Just add Element - aaa\");\n\n//    el.append(out iter);\n\n    \n//    el.set_value(iter, 0, \"\");\n  //  el.set_value(iter, 1, \"-- select a directoyr --\");\n    //_this.build_module.el.set_active_iter(iter);\n    \n    for (var i = 0; i < sd.length;i++) {\n    \n\n        el.append(out iter);\n        \n        el.set_value(iter, 0, sd[i]);\n        el.set_value(iter, 1, sd[i]);\n        \n        //if (data.get(i) == cur) {\n        //    _this.build_module.el.set_active_iter(iter);\n       // }\n        \n    }\n  //  this.el.set_sort_column_id(0, Gtk.SortType.ASCENDING);          \n                                     \n}\n"
211               }
212              ]
213             },
214             {
215              "label" : "Filename",
216              "xalign" : 0,
217              "* pack" : "attach,0,0,1,1",
218              "xtype" : "Label",
219              "gint margin" : 3,
220              "$ xns" : "Gtk"
221             },
222             {
223              "label" : "filename",
224              "id" : "path",
225              "xalign" : 0,
226              "* pack" : "attach,1,0,1,1",
227              "xtype" : "Label",
228              "gint margin" : 3,
229              "$ xns" : "Gtk"
230             },
231             {
232              "label" : "HTML template file",
233              "xtype" : "Label",
234              "* pack" : "attach,0,1,1,1",
235              "gint margin" : 3,
236              "$ xns" : "Gtk"
237             },
238             {
239              "listeners" : {
240               "changed" : "() => {\n\tGtk.TreeIter iter;\n \n\t// this get's called when we are filling in the data... ???\n\tif (this.loading) {\n\t\treturn;\n\t}\n\t\n \n\tif (this.el.get_active_iter(out iter)) {\n\t\tValue vfname;\n\t\t_this.base_template_model.el.get_value (iter, 0, out vfname);\n\t\t_this.project.base_template = ((string)vfname) ;\n\t\t\n\t\t print(\"\\nSET base template to %s\\n\", _this.project.base_template );\n\t\t// is_bjs = ((string)vfname) == \"bjs\";\n\t}\n    \n  \n    // directory is only available for non-bjs \n \n\n\n}\n"
241              },
242              "id" : "base_template",
243              "* init" : "this.el.add_attribute(_this.base_template_cellrenderer.el , \"markup\", 0 );",
244              "bool loading" : false,
245              "* pack" : "attach,1,1,1,1",
246              "xtype" : "ComboBox",
247              "$ xns" : "Gtk",
248              "items" : [
249               {
250                "id" : "base_template_cellrenderer",
251                "* pack" : "pack_start,true",
252                "xtype" : "CellRendererText",
253                "$ xns" : "Gtk"
254               },
255               {
256                "id" : "base_template_model",
257                "* pack" : "set_model",
258                "xtype" : "ListStore",
259                "$ columns" : "typeof(string)",
260                "n_columns" : 1,
261                "$ xns" : "Gtk",
262                "| void loadData" : "  () {\n\t_this.base_template.loading = true;\n  \n    this.el.clear();                                    \n    Gtk.TreeIter iter;\n    var el = this.el;\n    \n   /// el.append(out iter);\n    \n   \n    el.append(out iter);\n    el.set_value(iter, 0, \"roo.builder.html\");\n    _this.base_template.el.set_active_iter(iter);\n\tif (_this.project.base_template == \"roo.builder.html\") {\n\t   _this.base_template.el.set_active_iter(iter);\n    }\n\n    el.append(out iter);\n    el.set_value(iter, 0, \"bootstrap.builder.html\");\n \n\tprint(\"\\ncur template = %s\\n\", _this.project.base_template);\n \n    if (_this.project.base_template == \"bootstrap.builder.html\") {\n\t   _this.base_template.el.set_active_iter(iter);\n    }\n\n\tel.append(out iter);\n    el.set_value(iter, 0, \"mailer.builder.html\");\n\n\tif (_this.project.base_template == \"mailer.builder.html\") {\n\t    _this.base_template.el.set_active_iter(iter);\n    }\n\t_this.base_template.loading = false;\n                                     \n}\n"
263               }
264              ]
265             }
266            ]
267           },
268           {
269            "* pack" : "pack_start,true,true,0",
270            "xtype" : "ScrolledWindow",
271            "$ xns" : "Gtk",
272            "items" : [
273             {
274              "listeners" : {
275               "key_release_event" : " ( event) =>{\n    if (event.keyval != 115) {\n        return false;\n         \n    }\n    if   ( (event.state & Gdk.ModifierType.CONTROL_MASK ) < 1 ) {\n        return false;\n    }\n     var buf =    this.el.get_buffer();\n    Gtk.TextIter s;\n    Gtk.TextIter e;\n    buf.get_start_iter(out s);\n    buf.get_end_iter(out e);\n    _this.project.runhtml = buf.get_text(s,e,true);\n    \n          \n    _this.buttonPressed(\"save\");\n     \n    return false;\n         \n}"
276              },
277              "id" : "view",
278              "* init" : " \n    var description =   Pango.FontDescription.from_string(\"monospace\");\n    description.set_size(9000);\n    this.el.override_font(description);",
279              "xtype" : "View",
280              "* pack" : "add",
281              "$ xns" : "GtkSource"
282             }
283            ]
284           }
285          ]
286         },
287         {
288          "* pack" : "append_page,_this.label_database.el",
289          "xtype" : "Box",
290          "gboolean homogeneous" : false,
291          "$ xns" : "Gtk",
292          "Gtk.Orientation orientation" : "Gtk.Orientation.VERTICAL",
293          "items" : [
294           {
295            "label" : "Type (eg. MySQL or PostgreSQL)",
296            "xalign" : 0,
297            "* pack" : "pack_start,false,false,0",
298            "xtype" : "Label",
299            "$ xns" : "Gtk"
300           },
301           {
302            "listeners" : {
303             "key_press_event" : "(ev) => {\n\n    if (ev.keyval == Gdk.Key.Tab) {\n        _this.database_DBNAME.el.grab_focus();\n        return true;\n    }\n\n\n    return false;\n}\n"
304            },
305            "id" : "database_DBTYPE",
306            "xtype" : "Entry",
307            "* pack" : "pack_start,false,false,0",
308            "$ xns" : "Gtk"
309           },
310           {
311            "label" : "Name",
312            "xalign" : 0,
313            "* pack" : "pack_start,false,false,0",
314            "xtype" : "Label",
315            "$ xns" : "Gtk"
316           },
317           {
318            "listeners" : {
319             "key_press_event" : "(ev) => {\n\n    if (ev.keyval == Gdk.Key.Tab) {\n        _this.database_DBUSERNAME.el.grab_focus();\n        return true;\n    }\n\n\n    return false;\n}\n"
320            },
321            "id" : "database_DBNAME",
322            "* pack" : "pack_start,false,false,0",
323            "xtype" : "Entry",
324            "$ xns" : "Gtk"
325           },
326           {
327            "label" : "Username",
328            "xalign" : 0,
329            "* pack" : "pack_start,false,false,0",
330            "xtype" : "Label",
331            "$ xns" : "Gtk"
332           },
333           {
334            "listeners" : {
335             "key_press_event" : "(ev) => {\n\n    if (ev.keyval == Gdk.Key.Tab) {\n        _this.database_DBPASSWORD.el.grab_focus();\n        return true;\n    }\n\n\n    return false;\n}\n"
336            },
337            "id" : "database_DBUSERNAME",
338            "xtype" : "Entry",
339            "* pack" : "pack_start,false,false,0",
340            "$ xns" : "Gtk"
341           },
342           {
343            "label" : "Password",
344            "xalign" : 0,
345            "* pack" : "pack_start,false,false,0",
346            "xtype" : "Label",
347            "$ xns" : "Gtk"
348           },
349           {
350            "id" : "database_DBPASSWORD",
351            "* pack" : "pack_start,false,false,0",
352            "xtype" : "Entry",
353            "$ xns" : "Gtk"
354           },
355           {
356            "listeners" : {
357             "clicked" : "() => {\n\n\n  _this.database_ERROR.el.label    = \"\";\n    Gda.Connection cnc;\n    try {\n        // assumes localhost...\n         cnc = Gda.Connection.open_from_string (\n\t\t\t_this.database_DBTYPE.el.get_text(),\n\t\t\t\"DB_NAME=\" + _this.database_DBNAME.el.get_text(), \n\t\t\t\"USERNAME=\" + _this.database_DBUSERNAME.el.get_text() + \n\t\t\t\";PASSWORD=\" + _this.database_DBPASSWORD.el.get_text(),\n\t\t\tGda.ConnectionOptions.NONE\n\t\t);\n   //} catch (Gda.ConnectionError ce) { \n   //   _this.database_ERROR.el.label = ce.message;        \n   } catch(Gda.ConnectionError ue) {\n      _this.database_ERROR.el.label = ue.message;\n        return;\n   }  catch(Gda.ConfigError ue) {\n      _this.database_ERROR.el.label = ue.message;\n        return;\n   }\n  _this.database_ERROR.el.label = \"Connection Succeeded\";\n   cnc.close();\n}"
358            },
359            "* pack" : "pack_start,false,false,0",
360            "xtype" : "Button",
361            "$ xns" : "Gtk",
362            "utf8 label" : "Check Connection"
363           },
364           {
365            "label" : " ",
366            "id" : "database_ERROR",
367            "xalign" : 0,
368            "* pack" : "pack_start,false,false,0",
369            "xtype" : "Label",
370            "gint margin" : 3,
371            "$ xns" : "Gtk"
372           }
373          ]
374         }
375        ]
376       },
377       {
378        "* pack" : "pack_end,false,false,0",
379        "xtype" : "Box",
380        "gboolean expand" : false,
381        "$ xns" : "Gtk",
382        "Gtk.Orientation orientation" : "Gtk.Orientation.HORIZONTAL",
383        "$ homogeneous" : true,
384        "gboolean vexpand" : false,
385        "items" : [
386         {
387          "listeners" : {
388           "button_press_event" : "() => {\n    _this.save();\n          \n    _this.buttonPressed(\"apply\");\n        return false;\n}"
389          },
390          "label" : "Apply",
391          "xtype" : "Button",
392          "* pack" : "add",
393          "$ xns" : "Gtk"
394         },
395         {
396          "listeners" : {
397           "button_press_event" : "() => {\n       _this.save();\n          \n    _this.buttonPressed(\"save\");\n        return false;\n}"
398          },
399          "label" : "Save",
400          "xtype" : "Button",
401          "* pack" : "add",
402          "$ xns" : "Gtk"
403         }
404        ]
405       }
406      ]
407     }
408    ]
409   }
410  ]
411 }