Committed by
Gerrit Code Review
ONOS-3129 : GUI Intents to Topo :: part 2 - pushing data through topo view and h…
…aving the intent path show up. Change-Id: Ie626a46e189d2b704d683e0f58762a68cd3d3a7d
Showing
9 changed files
with
101 additions
and
12 deletions
| ... | @@ -27,6 +27,7 @@ public final class AppIdFormatter extends AbstractCellFormatter { | ... | @@ -27,6 +27,7 @@ public final class AppIdFormatter extends AbstractCellFormatter { |
| 27 | // non-instantiable | 27 | // non-instantiable |
| 28 | private AppIdFormatter() { } | 28 | private AppIdFormatter() { } |
| 29 | 29 | ||
| 30 | + // NOTE: do not change this format; we parse it on the client side. | ||
| 30 | @Override | 31 | @Override |
| 31 | protected String nonNullFormat(Object value) { | 32 | protected String nonNullFormat(Object value) { |
| 32 | ApplicationId appId = (ApplicationId) value; | 33 | ApplicationId appId = (ApplicationId) value; | ... | ... |
| ... | @@ -27,6 +27,7 @@ import org.onosproject.cluster.ClusterEventListener; | ... | @@ -27,6 +27,7 @@ import org.onosproject.cluster.ClusterEventListener; |
| 27 | import org.onosproject.cluster.ControllerNode; | 27 | import org.onosproject.cluster.ControllerNode; |
| 28 | import org.onosproject.core.ApplicationId; | 28 | import org.onosproject.core.ApplicationId; |
| 29 | import org.onosproject.core.CoreService; | 29 | import org.onosproject.core.CoreService; |
| 30 | +import org.onosproject.core.DefaultApplicationId; | ||
| 30 | import org.onosproject.event.Event; | 31 | import org.onosproject.event.Event; |
| 31 | import org.onosproject.mastership.MastershipAdminService; | 32 | import org.onosproject.mastership.MastershipAdminService; |
| 32 | import org.onosproject.mastership.MastershipEvent; | 33 | import org.onosproject.mastership.MastershipEvent; |
| ... | @@ -49,11 +50,14 @@ import org.onosproject.net.flow.TrafficTreatment; | ... | @@ -49,11 +50,14 @@ import org.onosproject.net.flow.TrafficTreatment; |
| 49 | import org.onosproject.net.host.HostEvent; | 50 | import org.onosproject.net.host.HostEvent; |
| 50 | import org.onosproject.net.host.HostListener; | 51 | import org.onosproject.net.host.HostListener; |
| 51 | import org.onosproject.net.intent.HostToHostIntent; | 52 | import org.onosproject.net.intent.HostToHostIntent; |
| 53 | +import org.onosproject.net.intent.Intent; | ||
| 52 | import org.onosproject.net.intent.IntentEvent; | 54 | import org.onosproject.net.intent.IntentEvent; |
| 53 | import org.onosproject.net.intent.IntentListener; | 55 | import org.onosproject.net.intent.IntentListener; |
| 56 | +import org.onosproject.net.intent.Key; | ||
| 54 | import org.onosproject.net.intent.MultiPointToSinglePointIntent; | 57 | import org.onosproject.net.intent.MultiPointToSinglePointIntent; |
| 55 | import org.onosproject.net.link.LinkEvent; | 58 | import org.onosproject.net.link.LinkEvent; |
| 56 | import org.onosproject.net.link.LinkListener; | 59 | import org.onosproject.net.link.LinkListener; |
| 60 | +import org.onosproject.ui.JsonUtils; | ||
| 57 | import org.onosproject.ui.RequestHandler; | 61 | import org.onosproject.ui.RequestHandler; |
| 58 | import org.onosproject.ui.UiConnection; | 62 | import org.onosproject.ui.UiConnection; |
| 59 | import org.onosproject.ui.impl.TrafficMonitor.Mode; | 63 | import org.onosproject.ui.impl.TrafficMonitor.Mode; |
| ... | @@ -77,7 +81,9 @@ import static org.onlab.util.Tools.groupedThreads; | ... | @@ -77,7 +81,9 @@ import static org.onlab.util.Tools.groupedThreads; |
| 77 | import static org.onosproject.cluster.ClusterEvent.Type.INSTANCE_ADDED; | 81 | import static org.onosproject.cluster.ClusterEvent.Type.INSTANCE_ADDED; |
| 78 | import static org.onosproject.net.DeviceId.deviceId; | 82 | import static org.onosproject.net.DeviceId.deviceId; |
| 79 | import static org.onosproject.net.HostId.hostId; | 83 | import static org.onosproject.net.HostId.hostId; |
| 80 | -import static org.onosproject.net.device.DeviceEvent.Type.*; | 84 | +import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED; |
| 85 | +import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_UPDATED; | ||
| 86 | +import static org.onosproject.net.device.DeviceEvent.Type.PORT_STATS_UPDATED; | ||
| 81 | import static org.onosproject.net.host.HostEvent.Type.HOST_ADDED; | 87 | import static org.onosproject.net.host.HostEvent.Type.HOST_ADDED; |
| 82 | import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED; | 88 | import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED; |
| 83 | import static org.onosproject.ui.JsonUtils.envelope; | 89 | import static org.onosproject.ui.JsonUtils.envelope; |
| ... | @@ -98,6 +104,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { | ... | @@ -98,6 +104,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { |
| 98 | private static final String REQ_NEXT_INTENT = "requestNextRelatedIntent"; | 104 | private static final String REQ_NEXT_INTENT = "requestNextRelatedIntent"; |
| 99 | private static final String REQ_PREV_INTENT = "requestPrevRelatedIntent"; | 105 | private static final String REQ_PREV_INTENT = "requestPrevRelatedIntent"; |
| 100 | private static final String REQ_SEL_INTENT_TRAFFIC = "requestSelectedIntentTraffic"; | 106 | private static final String REQ_SEL_INTENT_TRAFFIC = "requestSelectedIntentTraffic"; |
| 107 | + private static final String SEL_INTENT = "selectIntent"; | ||
| 101 | private static final String REQ_ALL_FLOW_TRAFFIC = "requestAllFlowTraffic"; | 108 | private static final String REQ_ALL_FLOW_TRAFFIC = "requestAllFlowTraffic"; |
| 102 | private static final String REQ_ALL_PORT_TRAFFIC = "requestAllPortTraffic"; | 109 | private static final String REQ_ALL_PORT_TRAFFIC = "requestAllPortTraffic"; |
| 103 | private static final String REQ_DEV_LINK_FLOWS = "requestDeviceLinkFlows"; | 110 | private static final String REQ_DEV_LINK_FLOWS = "requestDeviceLinkFlows"; |
| ... | @@ -118,9 +125,13 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { | ... | @@ -118,9 +125,13 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { |
| 118 | private static final String SPRITE_LIST_RESPONSE = "spriteListResponse"; | 125 | private static final String SPRITE_LIST_RESPONSE = "spriteListResponse"; |
| 119 | private static final String SPRITE_DATA_RESPONSE = "spriteDataResponse"; | 126 | private static final String SPRITE_DATA_RESPONSE = "spriteDataResponse"; |
| 120 | private static final String UPDATE_INSTANCE = "updateInstance"; | 127 | private static final String UPDATE_INSTANCE = "updateInstance"; |
| 128 | + private static final String TOPO_START_DONE = "topoStartDone"; | ||
| 121 | 129 | ||
| 122 | // fields | 130 | // fields |
| 123 | private static final String ID = "id"; | 131 | private static final String ID = "id"; |
| 132 | + private static final String KEY = "key"; | ||
| 133 | + private static final String APP_ID = "appId"; | ||
| 134 | + private static final String APP_NAME = "appName"; | ||
| 124 | private static final String DEVICE = "device"; | 135 | private static final String DEVICE = "device"; |
| 125 | private static final String HOST = "host"; | 136 | private static final String HOST = "host"; |
| 126 | private static final String CLASS = "class"; | 137 | private static final String CLASS = "class"; |
| ... | @@ -136,7 +147,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { | ... | @@ -136,7 +147,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { |
| 136 | private static final String DEACTIVATE = "deactivate"; | 147 | private static final String DEACTIVATE = "deactivate"; |
| 137 | 148 | ||
| 138 | 149 | ||
| 139 | - private static final String APP_ID = "org.onosproject.gui"; | 150 | + private static final String MY_APP_ID = "org.onosproject.gui"; |
| 140 | 151 | ||
| 141 | private static final long TRAFFIC_PERIOD = 5000; | 152 | private static final long TRAFFIC_PERIOD = 5000; |
| 142 | private static final long SUMMARY_PERIOD = 30000; | 153 | private static final long SUMMARY_PERIOD = 30000; |
| ... | @@ -177,7 +188,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { | ... | @@ -177,7 +188,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { |
| 177 | @Override | 188 | @Override |
| 178 | public void init(UiConnection connection, ServiceDirectory directory) { | 189 | public void init(UiConnection connection, ServiceDirectory directory) { |
| 179 | super.init(connection, directory); | 190 | super.init(connection, directory); |
| 180 | - appId = directory.get(CoreService.class).registerApplication(APP_ID); | 191 | + appId = directory.get(CoreService.class).registerApplication(MY_APP_ID); |
| 181 | traffic = new TrafficMonitor(TRAFFIC_PERIOD, servicesBundle, this); | 192 | traffic = new TrafficMonitor(TRAFFIC_PERIOD, servicesBundle, this); |
| 182 | } | 193 | } |
| 183 | 194 | ||
| ... | @@ -214,6 +225,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { | ... | @@ -214,6 +225,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { |
| 214 | new ReqNextIntent(), | 225 | new ReqNextIntent(), |
| 215 | new ReqPrevIntent(), | 226 | new ReqPrevIntent(), |
| 216 | new ReqSelectedIntentTraffic(), | 227 | new ReqSelectedIntentTraffic(), |
| 228 | + new SelIntent(), | ||
| 217 | 229 | ||
| 218 | new CancelTraffic() | 230 | new CancelTraffic() |
| 219 | ); | 231 | ); |
| ... | @@ -242,6 +254,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { | ... | @@ -242,6 +254,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { |
| 242 | sendAllDevices(); | 254 | sendAllDevices(); |
| 243 | sendAllLinks(); | 255 | sendAllLinks(); |
| 244 | sendAllHosts(); | 256 | sendAllHosts(); |
| 257 | + sendTopoStartDone(); | ||
| 245 | } | 258 | } |
| 246 | } | 259 | } |
| 247 | 260 | ||
| ... | @@ -527,6 +540,31 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { | ... | @@ -527,6 +540,31 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { |
| 527 | } | 540 | } |
| 528 | } | 541 | } |
| 529 | 542 | ||
| 543 | + private final class SelIntent extends RequestHandler { | ||
| 544 | + private SelIntent() { | ||
| 545 | + super(SEL_INTENT); | ||
| 546 | + } | ||
| 547 | + | ||
| 548 | + @Override | ||
| 549 | + public void process(long sid, ObjectNode payload) { | ||
| 550 | + int appId = Integer.parseInt(string(payload, APP_ID)); | ||
| 551 | + String appName = string(payload, APP_NAME); | ||
| 552 | + ApplicationId applicId = new DefaultApplicationId(appId, appName); | ||
| 553 | + long intentKey = Long.decode(string(payload, KEY)); | ||
| 554 | + | ||
| 555 | + Key key = Key.of(intentKey, applicId); | ||
| 556 | + log.debug("Attempting to select intent key={}", key); | ||
| 557 | + | ||
| 558 | + Intent intent = intentService.getIntent(key); | ||
| 559 | + if (intent == null) { | ||
| 560 | + log.debug("no such intent found!"); | ||
| 561 | + } else { | ||
| 562 | + log.debug("starting to monitor intent {}", key); | ||
| 563 | + traffic.monitor(intent); | ||
| 564 | + } | ||
| 565 | + } | ||
| 566 | + } | ||
| 567 | + | ||
| 530 | private final class CancelTraffic extends RequestHandler { | 568 | private final class CancelTraffic extends RequestHandler { |
| 531 | private CancelTraffic() { | 569 | private CancelTraffic() { |
| 532 | super(CANCEL_TRAFFIC); | 570 | super(CANCEL_TRAFFIC); |
| ... | @@ -626,6 +664,9 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { | ... | @@ -626,6 +664,9 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase { |
| 626 | return hostIds; | 664 | return hostIds; |
| 627 | } | 665 | } |
| 628 | 666 | ||
| 667 | + private void sendTopoStartDone() { | ||
| 668 | + sendMessage(JsonUtils.envelope(TOPO_START_DONE, objectNode())); | ||
| 669 | + } | ||
| 629 | 670 | ||
| 630 | private synchronized void startSummaryMonitoring() { | 671 | private synchronized void startSummaryMonitoring() { |
| 631 | stopSummaryMonitoring(); | 672 | stopSummaryMonitoring(); | ... | ... |
| ... | @@ -23,12 +23,21 @@ | ... | @@ -23,12 +23,21 @@ |
| 23 | 23 | ||
| 24 | angular.module('ovIntent', []) | 24 | angular.module('ovIntent', []) |
| 25 | .controller('OvIntentCtrl', | 25 | .controller('OvIntentCtrl', |
| 26 | - ['$log', '$scope', 'TableBuilderService', | 26 | + ['$log', '$scope', 'TableBuilderService', 'NavService', |
| 27 | 27 | ||
| 28 | - function ($log, $scope, tbs) { | 28 | + function ($log, $scope, tbs, ns) { |
| 29 | 29 | ||
| 30 | function selCb($event, row) { | 30 | function selCb($event, row) { |
| 31 | $log.debug('Got a click on:', row); | 31 | $log.debug('Got a click on:', row); |
| 32 | + var m = /(\d+)\s:\s(.*)/.exec(row.appId), | ||
| 33 | + id = m ? m[1] : null, | ||
| 34 | + name = m ? m[2] : null; | ||
| 35 | + | ||
| 36 | + $scope.intentData = m ? { | ||
| 37 | + intentAppId: id, | ||
| 38 | + intentAppName: name, | ||
| 39 | + intentKey: row.key | ||
| 40 | + } : null; | ||
| 32 | } | 41 | } |
| 33 | 42 | ||
| 34 | tbs.buildTable({ | 43 | tbs.buildTable({ |
| ... | @@ -41,8 +50,9 @@ | ... | @@ -41,8 +50,9 @@ |
| 41 | $scope.topoTip = 'Show selected intent on topology view'; | 50 | $scope.topoTip = 'Show selected intent on topology view'; |
| 42 | 51 | ||
| 43 | $scope.showIntent = function () { | 52 | $scope.showIntent = function () { |
| 44 | - // TODO: navigate to topology view with selected intent context | 53 | + var d = $scope.intentData; |
| 45 | - $log.debug("+++ showIntent +++", $scope.selId); | 54 | + $log.debug("+++ showIntent +++", d); |
| 55 | + ns.navTo('topo', d); | ||
| 46 | }; | 56 | }; |
| 47 | 57 | ||
| 48 | $log.log('OvIntentCtrl has been created'); | 58 | $log.log('OvIntentCtrl has been created'); | ... | ... |
| ... | @@ -412,6 +412,12 @@ | ... | @@ -412,6 +412,12 @@ |
| 412 | flash.enable(true); | 412 | flash.enable(true); |
| 413 | } | 413 | } |
| 414 | 414 | ||
| 415 | + function topoStartDone() { | ||
| 416 | + var d = $scope.intentData; | ||
| 417 | + if (d) { | ||
| 418 | + tts.selectIntent(d); | ||
| 419 | + } | ||
| 420 | + } | ||
| 415 | 421 | ||
| 416 | // --- Controller Definition ----------------------------------------- | 422 | // --- Controller Definition ----------------------------------------- |
| 417 | 423 | ||
| ... | @@ -430,7 +436,8 @@ | ... | @@ -430,7 +436,8 @@ |
| 430 | _zs_, _gs_, _ms_, _sus_, _flash_, _wss_, _ps_, _tes_, _tfs_, | 436 | _zs_, _gs_, _ms_, _sus_, _flash_, _wss_, _ps_, _tes_, _tfs_, |
| 431 | _tps_, _tis_, _tss_, _tls_, _tts_, _tos_, _fltr_, _ttbs_, tspr, | 437 | _tps_, _tis_, _tss_, _tls_, _tts_, _tos_, _fltr_, _ttbs_, tspr, |
| 432 | _ttip_, _tov_) { | 438 | _ttip_, _tov_) { |
| 433 | - var projection, | 439 | + var params = $loc.search(), |
| 440 | + projection, | ||
| 434 | dim, | 441 | dim, |
| 435 | uplink = { | 442 | uplink = { |
| 436 | // provides function calls back into this space | 443 | // provides function calls back into this space |
| ... | @@ -438,7 +445,8 @@ | ... | @@ -438,7 +445,8 @@ |
| 438 | projection: function () { return projection; }, | 445 | projection: function () { return projection; }, |
| 439 | zoomLayer: function () { return zoomLayer; }, | 446 | zoomLayer: function () { return zoomLayer; }, |
| 440 | zoomer: function () { return zoomer; }, | 447 | zoomer: function () { return zoomer; }, |
| 441 | - opacifyMap: opacifyMap | 448 | + opacifyMap: opacifyMap, |
| 449 | + topoStartDone: topoStartDone | ||
| 442 | }; | 450 | }; |
| 443 | 451 | ||
| 444 | $scope = _$scope_; | 452 | $scope = _$scope_; |
| ... | @@ -469,6 +477,14 @@ | ... | @@ -469,6 +477,14 @@ |
| 469 | ttip = _ttip_; | 477 | ttip = _ttip_; |
| 470 | tov = _tov_; | 478 | tov = _tov_; |
| 471 | 479 | ||
| 480 | + if (params.intentKey && params.intentAppId && params.intentAppName) { | ||
| 481 | + $scope.intentData = { | ||
| 482 | + key: params.intentKey, | ||
| 483 | + appId: params.intentAppId, | ||
| 484 | + appName: params.intentAppName | ||
| 485 | + }; | ||
| 486 | + } | ||
| 487 | + | ||
| 472 | $scope.notifyResize = function () { | 488 | $scope.notifyResize = function () { |
| 473 | svgResized(fs.windowSize(mast.mastHeight())); | 489 | svgResized(fs.windowSize(mast.mastHeight())); |
| 474 | }; | 490 | }; | ... | ... |
| ... | @@ -240,6 +240,11 @@ | ... | @@ -240,6 +240,11 @@ |
| 240 | } | 240 | } |
| 241 | } | 241 | } |
| 242 | 242 | ||
| 243 | + function topoStartDone(data) { | ||
| 244 | + // called when the initial barrage of data has been sent from server | ||
| 245 | + uplink.topoStartDone(); | ||
| 246 | + } | ||
| 247 | + | ||
| 243 | // ======================== | 248 | // ======================== |
| 244 | 249 | ||
| 245 | function nodeById(id) { | 250 | function nodeById(id) { |
| ... | @@ -1140,7 +1145,8 @@ | ... | @@ -1140,7 +1145,8 @@ |
| 1140 | removeHost: removeHost, | 1145 | removeHost: removeHost, |
| 1141 | addLink: addLink, | 1146 | addLink: addLink, |
| 1142 | updateLink: updateLink, | 1147 | updateLink: updateLink, |
| 1143 | - removeLink: removeLink | 1148 | + removeLink: removeLink, |
| 1149 | + topoStartDone: topoStartDone | ||
| 1144 | }; | 1150 | }; |
| 1145 | }]); | 1151 | }]); |
| 1146 | }()); | 1152 | }()); | ... | ... |
| ... | @@ -34,7 +34,8 @@ | ... | @@ -34,7 +34,8 @@ |
| 34 | 34 | ||
| 35 | // internal state | 35 | // internal state |
| 36 | var overlays = {}, | 36 | var overlays = {}, |
| 37 | - current = null; | 37 | + current = null, |
| 38 | + reset = true; | ||
| 38 | 39 | ||
| 39 | function error(fn, msg) { | 40 | function error(fn, msg) { |
| 40 | $log.error(tos + fn + '(): ' + msg); | 41 | $log.error(tos + fn + '(): ' + msg); |
| ... | @@ -144,7 +145,8 @@ | ... | @@ -144,7 +145,8 @@ |
| 144 | payload[op] = oid; | 145 | payload[op] = oid; |
| 145 | } | 146 | } |
| 146 | 147 | ||
| 147 | - if (!same) { | 148 | + if (reset || !same) { |
| 149 | + reset = false; | ||
| 148 | current && doop('deactivate'); | 150 | current && doop('deactivate'); |
| 149 | current = overlays[id]; | 151 | current = overlays[id]; |
| 150 | current && doop('activate'); | 152 | current && doop('activate'); |
| ... | @@ -390,6 +392,7 @@ | ... | @@ -390,6 +392,7 @@ |
| 390 | tbSelection: tbSelection, | 392 | tbSelection: tbSelection, |
| 391 | installButtons: installButtons, | 393 | installButtons: installButtons, |
| 392 | addDetailButton: addDetailButton, | 394 | addDetailButton: addDetailButton, |
| 395 | + resetOnToolbarDestroy: function () { reset = true; }, | ||
| 393 | hooks: { | 396 | hooks: { |
| 394 | escape: escapeHook, | 397 | escape: escapeHook, |
| 395 | emptySelect: emptySelectHook, | 398 | emptySelect: emptySelectHook, | ... | ... |
| ... | @@ -243,6 +243,7 @@ | ... | @@ -243,6 +243,7 @@ |
| 243 | 243 | ||
| 244 | function destroyToolbar() { | 244 | function destroyToolbar() { |
| 245 | tbs.destroyToolbar(name); | 245 | tbs.destroyToolbar(name); |
| 246 | + tov.resetOnToolbarDestroy(); | ||
| 246 | } | 247 | } |
| 247 | 248 | ||
| 248 | // allows us to ensure the button states track key strokes | 249 | // allows us to ensure the button states track key strokes | ... | ... |
| ... | @@ -152,6 +152,14 @@ | ... | @@ -152,6 +152,14 @@ |
| 152 | } | 152 | } |
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | + // force the system to create a single intent selection | ||
| 156 | + function selectIntent(data) { | ||
| 157 | + trafficMode = 'intents'; | ||
| 158 | + hoverMode = null; | ||
| 159 | + wss.sendEvent('selectIntent', data); | ||
| 160 | + flash.flash('Selecting Intent ' + data.key); | ||
| 161 | + } | ||
| 162 | + | ||
| 155 | 163 | ||
| 156 | // === ------------------------------------------------------ | 164 | // === ------------------------------------------------------ |
| 157 | // action buttons on detail panel (multiple selection) | 165 | // action buttons on detail panel (multiple selection) |
| ... | @@ -207,6 +215,7 @@ | ... | @@ -207,6 +215,7 @@ |
| 207 | showPrevIntent: showPrevIntent, | 215 | showPrevIntent: showPrevIntent, |
| 208 | showNextIntent: showNextIntent, | 216 | showNextIntent: showNextIntent, |
| 209 | showSelectedIntentTraffic: showSelectedIntentTraffic, | 217 | showSelectedIntentTraffic: showSelectedIntentTraffic, |
| 218 | + selectIntent: selectIntent, | ||
| 210 | 219 | ||
| 211 | // invoked from mouseover/mouseout and selection change | 220 | // invoked from mouseover/mouseout and selection change |
| 212 | requestTrafficForMode: requestTrafficForMode, | 221 | requestTrafficForMode: requestTrafficForMode, | ... | ... |
-
Please register or login to post a comment