def rewrite_elife_datasets_json(json_content, doi):
    """ this does the work of rewriting elife datasets json """
    elife_dataset_dates = []
    elife_dataset_dates.append(('10.7554/eLife.00348', 'used', 'dataro17',
        u'2010'))
    elife_dataset_dates.append(('10.7554/eLife.01179', 'used', 'dataro4',
        u'2016'))
    elife_dataset_dates.append(('10.7554/eLife.01603', 'used', 'dataro2',
        u'2012'))
    elife_dataset_dates.append(('10.7554/eLife.02304', 'used', 'dataro15',
        u'2005'))
    elife_dataset_dates.append(('10.7554/eLife.02935', 'used', 'dataro2',
        u'2014'))
    elife_dataset_dates.append(('10.7554/eLife.03583', 'used', 'dataro5',
        u'2013'))
    if doi in map(lambda dataset: dataset[0], elife_dataset_dates):
        for match_doi, used_or_generated, id, dataset_date in elife_dataset_dates:
            if doi == match_doi:
                if json_content.get(used_or_generated):
                    for dataset in json_content[used_or_generated]:
                        if dataset.get('id') and dataset['id'] == id:
                            if not dataset.get('date'):
                                dataset['date'] = dataset_date
    if doi == '10.7554/eLife.01311':
        if json_content.get('used'):
            for dataset in json_content['used']:
                if dataset.get('id') and dataset['id'] in ['dataro3',
                    'dataro4', 'dataro5']:
                    if not dataset.get('date'):
                        dataset['date'] = u'2012'
                    if not dataset.get('authors'):
                        dataset['authors'] = [{'type': 'group', 'name': 'Duke'}
                            ]
                if dataset.get('id') and dataset['id'] == 'dataro6':
                    if not dataset.get('date'):
                        dataset['date'] = u'2011'
                    if not dataset.get('authors'):
                        dataset['authors'] = [{'type': 'group', 'name':
                            'FlyBase'}]
                if dataset.get('id') and dataset['id'] == 'dataro7':
                    if not dataset.get('date'):
                        dataset['date'] = u'2011'
                    if not dataset.get('authors'):
                        dataset['authors'] = [{'type': 'group', 'name':
                            'Baylor College of Medicine (BCM)'}]
                if dataset.get('id') and dataset['id'] in ['dataro8', 'dataro9'
                    ]:
                    if not dataset.get('date'):
                        dataset['date'] = u'2012'
                    if not dataset.get('authors'):
                        dataset['authors'] = [{'type': 'group', 'name':
                            'University of California, Berkeley'}]
    if doi == '10.7554/eLife.01440':
        if json_content.get('used'):
            for dataset in json_content['used']:
                if dataset.get('id') and dataset['id'] == 'dataro1':
                    if not dataset.get('authors'):
                        dataset['authors'] = [{'type': 'group', 'name':
                            'EnsemblMetazoa'}]
    if doi == '10.7554/eLife.01535':
        if json_content.get('used'):
            for dataset in json_content['used']:
                if dataset.get('id') and dataset['id'] == 'dataro1':
                    if dataset.get('date') and dataset.get('date'
                        ) == '2000, 2005':
                        dataset['date'] = u'2000'
    if doi == '10.7554/eLife.02304':
        if json_content.get('used'):
            for dataset in json_content['used']:
                if dataset.get('id') and dataset['id'] == 'dataro11':
                    if not dataset.get('title'):
                        dataset['title'] = (
                            u'T.gondii LDH1 ternary complex with APAD+ and oxalate'
                            )
    if doi == '10.7554/eLife.03574':
        if json_content.get('used'):
            for dataset in json_content['used']:
                if dataset.get('id') and dataset['id'] == 'dataro2':
                    if not dataset.get('date'):
                        dataset['date'] = u'2006'
                    if not dataset.get('authors'):
                        dataset['authors'] = [{'type': 'group', 'name':
                            'Riley,M.'}, {'type': 'group', 'name': 'Abe,T.'
                            }, {'type': 'group', 'name': 'Arnaud,M.B.'}, {
                            'type': 'group', 'name': 'Berlyn,M.K.'}, {
                            'type': 'group', 'name': 'Blattner,F.R.'}, {
                            'type': 'group', 'name': 'Chaudhuri,R.R.'}, {
                            'type': 'group', 'name': 'Glasner,J.D.'}, {
                            'type': 'group', 'name': 'Horiuchi,T.'}, {
                            'type': 'group', 'name': 'Keseler,I.M.'}, {
                            'type': 'group', 'name': 'Kosuge,T.'}, {'type':
                            'group', 'name': 'Mori,H.'}, {'type': 'group',
                            'name': 'Perna,N.T.'}, {'type': 'group', 'name':
                            'Plunkett,G. III'}, {'type': 'group', 'name':
                            'Rudd,K.E.'}, {'type': 'group', 'name':
                            'Serres,M.H.'}, {'type': 'group', 'name':
                            'Thomas,G.H.'}, {'type': 'group', 'name':
                            'Thomson,N.R.'}, {'type': 'group', 'name':
                            'Wishart,D.'}, {'type': 'group', 'name':
                            'Wanner,B.L.'}]
    if doi == '10.7554/eLife.03676':
        if json_content.get('used'):
            for dataset in json_content['used']:
                if dataset.get('id') and dataset['id'] == 'dataro4':
                    if not dataset.get('date'):
                        dataset['date'] = u'2013'
                    if not dataset.get('authors'):
                        dataset['authors'] = [{'type': 'group', 'name':
                            'Human Gene Sequencing Center'}]
    if doi == '10.7554/eLife.03971':
        if json_content.get('used'):
            for dataset in json_content['used']:
                if dataset.get('id') and dataset['id'] == 'dataro2':
                    if not dataset.get('authors'):
                        dataset['authors'] = [{'type': 'group', 'name':
                            'Vanderperre B.'}]
    if doi == '10.7554/eLife.04660':
        if json_content.get('generated'):
            for dataset in json_content['generated']:
                if dataset.get('id') and dataset['id'] == 'dataro1':
                    if dataset.get('date') and dataset.get('date'
                        ) == '2014-2015':
                        dataset['date'] = u'2014'
    if doi == '10.7554/eLife.06421':
        if json_content.get('used'):
            for dataset in json_content['used']:
                if dataset.get('id') and dataset['id'] == 'dataro2':
                    if dataset.get('date') and dataset.get('date') == 'NA':
                        dataset['date'] = u'2006'
    if doi == '10.7554/eLife.08445':
        if json_content.get('used'):
            for dataset in json_content['used']:
                if dataset.get('id') and dataset['id'] == 'data-ro1':
                    if not dataset.get('date'):
                        dataset['date'] = u'2006'
                    if not dataset.get('authors'):
                        dataset['authors'] = [{'type': 'group', 'name':
                            'BDTNP SELEX'}]
    if doi == '10.7554/eLife.08916':
        if json_content.get('used'):
            for dataset in json_content['used']:
                if dataset.get('id') and dataset['id'] == 'dataro2':
                    if dataset.get('date') and dataset.get('date'
                        ) == '2008, updated 2014':
                        dataset['date'] = u'2008'
                if dataset.get('id') and dataset['id'] == 'dataro3':
                    if dataset.get('date') and dataset.get('date'
                        ) == '2013, updated 2014':
                        dataset['date'] = u'2013'
    if doi == '10.7554/eLife.08955':
        if json_content.get('generated'):
            for dataset in json_content['generated']:
                if dataset.get('id') and dataset['id'] == 'dataro2':
                    if not dataset.get('authors'):
                        dataset['authors'] = [{'type': 'group', 'name':
                            'Kurdistani S'}, {'type': 'group', 'name':
                            'Marrban C'}, {'type': 'group', 'name': 'Su T'}]
    if doi == '10.7554/eLife.09207':
        if json_content.get('used'):
            for dataset in json_content['used']:
                if dataset.get('id') and dataset['id'] == 'dataro1':
                    if not dataset.get('authors'):
                        dataset['authors'] = [{'type': 'group', 'name':
                            'Prostate Cancer Genome Sequencing Project'}]
    if doi == '10.7554/eLife.10607':
        if json_content.get('generated'):
            for dataset in json_content['generated']:
                if dataset.get('id') and dataset['id'] == 'data-ro4':
                    if not dataset.get('authors'):
                        dataset['authors'] = [{'type': 'group', 'name':
                            'Authors'}]
    if doi == '10.7554/eLife.10670':
        if json_content.get('used'):
            for dataset in json_content['used']:
                if dataset.get('id') and dataset['id'] == 'data-ro1':
                    if not dataset.get('authors'):
                        dataset['authors'] = [{'type': 'group', 'name':
                            'HIVdb'}]
    if doi == '10.7554/eLife.10856':
        if json_content.get('generated'):
            datasets_authors_for_10856 = [{'type': 'group', 'name':
                'Dagdas YF'}, {'type': 'group', 'name': 'Belhaj K'}, {
                'type': 'group', 'name': 'Maqbool A'}, {'type': 'group',
                'name': 'Chaparro-Garcia A'}, {'type': 'group', 'name':
                'Pandey P'}, {'type': 'group', 'name': 'Petre B'}, {'type':
                'group', 'name': 'Tabassum N'}, {'type': 'group', 'name':
                'Cruz-Mireles N'}, {'type': 'group', 'name': 'Hughes RK'},
                {'type': 'group', 'name': 'Sklenar J'}, {'type': 'group',
                'name': 'Win J'}, {'type': 'group', 'name': 'Menke F'}, {
                'type': 'group', 'name': 'Findlay K'}, {'type': 'group',
                'name': 'Banfield MJ'}, {'type': 'group', 'name':
                'Kamoun S'}, {'type': 'group', 'name': 'Bozkurt TO'}]
            for dataset in json_content['generated']:
                if dataset.get('id') and dataset['id'] == 'dataro7':
                    if not dataset.get('date'):
                        dataset['date'] = u'2016'
                    if not dataset.get('title'):
                        dataset['title'] = (
                            u'An effector of the Irish potato famine pathogen antagonizes a host autophagy cargo receptor'
                            )
                    if not dataset.get('authors'):
                        dataset['authors'] = datasets_authors_for_10856
                    if dataset.get('uri') and dataset['uri'
                        ] == 'http://www.ncbi.nlm.nih.':
                        dataset['uri'
                            ] = 'https://www.ncbi.nlm.nih.gov/nuccore/976151098/'
                if dataset.get('id') and dataset['id'] == 'dataro8':
                    if not dataset.get('date'):
                        dataset['date'] = u'2015'
                    if not dataset.get('title'):
                        dataset['title'] = (
                            u'An effector of the Irish potato famine pathogen antagonizes a host autophagy cargo receptor'
                            )
                    if not dataset.get('authors'):
                        dataset['authors'] = datasets_authors_for_10856
                    if dataset.get('uri') and dataset['uri'
                        ] == 'http://www.ncbi.nlm.nih.':
                        dataset['uri'
                            ] = 'https://www.ncbi.nlm.nih.gov/nuccore/976151096/'
                if dataset.get('id') and dataset['id'] == 'dataro9':
                    if not dataset.get('authors'):
                        dataset['authors'] = datasets_authors_for_10856
    if doi == '10.7554/eLife.10877':
        if json_content.get('generated'):
            for dataset in json_content['generated']:
                if dataset.get('id') and dataset['id'] == 'dataro1':
                    if not dataset.get('title'):
                        dataset['title'] = (
                            u'Oct4 ChIP-Seq at G1 and G2/M phase of cell cycle in mouse embryonic stem cells'
                            )
    if doi == '10.7554/eLife.10921':
        if json_content.get('generated'):
            for dataset in json_content['generated']:
                if dataset.get('id') and dataset['id'] == 'dataro1':
                    if not dataset.get('authors'):
                        dataset['authors'] = [{'type': 'group', 'name':
                            'Floor SN'}, {'type': 'group', 'name': 'Doudna JA'}
                            ]
        if json_content.get('used'):
            for dataset in json_content['used']:
                if dataset.get('id') and dataset['id'] == 'dataro2':
                    if not dataset.get('authors'):
                        dataset['authors'] = [{'type': 'group', 'name':
                            'Sidrauski C'}, {'type': 'group', 'name':
                            'McGeachy A'}, {'type': 'group', 'name':
                            'Ingolia N'}, {'type': 'group', 'name': 'Walter P'}
                            ]
    if doi == '10.7554/eLife.11117':
        if json_content.get('used'):
            for dataset in json_content['used']:
                if dataset.get('id') and dataset['id'] == 'dataro14':
                    if not dataset.get('authors'):
                        dataset['authors'] = [{'type': 'group', 'name':
                            'Authors'}]
    if doi == '10.7554/eLife.12204':
        if json_content.get('used'):
            for dataset in json_content['used']:
                if dataset.get('id') and dataset['id'] == 'dataro1':
                    if not dataset.get('authors'):
                        dataset['authors'] = [{'type': 'group', 'name':
                            'Rhodes DR'}, {'type': 'group', 'name':
                            'Kalyana-Sundaram S'}, {'type': 'group', 'name':
                            'Mahavisno V'}, {'type': 'group', 'name':
                            'Varambally R'}, {'type': 'group', 'name':
                            'Yu J'}, {'type': 'group', 'name': 'Briggs BB'},
                            {'type': 'group', 'name': 'Barrette TR'}, {
                            'type': 'group', 'name': 'Anstet MJ'}, {'type':
                            'group', 'name': 'Kincead-Beal C'}, {'type':
                            'group', 'name': 'Kulkarni P'}, {'type':
                            'group', 'name': 'Varambally S'}, {'type':
                            'group', 'name': 'Ghosh D'}, {'type': 'group',
                            'name': 'Chinnaiyan AM.'}]
                if dataset.get('id') and dataset['id'] == 'dataro2':
                    if not dataset.get('authors'):
                        dataset['authors'] = [{'type': 'group', 'name':
                            'Gaspar C'}, {'type': 'group', 'name':
                            'Cardoso J'}, {'type': 'group', 'name':
                            'Franken P'}, {'type': 'group', 'name':
                            'Molenaar L'}, {'type': 'group', 'name':
                            'Morreau H'}, {'type': 'group', 'name':
                            'Möslein G'}, {'type': 'group', 'name':
                            'Sampson J'}, {'type': 'group', 'name':
                            'Boer JM'}, {'type': 'group', 'name':
                            'de Menezes RX'}, {'type': 'group', 'name':
                            'Fodde R.'}]
                if dataset.get('id') and dataset['id'] == 'dataro3':
                    if not dataset.get('authors'):
                        dataset['authors'] = [{'type': 'group', 'name':
                            'Graudens E'}, {'type': 'group', 'name':
                            'Boulanger V'}, {'type': 'group', 'name':
                            'Mollard C'}, {'type': 'group', 'name':
                            'Mariage-Samson R'}, {'type': 'group', 'name':
                            'Barlet X'}, {'type': 'group', 'name':
                            'Grémy G'}, {'type': 'group', 'name':
                            'Couillault C'}, {'type': 'group', 'name':
                            'Lajémi M'}, {'type': 'group', 'name':
                            'Piatier-Tonneau D'}, {'type': 'group', 'name':
                            'Zaborski P'}, {'type': 'group', 'name':
                            'Eveno E'}, {'type': 'group', 'name':
                            'Auffray C'}, {'type': 'group', 'name':
                            'Imbeaud S.'}]
                if dataset.get('id') and dataset['id'] == 'dataro4':
                    if not dataset.get('authors'):
                        dataset['authors'] = [{'type': 'group', 'name':
                            'Hong Y'}, {'type': 'group', 'name': 'Downey T'
                            }, {'type': 'group', 'name': 'Eu KW'}, {'type':
                            'group', 'name': 'Koh PK'}, {'type': 'group',
                            'name': 'Cheah PY'}]
                if dataset.get('id') and dataset['id'] == 'dataro5':
                    if not dataset.get('authors'):
                        dataset['authors'] = [{'type': 'group', 'name':
                            'Kaiser S'}, {'type': 'group', 'name':
                            'Park YK'}, {'type': 'group', 'name':
                            'Franklin JL'}, {'type': 'group', 'name':
                            'Halberg RB'}, {'type': 'group', 'name': 'Yu M'
                            }, {'type': 'group', 'name': 'Jessen WJ'}, {
                            'type': 'group', 'name': 'Freudenberg J'}, {
                            'type': 'group', 'name': 'Chen X'}, {'type':
                            'group', 'name': 'Haigis K'}, {'type': 'group',
                            'name': 'Jegga AG'}, {'type': 'group', 'name':
                            'Kong S'}, {'type': 'group', 'name':
                            'Sakthivel B'}, {'type': 'group', 'name':
                            'Xu H'}, {'type': 'group', 'name':
                            'Reichling T'}, {'type': 'group', 'name':
                            'Azhar M'}, {'type': 'group', 'name':
                            'Boivin GP'}, {'type': 'group', 'name':
                            'Roberts RB'}, {'type': 'group', 'name':
                            'Bissahoyo AC'}, {'type': 'group', 'name':
                            'Gonzales F'}, {'type': 'group', 'name':
                            'Bloom GC'}, {'type': 'group', 'name':
                            'Eschrich S'}, {'type': 'group', 'name':
                            'Carter SL'}, {'type': 'group', 'name':
                            'Aronow JE'}, {'type': 'group', 'name':
                            'Kleimeyer J'}, {'type': 'group', 'name':
                            'Kleimeyer M'}, {'type': 'group', 'name':
                            'Ramaswamy V'}, {'type': 'group', 'name':
                            'Settle SH'}, {'type': 'group', 'name':
                            'Boone B'}, {'type': 'group', 'name': 'Levy S'},
                            {'type': 'group', 'name': 'Graff JM'}, {'type':
                            'group', 'name': 'Doetschman T'}, {'type':
                            'group', 'name': 'Groden J'}, {'type': 'group',
                            'name': 'Dove WF'}, {'type': 'group', 'name':
                            'Threadgill DW'}, {'type': 'group', 'name':
                            'Yeatman TJ'}, {'type': 'group', 'name':
                            'Coffey RJ Jr'}, {'type': 'group', 'name':
                            'Aronow BJ.'}]
                if dataset.get('id') and dataset['id'] == 'dataro6':
                    if not dataset.get('authors'):
                        dataset['authors'] = [{'type': 'group', 'name':
                            'Muzny DM et al'}]
                if dataset.get('id') and dataset['id'] == 'dataro7':
                    if not dataset.get('authors'):
                        dataset['authors'] = [{'type': 'group', 'name':
                            'Skrzypczak M'}, {'type': 'group', 'name':
                            'Goryca K'}, {'type': 'group', 'name':
                            'Rubel T'}, {'type': 'group', 'name':
                            'Paziewska A'}, {'type': 'group', 'name':
                            'Mikula M'}, {'type': 'group', 'name':
                            'Jarosz D'}, {'type': 'group', 'name':
                            'Pachlewski J'}, {'type': 'group', 'name':
                            'Oledzki J'}, {'type': 'group', 'name':
                            'Ostrowski J.'}]
                if dataset.get('id') and dataset['id'] == 'dataro8':
                    if not dataset.get('authors'):
                        dataset['authors'] = [{'type': 'group', 'name':
                            'Cancer Genome Atlas Network'}]
    if doi == '10.7554/eLife.12876':
        if json_content.get('used'):
            for dataset in json_content['used']:
                if dataset.get('id') and dataset['id'] == 'dataro1':
                    if not dataset.get('authors'):
                        dataset['authors'] = [{'type': 'group', 'name':
                            'Department of Human Genetics, University of Utah'}
                            ]
    if doi == '10.7554/eLife.13195':
        if json_content.get('generated'):
            for dataset in json_content['generated']:
                if dataset.get('id') and dataset['id'] == 'dataro1':
                    if not dataset.get('authors'):
                        dataset['authors'] = [{'type': 'group', 'name':
                            'Microbial Ecology Group, Colorado State University'
                            }]
    if doi == '10.7554/eLife.14158':
        if json_content.get('generated'):
            for dataset in json_content['generated']:
                if dataset.get('id') and dataset['id'] == 'data-ro1':
                    if not dataset.get('title'):
                        dataset['title'] = u'Bacterial initiation protein'
                if dataset.get('id') and dataset['id'] == 'data-ro2':
                    if not dataset.get('title'):
                        dataset['title'] = (
                            u'Bacterial initiation protein in complex with Phage inhibitor protein'
                            )
        if json_content.get('used'):
            for dataset in json_content['used']:
                if dataset.get('id') and dataset['id'] == 'dataro3':
                    if not dataset.get('date'):
                        dataset['date'] = u'2007'
    if doi == '10.7554/eLife.14243':
        if json_content.get('generated'):
            for dataset in json_content['generated']:
                if dataset.get('id') and dataset['id'] == 'dataro2':
                    if not dataset.get('authors'):
                        dataset['authors'] = [{'type': 'group', 'name':
                            'Tramantano M'}, {'type': 'group', 'name':
                            'Sun L'}, {'type': 'group', 'name': 'Au C'}, {
                            'type': 'group', 'name': 'Labuz D'}, {'type':
                            'group', 'name': 'Liu Z'}, {'type': 'group',
                            'name': 'Chou M'}, {'type': 'group', 'name':
                            'Shen C'}, {'type': 'group', 'name': 'Luk E'}]
    if doi == '10.7554/eLife.16078':
        if json_content.get('generated'):
            for dataset in json_content['generated']:
                if dataset.get('id') and dataset['id'] == 'dataro1':
                    if dataset.get('date') and dataset.get('date'
                        ) == 'current manuscript':
                        dataset['date'] = u'2016'
    if doi == '10.7554/eLife.17082':
        if json_content.get('used'):
            for dataset in json_content['used']:
                if dataset.get('id') and dataset['id'] == 'data-ro4':
                    if not dataset.get('date'):
                        dataset['date'] = u'2012'
                if dataset.get('id') and dataset['id'] == 'data-ro5':
                    if not dataset.get('date'):
                        dataset['date'] = u'2014'
                if dataset.get('id') and dataset['id'] == 'data-ro6':
                    if not dataset.get('date'):
                        dataset['date'] = u'2014'
                    if not dataset.get('authors'):
                        dataset['authors'] = [{'type': 'group', 'name':
                            'The Cancer Genome Atlas (TCGA)'}]
    if doi == '10.7554/eLife.17473':
        if json_content.get('generated'):
            for dataset in json_content['generated']:
                if dataset.get('id') and dataset['id'] == 'dataro1':
                    if dataset.get('date') and dataset.get('date').startswith(
                        'Release date'):
                        dataset['date'] = u'2016'
    return json_content


def try_int(string):
    """
    Return an integer if possible, else string
    """
    if len(string) > 1 and string[0] == '0' and string.isdigit():
        return string
    try:
        return int(string)
    except ValueError:
        return string


def process_with_padding(x, F, process=lambda x: x, pad_width=(0, 0, 0, 0,
    1, 0, 1, 0)):
    """
    Auxiliary decorator for layer with NASNet specific extra padding.

    Parameters:
    ----------
    x : NDArray
        Input tensor.
    F : module
        Gluon API module.
    process : function, default (lambda x: x)
        a decorated layer
    pad_width : tuple of int, default (0, 0, 0, 0, 1, 0, 1, 0)
        Whether the layer uses a bias vector.

    Returns
    -------
    NDArray
        Resulted tensor.
    """
    x = F.pad(x, mode='constant', pad_width=pad_width, constant_value=0)
    x = process(x)
    x = F.slice(x, begin=(None, None, 1, 1), end=(None, None, None, None))
    return x


@classmethod
def get_field_name_to_field(cls):
    """
        Returns dictionary with fieldnames defined in searchset class and field instances
        """
    if cls._field_name_to_search_field_instance is None:
        cls._field_name_to_search_field_instance = dict()
        cls._field_source_to_search_field_instance = dict()
        for name, _cls in cls.__dict__.items():
            if isinstance(_cls, cls._field_base_class):
                cls._field_name_to_search_field_instance[name] = _cls
                if (_cls.use_field_class_for_sources and not _cls.
                    exclude_sources_from_mapping and _cls.sources):
                    for field_source in _cls.sources:
                        cls.append_field_source_to_search_field_instance(source
                            =field_source, instance=_cls.__class__())
    return cls._field_name_to_search_field_instance


def new_merged_dict(*dicts):
    """Merges dictionaries into a new dictionary. Necessary for python2 and
    python34 since neither have PEP448 implemented."""
    output = {}
    for d in dicts:
        output.update(d)
    return output


@classmethod
def collapse_data(cls, data, function=None, kdims=None, **kwargs):
    """
        Class method to collapse a list of data matching the
        data format of the Element type. By implementing this
        method HoloMap can collapse multiple Elements of the
        same type. The kwargs are passed to the collapse
        function. The collapse function must support the numpy
        style axis selection. Valid function include:
        np.mean, np.sum, np.product, np.std, scipy.stats.kurtosis etc.
        Some data backends also require the key dimensions
        to aggregate over.
        """
    raise NotImplementedError('Collapsing not implemented for %s.' % cls.
        __name__)


@staticmethod
def setup_command_line(parser):
    """Setup the command line options for Ramsey formula

        Arguments:
        - `parser`: parser to load with options.
        """
    parser.add_argument('s', metavar='<s>', type=int, help=
        'Forbidden independent set size')
    parser.add_argument('k', metavar='<k>', type=int, help=
        'Forbidden independent clique')
    parser.add_argument('N', metavar='<N>', type=int, help='Graph size')


def nodeset_cmpkey(nodeset):
    """We want larger nodeset first, then sorted by first node index."""
    return -len(nodeset), nodeset[0]


def elem_Q(w, Q, n):
    """
    Simulation Function: -Q-

    Inputs
    ----------
    w = Angular frequency [1/s]
    Q = Constant phase element [s^n/ohm]
    n = Constant phase elelment exponent [-]
    """
    return 1 / (Q * (w * 1.0j) ** n)


def scrub_output_pre_save(model, **kwargs):
    """scrub output before saving notebooks"""
    if model['type'] != 'notebook':
        return
    if model['content']['nbformat'] != 4:
        return
    for cell in model['content']['cells']:
        if cell['cell_type'] != 'code':
            continue
        cell['outputs'] = []
        cell['execution_count'] = None


def edgecolor_by_source(G, node_colors):
    """ Returns a list of colors to set as edge colors based on the source node for each edge.

    Parameters
    ----------

    G : graph.
        A networkx graph.

    node_colors : list
        List of node colors.

    Example
    --------

    >>> colormap = {'male':'b','female':'r'}
    >>> node_colors = set_node_color(G,"gender",colormap)
    >>> edge_colors = edgecolor_by_source(G,node_colors)

    Returns
    -------
    list
        list of colors for each edge of the graph color set by the source node.

    """
    edge_colormap = []
    node_colormap = dict(zip(G.nodes(), node_colors))
    for edge in G.edges():
        edge_colormap.append(node_colormap[edge[0]])
    return edge_colormap


@staticmethod
def positional_to_model(value):
    """Converts a positional argument to a model value"""
    return value


def authenticator(f):
    """A wrapper to allow developers to set a context creator that's appropriate
    for their particular API.
    """
    global authenticate_context
    authenticate_context = f
    return f


def shift_mesh(mesh, vector):
    """
    Shift a given mesh with a given vector.

    Parameters
    ----------
    mesh : single dict
        dictionary containing
        at least the following keyword
            nodes : ndarray
                Array with all node postions.
    vector : ndarray
        array containing the shifting vector
    """
    for i in range(3):
        mesh['nodes'][:, (i)] += vector[i]
    return mesh


def instance(obj):
    """
    Return the instance the proxy is wrapping.

    Usage:

    >>> class Example(object):
    ...     pass
    >>> class Proxy(object):
    ...     pass
    >>> Proxy = wrap_with(Example)
    >>> example = Example()
    >>> proxy_obj = Proxy(example)
    >>> instance(proxy_obj) is example
    True
    """
    return obj.__instance__


@classmethod
def from_results(cls, api_results):
    """Generates HelpScout objects from API results.

        Parameters
        ----------
        api_results: generator({cls.key: [dict]}) or generator(dict)
            A generator returning API responses that cointain a list of
            objects each under the class key.

        Returns
        -------
        [HelpScoutObject]
        """
    results = []
    for api_result in api_results:
        for object_data in api_result.get(cls.key, [api_result]):
            if len(object_data) > 0:
                results.append(cls(object_data))
    return results


@classmethod
def restore_padding(cls, receipt):
    """Restore padding based on receipt size.

        :param receipt: receipt to restore padding on
        :type receipt: six.text_type
        :returns: receipt with correct padding

        """
    mod_returned = len(receipt) % 4
    if mod_returned:
        missing_padding = 4 - mod_returned
        receipt += '=' * missing_padding
    return receipt


def do_gc(opts, repository):
    """Clean up the repository"""
    repository.gc(max_versions=opts.max_versions)


@staticmethod
def get_active_x(plot):
    """ Return the active x which is a parameter belonging to the x parameters list

        Args:
            plot:

        Returns:

        """
    return plot.active_x


def describe_reserved_node_offerings(ReservedNodeOfferingId=None,
    MaxRecords=None, Marker=None):
    """
    Returns a list of the available reserved node offerings by Amazon Redshift with their descriptions including the node type, the fixed and recurring costs of reserving the node and duration the node will be reserved for you. These descriptions help you determine which reserve node offering you want to purchase. You then use the unique offering ID in you call to  PurchaseReservedNodeOffering to reserve one or more nodes for your Amazon Redshift cluster.
    For more information about reserved node offerings, go to Purchasing Reserved Nodes in the Amazon Redshift Cluster Management Guide .
    See also: AWS API Documentation

    :example: response = client.describe_reserved_node_offerings(
        ReservedNodeOfferingId='string',
        MaxRecords=123,
        Marker='string'
    )

    :type ReservedNodeOfferingId: string
    :param ReservedNodeOfferingId: The unique identifier for the offering.

    :type MaxRecords: integer
    :param MaxRecords: The maximum number of response records to return in each call. If the number of remaining response records exceeds the specified MaxRecords value, a value is returned in a marker field of the response. You can retrieve the next set of records by retrying the command with the returned marker value.
            Default: 100
            Constraints: minimum 20, maximum 100.

    :type Marker: string
    :param Marker: An optional parameter that specifies the starting point to return a set of response records. When the results of a DescribeReservedNodeOfferings request exceed the value specified in MaxRecords , AWS returns a value in the Marker field of the response. You can retrieve the next set of response records by providing the returned marker value in the Marker parameter and retrying the request.

    :rtype: dict
    :return: {
        'Marker': 'string',
        'ReservedNodeOfferings': [
            {
                'ReservedNodeOfferingId': 'string',
                'NodeType': 'string',
                'Duration': 123,
                'FixedPrice': 123.0,
                'UsagePrice': 123.0,
                'CurrencyCode': 'string',
                'OfferingType': 'string',
                'RecurringCharges': [
                    {
                        'RecurringChargeAmount': 123.0,
                        'RecurringChargeFrequency': 'string'
                    },
                ]
            },
        ]
    }

    """
    pass


def nextWord(s, i0, ignoreNewLine=False):
    """
    Find word from position i
    :param s: text string
    :param i0: current position
    :param ignoreNewLine: pass newline, when search for word
    :return: word, positionJustAfterWord. None, None if end of string or newline encountered
    """
    if i0 >= len(s):
        return None, None
    allwhitespace = [' ', '\t', '\n', '\r']
    whitespace = [' ', '\t']
    if ignoreNewLine:
        whitespace = allwhitespace
    i = i0
    while s[i] in whitespace:
        i += 1
        if i >= len(s):
            return None, None
    if s[i] in allwhitespace:
        return None, None
    k = i
    while s[k] not in allwhitespace:
        k += 1
        if k >= len(s):
            return s[i:k], k
    word = s[i:k]
    return word, k


@classmethod
def remove_compute_resource(cls, options=None):
    """Disassociate a compute resource"""
    cls.command_sub = 'remove-compute-resource'
    return cls.execute(cls._construct_command(options))


def doc_view(doc_id: str=''):
    """Open online reference docs in a web browser

    :param doc_id: Doc ID
    :type doc_id: str
    """
    pass


def delete_bucket(Bucket=None):
    """
    Deletes the bucket. All objects (including all object versions and Delete Markers) in the bucket must be deleted before the bucket itself can be deleted.
    See also: AWS API Documentation

    :example: response = client.delete_bucket(
        Bucket='string'
    )

    :type Bucket: string
    :param Bucket: [REQUIRED]

    """
    pass


def calc_crc(raw):
    """Calculate cyclic redundancy check (CRC)."""
    crc = 0
    for sym in raw:
        crc = crc ^ int(sym)
    return crc


def write_to_file(path: str, content: str, mode: str='a') ->None:
    """Writes content into filepath."""
    with open(path, mode) as file:
        file.write(content)


def read_decorrelation_weights(block_header, decorrelation_terms_count,
    sub_block_size, actual_size_1_less, sub_block_data):
    """returns one tuple of decorrelation weights per decorrelation pass
    the number of weights in each tuple equals the number of channels

    weight[pass][channel]
    """
    if actual_size_1_less == 0:
        weight_count = sub_block_size * 2
    else:
        weight_count = sub_block_size * 2 - 1
    weight_values = []
    for i in range(weight_count):
        value_i = sub_block_data.read_signed(8)
        if value_i > 0:
            weight_values.append(value_i * 2 ** 3 + (value_i * 2 ** 3 + 2 **
                6) // 2 ** 7)
        elif value_i == 0:
            weight_values.append(0)
        else:
            weight_values.append(value_i * 2 ** 3)
    weights = []
    if block_header.mono_output == 0 and block_header.false_stereo == 0:
        if weight_count // 2 > decorrelation_terms_count:
            raise ValueError('invalid number of decorrelation weights')
        for i in range(weight_count // 2):
            weights.append((weight_values[i * 2], weight_values[i * 2 + 1]))
        for i in range(weight_count // 2, decorrelation_terms_count):
            weights.append((0, 0))
        weights.reverse()
    else:
        if weight_count > decorrelation_terms_count:
            raise ValueError('invalid number of decorrelation weights')
        for i in range(weight_count):
            weights.append((weight_values[i],))
        for i in range(weight_count, decorrelation_terms_count):
            weights.append((0, 0))
        weights.reverse()
    return weights


def make_template_name(base):
    """Create template name from base."""
    return base + '_tmpl'


def is_url(string):
    """
    Checks if the given string starts with 'http(s)'.
    """
    try:
        return string.startswith('http://') or string.startswith('https://')
    except AttributeError:
        return False


def db2mag(dB):
    """
      Converts from dB to linear magnitude.

    :param dB:  dB level to be converted.
    :return:    linear magnitude of the dB input.
    """
    mag = 10 ** (dB / 20.0)
    return mag


@staticmethod
def _reversechunks(fulllist, chunklength):
    """Yield successive n-sized chunks from l."""
    for pos in range(len(fulllist) - chunklength, -1, -chunklength):
        yield fulllist[pos:pos + chunklength]


def clean_database():
    """
    Clean the database
    :return:
    """
    return None


def getParamNames(v):
    """
    Takes a VOEvent and produces a list of pairs of group name and param name.
    For a bare param, the group name is the empty string.
    """
    list = []
    w = v.get_What()
    if not w:
        return list
    for p in v.get_What().get_Param():
        list.append(('', p.get_name()))
    for g in v.get_What().get_Group():
        for p in v.get_What().get_Param():
            list.append((g.get_name(), p.get_name()))
    return list


def import_onnx_modules():
    """ To make sure ONNX is runtime dependency, it is imported used only when needed"""
    try:
        from onnx import helper, numpy_helper, mapping
    except ImportError:
        raise ImportError('Onnx and protobuf need to be installed. ' +
            'Instructions to install - https://github.com/onnx/onnx')
    return helper, numpy_helper, mapping


def pairwise_snp_counts(fas, out_tsv):
    """ calculate pairwise snp overlap amongst a list of fasta using multiple
    alignment

    Parameters
    ----------
    fas: list
        a list of fasta files
    out_tsv: str
        output path of the pairwise SNP matrix
    """


def create_package(name, data, package_cls=None):
    """Create a package given package data.

    Args:
        name (str): Package name.
        data (dict): Package data. Must conform to `package_maker.package_schema`.

    Returns:
        `Package` object.
    """
    from rez.package_maker__ import PackageMaker
    maker = PackageMaker(name, data, package_cls=package_cls)
    return maker.get_package()


@staticmethod
def __looks_like_html(response):
    """Guesses entity type when Content-Type header is missing.
        Since Content-Type is not strictly required, some servers leave it out.
        """
    text = response.text.lstrip().lower()
    return text.startswith('<html') or text.startswith('<!doctype')


@classmethod
def _bld(cls, adapter, tag=None, has_metadata=None, ns=None, attrib=None):
    """Create a fresh ElementWrapper.

        :param adapter: A pypowervm.adapter.Adapter (for traits, etc.)
        :param tag: XML tag for the ElementWrapper's root Element.
        :param has_metadata: If True, a basic <Metadata/> child is created
                             under the root element.
        :param ns: XML namespace for the contents.
        :param attrib: XML attributes for the root element.
        """
    ret = cls()
    ret.element = cls._bld_element(adapter, tag=tag, has_metadata=
        has_metadata, ns=ns, attrib=attrib)
    return ret


def setup(mail_verification=False, require_user_to_be_verified=False,
    use_sessions_when_client_calls_endpoint=False, *fixed_user_attributes):
    """Use `mail_verification` to control whether the register function should automatically try to verify the users' email. You can also manually do that by calling `serverly.user.mail.send_verification_email()`.

    If `require_user_to_be_verified`, users will only authenticate if their email is verified.

    If `use_sessions_when_client_calls_endpoint`, a new user activity will automatically be registered if the client uses an endpoint.

    `fixed_user_attributes` is a list which contains the attribute names of User attributes which may not be changed by the API. Useful for roles.
    """
    global verify_mail, only_user_verified, use_sessions, persistant_user_attributes
    verify_mail = mail_verification
    only_user_verified = require_user_to_be_verified
    use_sessions = use_sessions_when_client_calls_endpoint
    persistant_user_attributes = fixed_user_attributes


@staticmethod
def _has_policy(fwg):
    """Verifying fwg has policy or not"""
    return bool(fwg['ingress_firewall_policy_id'] or fwg[
        'egress_firewall_policy_id'])


def read_file_to_dict_with_start(filepath):
    """
    Returns dictionary with the first column as key and second column as value.
    Allows for a start column, at which point there is a data key added and the info is added as a list.
    """
    with open(filepath) as F:
        fileDict = dict()
        startFlag = 0
        dataList = list()
        for i in F:
            i = i.rstrip().split(',')
            if startFlag == 0 and i[0] != 'START':
                fileDict[i[0]] = i[1]
            elif i[0] == 'START':
                startFlag += 1
            else:
                dataList.append(i)
        fileDict['data'] = dataList
    return fileDict


def rate(hit, num):
    """Return the fraction of `hit`/`num`, as a string."""
    if num == 0:
        return '1'
    else:
        return '%.4g' % (float(hit) / num)


def render_pep440_pre(pieces):
    """TAG[.post.devDISTANCE] -- No -dirty.

    Exceptions:
    1: no tags. 0.post.devDISTANCE
    """
    if pieces['closest-tag']:
        rendered = pieces['closest-tag']
        if pieces['distance']:
            rendered += '.post.dev%d' % pieces['distance']
    else:
        rendered = '0.post.dev%d' % pieces['distance']
    return rendered


def format_size(size, threshold=1536):
    """Return file size as string from byte size.

    >>> format_size(1234)
    '1234 B'
    >>> format_size(12345678901)
    '11.50 GiB'

    """
    if size < threshold:
        return f'{size} B'
    for unit in ('KiB', 'MiB', 'GiB', 'TiB', 'PiB'):
        size /= 1024.0
        if size < threshold:
            return f'{size:.2f} {unit}'
    return 'ginormous'


def get_z() ->int:
    """Gives the reading of the magnetic force on the ``x`` axis, as a
    positive or negative integer, depending on the direction of the
    force.
    """


def gby_count(df, col, col_full_name=False):
    """
    Perform groupby count aggregation, rename column to count,
    and keep flat structure of DataFrame.
    Wrapper on pd.DataFrame.groupby
    """
    if col_full_name:
        col_name = 'count_' + col
    else:
        col_name = 'count'
    return df.groupby(col).size().reset_index(name=col_name).sort_values(by
        =col_name, ascending=False)


def normalize_deps(dep_map):
    """Returns a copy of *dep_map* with no duplicate dependencies for a
    given target, and all dependencies properly represented as targets.
    """
    ret = type(dep_map)()
    for k, _deps in dep_map.items():
        cur_seen = set()
        ret[k] = []
        for d in _deps:
            if d not in ret:
                ret[d] = []
            if d in cur_seen:
                continue
            ret[k].append(d)
            cur_seen.add(d)
    return ret


def new_file(id):
    """Allocate a new file with the given ID.
        """


@staticmethod
def psychrometric_constant(p, **kwargs):
    """Return the psychrometric constant (:math:`\\gamma`) *[kPa/°C]* according to
        `FAO 56 <http://www.fao.org/tempref/SD/Reserved/Agromet/PET/FAO_Irrigation_Drainage_Paper_56.pdf>`_
        eq. 8, p. 32:

        .. math::

            \\gamma = \\frac{c_p P}{\\varepsilon \\lambda}

        or, using default values:

        .. math::

            \\gamma = a_{psy} \\cdot P

        :param p: atmospheric pressure (:math:`P`) *[kPa]*
        :type p: float or np.array

        :Keyword Arguments:

           * **lamda** (*float*) - latent heat of vaporization (:math:`\\lambda`) *[MJ/kg]*. Default :math:`lamda=2.45`.
             See Used in :meth:`latent_heat_of_vaporization`
           * **cp** (*float*) - specific heat at constant pressure (:math:`c_p`) *[MJ/kg]*. Default
             :math:`cp=1.013e^{-3}`
           * **epsilon** (*float*) - ratio molecular weight of water vapour/dry air (:math:`\\epsilon`) *[-]*.
             Default :math:`epsilon=0.622`
           * **a_psy** (*float*) - coefficient depending on the type of the ventilation of the bulb *[1/°C]*. Examples:

             * :math:`a_{psy} = 0.000665` (default)
             * :math:`a_{psy} = 0.000662` for ventilated (Asmann type) psychrometers, with an air movement of some 5
               *m/s*
             * :math:`a_{psy} = 0.000800` for natural ventilated psychrometers (about 1 *m/s*)
             * :math:`a_{psy} = 0.001200` for non-ventilated psychrometers installed indoors

        The method uses :math:`a_{psy}` if given, otherwise eq. 8 (see above) with given or default values. Default
        values correspond to :math:`a_{psy} = 0.000665` as argument.

        :return: (*float or np.array*) psychrometric constant (:math:`\\gamma`) *[kPa/°C]*
        """
    if 'a_psy' in kwargs:
        return kwargs.get('a_psy', 0.000665) * p
    else:
        return kwargs.get('cp', 0.001013) * p / (kwargs.get('epsilon',
            0.622) * kwargs.get('lamda', 2.45))


def _shift(x, y, z, A, B, C, d):
    """
    Shift point p=(x, y, z) along n=(A, B, C) to distance d.

    It is assumed that |n| = 1. In many cases I define coordinates of n manually
    and thus know in advance that they are normalized. Do not computing
    normalization here helps to save this computation for these case.
    """
    xx = x + A * d
    yy = y + B * d
    zz = z + C * d
    return xx, yy, zz


def when(event_name, *next_steps):
    """
    Constructs tuples for use by `feature`
    :param event_name:
    :param next_steps:
    :return:
    """
    return event_name, next_steps


@classmethod
def fromstring(cls, string):
    """
        Parse the string into a quantity object.
        :param string:
        :return:
        """
    values = cls.parser_re.match(string).groupdict()
    try:
        magnitude = int(values['magnitude'])
    except ValueError:
        magnitude = float(values['magnitude'])
    units = cls.parse_units(values['units'])
    return cls(magnitude, units)


def hide_view_clear():
    """Reveal the layer by setting the hide flag

    """
    pass


def fromSuccessResponse(cls, success_response, signed_only=True):
    """Create a C{L{TeamsResponse}} object from a successful OpenID
        library response
        (C{L{openid.consumer.consumer.SuccessResponse}}) response
        message

        @param success_response: A SuccessResponse from consumer.complete()
        @type success_response: C{L{openid.consumer.consumer.SuccessResponse}}

        @param signed_only: Whether to process only data that was
            signed in the id_res message from the server.
        @type signed_only: bool

        @rtype: TeamsResponse
        @returns: A teams extension response with the teams the OpenID
            provider provided.
        """
    self = cls()
    if signed_only:
        args = success_response.getSignedNS(self.ns_uri)
    else:
        args = success_response.message.getArgs(self.ns_uri)
    if not args:
        return None
    self.teams = args['is_member'].split(',')
    return self


def duck_type_collection(specimen, default=None):
    """Given an instance or class, guess if it is or is acting as one of
    the basic collection types: list, set and dict.  If the __emulates__
    property is present, return that preferentially.
    """
    if hasattr(specimen, '__emulates__'):
        if specimen.__emulates__ is not None and issubclass(specimen.
            __emulates__, set):
            return set
        else:
            return specimen.__emulates__
    isa = isinstance(specimen, type) and issubclass or isinstance
    if isa(specimen, list):
        return list
    elif isa(specimen, set):
        return set
    elif isa(specimen, dict):
        return dict
    if hasattr(specimen, 'append'):
        return list
    elif hasattr(specimen, 'add'):
        return set
    elif hasattr(specimen, 'set'):
        return dict
    else:
        return default


def successor(i, k, l):
    """
    Computes the successor of time `i` in a k-l loop.

    .. note::
        References, see Definition 6
        in Biere et al - ``Bounded Model Checking'' - 2003

    .. note::
        An other implementation of this function (w/ the same semantics) exists
        in :mod:`pynusmv.bmc.utils`. This version is merely re-implemented to
        1. show that it can be easily done
        2. stick closely to the definition given in the paper by Biere et al.
            (see other note)

    .. warning::
        To be consistent with the way the loop condition is implemented (equiv
        of all the state variables), we have that walking 'k' steps means to be
        back at step 'l'. Hence, the value of i can only vary from 0 to k-1
        (and will repeat itself in the range [l; k-1]

    :param i: the current time
    :param k: the maximum (horizon/bound) time of the problem
    :param l: the time where the loop starts

    :return: the k-l loop successor of i
    """
    return i + 1 if i < k - 1 else l


def parent_status_update_needed(action):
    """Return if the status of the parent action needs to be updated

    Return value for update_parent_status key in action inputs
    """
    return len(action) > 0 and hasattr(action[0], 'inputs') and action[0
        ].inputs.get('update_parent_status', True)


def ma(f, c, p=20):
    """Calculate the mean on a rolling basis.

    Parameters
    ----------
    f : pandas.DataFrame
        Dataframe containing the column ``c``.
    c : str
        Name of the column in the dataframe ``f``.
    p : int
        The period over which to calculate the rolling mean.

    Returns
    -------
    new_column : pandas.Series (float)
        The array containing the new feature.

    References
    ----------
    *In statistics, a moving average (rolling average or running average)
    is a calculation to analyze data points by creating series of averages
    of different subsets of the full data set* [WIKI_MA]_.

    .. [WIKI_MA] https://en.wikipedia.org/wiki/Moving_average

    """
    new_column = f[c].rolling(p).mean()
    return new_column


@staticmethod
def _prune_tails(parent_map, child_map, tails_to_remove):
    """Remove tails from the parent map.

        This will remove the supplied revisions until no more children have 0
        parents.

        :param parent_map: A dict of {child: [parents]}, this dictionary will
            be modified in place.
        :param tails_to_remove: A list of tips that should be removed,
            this list will be consumed
        :param child_map: The reverse dict of parent_map ({parent: [children]})
            this dict will be modified
        :return: None, parent_map will be modified in place.
        """
    while tails_to_remove:
        next = tails_to_remove.pop()
        parent_map.pop(next)
        children = child_map.pop(next)
        for child in children:
            child_parents = parent_map[child]
            child_parents.remove(next)
            if len(child_parents) == 0:
                tails_to_remove.append(child)


def __call__(text):
    """
        return text formatted
        """


def expand_mins_secs(mins, secs):
    """Format string expansion of `mins`, `secs` to the appropriate units up to (days, hours)

    Parameters
    ----------
    mins: Integer
        Number of minutes to be expanded to the appropriate string format
    secs: Integer
        Number of seconds to be expanded to the appropriate string format

    Returns
    -------
    String
        Formatted pair of one of the following: (minutes, seconds); (hours, minutes); or
        (days, hours) depending on the appropriate units given `mins`

    Examples
    --------
    >>> assert expand_mins_secs(34, 57) == "34m57s"
    >>> assert expand_mins_secs(72, 57) == "01h12m"
    >>> assert expand_mins_secs(1501, 57) == "01d01h"
    >>> assert expand_mins_secs(2880, 57) == "02d00h"
    """
    if mins < 60:
        return '{:>02d}m{:>02d}s'.format(int(mins), int(secs))
    else:
        hours, mins = divmod(mins, 60)
        if hours < 24:
            return '{:>02d}h{:>02d}m'.format(int(hours), int(mins))
        else:
            days, hours = divmod(hours, 24)
            return '{:>02d}d{:>02d}h'.format(int(days), int(hours))


def dominates(p, q):
    """
    Test for path domination.  An individual path element *a*
    dominates another path element *b*, written as *a* >= *b* if
    either *a* == *b* or *a* is a wild card.  A path *p* = *p1*, *p2*,
    ..., *pn* dominates another path *q* = *q1*, *q2*, ..., *qm* if
    *n* == *m* and, for all *i*, *pi* >= *qi*.

    """
    return len(p) == len(q) and all(map(lambda es: es[0] == es[1] or es[0] ==
        '*', zip(p, q)))


@classmethod
def get_electeds(cls, ballottype, result):
    """Return the elected subject"""
    result_set = list(set(result))
    if len(result) == 0:
        return []
    sorted_results = sorted(result_set)
    len_result = len(result_set)
    median = len_result // 2
    if median == 0:
        return [sorted_results[-1]]
    elif len_result % 2 == 0:
        return [sorted_results[median + 1]]
    else:
        return [sorted_results[median]]


def chemical_symbol_first(chaine):
    """ Makes sure that the element symbol comes before the number.
    This is only to comply with the xml format that prohibits string starting
    with a number.
    """
    valeur_num = ''
    valeur_car = ''
    for truc in range(len(chaine)):
        if chaine[truc] in '0123456789':
            valeur_num += chaine[truc]
        else:
            valeur_car += chaine[truc]
    return valeur_car + valeur_num


def append(a, vancestors):
    """
    Append ``a`` to the list of the virtual ancestors, unless it is already
    included.
    """
    add = True
    for j, va in enumerate(vancestors):
        if issubclass(va, a):
            add = False
            break
        if issubclass(a, va):
            vancestors[j] = a
            add = False
    if add:
        vancestors.append(a)


def avg2(num1, num2):
    """Returns the average of two numbers."""
    return (num1 + num2) / 2.0


def revoke_mail_code(strategy, details, **kwargs):
    """Remove old mail validation code for Python Social Auth.

    PSA keeps them around, but we really don't need them again.
    """
    data = strategy.request_data()
    if 'email' in details and details['email'] and 'verification_code' in data:
        try:
            code = strategy.storage.code.objects.get(code=data[
                'verification_code'], email=details['email'], verified=True)
            code.delete()
        except strategy.storage.code.DoesNotExist:
            return


def write_cluster(adata, keys, cluster_fn, sep='\t'):
    """Export cell clustering as a text table
    """
    if not isinstance(keys, (list, tuple)):
        keys = [keys]
    for key in keys:
        if key not in adata.obs.keys():
            raise KeyError(f'{key} is not a valid `.uns` key')
    adata.obs[keys].reset_index(level=0).rename(columns={'index': 'cells'}
        ).to_csv(cluster_fn, sep=sep, header=True, index=False)


def cube_project(cube_size: float=1.0, correct_aspect: bool=True,
    clip_to_bounds: bool=False, scale_to_bounds: bool=False):
    """Project the UV vertices of the mesh over the six faces of a cube

    :param cube_size: Cube Size, Size of the cube to project on
    :type cube_size: float
    :param correct_aspect: Correct Aspect, Map UVs taking image aspect ratio into account
    :type correct_aspect: bool
    :param clip_to_bounds: Clip to Bounds, Clip UV coordinates to bounds after unwrapping
    :type clip_to_bounds: bool
    :param scale_to_bounds: Scale to Bounds, Scale UV coordinates to bounds after unwrapping
    :type scale_to_bounds: bool
    """
    pass


def size_to_kb_mb_string(data_size: int, as_additional_info: bool=False) ->str:
    """Returns human-readable string with kilobytes or megabytes depending on the data_size range.

		:param data_size: data size in bytes to convert
		:param as_additional_info:
		if True, the dynamic data appear in round bracket after the number in bytes. e.g. '12345678 bytes (11.7 MB)'
		if False, only the dynamic data is returned e.g. '11.7 MB' """
    if data_size < 1024:
        as_additional_info = False
        dynamic = f'{data_size} bytes'
    elif data_size < 1048576:
        dynamic = f'{data_size / 1024:0.1f} kB'
    else:
        dynamic = f'{data_size / 1048576:0.1f} MB'
    if as_additional_info:
        return f'{data_size} bytes ({dynamic})'
    else:
        return dynamic


def getTimes():
    """Returns a tuple of (start, end) but end==0 indicates that this
        is a 'point event', which has no duration.

        WorkerConnect/Disconnect are point events. Ping is not: it starts
        when requested and ends when the response (positive or negative) is
        returned"""


def subexon_connectivity(subexon_table, id_column='SubexonIDCluster'):
    """
    Return a set of connected subexon tuples.

    Each tuple has two elements, 'SubexonIDCluster' (directed) pairs.
    The first subexon appears before of the second in at least one transcript.
    """
    connected_pairs = []
    col_index = subexon_table.columns.get_loc(id_column)
    for _, transcript_df in subexon_table.groupby('TranscriptIDCluster'):
        transcript = transcript_df.sort_values(by='SubexonRank', ascending=True
            )
        nrows = transcript.shape[0]
        if nrows > 1:
            for row_index in range(1, nrows):
                connected_pairs.append((transcript.iloc[row_index - 1,
                    col_index], transcript.iloc[row_index, col_index]))
    return set(connected_pairs)


def _get_bw_summary(coords, annotation):
    """Return summary of BigWig scores in an interval
    """
    chrom, start, end = coords
    try:
        return annotation.summarize(str(chrom), start, end, end - start
            ).min_val[0]
    except AttributeError:
        return None


def load_config(path):
    """
    Load device configuration from file path and return list with parsed lines.

    :param path: Location of configuration file.
    :type path: str
    :rtype: list
    """
    args = []
    with open(path, 'r') as fp:
        for line in fp.readlines():
            if line.strip() and not line.startswith('#'):
                args.append(line.replace('\n', ''))
    return args


def _deduplication_todo(columns, df):
    """
    Returns what to compute for each column in dict form, given the metric parameters.

    :param columns:
    :type columns: list
    :param df:
    :type df: DataFrame
    :return: Dict containing what to run (pandas functions names or named lambdas) for each column.
    :rtype: dict
    """
    todo = dict()
    for col in columns:
        todo[col] = ['nunique']
    return todo


def remarkVersion():
    """
    Returns the version of Remark as a string.
    """
    return '1.7.7'


def create_description():
    """ create the html description of a list type """


def processEscapes(text, restore=False):
    """
    Parameter:  String (unicode or bytes).
    Returns:    The `text`, with after processing the following backslash
                escape sequences. This is useful if you want to force a "dumb"
                quote or other character to appear.

                Escape  Value
                ------  -----
                \\\\      \
                \\"      "
                \\'      '
                \\.      .
                \\-      -
                \\`      `
    """
    replacements = ('\\\\', '\'), ('\\"', '"'), ("\\'", '''), (
        '\\.', '.'), ('\\-', '-'), ('\\`', '`')
    if restore:
        for ch, rep in replacements:
            text = text.replace(rep, ch[1])
    else:
        for ch, rep in replacements:
            text = text.replace(ch, rep)
    return text


def integerify(B, r):
    """A bijection from ({0, 1} ** k) to {0, ..., (2 ** k) - 1"""
    Bi = (2 * r - 1) * 16
    return B[Bi]


def dependents():
    """Return a sequence of dependent object locations.
        """


def line2date(line, dlconfig):
    """
    Gets a date from a line of file according to dataloggerConfig object.

    Parameters
    ----------
    line: string
        line of file with date inside
    dlconfig: pymicra.dataloggerConfig
        configuration of the datalogger

    Returns
    -------
    timestamp: datetime object
    """
    import datetime as dt
    import numpy as np
    import re
    connector = dlconfig.date_connector
    date_col_names = dlconfig.date_col_names
    date_cols = dlconfig.date_cols
    sep = dlconfig.columns_separator
    datefmt = connector.join(date_col_names)
    if sep == 'whitespace':
        sep = '\\s*'
    line = np.array(re.split(sep, line.strip()))
    s = connector.join(line[date_cols])
    return dt.datetime.strptime(s, datefmt)


def _rem_dup_leg(ax):
    """
	Removes duplicate legend entries.

	Parameters
	----------
	ax : plt.axishandle
		Axis handle containing entries to remove.

	Returns
	-------
	han_list : list
		List of axis handles.

	lab_list : list
		List of axis handle labels.
	"""
    han, lab = ax.get_legend_handles_labels()
    han_list, lab_list = [], []
    for h, l in zip(han, lab):
        if l not in lab_list:
            han_list.append(h)
            lab_list.append(l)
    return han_list, lab_list


def check_satisfaction_criteria(shards):
    """check_satisfaction_criteria(shards)

    Given an interable collection of shards, this function determines
    both which of the group member thresholds have been satisfied by
    the selecton and whether the overall group threshold has been met.
    This function returns a pair of elements, the first item is a boolean
    representing whether or not the overall group threshold is met and the
    second is a set of group indexes whose thresholds have been met.
    """
    groups = {}
    filled = set()
    satisfied = False
    for s in shards:
        group_idx, _ = s.shard_id
        if not group_idx in groups:
            groups[group_idx] = 0
        groups[group_idx] += 1
        if groups[group_idx] >= s.member_threshold:
            filled.add(group_idx)
        satisfied = len(filled) >= s.group_threshold
    return satisfied, filled


def fingerprint(tokens, dict_limit=25, token_limit=None, debug=False):
    """
    Paper: "Locality Sensitive Hashing for Scalable Structural
    Classification and Clustering of Web Documents"

    Hachenberg, Christian; Gottron, Thomas (2013)
    https://west.uni-koblenz.de/de/forschung/datensaetze/template-detection
    https://dl.acm.org/citation.cfm?id=2505673
    """
    d = {}
    dict_entry_id = 1
    buff = tuple()
    prefix_id = 0
    output = []
    for cnt, tok in enumerate(tokens, start=1):
        if token_limit is not None and cnt > token_limit:
            break
        token = tok,
        buffer_token = buff + token
        if buffer_token in d:
            buff = buffer_token
        else:
            prefix_id = d.get(buff)
            if prefix_id is not None:
                output.append(prefix_id)
            else:
                output.append(0)
            d[buffer_token] = dict_entry_id
            dict_entry_id += 1
            buff = tuple()
        if dict_entry_id > dict_limit:
            break
    return output


def shape_extent_to_header(shape, extent, nan_value=-9999):
    """ Create a header dict with shape and extent of an array
    """
    ncols = shape[1]
    nrows = shape[0]
    xllcorner = extent[0]
    yllcorner = extent[2]
    cellsize_x = (extent[1] - extent[0]) / ncols
    cellsize_y = (extent[3] - extent[2]) / nrows
    if cellsize_x != cellsize_y:
        raise ValueError('extent produces different cellsize in x and y')
    cellsize = cellsize_x
    header = {'ncols': ncols, 'nrows': nrows, 'xllcorner': xllcorner,
        'yllcorner': yllcorner, 'cellsize': cellsize, 'NODATA_value': nan_value
        }
    return header


def short_id(id64):
    """Given a 64-bit id, make a shorter 16-bit one."""
    id16 = 0
    for offset in range(0, 64, 16):
        id16 ^= id64 >> offset
    return id16 & 65535


def info_basic(**kwargs):
    """Container for basic information.

    All kwargs are used to update the basic information dictionary for the
    report.

    Returns
    -------
    dict : A dictionary containing basic informations for the report.
    The keys are:

      - *'vendor'* : The vendor name that manufactures the camera.
      - *'model'* : The model of the tested camera.
      - *'data_type'* : The label given to the data used for the test.
      - *'sensor_type'*: The type of the tested sensor within the camera.
      - *'sensor_diagonal'* : The number of pixel in the sensor diagonal.
      - *'lens_category'* : The lens category used for the test.
      - *'resolution'* : The camera's resolution.
      - *'pixel_size'* : The sensor's pixel size.
      - *'readout_type'* : The readout type of the sensor (for CCD sensors).
      - *'transfer_type'* : The transfer type of the sensor (for CCDs).
      - *'shutter_type'* : The shutter type of the sensor (for CMOS sensors).
      - *'overlap_capabilities'* : The overlap capabilities of the sensor
        (for CMOS sensors).
      - *'maximum_readout_rate'* : The camera's maximal readout rate.
      - *'dark_current_compensation'* : If the camera support dark current
        compensation, specify it in this entry.
      - *'interface_type'* : The camera's interface type.
      - *'qe_plot'* : The sensor's quantum efficency plots.
    """
    b = {'vendor': None, 'model': None, 'data_type': None, 'sensor_type':
        None, 'sensor_diagonal': None, 'lens_category': None, 'resolution':
        None, 'pixel_size': None, 'readout_type': None, 'transfer_type':
        None, 'shutter_type': None, 'overlap_capabilities': None,
        'maximum_readout_rate': None, 'dark_current_compensation': None,
        'interface_type': None, 'qe_plot': None}
    b.update(kwargs)
    return b


def p_possible_comma(p):
    """possible_comma : empty
                      | COMMA"""
    pass


@staticmethod
def _plot_theme(grid_axis='both', grid_lines='both', theme='bw'):
    """Internal function provides consistent theme across plots.
        Currently a slightly modified version of theme_bw() with configurable grid lines.

        Args:
            grid_axis: controls the axis on which to draw grid lines
                - Accepts: None, 'x', 'y', 'both'
                - Default: 'both'
            grid_lines: controls whether major or minor grid lines are drawn
                - Accepts: None, 'major', 'minor', 'both'
                - Default: 'both'
            theme:
                - Accepts: 'bw', 'classic', 'gray', 'grey', 'seaborn', '538', 'dark', 'matplotlib', 'minimal', 'xkcd', 'light'
                - Default: 'bw'
        Returns:
            A theme object to be added to a plotnine.ggplot() object.
        """
    import plotnine as gg
    assert grid_axis in [None, 'x', 'y', 'both']
    assert grid_lines in [None, 'major', 'minor', 'both']
    assert theme in ['bw', 'classic', 'gray', 'grey', 'seaborn', '538',
        'dark', 'matplotlib', 'minimal', 'xkcd', 'light']
    drop_grid = set()
    if grid_axis is None or grid_lines is None:
        drop_grid.update(['panel_grid_major', 'panel_grid_minor'])
    elif grid_axis == 'x':
        drop_grid.update(['panel_grid_major_y', 'panel_grid_minor_y'])
        if grid_lines == 'major':
            drop_grid.add('panel_grid_minor_y')
        elif grid_lines == 'minor':
            drop_grid.add('panel_grid_major_y')
    elif grid_axis == 'y':
        drop_grid.update(['panel_grid_major_x', 'panel_grid_minor_x'])
        if grid_lines == 'major':
            drop_grid.add('panel_grid_minor_x')
        elif grid_lines == 'minor':
            drop_grid.add('panel_grid_major_x')
    grid_opt = dict()
    for x in drop_grid:
        grid_opt[x] = gg.element_blank()
    return getattr(gg, 'theme_' + theme)() + gg.theme(panel_border=gg.
        element_blank(), axis_line=gg.element_line(color='black'), **grid_opt)


def select_nth(nth: int=2, skip: int=1, offset: int=0):
    """Deselect every Nth element starting from the active vertex, edge or face

    :param nth: Nth Element, Skip every Nth element
    :type nth: int
    :param skip: Skip, Number of elements to skip at once
    :type skip: int
    :param offset: Offset, Offset from the starting point
    :type offset: int
    """
    pass


def get_list(cls, *fields):
    """
        List of *fields.
        :param fields: Field name of `Option`. Such as `code`, (`name`, `code`), [`code`, `name`, `text`] or etc.
        :return: List of *fields tuple or single value.
        """
    if len(fields) == 0:
        raise ValueError('No fields argument found.')
    found_fields = set()
    for f in fields:
        if f not in ['code', 'name', 'text']:
            raise NameError(
                "'%s' is incorrect Option field. Only 'code', 'name' and 'text' are available."
                 % str(f))
        if f in found_fields:
            raise ValueError("Duplicated fields '%s' found." % str(f))
        found_fields.add(f)
    lst = []
    for o in cls.__get_name_options_mapping().values():
        value = []
        for f in fields:
            value.append(getattr(o, f))
        lst.append(value[0] if len(value) == 1 else tuple(value))
    return lst


def ode45_step(f, x, t, dt, *args):
    """
    One step of 4th Order Runge-Kutta method
    """
    k = dt
    k1 = k * f(t, x, *args)
    k2 = k * f(t + 0.5 * k, x + 0.5 * k1, *args)
    k3 = k * f(t + 0.5 * k, x + 0.5 * k2, *args)
    k4 = k * f(t + dt, x + k3, *args)
    return x + 1 / 6.0 * (k1 + k2 + k3 + k4)


def extract_email_addresses(emails):
    """Returns a list of emails from either a string or a list"""
    if type(emails) == str:
        emails = emails.split(',')
        emails = list(map(lambda x: x.strip(), emails))
    return emails


@classmethod
def _from_dict(cls, _dict):
    """Initialize a NluEnrichmentEntities object from a json dictionary."""
    args = {}
    if 'sentiment' in _dict:
        args['sentiment'] = _dict.get('sentiment')
    if 'emotion' in _dict:
        args['emotion'] = _dict.get('emotion')
    if 'limit' in _dict:
        args['limit'] = _dict.get('limit')
    if 'mentions' in _dict:
        args['mentions'] = _dict.get('mentions')
    if 'mention_types' in _dict:
        args['mention_types'] = _dict.get('mention_types')
    if 'sentence_locations' in _dict:
        args['sentence_locations'] = _dict.get('sentence_locations')
    if 'model' in _dict:
        args['model'] = _dict.get('model')
    return cls(**args)


def pollutants_per_country(summary):
    """
    Get the available pollutants per country from the summary.

    :param list[dict] summary: The E1a summary.

    :return dict[list[dict]]: All available pollutants per country.
    """
    output = dict()
    for d in summary.copy():
        country = d.pop('ct')
        if country in output:
            output[country].append(d)
        else:
            output[country] = [d]
    return output


def particle_edit_toggle():
    """Toggle particle edit mode

    """
    pass


def normalized_pkg_name(pkg_name: str, dashed: bool=False):
    """ We maintain consistency by always specifying the package name as
        the "dashed version".

        Python/setuptools will replace "_" with "-" but resource_filename()
        expects the exact directory name, essentially. In order to keep it
        simple upstream and *always* provide package name as the dashed
        version, we do replacement here to 'normalize' both versions to
        whichever convention you need at the time.

        if `dashed`:
            my-package-name --> my-package-name
            my_package_name --> my-package-name

        else:
            my-package-name --> my_package_name
            my_package_name --> my_package_name
    """
    if dashed:
        return str(pkg_name).replace('_', '-')
    return str(pkg_name).replace('-', '_')


def _create_rest_url(host, version, resource, query_id):
    """Creates the URL for querying the REST service"""
    pokeapi_rest = 'api'
    url_parts = [host, pokeapi_rest, version]
    if resource is not None:
        url_parts.append(resource)
    if query_id is not None:
        url_parts.append(query_id)
    url = 'http://' + '/'.join(url_parts)
    return url


def query_resource_id(manageiq, resource_type, resource_name):
    """ Query the resource name in ManageIQ.

    Returns:
        the resource id if it exists in manageiq, Fail otherwise.
    """
    resource = manageiq.find_collection_resource_by(resource_type, name=
        resource_name)
    if resource:
        return resource['id']
    else:
        msg = ('{resource_name} {resource_type} does not exist in manageiq'
            .format(resource_name=resource_name, resource_type=resource_type))
        manageiq.module.fail_json(msg=msg)


def abort():
    """Abort the transaction.

        This is called from the application.  This can only be called
        before the two-phase commit protocol has been started.
        """


def should_build_with_cython(previous_cython_version, is_release):
    """
    Returns the previously used Cython version (or 'unknown' if not
    previously built) if Cython should be used to build extension modules from
    pyx files.
    """
    have_cython = False
    try:
        from Cython import __version__ as cython_version
        have_cython = True
    except ImportError:
        pass
    if have_cython and (not is_release or previous_cython_version == 'unknown'
        ):
        return cython_version
    else:
        return False


def present2annual(i, n, PV=1):
    """Present Value to Annualised"""
    return PV * (i * (1 + i) ** n) / ((1 + i) ** n - 1)


def createReferenceArtifact(queue, taskid, runid, name, url, expires,
    content_type):
    """Creates a Taskcluster reference artifact for the given taskid/runid"""
    queue.createArtifact(taskid, runid, name, {'storageType': 'reference',
        'contentType': content_type, 'expires': expires, 'url': url})


def parse_nick(name):
    """ parse a nickname and return a tuple of (nick, mode, user, host)

    <nick> [ '!' [<mode> = ] <user> ] [ '@' <host> ]
    """
    try:
        nick, rest = name.split('!')
    except ValueError:
        return name, None, None, None
    try:
        mode, rest = rest.split('=')
    except ValueError:
        mode, rest = None, rest
    try:
        user, host = rest.split('@')
    except ValueError:
        return name, mode, rest, None
    return name, mode, user, host


def scan_setup_py():
    """Validate the contents of setup.py against Versioneer's expectations."""
    found = set()
    setters = False
    errors = 0
    with open('setup.py', 'r') as f:
        for line in f.readlines():
            if 'import versioneer' in line:
                found.add('import')
            if 'versioneer.get_cmdclass()' in line:
                found.add('cmdclass')
            if 'versioneer.get_version()' in line:
                found.add('get_version')
            if 'versioneer.VCS' in line:
                setters = True
            if 'versioneer.versionfile_source' in line:
                setters = True
    if len(found) != 3:
        print('')
        print('Your setup.py appears to be missing some important items')
        print('(but I might be wrong). Please make sure it has something')
        print('roughly like the following:')
        print('')
        print(' import versioneer')
        print(' setup( version=versioneer.get_version(),')
        print('        cmdclass=versioneer.get_cmdclass(),  ...)')
        print('')
        errors += 1
    if setters:
        print("You should remove lines like 'versioneer.VCS = ' and")
        print("'versioneer.versionfile_source = ' . This configuration")
        print('now lives in setup.cfg, and should be removed from setup.py')
        print('')
        errors += 1
    return errors


def record_is_linear(record, default=True):
    """Return True if record.annotations['topology'] == 'linear'"""
    if 'topology' not in record.annotations:
        return default
    else:
        return record.annotations['topology'] == 'linear'


def valid_index(index, shape) ->tuple:
    """Get a valid index for a broadcastable shape.

    Parameters
    ----------
    index : tuple
        Given index.
    shape : tuple of int
        Shape.

    Returns
    -------
    tuple
        Valid index.
    """
    index = list(index)
    while len(index) < len(shape):
        index.append(slice(None))
    out = []
    for i, s in zip(index[::-1], shape[::-1]):
        if s == 1:
            if isinstance(i, slice):
                out.append(slice(None))
            else:
                out.append(0)
        else:
            out.append(i)
    return tuple(out[::-1])


def _replace(_self, **kwds):
    """Return a new Literal object replacing specified fields with new value"""
    result = _self._make(map(kwds.pop, ('value', 'language', 'datatype'),
        _self))
    if kwds:
        raise ValueError('Got unexpected field names: %r' % kwds.keys())
    return result


def landscape(pagesize):
    """Use this to get page orientation right"""
    a, b = pagesize
    if a < b:
        return b, a
    else:
        return a, b


@classmethod
def delete(cls, uri):
    """Delete a record from the API server

            :param uri: The URI to the item you wish to delete

            :return: returns servers response to the DELETE request
        """
    return cls._perform_request(uri, 'DELETE')


@classmethod
def group_join_policy_updated_details(cls, val):
    """
        Create an instance of this class set to the
        ``group_join_policy_updated_details`` tag with value ``val``.

        :param GroupJoinPolicyUpdatedDetails val:
        :rtype: EventDetails
        """
    return cls('group_join_policy_updated_details', val)


@conf
def xlc_common_flags(conf):
    """
	Flags required for executing the Aix C compiler
	"""
    v = conf.env
    v.CC_SRC_F = []
    v.CC_TGT_F = ['-c', '-o']
    if not v.LINK_CC:
        v.LINK_CC = v.CC
    v.CCLNK_SRC_F = []
    v.CCLNK_TGT_F = ['-o']
    v.CPPPATH_ST = '-I%s'
    v.DEFINES_ST = '-D%s'
    v.LIB_ST = '-l%s'
    v.LIBPATH_ST = '-L%s'
    v.STLIB_ST = '-l%s'
    v.STLIBPATH_ST = '-L%s'
    v.RPATH_ST = '-Wl,-rpath,%s'
    v.SONAME_ST = []
    v.SHLIB_MARKER = []
    v.STLIB_MARKER = []
    v.LINKFLAGS_cprogram = ['-Wl,-brtl']
    v.cprogram_PATTERN = '%s'
    v.CFLAGS_cshlib = ['-fPIC']
    v.LINKFLAGS_cshlib = ['-G', '-Wl,-brtl,-bexpfull']
    v.cshlib_PATTERN = 'lib%s.so'
    v.LINKFLAGS_cstlib = []
    v.cstlib_PATTERN = 'lib%s.a'


def line_add_lazy_describe(line):
    """if describe has no arguments, default silently to <describe version>"""
    l = line.split()
    if 'describe' in line and len(l) == 1:
        return 'describe version'
    return line


def update_container_instances_state(cluster=None, containerInstances=None,
    status=None):
    """
    Modifies the status of an Amazon ECS container instance.
    You can change the status of a container instance to DRAINING to manually remove an instance from a cluster, for example to perform system updates, update the Docker daemon, or scale down the cluster size.
    When you set a container instance to DRAINING , Amazon ECS prevents new tasks from being scheduled for placement on the container instance and replacement service tasks are started on other container instances in the cluster if the resources are available. Service tasks on the container instance that are in the PENDING state are stopped immediately.
    Service tasks on the container instance that are in the RUNNING state are stopped and replaced according the service's deployment configuration parameters, minimumHealthyPercent and maximumPercent . Note that you can change the deployment configuration of your service using  UpdateService .
    Any PENDING or RUNNING tasks that do not belong to a service are not affected; you must wait for them to finish or stop them manually.
    A container instance has completed draining when it has no more RUNNING tasks. You can verify this using  ListTasks .
    When you set a container instance to ACTIVE , the Amazon ECS scheduler can begin scheduling tasks on the instance again.
    See also: AWS API Documentation

    :example: response = client.update_container_instances_state(
        cluster='string',
        containerInstances=[
            'string',
        ],
        status='ACTIVE'|'DRAINING'
    )

    :type cluster: string
    :param cluster: The short name or full Amazon Resource Name (ARN) of the cluster that hosts the container instance to update. If you do not specify a cluster, the default cluster is assumed.

    :type containerInstances: list
    :param containerInstances: [REQUIRED]
            A list of container instance IDs or full Amazon Resource Name (ARN) entries.
            (string) --

    :type status: string
    :param status: [REQUIRED]
            The container instance state with which to update the container instance.

    :rtype: dict
    :return: {
        'containerInstances': [
            {
                'containerInstanceArn': 'string',
                'ec2InstanceId': 'string',
                'version': 123,
                'versionInfo': {
                    'agentVersion': 'string',
                    'agentHash': 'string',
                    'dockerVersion': 'string'
                },
                'remainingResources': [
                    {
                        'name': 'string',
                        'type': 'string',
                        'doubleValue': 123.0,
                        'longValue': 123,
                        'integerValue': 123,
                        'stringSetValue': [
                            'string',
                        ]
                    },
                ],
                'registeredResources': [
                    {
                        'name': 'string',
                        'type': 'string',
                        'doubleValue': 123.0,
                        'longValue': 123,
                        'integerValue': 123,
                        'stringSetValue': [
                            'string',
                        ]
                    },
                ],
                'status': 'string',
                'agentConnected': True|False,
                'runningTasksCount': 123,
                'pendingTasksCount': 123,
                'agentUpdateStatus': 'PENDING'|'STAGING'|'STAGED'|'UPDATING'|'UPDATED'|'FAILED',
                'attributes': [
                    {
                        'name': 'string',
                        'value': 'string',
                        'targetType': 'container-instance',
                        'targetId': 'string'
                    },
                ],
                'registeredAt': datetime(2015, 1, 1)
            },
        ],
        'failures': [
            {
                'arn': 'string',
                'reason': 'string'
            },
        ]
    }

    :returns:
    cluster (string) -- The short name or full Amazon Resource Name (ARN) of the cluster that hosts the container instance to update. If you do not specify a cluster, the default cluster is assumed.
    containerInstances (list) -- [REQUIRED]
    A list of container instance IDs or full Amazon Resource Name (ARN) entries.

    (string) --

    status (string) -- [REQUIRED]
    The container instance state with which to update the container instance.

    """
    pass


def chunks(l, n):
    """Yield successive n-sized chunks from l."""
    for i in range(0, len(l), n):
        yield l[i:i + n]


@staticmethod
def _time_to_TM(time):
    """
        Convert the time component of a Python datetime object into
        DICOM time (TM) value representation.
        """
    return '{:02}{:02}{:02}.{:06}'.format(time.hour, time.minute, time.
        second, time.microsecond)


def migrate_v0_to_v1(project):
    """Migrate from schema version 0 to version 1."""
    pass


def run_deltree(delitems, nexus_obj, log):
    """
    Returns a list of trees to be deleted

    :param deltree: A string of trees to be deleted.
    :type deltree: String

    :param nexus_obj: A `NexusReader` instance
    :type nexus_obj: NexusReader

    :return: A NexusReader instance with the given trees removed.
    """
    new = []
    log.info('Deleting: %d trees' % len(delitems))
    for index, tree in enumerate(nexus_obj.trees, 1):
        if index in delitems:
            log.info('Deleting tree %d' % index)
        else:
            new.append(tree)
    nexus_obj.trees.trees = new
    return nexus_obj


def get_environment_problems(environment, limit=None):
    """
        Returns a tuple of all the problems that occurred in given
        `environment` and dates of last occurrence in that environment.
        Optionally `limit` the number of results.
        """


@classmethod
def Lopen(cls, a, b):
    """Return an interval not including the left boundary."""
    return cls(a, b, True, False)


def layer_prev():
    """Switch to editing action in animation layer below the current action in the NLA Stack

    """
    pass


def dispname(child):
    """Get display name for HDF5 group/dataset."""
    return child.name.split('/')[-1]


def cir_RsQ(w, Rs, Q, n):
    """
    Simulation Function: -Rs-Q-

    Inputs
    ----------
    w = Angular frequency [1/s]
    Rs = Series resistance [Ohm]
    Q = Constant phase element [s^n/ohm]
    n = Constant phase elelment exponent [-]
    """
    return Rs + 1 / (Q * (w * 1.0j) ** n)


def should_build_with_cython(package, release=None):
    """Returns the previously used Cython version (or 'unknown' if not
    previously built) if Cython should be used to build extension modules from
    pyx files.  If the ``release`` parameter is not specified an attempt is
    made to determine the release flag from `astropy.version`.
    """
    try:
        version_module = __import__(package + '.cython_version', fromlist=[
            'release', 'cython_version'])
    except ImportError:
        version_module = None
    if release is None and version_module is not None:
        try:
            release = version_module.release
        except AttributeError:
            pass
    try:
        cython_version = version_module.cython_version
    except AttributeError:
        cython_version = 'unknown'
    have_cython = False
    try:
        import Cython
        have_cython = True
    except ImportError:
        pass
    if have_cython and (not release or cython_version == 'unknown'):
        return cython_version
    else:
        return False


def build_option_parser(parser):
    """Hook to add global options"""
    return parser


def ignore_signal(signum, frame):
    """A no-op signal handler."""
    return


def get_element_counts(basis):
    """
    Returns chemical elements with their count wrt their original order in the basis.
    Note: entries for the same element separated by another element are considered separately.
    [{"count":1, "value":"Zr"}, {"count":23, "value":"H"}, {"count":11, "value":"Zr"}, {"count":1, "value":"H"}]
    """
    element_counts = []
    previous_element = None
    for index, element in enumerate(basis['elements']):
        if previous_element and previous_element['value'] == element['value']:
            element_counts[-1]['count'] += 1
        else:
            element_counts.append({'count': 1, 'value': element['value']})
        previous_element = basis['elements'][index]
    return element_counts


def converse_implication(a, b):
    """ if a is False, b must be False """
    return a or not b


def p_UNIQUE(p):
    """opt_column_def_options : UNIQUE"""
    p[0] = {'unique': True}


@classmethod
def end_user(cls, val):
    """
        Create an instance of this class set to the ``end_user`` tag with value
        ``val``.

        :param SessionLogInfo val:
        :rtype: AccessMethodLogInfo
        """
    return cls('end_user', val)


def plus_or_dot(pieces):
    """Return a + if we don't already have one, else return a ."""
    if '+' in pieces.get('closest-tag', ''):
        return '.'
    return '+'


def get_first_enriched_date(repository_url):
    """ Retrieve the first/oldest metadata__updated_on of the item
    corresponding to given repository.
    """
    query_first_enriched_date = (
        """
    {
        "size": 0,
        "aggs": {
            "1": {
                "top_hits": {
                    "docvalue_fields": [
                        "metadata__updated_on"
                    ],
                    "_source": "metadata__updated_on",
                    "size": 1,
                    "sort": [{
                        "commit_date": {
                            "order": "asc"
                        }
                    }]
                }
            }
        },
        "query": {
            "bool": {
                "filter": [{
                    "term": {
                        "origin": "%s"
                    }
                }]
            }
        }
    }
    """
         % repository_url)
    return query_first_enriched_date


@classmethod
def from_server_response(cls, publicKey=None, data=None, iv=None, salt=None,
    public_key=None):
    """Creating Container object from Ambisafe KeyServer response
        :param publicKey: For backward compatibility
        :param data:
        :param iv:
        :param salt:
        :param public_key:
        :return:
        """
    if not public_key and not publicKey:
        raise ValueError('public_key must be provided')
    if not public_key:
        public_key = publicKey
    return cls(public_key, data, iv, salt)


def ip_for_request(request):
    """
    Returns ip address for request - first checks ``HTTP_X_FORWARDED_FOR``
    header, since app will generally be behind a public web server.
    """
    meta = request.META
    return meta.get('HTTP_X_FORWARDED_FOR', meta['REMOTE_ADDR']).split(',')[0]


def bonferroni(false_positive_rate, original_p_values):
    """ Bonferrnoi correction.

    :param false_positive_rate: alpha value before correction
    :type  false_positive_rate: float
    :param original_p_values: p values from all the tests
    :type  original_p_values: list[float]

    :return: new critical value (i.e. the corrected alpha)
    :rtype: float
    """
    assert original_p_values, 'empty array of p values to analyse'
    return false_positive_rate / len(original_p_values)


def p_gcl_length(t):
    """gcl_expr : LSPAREN INT RSPAREN"""
    t[0] = 'Length', t[2]


def _sacar_líms_coefs_interno(símismo):
    """
        Esta función genera una lista de las límites de los coeficientes propios al objeto de interés para la
        calibración actual. Se debe implementar para cada Coso (objeto) que tiene coeficientes.

        :return: Un tuple, conteniendo:
          1. Una lista de diccionarios de coeficientes, con el formato siguiente:
           [ {calib1: distribución o [lista de valores],
              calib2: ibid,
              ...},
              {coeficiente 2...},
              ...
           ]

           2. Una lista de los límites de los coeficientes, en el mismo orden que (1.)
        :rtype: (list, list)

        """
    raise NotImplementedError


@classmethod
def group_change_management_type(cls, val):
    """
        Create an instance of this class set to the
        ``group_change_management_type`` tag with value ``val``.

        :param GroupChangeManagementTypeType val:
        :rtype: EventType
        """
    return cls('group_change_management_type', val)


def __new__(cls, name, bases, dct):
    """
        Inherit Docstrings when creating a class definition. A variation of
        http://groups.google.com/group/comp.lang.python/msg/26f7b4fcb4d66c95
        by Paul McGuire.

        Source: http://stackoverflow.com/a/8101118/396967
        """
    if not ('__doc__' in dct and dct['__doc__']):
        for mro_cls in (cls for base in bases for cls in base.mro()):
            doc = mro_cls.__doc__
            if doc:
                dct['__doc__'] = doc
                break
    for attr, attribute in dct.items():
        if not attribute.__doc__:
            for mro_cls in (cls for base in bases for cls in base.mro() if
                hasattr(cls, attr)):
                doc = getattr(getattr(mro_cls, attr), '__doc__')
                if doc:
                    attribute.__doc__ = doc
                    break
    return type.__new__(cls, name, bases, dct)


def remove_type_hint(argument: str) ->str:
    """Removes any Python type hints.

    Those are incompatible with `exec` during dynamic `__init__` creation
    (at least not without major workarounds).

    Default values (right hand side) is preserved if exists.

    """
    splitted_on_type_hint = argument.split(':')
    no_type_hint = splitted_on_type_hint[0]
    if len(splitted_on_type_hint) > 1:
        splitted_on_default = splitted_on_type_hint[1].split('=')
        if len(splitted_on_default) > 1:
            no_type_hint += '={}'.format(splitted_on_default[1])
    return no_type_hint


def resolve_name(name):
    """Resolve a name like ``module.object`` to an object and return it.

    Raise `ImportError` if the module or name is not found.
    """
    parts = name.split('.')
    cursor = len(parts) - 1
    module_name = parts[:cursor]
    attr_name = parts[-1]
    while cursor > 0:
        try:
            ret = __import__('.'.join(module_name), fromlist=[attr_name])
            break
        except ImportError:
            if cursor == 0:
                raise
            cursor -= 1
            module_name = parts[:cursor]
            attr_name = parts[cursor]
            ret = ''
    for part in parts[cursor:]:
        try:
            ret = getattr(ret, part)
        except AttributeError:
            raise ImportError(name)
    return ret


def SDL_FOURCC(A, B, C, D):
    """Return a four-character code as a uint32."""
    return ord(A) | ord(B) << 8 | ord(C) << 16 | ord(D) << 24


@classmethod
def __getValues(cls, expressions):
    """
        Get values to count together.
        """
    values = list()
    last = 0
    index = 0
    for ch in expressions:
        if ch in ('%', '+', '-', '*', '/'):
            values.append(expressions[last:index])
            values.append(str(ch))
            last = index + 1
        index += 1
    if index != last:
        values.append(expressions[last:])
    return values


def allow_client(client_type):
    """Allows another type to act as client type.
    Intended for using with mock clients."""
    global ok_types
    ok_types += client_type,


def DarkenBitmap(bmp, caption_colour, new_colour):
    """
    Darkens the input bitmap on wxMAC using the input colour.

    :param wx.Bitmap `bmp`: the bitmap to be manipulated;
    :param wx.Colour `caption_colour`: the colour of the pane caption;
    :param wx.Colour `new_colour`: the colour used to darken the bitmap.
    """
    image = bmp.ConvertToImage()
    red = caption_colour.Red() / float(new_colour.Red())
    green = caption_colour.Green() / float(new_colour.Green())
    blue = caption_colour.Blue() / float(new_colour.Blue())
    image = image.AdjustChannels(red, green, blue)
    return image.ConvertToBitmap()


def get_file_contents(ssh, file):
    """
    Retrieve the contents of file from the remote server.
    """
    _, stdout, stderr = ssh.exec_command('cat {}'.format(file))
    err = stderr.read()
    if len(err) > 0:
        return False, err
    return stdout.read().decode('utf-8').strip()


def p_argument_list(p):
    """argument_list : argument
                     | argument COMMA argument_list"""
    if len(p) == 2:
        p[0] = p[1]
    else:
        p[0] = p[1][0] + p[3][0], {**p[1][1], **p[3][1]}, p[1][2] + p[3][2]


def disable_resampling():
    """
    Disable resampling in case of gantry tilted data (disabled by default)
    """
    global resample
    resample = False