Show More
@@ -39,7 +39,8 b' var IPython = (function (IPython) {' | |||||
39 | this.placeholder = options.placeholder || ''; |
|
39 | this.placeholder = options.placeholder || ''; | |
40 | this.read_only = options.cm_config.readOnly; |
|
40 | this.read_only = options.cm_config.readOnly; | |
41 | this.selected = false; |
|
41 | this.selected = false; | |
42 |
this. |
|
42 | this.rendered = false; | |
|
43 | this.mode = 'command'; | |||
43 | this.metadata = {}; |
|
44 | this.metadata = {}; | |
44 | // load this from metadata later ? |
|
45 | // load this from metadata later ? | |
45 | this.user_highlight = 'auto'; |
|
46 | this.user_highlight = 'auto'; | |
@@ -133,44 +134,121 b' var IPython = (function (IPython) {' | |||||
133 | if (window.MathJax){ |
|
134 | if (window.MathJax) { | |
134 | var cell_math = this.element.get(0); |
|
135 | var cell_math = this.element.get(0); | |
135 | MathJax.Hub.Queue(["Typeset", MathJax.Hub, cell_math]); |
|
136 | MathJax.Hub.Queue(["Typeset", MathJax.Hub, cell_math]); | |
136 | } |
|
137 | }; | |
137 | }; |
|
138 | }; | |
138 |
|
139 | |||
139 | /** |
|
140 | /** | |
140 | * handle cell level logic when a cell is selected |
|
141 | * handle cell level logic when a cell is selected | |
141 | * @method select |
|
142 | * @method select | |
|
143 | * @return is the action being taken | |||
142 | */ |
|
144 | */ | |
143 | Cell.prototype.select = function () { |
|
145 | Cell.prototype.select = function () { | |
|
146 | if (!this.selected) { | |||
144 | this.element.addClass('selected'); |
|
147 | this.element.addClass('selected'); | |
|
148 | this.element.removeClass('unselected'); | |||
145 | this.selected = true; |
|
149 | this.selected = true; | |
|
150 | return true; | |||
|
151 | } else { | |||
|
152 | return false; | |||
|
153 | }; | |||
146 | }; |
|
154 | }; | |
147 |
|
155 | |||
148 | /** |
|
156 | /** | |
149 | * handle cell level logic when a cell is unselected |
|
157 | * handle cell level logic when a cell is unselected | |
150 | * @method unselect |
|
158 | * @method unselect | |
|
159 | * @return is the action being taken | |||
151 | */ |
|
160 | */ | |
152 | Cell.prototype.unselect = function () { |
|
161 | Cell.prototype.unselect = function () { | |
|
162 | if (this.selected) { | |||
|
163 | this.element.addClass('unselected'); | |||
153 | this.element.removeClass('selected'); |
|
164 | this.element.removeClass('selected'); | |
154 | this.selected = false; |
|
165 | this.selected = false; | |
|
166 | return true; | |||
|
167 | } else { | |||
|
168 | return false; | |||
|
169 | }; | |||
155 | }; |
|
170 | }; | |
156 |
|
171 | |||
157 | /** |
|
172 | /** | |
158 |
* handle cell level logic when a cell is |
|
173 | * handle cell level logic when a cell is rendered | |
159 |
* @method |
|
174 | * @method render | |
|
175 | * @return is the action being taken | |||
160 | */ |
|
176 | */ | |
161 |
Cell.prototype. |
|
177 | Cell.prototype.render = function () { | |
162 | this.element.addClass('focused'); |
|
178 | if (!this.rendered) { | |
163 | this.focused = true; |
|
179 | this.element.addClass('rendered'); | |
|
180 | this.element.removeClass('unrendered'); | |||
|
181 | this.rendered = true; | |||
|
182 | return true; | |||
|
183 | } else { | |||
|
184 | return false; | |||
|
185 | }; | |||
|
186 | }; | |||
|
187 | ||||
|
188 | /** | |||
|
189 | * handle cell level logic when a cell is unrendered | |||
|
190 | * @method unrender | |||
|
191 | * @return is the action being taken | |||
|
192 | */ | |||
|
193 | Cell.prototype.unrender = function () { | |||
|
194 | if (this.rendered) { | |||
|
195 | this.element.addClass('unrendered'); | |||
|
196 | this.element.removeClass('rendered'); | |||
|
197 | this.rendered = false; | |||
|
198 | return true; | |||
|
199 | } else { | |||
|
200 | return false; | |||
|
201 | }; | |||
164 | }; |
|
202 | }; | |
165 |
|
203 | |||
166 | /** |
|
204 | /** | |
167 | * handle cell level logic when a cell is unfocused |
|
205 | * enter the command mode for the cell | |
168 |
* @method |
|
206 | * @method command_mode | |
|
207 | * @return is the action being taken | |||
169 | */ |
|
208 | */ | |
170 |
Cell.prototype. |
|
209 | Cell.prototype.command_mode = function () { | |
171 | this.element.removeClass('focused'); |
|
210 | if (this.mode !== 'command') { | |
172 | this.focused = false; |
|
211 | this.element.addClass('command_mode'); | |
|
212 | this.element.removeClass('edit_mode'); | |||
|
213 | this.mode = 'command'; | |||
|
214 | return true; | |||
|
215 | } else { | |||
|
216 | return false; | |||
173 | }; |
|
217 | }; | |
|
218 | }; | |||
|
219 | ||||
|
220 | /** | |||
|
221 | * enter the edit mode for the cell | |||
|
222 | * @method command_mode | |||
|
223 | * @return is the action being taken | |||
|
224 | */ | |||
|
225 | Cell.prototype.edit_mode = function () { | |||
|
226 | if (this.mode !== 'edit') { | |||
|
227 | this.element.addClass('edit_mode'); | |||
|
228 | this.element.removeClass('command_mode'); | |||
|
229 | this.mode = 'edit'; | |||
|
230 | return true; | |||
|
231 | } else { | |||
|
232 | return false; | |||
|
233 | }; | |||
|
234 | } | |||
|
235 | ||||
|
236 | /** | |||
|
237 | * Focus the cell in the DOM sense | |||
|
238 | * @method focus_cell | |||
|
239 | */ | |||
|
240 | Cell.prototype.focus_cell = function () { | |||
|
241 | this.element.focus(); | |||
|
242 | } | |||
|
243 | ||||
|
244 | /** | |||
|
245 | * Focus the editor area so a user can type | |||
|
246 | * @method focus_editor | |||
|
247 | */ | |||
|
248 | Cell.prototype.focus_editor = function () { | |||
|
249 | this.code_mirror.refresh(); | |||
|
250 | this.code_mirror.focus(); | |||
|
251 | } | |||
174 |
|
252 | |||
175 | /** |
|
253 | /** | |
176 | * should be overritten by subclass |
|
254 | * should be overritten by subclass |
@@ -149,11 +149,15 b' var IPython = (function (IPython) {' | |||||
149 | CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) { |
|
149 | CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) { | |
150 |
|
150 | |||
151 | var that = this; |
|
151 | var that = this; | |
|
152 | ||||
|
153 | if (this.mode === 'command') { | |||
|
154 | return false | |||
|
155 | } else if (this.mode === 'edit') { | |||
152 | // whatever key is pressed, first, cancel the tooltip request before |
|
156 | // whatever key is pressed, first, cancel the tooltip request before | |
153 | // they are sent, and remove tooltip if any, except for tab again |
|
157 | // they are sent, and remove tooltip if any, except for tab again | |
154 | if (event.type === 'keydown' && event.which != key.TAB ) { |
|
158 | if (event.type === 'keydown' && event.which != key.TAB ) { | |
155 | IPython.tooltip.remove_and_cancel_tooltip(); |
|
159 | IPython.tooltip.remove_and_cancel_tooltip(); | |
156 | } |
|
160 | }; | |
157 |
|
161 | |||
158 | var cur = editor.getCursor(); |
|
162 | var cur = editor.getCursor(); | |
159 | if (event.keyCode === key.ENTER){ |
|
163 | if (event.keyCode === key.ENTER){ | |
@@ -163,6 +167,7 b' var IPython = (function (IPython) {' | |||||
163 | if (event.keyCode === key.ENTER && (event.shiftKey || event.ctrlKey)) { |
|
167 | if (event.keyCode === key.ENTER && (event.shiftKey || event.ctrlKey)) { | |
164 | // Always ignore shift-enter in CodeMirror as we handle it. |
|
168 | // Always ignore shift-enter in CodeMirror as we handle it. | |
165 | return true; |
|
169 | return true; | |
|
170 | ||||
166 | } else if (event.which === 40 && event.type === 'keypress' && IPython.tooltip.time_before_tooltip >= 0) { |
|
171 | } else if (event.which === 40 && event.type === 'keypress' && IPython.tooltip.time_before_tooltip >= 0) { | |
167 | // triger on keypress (!) otherwise inconsistent event.which depending on plateform |
|
172 | // triger on keypress (!) otherwise inconsistent event.which depending on plateform | |
168 | // browser and keyboard layout ! |
|
173 | // browser and keyboard layout ! | |
@@ -178,9 +183,10 b' var IPython = (function (IPython) {' | |||||
178 | return false; |
|
183 | return false; | |
179 | } else { |
|
184 | } else { | |
180 | return true; |
|
185 | return true; | |
181 | } |
|
186 | }; | |
182 | } else if (event.which === key.ESC) { |
|
187 | } else if (event.which === key.ESC) { | |
183 |
|
|
188 | IPython.tooltip.remove_and_cancel_tooltip(true); | |
|
189 | return true; | |||
184 | } else if (event.which === key.DOWNARROW && event.type === 'keydown') { |
|
190 | } else if (event.which === key.DOWNARROW && event.type === 'keydown') { | |
185 | // If we are not at the bottom, let CM handle the down arrow and |
|
191 | // If we are not at the bottom, let CM handle the down arrow and | |
186 | // prevent the global keydown handler from handling it. |
|
192 | // prevent the global keydown handler from handling it. | |
@@ -189,7 +195,7 b' var IPython = (function (IPython) {' | |||||
189 | return false; |
|
195 | return false; | |
190 | } else { |
|
196 | } else { | |
191 | return true; |
|
197 | return true; | |
192 | } |
|
198 | }; | |
193 | } else if (event.keyCode === key.TAB && event.type == 'keydown' && event.shiftKey) { |
|
199 | } else if (event.keyCode === key.TAB && event.type == 'keydown' && event.shiftKey) { | |
194 | if (editor.somethingSelected()){ |
|
200 | if (editor.somethingSelected()){ | |
195 | var anchor = editor.getCursor("anchor"); |
|
201 | var anchor = editor.getCursor("anchor"); | |
@@ -198,6 +204,7 b' var IPython = (function (IPython) {' | |||||
198 | return false; |
|
204 | return false; | |
199 | } |
|
205 | } | |
200 | } |
|
206 | } | |
|
207 | } | |||
201 | IPython.tooltip.request(that); |
|
208 | IPython.tooltip.request(that); | |
202 | event.stop(); |
|
209 | event.stop(); | |
203 | return true; |
|
210 | return true; | |
@@ -213,14 +220,11 b' var IPython = (function (IPython) {' | |||||
213 | // is empty. In this case, let CodeMirror handle indentation. |
|
220 | // is empty. In this case, let CodeMirror handle indentation. | |
214 | return false; |
|
221 | return false; | |
215 | } else { |
|
222 | } else { | |
216 | event.stop(); |
|
|||
217 | this.completer.startCompletion(); |
|
|||
218 | return true; |
|
|||
219 | } |
|
|||
220 | } else { |
|
|||
221 | // keypress/keyup also trigger on TAB press, and we don't want to |
|
223 | // keypress/keyup also trigger on TAB press, and we don't want to | |
222 | // use those to disable tab completion. |
|
224 | // use those to disable tab completion. | |
223 | return false; |
|
225 | return false; | |
|
226 | }; | |||
|
227 | return false; | |||
224 | } |
|
228 | } | |
225 | return false; |
|
229 | return false; | |
226 | }; |
|
230 | }; | |
@@ -304,20 +308,45 b' var IPython = (function (IPython) {' | |||||
304 | // Basic cell manipulation. |
|
308 | // Basic cell manipulation. | |
305 |
|
309 | |||
306 | CodeCell.prototype.select = function () { |
|
310 | CodeCell.prototype.select = function () { | |
307 | IPython.Cell.prototype.select.apply(this); |
|
311 | var continue = IPython.Cell.prototype.select.apply(this); | |
|
312 | if (continue) { | |||
308 | this.code_mirror.refresh(); |
|
313 | this.code_mirror.refresh(); | |
309 | this.auto_highlight(); |
|
314 | this.auto_highlight(); | |
310 | }; |
|
315 | }; | |
|
316 | return continue; | |||
|
317 | }; | |||
|
318 | ||||
|
319 | CodeCell.prototype.render = function () { | |||
|
320 | var continue = IPython.Cell.prototype.render.apply(this); | |||
|
321 | if (continue) { | |||
|
322 | this.execute(); | |||
|
323 | }; | |||
|
324 | return continue; | |||
|
325 | }; | |||
|
326 | ||||
|
327 | CodeCell.prototype.unrender = function () { | |||
|
328 | var continue = IPython.Cell.prototype.unrender.apply(this); | |||
|
329 | if (continue) { | |||
|
330 | this.clear_output(true, true, true); | |||
|
331 | }; | |||
|
332 | return continue; | |||
|
333 | }; | |||
311 |
|
334 | |||
312 |
CodeCell.prototype. |
|
335 | CodeCell.prototype.command_mode = function () { | |
313 |
IPython.Cell.prototype. |
|
336 | var continue = IPython.Cell.prototype.command_mode.apply(this); | |
314 | this.code_mirror.focus(); |
|
337 | if (continue) { | |
|
338 | this.focus_cell(); | |||
315 | }; |
|
339 | }; | |
|
340 | return continue; | |||
|
341 | } | |||
316 |
|
342 | |||
317 |
CodeCell.prototype. |
|
343 | CodeCell.prototype.edit_mode = function () { | |
318 |
IPython.Cell.prototype. |
|
344 | var continue = IPython.Cell.prototype.edit_mode.apply(this); | |
319 | this.code_mirror.blur(); |
|
345 | if (continue) { | |
|
346 | this.focus_editor(); | |||
320 | }; |
|
347 | }; | |
|
348 | return continue; | |||
|
349 | } | |||
321 |
|
350 | |||
322 | CodeCell.prototype.select_all = function () { |
|
351 | CodeCell.prototype.select_all = function () { | |
323 | var start = {line: 0, ch: 0}; |
|
352 | var start = {line: 0, ch: 0}; |
@@ -946,7 +946,7 b' var IPython = (function (IPython) {' | |||||
946 | text = ''; |
|
946 | text = ''; | |
947 | }; |
|
947 | }; | |
948 | // The edit must come before the set_text. |
|
948 | // The edit must come before the set_text. | |
949 |
target_cell. |
|
949 | target_cell.unrender(); | |
950 | target_cell.set_text(text); |
|
950 | target_cell.set_text(text); | |
951 | // make this value the starting point, so that we can only undo |
|
951 | // make this value the starting point, so that we can only undo | |
952 | // to this state, instead of a blank cell |
|
952 | // to this state, instead of a blank cell | |
@@ -976,7 +976,7 b' var IPython = (function (IPython) {' | |||||
976 | text = ''; |
|
976 | text = ''; | |
977 | }; |
|
977 | }; | |
978 | // The edit must come before the set_text. |
|
978 | // The edit must come before the set_text. | |
979 |
target_cell. |
|
979 | target_cell.unrender(); | |
980 | target_cell.set_text(text); |
|
980 | target_cell.set_text(text); | |
981 | // make this value the starting point, so that we can only undo |
|
981 | // make this value the starting point, so that we can only undo | |
982 | // to this state, instead of a blank cell |
|
982 | // to this state, instead of a blank cell | |
@@ -1011,7 +1011,7 b' var IPython = (function (IPython) {' | |||||
1011 | }; |
|
1011 | }; | |
1012 | // The edit must come before the set_text. |
|
1012 | // The edit must come before the set_text. | |
1013 | target_cell.set_level(level); |
|
1013 | target_cell.set_level(level); | |
1014 |
target_cell. |
|
1014 | target_cell.unrender(); | |
1015 | target_cell.set_text(text); |
|
1015 | target_cell.set_text(text); | |
1016 | // make this value the starting point, so that we can only undo |
|
1016 | // make this value the starting point, so that we can only undo | |
1017 | // to this state, instead of a blank cell |
|
1017 | // to this state, instead of a blank cell | |
@@ -1179,7 +1179,7 b' var IPython = (function (IPython) {' | |||||
1179 | cell.set_text(textb); |
|
1179 | cell.set_text(textb); | |
1180 | cell.render(); |
|
1180 | cell.render(); | |
1181 | var new_cell = this.insert_cell_above('markdown'); |
|
1181 | var new_cell = this.insert_cell_above('markdown'); | |
1182 |
new_cell. |
|
1182 | new_cell.unrender(); // editor must be visible to call set_text | |
1183 | new_cell.set_text(texta); |
|
1183 | new_cell.set_text(texta); | |
1184 | new_cell.render(); |
|
1184 | new_cell.render(); | |
1185 | this.select_next(); |
|
1185 | this.select_next(); | |
@@ -1208,7 +1208,7 b' var IPython = (function (IPython) {' | |||||
1208 | if (cell instanceof IPython.CodeCell) { |
|
1208 | if (cell instanceof IPython.CodeCell) { | |
1209 | cell.set_text(upper_text+'\n'+text); |
|
1209 | cell.set_text(upper_text+'\n'+text); | |
1210 | } else if (cell instanceof IPython.MarkdownCell) { |
|
1210 | } else if (cell instanceof IPython.MarkdownCell) { | |
1211 |
cell. |
|
1211 | cell.unrender(); | |
1212 | cell.set_text(upper_text+'\n'+text); |
|
1212 | cell.set_text(upper_text+'\n'+text); | |
1213 | cell.render(); |
|
1213 | cell.render(); | |
1214 | }; |
|
1214 | }; | |
@@ -1238,7 +1238,7 b' var IPython = (function (IPython) {' | |||||
1238 | if (cell instanceof IPython.CodeCell) { |
|
1238 | if (cell instanceof IPython.CodeCell) { | |
1239 | cell.set_text(text+'\n'+lower_text); |
|
1239 | cell.set_text(text+'\n'+lower_text); | |
1240 | } else if (cell instanceof IPython.MarkdownCell) { |
|
1240 | } else if (cell instanceof IPython.MarkdownCell) { | |
1241 |
cell. |
|
1241 | cell.unrender(); | |
1242 | cell.set_text(text+'\n'+lower_text); |
|
1242 | cell.set_text(text+'\n'+lower_text); | |
1243 | cell.render(); |
|
1243 | cell.render(); | |
1244 | }; |
|
1244 | }; |
@@ -104,13 +104,13 b' var IPython = (function (IPython) {' | |||||
104 | this.element.keydown(function (event) { |
|
104 | this.element.keydown(function (event) { | |
105 | if (event.which === 13 && !event.shiftKey) { |
|
105 | if (event.which === 13 && !event.shiftKey) { | |
106 | if (that.rendered) { |
|
106 | if (that.rendered) { | |
107 |
that. |
|
107 | that.unrender(); | |
108 | return false; |
|
108 | return false; | |
109 | }; |
|
109 | }; | |
110 | }; |
|
110 | }; | |
111 | }); |
|
111 | }); | |
112 | this.element.dblclick(function () { |
|
112 | this.element.dblclick(function () { | |
113 |
that. |
|
113 | that.unrender(); | |
114 | }); |
|
114 | }); | |
115 | }; |
|
115 | }; | |
116 |
|
116 | |||
@@ -134,57 +134,59 b' var IPython = (function (IPython) {' | |||||
134 | return false; |
|
134 | return false; | |
135 | }; |
|
135 | }; | |
136 |
|
136 | |||
137 | /** |
|
137 | // Cell level actions | |
138 | * Select the current cell and trigger 'focus' |
|
138 | ||
139 | * @method select |
|
|||
140 | */ |
|
|||
141 | TextCell.prototype.select = function () { |
|
139 | TextCell.prototype.select = function () { | |
142 | IPython.Cell.prototype.select.apply(this); |
|
140 | var continue = IPython.Cell.prototype.select.apply(this); | |
143 | var output = this.element.find("div.text_cell_render"); |
|
141 | if (continue) { | |
144 | output.trigger('focus'); |
|
142 | if (this.mode === 'edit') { | |
|
143 | this.code_mirror.refresh(); | |||
|
144 | } | |||
|
145 | }; | |||
|
146 | return continue; | |||
145 | }; |
|
147 | }; | |
146 |
|
148 | |||
147 | /** |
|
149 | TextCell.prototype.render = function () { | |
148 | * unselect the current cell and `render` it |
|
150 | var continue = IPython.Cell.prototype.render.apply(this); | |
149 | * @method unselect |
|
151 | if (continue) { | |
150 | */ |
|
152 | this.execute(); | |
151 | TextCell.prototype.unselect = function() { |
|
153 | }; | |
152 | // render on selection of another cell |
|
154 | return continue; | |
153 | this.render(); |
|
|||
154 | IPython.Cell.prototype.unselect.apply(this); |
|
|||
155 | }; |
|
155 | }; | |
156 |
|
156 | |||
157 | /** |
|
157 | TextCell.prototype.unrender = function () { | |
158 | * |
|
158 | if (this.read_only) return; | |
159 | * put the current cell in edition mode |
|
159 | var continue = IPython.Cell.prototype.unrender.apply(this); | |
160 | * @method edit |
|
160 | if (continue) { | |
161 | */ |
|
|||
162 | TextCell.prototype.edit = function () { |
|
|||
163 | if (this.rendered === true) { |
|
|||
164 | var text_cell = this.element; |
|
161 | var text_cell = this.element; | |
165 | var output = text_cell.find("div.text_cell_render"); |
|
162 | var output = text_cell.find("div.text_cell_render"); | |
166 | output.hide(); |
|
163 | output.hide(); | |
167 | text_cell.find('div.text_cell_input').show(); |
|
164 | text_cell.find('div.text_cell_input').show(); | |
168 |
this. |
|
165 | this.focus_editor(); | |
169 | this.code_mirror.focus(); |
|
|||
170 | // We used to need an additional refresh() after the focus, but |
|
|||
171 | // it appears that this has been fixed in CM. This bug would show |
|
|||
172 | // up on FF when a newly loaded markdown cell was edited. |
|
|||
173 | this.rendered = false; |
|
|||
174 | if (this.get_text() === this.placeholder) { |
|
166 | if (this.get_text() === this.placeholder) { | |
175 | this.set_text(''); |
|
167 | this.set_text(''); | |
176 | this.refresh(); |
|
168 | this.refresh(); | |
177 | } |
|
169 | } | |
178 | } |
|
|||
179 | }; |
|
|||
180 |
|
170 | |||
|
171 | }; | |||
|
172 | return continue; | |||
|
173 | }; | |||
181 |
|
174 | |||
182 | /** |
|
175 | TextCell.prototype.command_mode = function () { | |
183 | * Empty, Subclasses must define render. |
|
176 | var continue = IPython.Cell.prototype.command_mode.apply(this); | |
184 | * @method render |
|
177 | if (continue) { | |
185 | */ |
|
178 | this.focus_cell(); | |
186 | TextCell.prototype.render = function () {}; |
|
179 | }; | |
|
180 | return continue; | |||
|
181 | } | |||
187 |
|
182 | |||
|
183 | TextCell.prototype.edit_mode = function () { | |||
|
184 | var continue = IPython.Cell.prototype.edit_mode.apply(this); | |||
|
185 | if (continue) { | |||
|
186 | this.focus_editor(); | |||
|
187 | }; | |||
|
188 | return continue; | |||
|
189 | } | |||
188 |
|
190 | |||
189 | /** |
|
191 | /** | |
190 | * setter: {{#crossLink "TextCell/set_text"}}{{/crossLink}} |
|
192 | * setter: {{#crossLink "TextCell/set_text"}}{{/crossLink}} | |
@@ -382,11 +384,12 b' var IPython = (function (IPython) {' | |||||
382 |
|
384 | |||
383 | /** @method render **/ |
|
385 | /** @method render **/ | |
384 | RawCell.prototype.render = function () { |
|
386 | RawCell.prototype.render = function () { | |
|
387 | ||||
385 | this.rendered = true; |
|
388 | this.rendered = true; | |
386 | var text = this.get_text(); |
|
389 | var text = this.get_text(); | |
387 | if (text === "") { text = this.placeholder; } |
|
390 | if (text === "") { text = this.placeholder; } | |
388 | console.log('rendering', text); |
|
|||
389 | this.set_text(text); |
|
391 | this.set_text(text); | |
|
392 | this.unrender(); | |||
390 | }; |
|
393 | }; | |
391 |
|
394 | |||
392 |
|
395 |
General Comments 0
You need to be logged in to leave comments.
Login now