Changeset 179
- Timestamp:
- 08/21/08 20:30:55 (3 months ago)
- Files:
-
- trunk/microfacts/public/behaviour/app/controllers/geochronopage_controller.js (modified) (1 diff)
- trunk/microfacts/public/behaviour/app/views/mapview.js (moved) (moved from trunk/microfacts/public/behaviour/lib/mapcontroller.js) (11 diffs)
- trunk/microfacts/public/behaviour/app/views/timelineview.js (moved) (moved from trunk/microfacts/public/behaviour/lib/timelinecontroller.js) (5 diffs)
- trunk/microfacts/public/behaviour/lib/domainobject.js (modified) (2 diffs)
- trunk/microfacts/public/behaviour/lib/moovc.js (added)
- trunk/microfacts/public/behaviour/load.js (modified) (7 diffs)
- trunk/microfacts/public/test/index.html (modified) (3 diffs)
- trunk/microfacts/public/test/spec/domain_data.js (added)
- trunk/microfacts/public/test/spec/geochronopage_controller_spec.js (added)
- trunk/microfacts/public/test/spec/mapview_spec.js (moved) (moved from trunk/microfacts/public/test/spec/mapcontroller_spec.js) (7 diffs)
- trunk/microfacts/public/test/spec/timelineview_spec.js (moved) (moved from trunk/microfacts/public/test/spec/timelinecontroller_spec.js) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/microfacts/public/behaviour/app/controllers/geochronopage_controller.js
r172 r179 1 1 var GeochronoPageController = new Class({ 2 Extends: Controller, 2 Extends: BaseController, 3 name: 'GeochronoPageController', 3 4 4 onFactletSelect: function(factlet) { 5 console.log('GeoChronoPageController: saw factletSelect event'); 6 console.log(factlet); 7 this.fireEvent('factletSelect', factlet); 8 }, 5 setupViews: function (element) { 6 this.element.getElements('#map').each(function (el) { 7 this.log("Creating map view for element:"); 8 this.log(el); 9 var view = new MapView(el); 10 this.addView(view); 11 }, this); 12 this.element.getElements('#timeline').each(function (el) { 13 this.log("Creating timeline view for element:"); 14 this.log(el); 15 var view = new TimelineView(el); 16 this.addView(view); 17 }, this); 18 this.log('Done'); 19 20 this.model.startWithThread( 21 payloadThread, // From HTML doc. 22 payloadThreadFactlets // From HTML doc. 23 ); 24 } 9 25 10 onFactletUnselect: function(factlet) {11 console.log('GeoChronoPageController: saw factletUnselect event');12 console.log(factlet);13 this.fireEvent('factletUnselect', factlet);14 },15 16 initialize: function (element) {17 this.initModel();18 console.log('GeochronoPageController: initialize');19 this.controllers = [];20 element.getElements('#map').each(function (el) {21 console.log("Constructing map controller for element:");22 console.log(el);23 var controller = new MapController(el);24 this.addController(controller);25 }, this);26 element.getElements('#timeline').each(function (el) {27 console.log("Constructing timeline controller for element:");28 console.log(el);29 var controller = new TimelineController(el);30 this.addController(controller);31 }, this);32 console.log('Done');33 34 this.model.startWithThread(payloadThread, payloadThreadFactlets);35 },36 37 initModel: function (payloadThread) {38 this.model = new Model();39 this.model.addEvent('threadStart', this.onThreadStart.bind(this));40 },41 42 onThreadStart: function() {43 console.log('ThreadPageController: onThreadStart');44 console.log(arguments);45 this.fireEvent('threadStart', arguments);46 },47 48 addController: function(controller) {49 console.log("Adding controller:");50 console.log(controller);51 this.controllers.push(controller);52 this.addEvent('threadStart', controller.onThreadStart.bind(controller));53 controller.addEvent('factletSelect', this.onFactletSelect.bind(this));54 this.addEvent('factletSelect', controller.onFactletSelect.bind(controller));55 controller.addEvent('factletUnselect', this.onFactletUnselect.bind(this));56 this.addEvent('factletUnselect', controller.onFactletUnselect.bind(controller));57 }58 26 }); 59 27 trunk/microfacts/public/behaviour/app/views/mapview.js
r172 r179 1 // OpenLayers.Feature.Vector.style['default']['strokeWidth'] = '2'; 2 3 var MapController = new Class({ 4 Implements: Events, 5 6 initialize: function (element) { 7 this.element = element; 8 //if (! this.element.id) { 9 // console.error("Map element has no id attribute."); 10 // Now die. 11 //} 12 this.initMap(); 13 //this.addEvent('factletSelect', this.onFactletSelected.bind(this)); 14 }, 15 16 initMap: function () { 1 var MapView = new Class({ 2 Extends: BaseView, 3 name: 'MapView', 4 5 setupView: function () { 17 6 this.map = new OpenLayers.Map(this.element.id); 18 7 this.baseLayer = new OpenLayers.Layer.WMS( … … 70 59 }, 71 60 72 onThreadStart: function() {73 this.factletObjectsById = {};74 console.log("MapController saw threadStart event");75 console.log(arguments);76 this.thread = arguments[0];77 this.factlets = arguments[1];78 this.factlets.each(function (factletObject) {79 this.storeFactletObjectById(factletObject);80 }, this);81 var factletsData = [];82 this.factlets.each(function (factletObject) {83 if (factletObject.data.location) {84 factletsData.push(factletObject.data);85 }86 });87 console.log("Factlet data:");88 console.log(factletsData);89 this.drawFactlets(factletsData);90 },91 92 61 drawFactlets: function(factletsData) { 93 62 var featuresData = this.factletsToGeoJson(factletsData); … … 124 93 var minLon = null; 125 94 var maxLon = null; 126 console.log("Making bounds.");95 this.log("Making bounds."); 127 96 factletsData.each(function (factletData) { 128 97 var location = factletData.location; … … 130 99 var lon = location.coordinates[0]; 131 100 var lat = location.coordinates[1]; 132 console.log("Location:");133 console.log(location);101 this.log("Location:"); 102 this.log(location); 134 103 if (maxLon == null) { 135 104 maxLon = lon; … … 161 130 bounds.extend(new OpenLayers.LonLat(minLon, minLat)); 162 131 bounds.extend(new OpenLayers.LonLat(maxLon, maxLat)); 163 console.log("Zooming to bounds:");164 console.log(bounds);132 this.log("Zooming to bounds:"); 133 this.log(bounds); 165 134 this.map.zoomToExtent(bounds); 166 135 this.map.zoomToScale(0); … … 172 141 173 142 onFeatureSelect: function(feature) { 174 console.log("onFeatureSelect");175 console.log(feature);143 this.log("onFeatureSelect"); 144 this.log(feature); 176 145 var factletId = this.getIdFromFeature(feature); 177 146 var factletObject = this.findFactletObject(factletId); … … 180 149 181 150 getIdFromFeature: function(feature) { 182 console.log("Getting factlet id from feature:");151 this.log("Getting factlet id from feature:"); 183 152 var id = feature.data.factlet.id; 184 console.log(id);153 this.log(id); 185 154 return id; 186 155 }, … … 193 162 194 163 onFactletSelect: function(factletObject) { 195 console.log("MapControllersaw factletSelect event");196 console.log("factletObject:");197 console.log(factletObject);164 this.log("MapView saw factletSelect event"); 165 this.log("factletObject:"); 166 this.log(factletObject); 198 167 if (this.selectedFeature) { 199 168 this.removeFactletSummary(); … … 206 175 207 176 onFactletUnselect: function(factlet) { 208 console.log("MapControllersaw factletUnselect event:");177 this.log("MapView saw factletUnselect event:"); 209 178 if (this.selectedFeature) { 210 179 this.removeFactletSummary(); … … 213 182 }, 214 183 215 findFactletObject: function(factletId) {216 return this.factletObjectsById[factletId];217 },218 219 storeFactletObjectById: function(factletObject) {220 this.factletObjectsById[factletObject.data.id] = factletObject;221 },222 223 184 findFeature: function(factletObject) { 224 console.log("MapController: finding map feature for factlet");225 console.log("factletObject:");226 console.log(factletObject);185 this.log("MapView: finding map feature for factlet"); 186 this.log("factletObject:"); 187 this.log(factletObject); 227 188 var mapFeature = null; 228 189 this.markerLayer.features.each( function(mf) { … … 233 194 } 234 195 }, this); 235 console.log("mapFeature:");236 console.log(mapFeature);196 this.log("mapFeature:"); 197 this.log(mapFeature); 237 198 return mapFeature; 238 199 }, trunk/microfacts/public/behaviour/app/views/timelineview.js
r172 r179 1 var TimelineController = new Class({ 2 Implements: Events, 1 var TimelineView = new Class({ 2 Extends: BaseView, 3 name: 'TimelineView', 3 4 4 initialize: function (element) { 5 this.element = element; 6 this.initTimeline(); 7 }, 8 9 initTimeline: function () { 5 setupView: function () { 10 6 var eventSource = new Timeline.DefaultEventSource(); 11 7 var theme = Timeline.ClassicTheme.create(); … … 44 40 }, 45 41 46 onThreadStart: function() {47 console.log("TimelineController saw threadStart event");48 console.log(arguments);49 this.thread = arguments[0];50 this.factlets = arguments[1]; // Model objects.51 console.log(this.thread);52 console.log("Timeline factlets:");53 console.log(this.factlets);54 55 this.factletObjectsById = {};56 this.factlets.each(function (factletObject) {57 this.storeFactletObjectById(factletObject);58 }, this);59 60 var factletsData = [];61 this.factlets.each(function (factletObject) {62 if (factletObject.data.start) {63 factletsData.push(factletObject.data);64 }65 });66 console.log("Factlet data:");67 console.log(factletsData);68 this.drawFactlets(factletsData);69 },70 71 42 findFactletFromEvent: function(timelineEvent) { 72 43 var factletId = timelineEvent._obj.id; 73 44 return this.findFactletObject(factletId); 74 },75 76 findFactletObject: function(factletId) {77 return this.factletObjectsById[factletId];78 },79 80 storeFactletObjectById: function(factletObject) {81 var factletId = factletObject.data.id;82 this.factletObjectsById[factletId] = factletObject;83 45 }, 84 46 … … 103 65 onEventSelect: function(x, y, timelineEvent) { 104 66 var factletObject = this.findFactletFromEvent(timelineEvent); 105 console.log("TimelineController: fired factletSelect event");106 console.log("factlet object:");107 console.log(factletObject);67 this.log("TimelineView: fired factletSelect event"); 68 this.log("factlet object:"); 69 this.log(factletObject); 108 70 this.fireEvent('factletSelect', factletObject, x, y); 109 71 }, 110 72 111 73 onFactletSelect: function(factletObject, x, y) { 112 console.log("TimelineController: saw factletSelect event");113 console.log("factlet object:");114 console.log(factletObject);74 this.log("TimelineView: saw factletSelect event"); 75 this.log("factlet object:"); 76 this.log(factletObject); 115 77 this.selectedEvent = this.findEvent(factletObject); 116 console.log("selected event:");117 console.log(this.selectedEvent);78 this.log("selected event:"); 79 this.log(this.selectedEvent); 118 80 if (this.selectedEvent) { 119 81 this.scrollSelectedEvent(); … … 121 83 }, 122 84 85 getEventsIterator: function() { 86 return this.eventSource._events.getAllIterator(); 87 }, 88 123 89 findEvent: function(factletObject) { 124 console.log("TimelineController: Finding timeline event for factlet");125 console.log("factlet object:");126 console.log(factletObject);90 this.log("TimelineView: Finding timeline event for factlet"); 91 this.log("factlet object:"); 92 this.log(factletObject); 127 93 var timelineEvent = null; 128 var iterator = this. eventSource._events.getAllIterator()94 var iterator = this.getEventsIterator() 129 95 var te = iterator.next(); 130 96 while(te) { … … 136 102 te = iterator.next(); 137 103 } 138 console.log("timeline event:");139 console.log(timelineEvent);104 this.log("timeline event:"); 105 this.log(timelineEvent); 140 106 return timelineEvent; 141 107 }, 142 108 143 109 scrollEarliestLeft: function() { 144 var d = this.eventSource.getEarliestDate(); 145 console.warn("Earliest date:"); 146 console.warn(d); 147 this.band.setMinVisibleDate(d); 110 var startDate = this.eventSource.getEarliestDate(); 111 this.log("Scrolling earliest left"); 112 this.log("date:"); 113 this.log(startDate); 114 if (startDate) { 115 this.band.setMinVisibleDate(startDate); 116 } 148 117 }, 149 118 150 119 scrollSelectedEvent: function() { 151 console.log("Scrolling event left:"); 152 var start = this.selectedEvent.getStart(); 153 console.log("start:"); 154 console.log(start); 155 this.band.setCenterVisibleDate(start); 120 this.log("Scrolling event centre:"); 121 var startDate = this.selectedEvent.getStart(); 122 this.log("date:"); 123 this.log(startDate); 124 if (startDate) { 125 this.band.setCenterVisibleDate(startDate); 126 } 156 127 }, 157 128 trunk/microfacts/public/behaviour/lib/domainobject.js
r163 r179 1 1 var DomainObject = new Class({ 2 Implements: [Events, Options],2 Extends: BaseModel, 3 3 4 4 options: { … … 59 59 60 60 requestFailure: function (json) { 61 console.error("request failed!");62 console.error(arguments);61 this.error("request failed!"); 62 this.error(arguments); 63 63 } 64 64 }); 65 66 // TODO: Move below functionality to Model. 65 67 66 68 DomainObject.Register = { 'Thread': {}, 'Factlet': {} }; trunk/microfacts/public/behaviour/load.js
r173 r179 36 36 }); 37 37 38 loader.addModule({ 39 name: "simile", 40 type: "js", 41 path: "vendor/simile/timeline/timeline-api.js", 42 varName: "Timeline" 43 }); 44 38 45 // ==================================================== 39 46 // = Base classes, DomainObject, View, Controller, Delegator = … … 41 48 42 49 loader.addModule({ 50 name: "moovc", 51 type: "js", 52 path: "lib/moovc.js?" + Math.random(), 53 requires: ['mootools'], 54 varName: "LayerBase" 55 }); 56 57 loader.addModule({ 43 58 name: "model", 44 59 type: "js", 45 60 path: "app/models/model.js?" + Math.random(), 46 requires: ['moo tools'],61 requires: ['moovc'], 47 62 varName: "Model" 48 63 }); … … 52 67 type: "js", 53 68 path: "lib/domainobject.js?" + Math.random(), 54 requires: ['moo tools'],69 requires: ['moovc'], 55 70 varName: "DomainObject" 56 71 }); … … 60 75 type: "js", 61 76 path: "lib/view.js?" + Math.random(), 62 requires: ['moo tools'],77 requires: ['moovc'], 63 78 varName: "View" 64 79 }); … … 121 136 }); 122 137 138 loader.addModule({ 139 name: "mapview", 140 type: "js", 141 path: "app/views/mapview.js?" + Math.random(), 142 requires: ['moovc', 'openlayers'], 143 varName: "MapView" 144 }); 145 146 loader.addModule({ 147 name: "timelineview", 148 type: "js", 149 path: "app/views/timelineview.js?" + Math.random(), 150 requires: ['moovc', 'simile'], 151 varName: "TimelineView" 152 }); 153 123 154 // =============== 124 155 // = Controllers = … … 163 194 164 195 loader.addModule({ 165 name: "simile",166 type: "js",167 path: "vendor/simile/timeline/timeline-api.js",168 varName: "Timeline"169 });170 171 loader.addModule({172 name: "mapcontroller",173 type: "js",174 path: "lib/mapcontroller.js?" + Math.random(),175 requires: ['controller', 'openlayers'],176 varName: "MapController"177 });178 179 loader.addModule({180 name: "timelinecontroller",181 type: "js",182 path: "lib/timelinecontroller.js?" + Math.random(),183 requires: ['mootools', 'simile'],184 varName: "TimelineController"185 });186 187 loader.addModule({188 196 name: "microfacts", 189 197 type: "js", 190 198 path: "app/microfacts.js?" + Math.random(), 191 requires: ['domainobject', 'view', 'controller', 'microfactscontroller', 'factletcontroller', 'threadfactletscontroller', 'map controller', 'timelinecontroller'],199 requires: ['domainobject', 'view', 'controller', 'microfactscontroller', 'factletcontroller', 'threadfactletscontroller', 'mapview', 'timelineview', 'geochronopagecontroller'], 192 200 varName: "Microfacts" 193 201 }); … … 205 213 type: "js", 206 214 path: "app/controllers/geochronopage_controller.js?" + Math.random(), 207 requires: ['mo del', 'domainobject', 'view', 'controller', 'thread', 'factlet', 'mapcontroller', 'timelinecontroller'],215 requires: ['moovc', 'model', 'domainobject', 'view', 'controller', 'thread', 'factlet', 'mapview', 'timelineview'], 208 216 varName: "GeochronoPageController" 209 217 }); trunk/microfacts/public/test/index.html
r176 r179 30 30 position: absolute; 31 31 bottom: 0; 32 visibility: hidden; 32 33 } 33 34 </style> … … 49 50 </script> 50 51 52 <script type="text/javascript" src="spec/domain_data.js?123"></script> 51 53 <script type="text/javascript" src="spec/model_spec.js?123"></script> 52 54 <script type="text/javascript" src="spec/controller_spec.js?123"></script> 53 55 <script type="text/javascript" src="spec/view_spec.js?123"></script> 56 <script type="text/javascript" src="spec/mapview_spec.js?123"></script> 57 <script type="text/javascript" src="spec/timelineview_spec.js?123"></script> 58 <script type="text/javascript" src="spec/geochronopage_controller_spec.js?123"></script> 59 <!-- 54 60 <script type="text/javascript" src="spec/threadfactletscontroller_spec.js?123"></script> 55 <!--56 <script type="text/javascript" src="spec/mapcontroller_spec.js?123"></script>57 <script type="text/javascript" src="spec/timelinecontroller_spec.js?123"></script>58 61 --> 59 62 … … 98 101 </div> 99 102 </div> 100 103 104 <script type="text/javascript" charset="utf-8"> 105 var payloadThread = {"factlets": [1030, 1031, 1032], "id": 364, "title": "The Bloomsbury Group"}; 106 var payloadThreadFactlets = [{"end": "1941-03-28 00:00:00", "description": "(Adeline) Virginia Woolf (n\u00e9e Stephen; 25 January 1882 \u2013 28 March 1941) was an English novelist and essayist regarded as one of the foremost modernist literary figures of the twentieth century.\n\nDuring the interwar period, Woolf was a significant figure in London literary society and a member of the Bloomsbury Group. Her most famous works include the novels Mrs Dalloway (1925), To the Lighthouse (1927), and Orlando (1928), and the book-length essay A Room of One's Own (1929) with its famous dictum, 'a woman must have money and a room of her own if she is to write fiction.'", "title": "Virginia Woolf", "start": "1882-01-25 00:00:00", "location": {"type": "Point", "coordinates": [-0.12553, 51.50842]}, "id": 1030}, {"end": "1932-01-21 00:00:00", "description": "British writer and critic. He is best known for establishing a new form of biography in which psychological insight and sympathy are combined with irreverence and wit. His 1921 biography Queen Victoria was awarded the James Tait Black Memorial Prize.", "title": "Lytton Strachey", "start": "1880-03-01 00:00:00", "location": null, "id": 1031}, {"end": "1946-04-21 00:00:00", "description": "John Maynard Keynes, 1st Baron Keynes (Styled: The Rt. Hon. The Lord Keynes), CB (5 June 1883 \u2013 21 April 1946) was a British economist whose ideas, called Keynesian economics, had a major impact on modern economic and political theory as well as on many governments' fiscal policies. He advocated interventionist government policy, by which the government would use fiscal and monetary measures to mitigate the adverse effects of economic recessions, depressions and booms. He is one of the fathers of modern theoretical macroeconomics.", "title": "John Maynard Keynes", "start": "1883-06-05 00:00:00", "location": null, "id": 1032}]; 107 </script> 108 101 109 </body> 102 110 </html> trunk/microfacts/public/test/spec/mapview_spec.js
r154 r179 1 var factlets = [ 2 { 3 'id': 101, 4 'title': 'My Factlet', 5 'location' : { 6 "type": "Point", 7 "coordinates": [51.50842, -0.12553] 8 } 9 }, 10 { 11 'id': 102, 12 'title': 'Your Factlet', 13 'location' : { 14 "type": "Point", 15 "coordinates": [0, 0] 16 } 17 } 18 ]; 19 20 describe('MapController', { 1 describe('MapView', { 21 2 22 3 // 0. Instantiate javascript object. … … 31 12 before_each: function () { 32 13 var elem = $('map'); 33 m = new Map Controller(elem);14 m = new MapView(elem); 34 15 }, 35 16 … … 43 24 44 25 'should convert factlets to GeoJSON': function () { 45 var geojson = m.factletsToGeoJson(factlets );26 var geojson = m.factletsToGeoJson(factletsData); 46 27 expect(geojson.type).should_be("FeatureCollection"); 47 28 expect(geojson.features[0].type).should_be("Feature"); … … 80 61 }, 81 62 82 'should draw factlet on map': function () {83 expect($chk(m.drawFactlets(factlets ))).should_be(false);63 'should draw factlets on map': function () { 64 expect($chk(m.drawFactlets(factletsData))).should_be(false); 84 65 }, 85 66 … … 89 70 returns.push('factletSelect event fired!'); 90 71 }); 91 m. drawFactlets(factlets);72 m.onThreadStart(threadObject, factletObjects); 92 73 m.onFeatureSelect(m.markerLayer.features[0]); 93 74 expect(returns).should_be(['factletSelect event fired!']); … … 99 80 returns.push('factletSelect event fired!'); 100 81 }); 101 m. drawFactlets(factlets);102 m.onFactletSelect(factlet s[0]);82 m.onThreadStart(threadObject, factletObjects); 83 m.onFactletSelect(factletObjects[0]); 103 84 expect(returns).should_be([]); 104 85 }, … … 110 91 returns.push('factletSelect event fired!'); 111 92 }); 112 m. drawFactlets(factlets);93 m.onThreadStart(threadObject, factletObjects); 113 94 m.onFeatureSelect(m.markerLayer.features[0]); 114 95 expect(returns).should_be(['factletSelect event fired!']); trunk/microfacts/public/test/spec/timelineview_spec.js
r154 r179 1 var factlets = [ 2 { 3 'id': 101, 4 'title': 'My Factlet', 5 'location' : { 6 "type": "Point", 7 "coordinates": [51.50842, -0.12553] 8 }, 9 'start': '1920', 10 'end': '1921' 11 }, 12 { 13 'id': 102, 14 'title': 'Your Factlet', 15 'location' : { 16 "type": "Point", 17 "coordinates": [0, 0] 18 }, 19 'start': '1925' 20 } 21 ]; 22 23 describe('TimelineController', { 1 describe('TimelineView', { 24 2 25 3 // 0. Instantiate javascript object. … … 34 12 before_each: function () { 35 13 var elem = $('timeline'); 36 t = new Timeline Controller(elem);14 t = new TimelineView(elem); 37 15 }, 38 16 … … 46 24 47 25 'should draw factlet on timeline': function () { 48 expect(t. drawFactlets(factlets)).should_be(undefined);26 expect(t.onThreadStart(threadObject, factletObjects)).should_be(undefined); 49 27 }, 50 28 … … 54 32 returns.push('factletSelect event fired!'); 55 33 }); 56 t.drawFactlets(factlets); 57 var event = t.simile.getBand(0).getEventSource()._events.getAllIterator().next(); 58 t.onEventSelect(0, 0 , event); 34 t.onThreadStart(threadObject, factletObjects); 35 var timelineEvent = t.getEventsIterator().next(); 36 expect($chk(timelineEvent)).should_be(true); 37 t.onEventSelect(0, 0 , timelineEvent); 59 38 expect(returns).should_be(['factletSelect event fired!']); 60 39 }, … … 65 44 returns.push('factletSelect event fired!'); 66 45 }); 67 t. drawFactlets(factlets);68 t.onFactletSelect(factlet s[0]);46 t.onThreadStart(threadObject, factletObjects); 47 t.onFactletSelect(factletObjects[0]); 69 48 expect(returns).should_be([]); 70 49 }, … … 77 56 returns.push('factletSelect event fired!'); 78 57 }); 79 t. drawFactlets(factlets);80 var event = t.simile.getBand(0).getEventSource()._events.getAllIterator().next();81 t.onEventSelect(0, 0 , event);58 t.onThreadStart(threadObject, factletObjects); 59 var timelineEvent = t.simile.getBand(0).getEventSource()._events.getAllIterator().next(); 60 t.onEventSelect(0, 0 , timelineEvent); 82 61 expect(returns).should_be(['factletSelect event fired!']); 83 62 }
