[rhmessaging-commits] rhmessaging commits: r3662 - mgmt/trunk/cumin/python/cumin/grid.

rhmessaging-commits at lists.jboss.org rhmessaging-commits at lists.jboss.org
Wed Sep 30 10:58:46 EDT 2009


Author: eallen
Date: 2009-09-30 10:58:46 -0400 (Wed, 30 Sep 2009)
New Revision: 3662

Modified:
   mgmt/trunk/cumin/python/cumin/grid/job.py
   mgmt/trunk/cumin/python/cumin/grid/main.py
   mgmt/trunk/cumin/python/cumin/grid/pool.py
   mgmt/trunk/cumin/python/cumin/grid/pool.strings
   mgmt/trunk/cumin/python/cumin/grid/slot.py
   mgmt/trunk/cumin/python/cumin/grid/slot.strings
Log:
Consolidated an error message in job.py
Added a page for the fullpage flash slot vis
Implemented a flash slot vis if flash >= 9 is available

Modified: mgmt/trunk/cumin/python/cumin/grid/job.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/job.py	2009-09-30 14:53:24 UTC (rev 3661)
+++ mgmt/trunk/cumin/python/cumin/grid/job.py	2009-09-30 14:58:46 UTC (rev 3662)
@@ -709,6 +709,7 @@
             self.process_cancel(session)
 
 class OutputFile(Widget):
+    err_msg = "Output, Error, and UserLog file names are invalid."
     def __init__(self, app, name, which_file, first_last):
         super(OutputFile, self).__init__(app, name)
 
@@ -725,6 +726,7 @@
             action = self.app.model.scheduler.Fetch
             data = action.qmfcall(scheduler, job, file, start, end)
             return escape_entity(data)
+        return self.err_msg
 
     def get_file_args(self, session):
         first_last = self.first_last.get(session)
@@ -739,7 +741,7 @@
 
     def render_loading(self, session, *args):
         file = self.which_file.get_current_file_name(session)
-        return file and "loading..." or "Output, Error, and UserLog file names are invalid."
+        return file and "loading..." or self.err_msg
 
 class JobOutput(Form):
     def __init__(self, app, name, job):

Modified: mgmt/trunk/cumin/python/cumin/grid/main.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/main.py	2009-09-30 14:53:24 UTC (rev 3661)
+++ mgmt/trunk/cumin/python/cumin/grid/main.py	2009-09-30 14:58:46 UTC (rev 3662)
@@ -55,9 +55,12 @@
         app.main_page.main.grid = self.frame
         app.main_page.main.add_tab(self.frame)
 
-        self.pool_slots_page = PoolSlotMapPage(app, "poolslots.png")
+        self.pool_slots_page = PoolSlotMapPage(app, "poolslots.vis")
         app.add_page(self.pool_slots_page)
 
+        self.pool_slots_fullpage = PoolSlotFullPage(app, "poolslotsfull.vis")
+        app.add_page(self.pool_slots_fullpage)
+
     def init_test(self, test):
         GridTest("grid", test)
 

Modified: mgmt/trunk/cumin/python/cumin/grid/pool.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/pool.py	2009-09-30 14:53:24 UTC (rev 3661)
+++ mgmt/trunk/cumin/python/cumin/grid/pool.py	2009-09-30 14:58:46 UTC (rev 3662)
@@ -18,7 +18,7 @@
 from collector import CollectorSet, CollectorFrame
 from negotiator import NegotiatorSet, NegotiatorFrame
 from limit import LimitSet, LimitFrame
-from slot import SlotSet, SlotFrame, SlotMap, SlotMapPage
+from slot import SlotSet, SlotFrame, SlotMap, SlotMapPage, SlotActivities
 
 from cumin.widgets import Session
 
@@ -253,9 +253,12 @@
         stats = GridStats(app, "grid_stats", self.grid)
         self.add_child(stats)
 
-        slot_map = PoolSlotMap(app, "slot_map", self.pool)
+        slot_map = PoolSlotMap(app, "slot_png", self.pool)
         self.add_child(slot_map)
 
+        slot_vis = PoolSlotFlashVis(app, "slot_map", self.pool)
+        self.add_child(slot_vis)
+
         chart = self.JobStackedChart(app, "jobs", self.collector)
         chart.duration.param.default = "3600"
         chart.stats = ("RunningJobs", "IdleJobs")
@@ -349,11 +352,15 @@
 
         return sess.marshal()
 
+    def get_scheduler_select(self, session):
+        pool = self.pool.get(session)
+        return "pool='%s'" % pool.id
+
 class PoolSlotMapPage(SlotMapPage):
     def __init__(self, app, name):
-        super(PoolSlotMapPage, self).__init__(app, name)
+        self.pool = PoolParameter(app, "id")
+        super(PoolSlotMapPage, self).__init__(app, name, self.pool, "Pool")
 
-        self.pool = PoolParameter(app, "id")
         self.add_parameter(self.pool)
 
     def do_process(self, session):
@@ -367,3 +374,97 @@
 
         if pool:
             self.slots.add_where_expr(session, "s.pool = '%s'", pool.id)
+
+class PoolSlotFlashVis(PoolSlotMap):
+    def __init__(self, app, name, object):
+        super(PoolSlotFlashVis, self).__init__(app, name, object)
+
+        self.group_by = self.GroupBySwitch(app, "group_by")
+        self.add_child(self.group_by)
+
+        self.activities = SlotActivities(app, "activities_legend")
+        self.add_child(self.activities)
+        self.fullpageable = True
+
+    def render_slots_href(self, session):
+        pool = self.pool.get(session)
+
+        page = main.module.pool_slots_page
+        sess = Session(page)
+
+        page.pool.set(sess, pool)
+        page.json.set(sess, "slots")
+        page.groups.set(sess, [self.group_by.get(session)])
+
+        return sess.marshal()
+
+    def render_image_href(self, session):
+        pool = self.pool.get(session)
+
+        page = main.module.pool_slots_page
+        sess = Session(page)
+
+        page.pool.set(sess, pool)
+
+        return sess.marshal()
+
+    def render_ctrl_href(self, session):
+        pool = self.pool.get(session)
+
+        page = main.module.pool_slots_page
+        sess = Session(page)
+
+        page.pool.set(sess, pool)
+        page.json.set(sess, "ctrl")
+        page.groups.set(sess, [self.group_by.get(session)])
+
+        return sess.marshal()
+
+    def render_slot_chart_width(self, session):
+        return self.render_slot_clip_size(session)
+
+    def render_slot_chart_height(self, session):
+        return self.render_slot_clip_size(session)
+
+    def render_slot_ctrl_height(self, session):
+        return 80
+
+    def render_fullpageable(self, session):
+        return self.fullpageable and "fullpageable" or ""
+
+    def render_fullpage_href(self, session):
+        pool = self.pool.get(session)
+
+        page = main.module.pool_slots_fullpage
+        sess = Session(page)
+
+        page.pool.set(sess, pool)
+
+        return sess.marshal()
+
+    class GroupBySwitch(StateSwitch):
+        def __init__(self, app, name):
+            super(PoolSlotFlashVis.GroupBySwitch, self).__init__(app, name)
+
+            self.add_state("system", "By system")
+            #self.add_state("state", "By slot state")
+            self.add_state("None", "No Grouping")
+
+        def get_click(self, session, state):
+            href = self.parent.render_slots_href(session)
+            return "return slot_vis('%s', this, '%s', '%s')" % (state, self.parent.path, href)
+
+class PoolSlotFullPage(FlashFullPage):
+    def __init__(self, app, name):
+        super(PoolSlotFullPage, self).__init__(app, name)
+
+        self.pool = PoolParameter(app, "id")
+        self.add_parameter(self.pool)
+
+        self.flash_chart = PoolSlotFlashVis(app, "chart", self.pool)
+        self.flash_chart.fullpageable = False
+        self.add_child(self.flash_chart)
+
+    def render_content(self, session):
+        return self.flash_chart.render(session)
+        
\ No newline at end of file

Modified: mgmt/trunk/cumin/python/cumin/grid/pool.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/pool.strings	2009-09-30 14:53:24 UTC (rev 3661)
+++ mgmt/trunk/cumin/python/cumin/grid/pool.strings	2009-09-30 14:58:46 UTC (rev 3662)
@@ -22,6 +22,9 @@
 div#PoolOverview div.col1 {
     padding-right: 2em;
 }
+div#flashSlotMap, div#pngSlotMap {
+	display: none;
+}
 
 [PoolOverview.html]
 <div id="PoolOverview">
@@ -34,7 +37,8 @@
 </div>
 <div class="col2">
   <h2>Slots</h2>
-  <div>{slot_map}</div>
+  <div id="flashSlotMap">{slot_map}</div>
+  <div id="pngSlotMap">{slot_png}</div>
 </div>
 </div>
 <div style="clear:left;"><!-- --></div>
@@ -45,3 +49,85 @@
 {stats}
 <div>{jobs_chart}</div>
 <div>{submit_chart}</div>
+
+[PoolSlotFlashVis.html]
+<div>
+    <div class="StatValueChart {fullpageable}" id="{id}">
+      <h2>{title}</h2>
+      <div class="duration">{group_by}</div>
+	  <div id="{id}_chart"></div>
+     <div id="{id}ctrl_chart"></div>
+    </div>
+</div>
+<script type="text/javascript">
+//<![CDATA[
+    function updatePoolSlotVis(id, loadType) {
+        var chart = cumin.getFlashChart(id);
+        if ((chart != null)  && (typeof chart.src != "undefined")) {
+            if (typeof loadType != "undefined")
+                chart.reload(chart.src, false);
+            else
+                chart.load(chart.src, false);
+        }
+    }
+    function vis_ready(vis) {
+        if (vis == "slots") {
+            var chart = cumin.getFlashChart("{id}");
+            chart.src = "{slots_href}";
+            updatePoolSlotVis('{id}');
+        } else {
+            var chart = cumin.getFlashChart("{id}ctrl");
+            chart.src = "{ctrl_href}";
+            updatePoolSlotVis('{id}ctrl');
+        }
+    }
+    function vis_treemap_over(type, value) {
+        var chart = cumin.getFlashChart("{id}");
+        if (chart) {
+            chart.highlight(type, value);
+        }
+    }
+    function vis_treemap_out(type, value) {
+        var chart = cumin.getFlashChart("{id}");
+        if (chart) {
+            chart.lowlight(type, value);
+        }
+    }
+    function slot_vis(state, a, id, href) {
+        var li = a.parentNode;
+        var ul = li.parentNode;
+        var as = ul.getElementsByTagName('a');
+        for (var i=0; i < as.length; i++) {
+            as[i].className = (as[i] == a) ?  "selected" : "";
+        }
+
+        var branch = wooly.session.branch(href);
+        if (state == "None") {
+            if ("group" in branch)
+                delete branch.group;
+        } else {
+            branch.group = state;
+        }
+        var src = branch.marshal();
+        var chart = cumin.getFlashChart(id);
+        chart.src = src
+        updatePoolSlotVis(id, "reload");
+        return false;
+    }
+    var flashversion = swfobject.getFlashPlayerVersion();
+    if (flashversion.major >= 9) {
+ 		var fsm = document.getElementById('flashSlotMap');
+ 		if (fsm)
+ 			fsm.style.display = "block";
+ 		
+        swfobject.embedSWF("resource?name=slots.swf", "{id}_chart", "{slot_chart_width}", "{slot_chart_height}", "9.0.0", "", {vis:"slots"});
+        swfobject.embedSWF("resource?name=slots.swf", "{id}ctrl_chart", "{slot_chart_width}", "{slot_ctrl_height}", "9.0.0", "", {vis:"ctrl"});
+
+        wooly.addPageUpdateListener(function () { updatePoolSlotVis('{id}', "reload"); });
+        wooly.addPageUpdateListener(function () { updatePoolSlotVis('{id}ctrl', "reload"); });
+        window.addEvent('domready',function () {
+            cumin.setFullpageHandler('{id}', '{fullpage_href}');
+        });
+    }
+//]]>
+</script>

Modified: mgmt/trunk/cumin/python/cumin/grid/slot.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/slot.py	2009-09-30 14:53:24 UTC (rev 3661)
+++ mgmt/trunk/cumin/python/cumin/grid/slot.py	2009-09-30 14:58:46 UTC (rev 3662)
@@ -141,70 +141,68 @@
             return "Load"
 
 class SlotMapPage(Page):
-    interiors = {"Idle": (.7, .7, .7),
-                 "Busy": (0.0, 0.4, 0.0),
-                 "Suspended": (1, 0, 0),
-                 "Vacating": (1, .73, .367),
-                 "Killing": (0, 0, 1),
-                 "Benchmarking": (1, .8, .8),
-                 "Retiring": (.8, .2, .8),
-                 None: (.8, .8, .8)}
+    """ handles the slots.vis request """
 
+    interiors = {"Idle": (.7,.7,.7),
+               "Busy": (0.0, 0.4, 0.0),
+               "Suspended": (1,0,0),
+               "Vacating": (1,.73,.367),
+               "Killing": (0,0,1),
+               "Benchmarking": (1,.8,.8),
+               "Retiring": (.8,.2,.8),
+               "Unknown": (.8,.8,.8)}
+
+    shapes = ["rectangle", "circle", "circle"]
     max_width = 400
     max_png_age = 30
-
-    def __init__(self, app, name):
+    def __init__(self, app, name, param, desc):
         super(SlotMapPage, self).__init__(app, name)
 
+        self.object_param = param
+        self.object_description = desc
+
         self.zoom_level = IntegerParameter(app, "zl")
         self.zoom_level.default = 1
         self.add_parameter(self.zoom_level)
 
-        self.zoom_x = IntegerParameter(app, "zx")
-        self.zoom_x.default = 0
-        self.add_parameter(self.zoom_x)
-
-        self.zoom_y = IntegerParameter(app, "zy")
-        self.zoom_y.default = 0
-        self.add_parameter(self.zoom_y)
-
         self.dot = Parameter(app, "dot")
         self.add_parameter(self.dot)
 
+        self.json = Parameter(app, "json")
+        self.add_parameter(self.json)
+
+        group = Parameter(app, "agroup")
+        self.groups = ListParameter(app, "group", group)
+        self.add_parameter(self.groups)
+
         self.cache = ImageCache()
         self.slots = SlotDataSet(app)
 
     def get_content_type(self, session):
-        return "image/png"
+        return self.json.get(session) and "text/plain" or "image/png"
 
     def get_cache_control(self, session):
         return "no-cache"
 
     def render_dot(self, session, dot):
         map = HeatMapChart()
-
-        if dot == "Unknown":
-            dot = None
-
         surface = map.plot_dot(self.interiors[dot], 12, 12)
-
         writer = Writer()
         surface.write_to_png(writer)
         return writer.to_string()
 
     def do_render(self, session):
         dot = self.dot.get(session)
-
         if dot:
             return self.render_dot(session, dot)
 
+        if self.json.get(session):
+            return self.render_json(session)
+
         zl = self.zoom_level.get(session)
-        zx = self.zoom_x.get(session)
-        zy = self.zoom_y.get(session)
 
         # determine if cached copy is recent enough
         cached_png, args = self.get_cached(session, zl)
-
         if cached_png:
             self.set_cookie(session, args)
             return cached_png
@@ -221,8 +219,10 @@
         activity = columns.index("activity")
         state = columns.index("state")
 
-        slots = [(self.interiors[x[activity]], x[state]) for x in records]
-        size = map.plot_slots(slots, zl, zx, zy)
+        interiors = self.interiors.copy()
+        interiors[None] = interiors["Unknown"]
+        slots = [(interiors[x[activity]], x[state]) for x in records]
+        size = map.plot_slots(slots, zl)
 
         args = (size, map.width, map.height, len(slots), map.rows, map.cols)
         self.set_cookie(session, args)
@@ -232,6 +232,67 @@
         map.write(writer)
         return writer.to_string()
 
+    def get_info_array(self, records, array, attr):
+        d = dict()
+        for i in array:
+            atr = records[i][attr]
+            if not atr in d:
+                d[atr] = list()
+            d[atr].append(i)
+        return d
+
+    def render_json(self, session):
+        cursor = self.slots.execute(session)
+        records = cursor_to_rows(cursor)
+
+        if len(records) == 0:
+            return "[]"
+
+        groups = self.groups.get(session)
+        slot_count = len(records)
+
+        root = Element()
+        root.name = self.object_description
+        root.value = self.object_param.get(session).id
+        root.slots = slot_count
+        root.vis = self.json.get(session)
+        root.activity_colors = self.interiors
+        root.tree = self.treeify(records, range(slot_count), groups, 0)
+        return "[%s]" % root.create()
+
+    def treeify(self, records, plist, groups, level):
+        level_list = list()
+        # leaf
+        if level == len(groups):
+            el = Element()
+            el.name = "Slot"
+            interiors = self.interiors.copy()
+            interiors[None] = interiors["Unknown"]
+            for i in sorted(plist, key=lambda x:records[x]["name"]):
+                el = Element()
+                el.job_id = records[i]["job_id"] and records[i]["job_id"] or ""
+                el.activity = records[i]["activity"] and records[i]["activity"] or "Unknown"
+                el.state = records[i]["state"] and records[i]["state"] or "Unknown"
+                el.value = records[i]["name"] and records[i]["name"] or ""
+                el.load_avg = records[i]["load_avg"] and round(records[i]["load_avg"], 2) or 0
+                el.name = "slot"
+                level_list.append(el)
+            return level_list
+
+        # not a leaf
+        group = groups[level]
+        level_dict = self.get_info_array(records, plist, group)
+        for key in sorted(level_dict):
+            el = Element()
+            el.name = group
+            el.value = key
+            el.slots = len(level_dict[key])
+            el.level = level
+            if level < len(groups):
+                el.tree = self.treeify(records, level_dict[key], groups, level + 1)
+            level_list.append(el)
+        return level_list
+
     def get_cached(self, session, zl):
         filename = self.gen_filename(session)
         return self.cache.find_recent(filename, self.max_png_age)
@@ -268,14 +329,17 @@
     def render_job_index_param(self, session):
         return "xargs"
 
+    def render_fullpageable(self, session):
+        return "fullpageable"
+
+    def get_scheduler_select(self, session):
+        raise Exception("Must implement get_scheduler_select")
+
     def render_slot_job_url(self, session):
         job = Identifiable("XXX")
-        object = self.frame.object.get(session) # XXX eeks
+        select = self.get_scheduler_select(session)
         try:
-            if isinstance(object, Sysimage):
-                scheduler = Scheduler.select("system='%s'" % object.nodeName)[0]
-            else:
-                scheduler = Scheduler.select("pool='%s'" % object.id)[0]
+            scheduler = Scheduler.select(select)[0]
             return self.page.main.grid.pool.job.get_href(session, job, scheduler)
         except:
             pass
@@ -290,7 +354,7 @@
             self.states = self.SlotStates(app, "slot_states")
             self.add_child(self.states)
 
-            self.activities = self.SlotActivities(app, "slot_activities")
+            self.activities = SlotActivities(app, "slot_activities")
             self.add_child(self.activities)
 
         class SlotStates(ItemSet):
@@ -305,31 +369,6 @@
             def render_item_title(self, session, state):
                 return state
 
-        class SlotActivities(ItemSet):
-            activities = (("Idle", "clear"),
-                          ("Busy", "green"),
-                          ("Suspended", "red"),
-                          ("Vacating", "orange"),
-                          ("Killing", "blue"),
-                          ("Benchmarking", "yellow"),
-                          ("Retiring", "purple"),
-                          ("Unknown", "grey"))
-
-            def render_item_size(self, session, activity):
-                return 12
-
-            def do_get_items(self, session):
-                return self.activities
-
-            def render_item_title(self, session, activity):
-                return activity[0]
-
-            def render_item_href(self, session, activity):
-                params = list()
-                params.append("dot=%s" % activity[0])
-
-                return "poolslots.png?" + ";".join(params)
-
     class SlotInfo(ItemSet):
         display_names = {"jid": "jid", "job_id": "Job ID",
                          "system": "System", "machine": "Machine",
@@ -397,3 +436,29 @@
 
         def render_item_row_class(self, session, item):
             return item[0] == "jid" and "class='hidden_row'" or ""
+
+class SlotActivities(ItemSet):
+    activities = (("Idle", "clear"),
+                  ("Busy", "green"),
+                  ("Suspended", "red"),
+                  ("Vacating", "orange"),
+                  ("Killing", "blue"),
+                  ("Benchmarking", "yellow"),
+                  ("Retiring", "purple"),
+                  ("Unknown", "grey"))
+
+    def render_item_size(self, session, activity):
+        return 12
+
+    def do_get_items(self, session):
+        return self.activities
+
+    def render_item_title(self, session, activity):
+        return activity[0]
+
+    def render_item_href(self, session, activity):
+        params = list()
+        params.append("dot=%s" % activity[0])
+
+        return "poolslots.vis?" + ";".join(params)
+

Modified: mgmt/trunk/cumin/python/cumin/grid/slot.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/grid/slot.strings	2009-09-30 14:53:24 UTC (rev 3661)
+++ mgmt/trunk/cumin/python/cumin/grid/slot.strings	2009-09-30 14:58:46 UTC (rev 3662)
@@ -5,6 +5,9 @@
   s.machine,
   s.system,
   s.job_id,
+  s.accounting_group,
+  s.op_sys,
+  s.arch,
   j.id as jid,
   c.activity,
   c.state,
@@ -1077,7 +1080,7 @@
   <div class="slot_map" id="{id}">
     <div id="slot_glass"><!-- mouse target to prevent selecting/dragging image --></div>
     <div id="slot_png">
-      <img name="{id}" src="{image_href}" border="0" onload="vis.img_loaded(this)" onerror="vis.img_error(this)" alt="slots"/>
+      <img name="{id}" border="0" onload="vis.img_loaded(this)" onerror="vis.img_error(this)" alt="slots"/>
     </div>
     <div id="slot_hover"><!-- red border around current slot --></div>
     <div id="slot_zooming"><p>Zooming...</p></div>
@@ -1089,25 +1092,37 @@
 <div style="clear: left"><!-- --></div>
 {slot_info}
 <script type="text/javascript">
-    var slot_current_id = "{id}";
-    var show_slot_job_url = "{slot_job_url}";
-    var slot_job_index = "{job_index_param}";
-    var slot_map_info = {size: 0, width: 0, height: 0, count: 0, rows: 0, cols: 0};
-    var slot_clip_size = {slot_clip_size};
-    var original_clip_size = slot_clip_size;
-    $('slot_visualization').onfullpage = function (width) { vis.notify(true, width); };
-    $('slot_visualization').onrestore = function () { vis.notify(false, original_clip_size); };
-    var oGlass = document.getElementById("slot_glass");
-    if (oGlass) {
-        oGlass.onmousedown = vis.downGlass;
-        oGlass.onmouseup   = vis.upGlass;
-        oGlass.onmousemove = vis.moveGlass;
-        oGlass.onmouseout  = vis.outGlass;
-        oGlass.ondblclick = clicks.doMouseDown;
-        oGlass.onclick    = clicks.doMouseDown;
-        oGlass.dragging = false;
-        oGlass.down_pos = null;
-    }
+//<![CDATA[
+    var flashversion = swfobject.getFlashPlayerVersion();
+    if (flashversion.major < 9) {
+ 		var psm = document.getElementById('pngSlotMap');
+ 		if (psm)
+ 			psm.style.display = "block";
+		var theImage = document.images['{id}'];
+		if (theImage) {
+			theImage.src = "{image_href}";
+		}
+        var slot_current_id = "{id}";
+	    var show_slot_job_url = "{slot_job_url}";
+	    var slot_job_index = "{job_index_param}";
+	    var slot_map_info = {size: 0, width: 0, height: 0, count: 0, rows: 0, cols: 0};
+	    var slot_clip_size = {slot_clip_size};
+	    var original_clip_size = slot_clip_size;
+	    $('slot_visualization').onfullpage = function (width) { vis.notify(true, width); };
+	    $('slot_visualization').onrestore = function () { vis.notify(false, original_clip_size); };
+	    var oGlass = document.getElementById("slot_glass");
+	    if (oGlass) {
+	        oGlass.onmousedown = vis.downGlass;
+	        oGlass.onmouseup   = vis.upGlass;
+	        oGlass.onmousemove = vis.moveGlass;
+	        oGlass.onmouseout  = vis.outGlass;
+	        oGlass.ondblclick = clicks.doMouseDown;
+	        oGlass.onclick    = clicks.doMouseDown;
+	        oGlass.dragging = false;
+	        oGlass.down_pos = null;
+	    }
+	}
+//]]>
 </script>
 
 [SlotInfo.css]



More information about the rhmessaging-commits mailing list