[gen] More work on Refs with popup='true'.
This commit is contained in:
		
							parent
							
								
									a14bff45a7
								
							
						
					
					
						commit
						0bcd0055a3
					
				
					 7 changed files with 80 additions and 37 deletions
				
			
		| 
						 | 
					@ -286,11 +286,8 @@ class Field:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def isMultiValued(self):
 | 
					    def isMultiValued(self):
 | 
				
			||||||
        '''Does this type definition allow to define multiple values?'''
 | 
					        '''Does this type definition allow to define multiple values?'''
 | 
				
			||||||
        res = False
 | 
					 | 
				
			||||||
        maxOccurs = self.multiplicity[1]
 | 
					        maxOccurs = self.multiplicity[1]
 | 
				
			||||||
        if (maxOccurs == None) or (maxOccurs > 1):
 | 
					        return (maxOccurs == None) or (maxOccurs > 1)
 | 
				
			||||||
            res = True
 | 
					 | 
				
			||||||
        return res
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def isSortable(self, usage):
 | 
					    def isSortable(self, usage):
 | 
				
			||||||
        '''Can fields of this type be used for sorting purposes (when sorting
 | 
					        '''Can fields of this type be used for sorting purposes (when sorting
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1273,7 +1273,7 @@ class Ref(Field):
 | 
				
			||||||
        # No object can be selected if the popup has not been opened yet.
 | 
					        # No object can be selected if the popup has not been opened yet.
 | 
				
			||||||
        if 'semantics' not in rq:
 | 
					        if 'semantics' not in rq:
 | 
				
			||||||
            # In this case, display already linked objects if any.
 | 
					            # In this case, display already linked objects if any.
 | 
				
			||||||
            if not obj.isEmpty(self.name): return getattr(obj, self.name)
 | 
					            if not obj.isEmpty(self.name): return self.getValue(obj.o)
 | 
				
			||||||
            return res
 | 
					            return res
 | 
				
			||||||
        uids = rq['selected'].split(',')
 | 
					        uids = rq['selected'].split(',')
 | 
				
			||||||
        tool = obj.tool
 | 
					        tool = obj.tool
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,16 +24,16 @@ from group import Group
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
class Search:
 | 
					class Search:
 | 
				
			||||||
    '''Used for specifying a search for a given class.'''
 | 
					    '''Used for specifying a search for a given class.'''
 | 
				
			||||||
    def __init__(self, name, group=None, sortBy='', sortOrder='asc', limit=None,
 | 
					    def __init__(self, name, group=None, sortBy='', sortOrder='asc',
 | 
				
			||||||
                 default=False, colspan=1, translated=None, show=True,
 | 
					                 maxPerPage=30, default=False, colspan=1, translated=None,
 | 
				
			||||||
                 translatedDescr=None, checkboxes=False, checkboxesDefault=True,
 | 
					                 show=True, translatedDescr=None, checkboxes=False,
 | 
				
			||||||
                 **fields):
 | 
					                 checkboxesDefault=True, **fields):
 | 
				
			||||||
        self.name = name
 | 
					        self.name = name
 | 
				
			||||||
        # Searches may be visually grouped in the portlet.
 | 
					        # Searches may be visually grouped in the portlet.
 | 
				
			||||||
        self.group = Group.get(group)
 | 
					        self.group = Group.get(group)
 | 
				
			||||||
        self.sortBy = sortBy
 | 
					        self.sortBy = sortBy
 | 
				
			||||||
        self.sortOrder = sortOrder
 | 
					        self.sortOrder = sortOrder
 | 
				
			||||||
        self.limit = limit
 | 
					        self.maxPerPage = maxPerPage
 | 
				
			||||||
        # If this search is the default one, it will be triggered by clicking
 | 
					        # If this search is the default one, it will be triggered by clicking
 | 
				
			||||||
        # on main link.
 | 
					        # on main link.
 | 
				
			||||||
        self.default = default
 | 
					        self.default = default
 | 
				
			||||||
| 
						 | 
					@ -188,4 +188,19 @@ class UiSearch:
 | 
				
			||||||
            _ = tool.translate
 | 
					            _ = tool.translate
 | 
				
			||||||
            self.translated = label and _(label) or ''
 | 
					            self.translated = label and _(label) or ''
 | 
				
			||||||
            self.translatedDescr = labelDescr and _(labelDescr) or ''
 | 
					            self.translatedDescr = labelDescr and _(labelDescr) or ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setInitiator(self, initiator, field):
 | 
				
			||||||
 | 
					        '''If the search is defined in an attribute Ref.select, we receive here
 | 
				
			||||||
 | 
					           the p_initiator object and its Ref p_field.'''
 | 
				
			||||||
 | 
					        self.initiator = initiator
 | 
				
			||||||
 | 
					        self.initiatorField = field
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def showCheckboxes(self):
 | 
				
			||||||
 | 
					        '''If checkboxes are enabled for this search (and if an initiator field
 | 
				
			||||||
 | 
					           is there), they must be visible only if the initiator field is
 | 
				
			||||||
 | 
					           multivalued. Indeed, if it is not the case, it has no sense to select
 | 
				
			||||||
 | 
					           multiple objects. But in this case, we still want checkboxes to be in
 | 
				
			||||||
 | 
					           the DOM because they store object UIDs.'''
 | 
				
			||||||
 | 
					        if not self.search.checkboxes: return
 | 
				
			||||||
 | 
					        return not self.initiator or self.initiatorField.isMultiValued()
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -354,14 +354,17 @@ class ToolMixin(BaseMixin):
 | 
				
			||||||
        # Use index "Allowed" if noSecurity is False
 | 
					        # Use index "Allowed" if noSecurity is False
 | 
				
			||||||
        if not noSecurity: params['Allowed'] = self.getAllowedValue()
 | 
					        if not noSecurity: params['Allowed'] = self.getAllowedValue()
 | 
				
			||||||
        brains = self.getPath("/catalog")(**params)
 | 
					        brains = self.getPath("/catalog")(**params)
 | 
				
			||||||
        if brainsOnly:
 | 
					        # Compute maxResults
 | 
				
			||||||
            # Return brains only.
 | 
					 | 
				
			||||||
            if not maxResults or (maxResults == 'NO_LIMIT'): return brains
 | 
					 | 
				
			||||||
            else: return brains[:maxResults]
 | 
					 | 
				
			||||||
        if not maxResults:
 | 
					        if not maxResults:
 | 
				
			||||||
            if refField: maxResults = refField.maxPerPage
 | 
					            if refField: maxResults = refField.maxPerPage
 | 
				
			||||||
            else:        maxResults = self.appy().numberOfResultsPerPage
 | 
					            else: maxResults = search.maxPerPage or \
 | 
				
			||||||
        elif maxResults == 'NO_LIMIT': maxResults = None
 | 
					                               self.appy().numberOfResultsPerPage
 | 
				
			||||||
 | 
					        elif maxResults == 'NO_LIMIT':
 | 
				
			||||||
 | 
					            maxResults = None
 | 
				
			||||||
 | 
					        # Return brains only if required.
 | 
				
			||||||
 | 
					        if brainsOnly:
 | 
				
			||||||
 | 
					            if not maxResults: return brains
 | 
				
			||||||
 | 
					            else: return brains[:maxResults]
 | 
				
			||||||
        res = gutils.SomeObjects(brains, maxResults, startNumber,
 | 
					        res = gutils.SomeObjects(brains, maxResults, startNumber,
 | 
				
			||||||
                                 noSecurity=noSecurity)
 | 
					                                 noSecurity=noSecurity)
 | 
				
			||||||
        res.brainsToObjects()
 | 
					        res.brainsToObjects()
 | 
				
			||||||
| 
						 | 
					@ -725,14 +728,18 @@ class ToolMixin(BaseMixin):
 | 
				
			||||||
    def getSearch(self, className, name, ui=False):
 | 
					    def getSearch(self, className, name, ui=False):
 | 
				
			||||||
        '''Gets the Search instance (or a UiSearch instance if p_ui is True)
 | 
					        '''Gets the Search instance (or a UiSearch instance if p_ui is True)
 | 
				
			||||||
           corresponding to the search named p_name, on class p_className.'''
 | 
					           corresponding to the search named p_name, on class p_className.'''
 | 
				
			||||||
 | 
					        initiator = None
 | 
				
			||||||
        if name == 'customSearch':
 | 
					        if name == 'customSearch':
 | 
				
			||||||
            # It is a custom search whose parameters are in the session.
 | 
					            # It is a custom search whose parameters are in the session.
 | 
				
			||||||
            fields = self.REQUEST.SESSION['searchCriteria']
 | 
					            fields = self.REQUEST.SESSION['searchCriteria']
 | 
				
			||||||
            res = Search('customSearch', **fields)
 | 
					            res = Search('customSearch', **fields)
 | 
				
			||||||
        elif ':' in name:
 | 
					        elif ':' in name:
 | 
				
			||||||
            # The search is defined in a Ref field with link=popup
 | 
					            # The search is defined in a Ref field with link=popup. Get the
 | 
				
			||||||
            refObject, ref = name.split(':')
 | 
					            # search, the initiator object and the Ref field.
 | 
				
			||||||
            res = getattr(self.getObject(refObject,appy=True).klass,ref).select
 | 
					            uid, ref = name.split(':')
 | 
				
			||||||
 | 
					            initiator = self.getObject(uid, appy=True)
 | 
				
			||||||
 | 
					            initiatorField = initiator.getField(ref)
 | 
				
			||||||
 | 
					            res = getattr(initiator.klass, ref).select
 | 
				
			||||||
        elif name:
 | 
					        elif name:
 | 
				
			||||||
            appyClass = self.getAppyClass(className)
 | 
					            appyClass = self.getAppyClass(className)
 | 
				
			||||||
            # Search among static searches
 | 
					            # Search among static searches
 | 
				
			||||||
| 
						 | 
					@ -747,7 +754,9 @@ class ToolMixin(BaseMixin):
 | 
				
			||||||
            # It is the search for every instance of p_className
 | 
					            # It is the search for every instance of p_className
 | 
				
			||||||
            res = Search('allSearch')
 | 
					            res = Search('allSearch')
 | 
				
			||||||
        # Return a UiSearch if required.
 | 
					        # Return a UiSearch if required.
 | 
				
			||||||
        if ui: res = UiSearch(res, className, self)
 | 
					        if ui:
 | 
				
			||||||
 | 
					            res = UiSearch(res, className, self)
 | 
				
			||||||
 | 
					            if initiator: res.setInitiator(initiator, initiatorField)
 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def advancedSearchEnabledFor(self, klass):
 | 
					    def advancedSearchEnabledFor(self, klass):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1041,7 +1041,6 @@ function onSelectObjects(nodeId, objectUrl, sortKey, sortOrder,
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  // Close the popup.
 | 
					  // Close the popup.
 | 
				
			||||||
  var parent = window.parent;
 | 
					 | 
				
			||||||
  closePopup('iframePopup');
 | 
					  closePopup('iframePopup');
 | 
				
			||||||
  /* Refresh the Ref edit widget to include the linked objects. All those
 | 
					  /* Refresh the Ref edit widget to include the linked objects. All those
 | 
				
			||||||
     parameters are needed to replay the query in the popup. */
 | 
					     parameters are needed to replay the query in the popup. */
 | 
				
			||||||
| 
						 | 
					@ -1051,6 +1050,25 @@ function onSelectObjects(nodeId, objectUrl, sortKey, sortOrder,
 | 
				
			||||||
            'filterValue': filterValue});
 | 
					            'filterValue': filterValue});
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function onSelectObject(tdId, nodeId, objectUrl) {
 | 
				
			||||||
 | 
					  /* In a Ref field with link="popup", a single object has been clicked. If
 | 
				
			||||||
 | 
					     multiple objects can be selected, simply update the corresponding checkbox
 | 
				
			||||||
 | 
					     status. Else, close the popup and return the selected object. p_tdId is
 | 
				
			||||||
 | 
					     the ID of the td that contains the checkbox. */
 | 
				
			||||||
 | 
					  var td = document.getElementById(tdId);
 | 
				
			||||||
 | 
					  // If the td is visible, simply click the checkbox.
 | 
				
			||||||
 | 
					  var checkbox = td.getElementsByTagName('input')[0];
 | 
				
			||||||
 | 
					  if (td.style.display == 'table-cell') { checkbox.click(); }
 | 
				
			||||||
 | 
					  else {
 | 
				
			||||||
 | 
					    /* Close the popup and directly refresh the initiator field with the
 | 
				
			||||||
 | 
					       selected object. */
 | 
				
			||||||
 | 
					    var uids=checkbox.value;
 | 
				
			||||||
 | 
					    closePopup('iframePopup');
 | 
				
			||||||
 | 
					    askField(':'+nodeId, objectUrl, 'edit', null, null, null, null, null,
 | 
				
			||||||
 | 
					             {'selected': uids, 'semantics': 'checked'});
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Sets the focus on the correct element in some page.
 | 
					// Sets the focus on the correct element in some page.
 | 
				
			||||||
function initFocus(pageId){
 | 
					function initFocus(pageId){
 | 
				
			||||||
  var id = pageId + '_title';
 | 
					  var id = pageId + '_title';
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -317,15 +317,18 @@ class ToolWrapper(AbstractWrapper):
 | 
				
			||||||
         var2="navInfo='search.%s.%s.%d.%d' % \
 | 
					         var2="navInfo='search.%s.%s.%d.%d' % \
 | 
				
			||||||
                (className, searchName, startNumber+currentNumber, totalNumber);
 | 
					                (className, searchName, startNumber+currentNumber, totalNumber);
 | 
				
			||||||
               cssClass=zobj.getCssFor('title')">
 | 
					               cssClass=zobj.getCssFor('title')">
 | 
				
			||||||
       <x>::zobj.getSupTitle(navInfo)</x>
 | 
					       <x var="sup=zobj.getSupTitle(navInfo)" if="sup">::sup</x>
 | 
				
			||||||
       <a if="enableLinks" class=":cssClass"
 | 
					       <a if="enableLinks" class=":cssClass"
 | 
				
			||||||
          var2="linkInPopup=inPopup or (target.target != '_self')"
 | 
					          var2="linkInPopup=inPopup or (target.target != '_self')"
 | 
				
			||||||
          target=":target.target" onclick=":target.openPopup"
 | 
					          target=":target.target" onclick=":target.openPopup"
 | 
				
			||||||
          href=":zobj.getUrl(nav=navInfo, page=zobj.getDefaultViewPage(), \
 | 
					          href=":zobj.getUrl(nav=navInfo, page=zobj.getDefaultViewPage(), \
 | 
				
			||||||
                 inPopup=linkInPopup)">:zobj.Title()</a><span
 | 
					                 inPopup=linkInPopup)">:zobj.Title()</a>
 | 
				
			||||||
          if="not enableLinks" class=":cssClass">:zobj.Title()</span><span
 | 
					       <span if="not enableLinks"
 | 
				
			||||||
          style=":showSubTitles and 'display:inline' or 'display:none'"
 | 
					             class=":not checkboxes and cssClass or ('%s clickable' % cssClass)"
 | 
				
			||||||
          name="subTitle">::zobj.getSubTitle()</span>
 | 
					             onclick=":checkboxes and ('onSelectObject(%s,%s,%s)' % (q(cbId), \
 | 
				
			||||||
 | 
					             q(rootHookId), q(uiSearch.initiator.url))) or ''">:obj.title</span>
 | 
				
			||||||
 | 
					       <span style=":showSubTitles and 'display:inline' or 'display:none'"
 | 
				
			||||||
 | 
					             name="subTitle" var="sub=zobj.getSubTitle()" if="sub">::sub</span>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
       <!-- Actions -->
 | 
					       <!-- Actions -->
 | 
				
			||||||
       <table class="noStyle" if="not inPopup and zobj.mayAct()">
 | 
					       <table class="noStyle" if="not inPopup and zobj.mayAct()">
 | 
				
			||||||
| 
						 | 
					@ -368,7 +371,9 @@ class ToolWrapper(AbstractWrapper):
 | 
				
			||||||
    pxQueryResultList = Px('''
 | 
					    pxQueryResultList = Px('''
 | 
				
			||||||
     <x var="showHeaders=showHeaders|True;
 | 
					     <x var="showHeaders=showHeaders|True;
 | 
				
			||||||
             checkboxes=uiSearch.search.checkboxes;
 | 
					             checkboxes=uiSearch.search.checkboxes;
 | 
				
			||||||
             checkboxesId=rootHookId + '_objs'">
 | 
					             checkboxesId=rootHookId + '_objs';
 | 
				
			||||||
 | 
					             cbShown=uiSearch.showCheckboxes();
 | 
				
			||||||
 | 
					             cbDisplay=cbShown and 'display:table-cell' or 'display:none'">
 | 
				
			||||||
      <table class="list" width="100%">
 | 
					      <table class="list" width="100%">
 | 
				
			||||||
       <!-- Headers, with filters and sort arrows -->
 | 
					       <!-- Headers, with filters and sort arrows -->
 | 
				
			||||||
       <tr if="showHeaders">
 | 
					       <tr if="showHeaders">
 | 
				
			||||||
| 
						 | 
					@ -380,7 +385,7 @@ class ToolWrapper(AbstractWrapper):
 | 
				
			||||||
         <x>::ztool.truncateText(_(field.labelId))</x>
 | 
					         <x>::ztool.truncateText(_(field.labelId))</x>
 | 
				
			||||||
         <x>:tool.pxSortAndFilter</x><x>:tool.pxShowDetails</x>
 | 
					         <x>:tool.pxSortAndFilter</x><x>:tool.pxShowDetails</x>
 | 
				
			||||||
        </th>
 | 
					        </th>
 | 
				
			||||||
        <th if="checkboxes" class="cbCell">
 | 
					        <th if="checkboxes" class="cbCell" style=":cbDisplay">
 | 
				
			||||||
         <img src=":url('checkall')" class="clickable"
 | 
					         <img src=":url('checkall')" class="clickable"
 | 
				
			||||||
              title=":_('check_uncheck')"
 | 
					              title=":_('check_uncheck')"
 | 
				
			||||||
              onclick=":'toggleAllCbs(%s)' % q(checkboxesId)"/>
 | 
					              onclick=":'toggleAllCbs(%s)' % q(checkboxesId)"/>
 | 
				
			||||||
| 
						 | 
					@ -391,30 +396,29 @@ class ToolWrapper(AbstractWrapper):
 | 
				
			||||||
       <tr if="not zobjects">
 | 
					       <tr if="not zobjects">
 | 
				
			||||||
        <td colspan=":len(columns)+1">:_('query_no_result')</td>
 | 
					        <td colspan=":len(columns)+1">:_('query_no_result')</td>
 | 
				
			||||||
       </tr>
 | 
					       </tr>
 | 
				
			||||||
       <tr for="zobj in zobjects" id="query_row" valign="top"
 | 
					       <tr for="zobj in zobjects" valign="top"
 | 
				
			||||||
           var2="@currentNumber=currentNumber + 1;
 | 
					           var2="@currentNumber=currentNumber + 1;
 | 
				
			||||||
                 obj=zobj.appy(); mayView=zobj.mayView()"
 | 
					                 obj=zobj.appy(); mayView=zobj.mayView();
 | 
				
			||||||
 | 
					                 cbId='%s_%s' % (checkboxesId, currentNumber)"
 | 
				
			||||||
           class=":loop.zobj.odd and 'even' or 'odd'">
 | 
					           class=":loop.zobj.odd and 'even' or 'odd'">
 | 
				
			||||||
        <td for="column in columns"
 | 
					        <td for="column in columns"
 | 
				
			||||||
            var2="field=column.field" id=":'field_%s' % field.name"
 | 
					            var2="field=column.field" id=":'field_%s' % field.name"
 | 
				
			||||||
            width=":column.width"
 | 
					            width=":column.width"
 | 
				
			||||||
            align=":column.align">:tool.pxQueryField</td>
 | 
					            align=":column.align">:tool.pxQueryField</td>
 | 
				
			||||||
        <!-- A checkbox if required -->
 | 
					        <!-- A checkbox if required -->
 | 
				
			||||||
        <td if="checkboxes" class="cbCell">
 | 
					        <td if="checkboxes" class="cbCell" id=":cbId" style=":cbDisplay">
 | 
				
			||||||
         <input type="checkbox" name=":checkboxesId" checked="checked"
 | 
					         <input type="checkbox" name=":checkboxesId" checked="checked"
 | 
				
			||||||
                value=":zobj.id" onclick="toggleCb(this)"/>
 | 
					                value=":zobj.id" onclick="toggleCb(this)"/>
 | 
				
			||||||
        </td>
 | 
					        </td>
 | 
				
			||||||
       </tr>
 | 
					       </tr>
 | 
				
			||||||
      </table>
 | 
					      </table>
 | 
				
			||||||
      <!-- The button for selecting objects and closing the popup. -->
 | 
					      <!-- The button for selecting objects and closing the popup. -->
 | 
				
			||||||
      <div if="inPopup" align=":dright">
 | 
					      <div if="inPopup and cbShown" align=":dright">
 | 
				
			||||||
       <input type="button" class="button"
 | 
					       <input type="button" class="button"
 | 
				
			||||||
              var="label=_('object_link_many');
 | 
					              var="label=_('object_link_many')"
 | 
				
			||||||
                   initiator=ztool.getObject(searchName.split(':')[0], \
 | 
					 | 
				
			||||||
                                             appy=True)"
 | 
					 | 
				
			||||||
              value=":label"
 | 
					              value=":label"
 | 
				
			||||||
              onclick=":'onSelectObjects(%s,%s,%s,%s,%s,%s)' % (q(rootHookId), \
 | 
					              onclick=":'onSelectObjects(%s,%s,%s,%s,%s,%s)' % (q(rootHookId), \
 | 
				
			||||||
                            q(initiator.url), q(sortKey), q(sortOrder), \
 | 
					                            q(uiSearch.initiator.url),q(sortKey),q(sortOrder), \
 | 
				
			||||||
                            q(filterKey), q(filterValue))"
 | 
					                            q(filterKey), q(filterValue))"
 | 
				
			||||||
              style=":'%s; %s' % (url('linkMany', bg=True), \
 | 
					              style=":'%s; %s' % (url('linkMany', bg=True), \
 | 
				
			||||||
                                  ztool.getButtonWidth(label))"/>
 | 
					                                  ztool.getButtonWidth(label))"/>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -949,7 +949,7 @@ class AbstractWrapper(object):
 | 
				
			||||||
        contentType = tool.getPortalType(klass)
 | 
					        contentType = tool.getPortalType(klass)
 | 
				
			||||||
        search = Search('customSearch', **fields)
 | 
					        search = Search('customSearch', **fields)
 | 
				
			||||||
        res = tool.executeQuery(contentType, search=search, brainsOnly=True,
 | 
					        res = tool.executeQuery(contentType, search=search, brainsOnly=True,
 | 
				
			||||||
                                noSecurity=noSecurity)
 | 
					                                noSecurity=noSecurity, maxResults='NO_LIMIT')
 | 
				
			||||||
        if res: return res._len # It is a LazyMap instance
 | 
					        if res: return res._len # It is a LazyMap instance
 | 
				
			||||||
        else: return 0
 | 
					        else: return 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue