docs: def find(self, query, **kwargs):
          '''Find concepts that match a certain query.
  
          Currently query is expected to be a dict, so that complex queries can
          be passed. You can use this dict to search for concepts or collections
          with a certain label, with a certain type and for concepts that belong
          to a certain collection.
  
          .. code-block:: python
  
              # Find anything that has a label of church.
              provider.find({'label': 'church'}
  
              # Find all concepts that are a part of collection 5.
              provider.find({'type': 'concept', 'collection': {'id': 5})
  
              # Find all concepts, collections or children of these
              # that belong to collection 5.
              provider.find({'collection': {'id': 5, 'depth': 'all'})
  
          :param query: A dict that can be used to express a query. The following
              keys are permitted:
  
              * `label`: Search for something with this label value. An empty \
                  label is equal to searching for all concepts.
              * `type`: Limit the search to certain SKOS elements. If not \
                  present `all` is assumed:
  
                  * `concept`: Only return :class:`skosprovider.skos.Concept` \
                      instances.
                  * `collection`: Only return \
                      :class:`skosprovider.skos.Collection` instances.
                  * `all`: Return both :class:`skosprovider.skos.Concept` and \
                      :class:`skosprovider.skos.Collection` instances.
              * `collection`: Search only for concepts belonging to a certain \
                  collection. This argument should be a dict with two keys:
  
                  * `id`: The id of a collection. Required.
                  * `depth`: Can be `members` or `all`. Optional. If not \
                      present, `members` is assumed, meaning only concepts or \
                      collections that are a direct member of the collection \
                      should be considered. When set to `all`, this method \
                      should return concepts and collections that are a member \
                      of the collection or are a narrower concept of a member \
                      of the collection.
  
          :returns: A :class:`lst` of concepts and collections. Each of these
              is a dict with the following keys:
  
              * id: id within the conceptscheme
              * uri: :term:`uri` of the concept or collection
              * type: concept or collection
              * label: A label to represent the concept or collection. It is \
                  determined by looking at the `**kwargs` parameter, the default \
                  language of the provider and finally falls back to `en`.
          '''
          # #  interprete and validate query parameters (label, type and collection)
          # Label
          label = None
          if 'label' in query:
              label = query['label']
          # Type: 'collection','concept' or 'all'
          type_c = 'all'
          if 'type' in query:
              type_c = query['type']
          if type_c not in ('all', 'concept', 'collection'):
              raise ValueError("type: only the following values are allowed: 'all', 'concept', 'collection'")
          #Collection to search in (optional)
          coll_id = None
          coll_depth = None
          if 'collection' in query:
              coll = query['collection']
              if not 'id' in coll:
                  raise ValueError("collection: 'id' is required key if a collection-dictionary is given")
              coll_id = coll['id']
              coll_depth = 'members'
              if 'depth' in coll:
                  coll_depth = coll['depth']
              if coll_depth not in ('members', 'all'):
                  raise ValueError(
                      "collection - 'depth': only the following values are allowed: 'members', 'all'")
  
          #build sparql query
          coll_x = ""
          if coll_id is not None and coll_depth == 'all':
              coll_x = "gvp:broaderExtended " + self.vocab_id + ":" + coll_id + ";"
          elif coll_id is not None and coll_depth == 'members':
              coll_x = "gvp:broader " + self.vocab_id + ":" + coll_id + ";"
  
  
          type_values = "((?Type = skos:Concept) || (?Type = skos:Collection))"
          if type_c == 'concept':
              type_values = "(?Type = skos:Concept)"
          elif type_c == 'collection':
              type_values = "(?Type = skos:Collection)"
          query = """
              SELECT ?Subject ?Term ?Type ?Id (lang(?Term) as ?Lang) {
              ?Subject rdf:type ?Type; dc:identifier ?Id; %s  skos:inScheme %s:; %s.
                              OPTIONAL {
                    {?Subject xl:prefLabel [skosxl:literalForm ?Term]}
                            }
              FILTER(%s)
              }""" % (self._build_keywords(label), self.vocab_id, coll_x, type_values)
          ret= self._get_answer(query, **kwargs)
          language = self._get_language(**kwargs)
          sort = self._get_sort(**kwargs)
          sort_order = self._get_sort_order(**kwargs)
          return self._sort(ret, sort, language, sort_order == 'desc')