# -*- coding: UTF-8 -*-
import os, sys, traceback, json
from pyopus.misc.debug import DbgSetup, DbgMsgOut
DbgSetup(True, 1)

useMPI=False

projData={'analyses': {'ac': {'command': "ac(1, 1e12, 'dec', 10)",
                     'head': 'ngspice',
                     'modules': ['def', 'tb'],
                     'options': {},
                     'params': {'rfb': 1000000.0, 'rin': 1000000.0},
                     'saves': []},
              'accom': {'command': "ac(1, 1e12, 'dec', 10)",
                        'head': 'ngspice',
                        'modules': ['def', 'tbrr'],
                        'options': {},
                        'params': {'accom': 1,
                                   'acvdd': 0,
                                   'acvss': 0,
                                   'cin': 1,
                                   'rfb': 1000000000.0},
                        'saves': []},
              'acvdd': {'command': "ac(1, 1e12, 'dec', 10)",
                        'head': 'ngspice',
                        'modules': ['def', 'tbrr'],
                        'options': {},
                        'params': {'accom': 0,
                                   'acvdd': 1,
                                   'acvss': 0,
                                   'cin': 1,
                                   'rfb': 1000000000.0},
                        'saves': []},
              'acvss': {'command': "ac(1, 1e12, 'dec', 10)",
                        'head': 'ngspice',
                        'modules': ['def', 'tbrr'],
                        'options': {},
                        'params': {'accom': 0,
                                   'acvdd': 0,
                                   'acvss': 1,
                                   'cin': 1,
                                   'rfb': 1000000000.0},
                        'saves': []},
              'blank': {'command': None,
                        'head': 'ngspice',
                        'modules': [],
                        'options': {},
                        'params': {},
                        'saves': []},
              'dc': {'command': "dc(-2.0, 2.0, 'lin', 100, 'vin1')",
                     'head': 'ngspice',
                     'modules': ['def', 'tb'],
                     'options': {},
                     'params': {'rfb': 1000000.0, 'rin': 1000000.0},
                     'saves': []},
              'noise': {'command': "noise(1, 1e12, 'dec', 10, 'vin1', 'out')",
                        'head': 'ngspice',
                        'modules': ['def', 'tb'],
                        'options': {},
                        'params': {'rfb': 1000000.0, 'rin': 1000000.0},
                        'saves': []},
              'op': {'command': 'op()',
                     'head': 'ngspice',
                     'modules': ['def', 'tb'],
                     'options': {},
                     'params': {'rfb': 1000000.0, 'rin': 1000000.0},
                     'saves': ['all()',
                               "p(ipath(mosList, 'x1', 'm0'), ['vgs', 'vth', "
                               "'vds', 'vdsat'])"]},
              'tran': {'command': "tran(param['tr']*1, "
                                  "param['tstart']+param['pw']*2)",
                       'head': 'ngspice',
                       'modules': ['def', 'tb'],
                       'options': {'reltol': 0.0001},
                       'params': {'rfb': 1000000.0, 'rin': 1000000.0},
                       'saves': []},
              'translew': {'command': "tran(param['tr']*1, "
                                      "param['tstart']+param['pw']*2)",
                           'head': 'ngspice',
                           'modules': ['def', 'tb'],
                           'options': {'reltol': 0.0001},
                           'params': {'lev1': -0.8,
                                      'lev2': 0.8,
                                      'rfb': 1000000.0,
                                      'rin': 1000000.0},
                           'saves': []}},
 'analysisNames': ['op',
                   'dc',
                   'ac',
                   'accom',
                   'acvdd',
                   'acvss',
                   'noise',
                   'tran',
                   'translew',
                   'blank'],
 'designPar': {'c_out': {'hi': 5e-11, 'init': 8.21e-12, 'lo': 1e-15},
               'diff_l': {'hi': 4e-06, 'init': 1.08e-06, 'lo': 1.8e-07},
               'diff_w': {'hi': 9.5e-05, 'init': 7.73e-06, 'lo': 1e-06},
               'load_l': {'hi': 4e-06, 'init': 2.57e-06, 'lo': 1.8e-07},
               'load_w': {'hi': 9.5e-05, 'init': 3.49e-05, 'lo': 1e-06},
               'mirr_l': {'hi': 4e-06, 'init': 5.63e-07, 'lo': 1.8e-07},
               'mirr_ld': {'hi': 4e-06, 'init': 5.63e-07, 'lo': 1.8e-07},
               'mirr_w': {'hi': 9.5e-05, 'init': 7.46e-05, 'lo': 1e-06},
               'mirr_wd': {'hi': 9.5e-05, 'init': 7.46e-05, 'lo': 1e-06},
               'mirr_wo': {'hi': 9.5e-05, 'init': 7.46e-05, 'lo': 1e-06},
               'out_l': {'hi': 4e-06, 'init': 3.75e-07, 'lo': 1.8e-07},
               'out_w': {'hi': 9.5e-05, 'init': 4.8e-05, 'lo': 1e-06},
               'r_out': {'hi': 200000.0, 'init': 19.7, 'lo': 1}},
 'designParNames': ['mirr_w',
                    'mirr_wd',
                    'mirr_wo',
                    'mirr_l',
                    'mirr_ld',
                    'out_w',
                    'out_l',
                    'load_w',
                    'load_l',
                    'diff_w',
                    'diff_l',
                    'c_out',
                    'r_out'],
 'headNames': ['ngspice'],
 'heads': {'ngspice': {'moddefs': {'def': {'file': 'miller.inc'},
                                   'mc': {'file': 'cmos180n.lib',
                                          'section': 'mc'},
                                   'tb': {'file': 'topdc.inc'},
                                   'tbrr': {'file': 'toprr.inc'},
                                   'tm': {'file': 'cmos180n.lib',
                                          'section': 'tm'},
                                   'wo': {'file': 'cmos180n.lib',
                                          'section': 'wo'},
                                   'wp': {'file': 'cmos180n.lib',
                                          'section': 'wp'},
                                   'ws': {'file': 'cmos180n.lib',
                                          'section': 'ws'},
                                   'wz': {'file': 'cmos180n.lib',
                                          'section': 'wz'}},
                       'options': {'method': 'trap'},
                       'params': {'cload': 1e-12,
                                  'ibias': 0.0001,
                                  'lev1': -0.2,
                                  'lev2': 0.2,
                                  'pw': 1e-05,
                                  'rload': 100000000.0,
                                  'tf': 1e-09,
                                  'tr': 1e-09,
                                  'tstart': 1e-05},
                       'settings': {'args': ['-n']},
                       'simulator': 'Ngspice'}},
 'measureLower': {'bw': 10000,
                  'cmrr': 70,
                  'gain': 60,
                  'out_op': -0.01,
                  'pm': 50,
                  'psrr_vdd': 60,
                  'psrr_vss': 60,
                  'slewdn': 2000000.0,
                  'slewup': 2000000.0,
                  'swing': 1,
                  'ugbw': 10000000.0,
                  'vds_drv': 0,
                  'vgs_drv': 0},
 'measureNames': ['isup',
                  'out_op',
                  'vgs_drv',
                  'vds_drv',
                  'swing',
                  'gain',
                  'gain_com',
                  'gain_vdd',
                  'gain_vss',
                  'bw',
                  'ugbw',
                  'pm',
                  'phase_slope',
                  'cmrr',
                  'psrr_vdd',
                  'psrr_vss',
                  'overshdn',
                  'overshup',
                  'tsetdn',
                  'tsetup',
                  'slewdn',
                  'slewup',
                  'onoise1k',
                  'inoise1k',
                  'in1kmn2id',
                  'in1kmn2rd',
                  'in1kmn2',
                  'area'],
 'measureNorm': {'area': 1e-10, 'phase_slope': 10},
 'measureUpper': {'area': 9e-09,
                  'isup': 0.001,
                  'out_op': 0.01,
                  'overshdn': 0.1,
                  'overshup': 0.1,
                  'phase_slope': 0,
                  'tsetdn': 1e-06,
                  'tsetup': 1e-06},
 'measures': {'area': {'analysis': 'blank',
                       'depends': [],
                       'expression': '(\n'
                                     '  '
                                     "(param['mirr_w']+param['mirr_wo'])*param['mirr_l']\n"
                                     " +param['mirr_wd']*param['mirr_ld']\n"
                                     " +param['out_w']*param['out_l']*(2)\n"
                                     " +param['load_w']*param['load_l']*(1+1)\n"
                                     " +param['diff_w']*param['diff_l']*(1+1)\n"
                                     " +param['r_out']/1e3*12e-12\n"
                                     " +param['c_out']/1e-12*100e-12\n"
                                     ')',
                       'vector': False},
              'bw': {'analysis': 'ac',
                     'depends': [],
                     'expression': "m.ACbandwidth(m.ACtf(v('out'), v('inp', "
                                   "'inn')), scale())",
                     'vector': False},
              'cmrr': {'analysis': 'blank',
                       'depends': ['gain_com', 'gain'],
                       'expression': "result['gain'][cornerName]-result['gain_com'][cornerName]",
                       'vector': False},
              'gain': {'analysis': 'ac',
                       'depends': [],
                       'expression': 'ndx=m.IatXval(np.abs(scale()), 10.0)[0]\n'
                                     "__result=m.XatI(m.ACmag(m.ACtf(v('out'), "
                                     "v('inp', 'inn'))), ndx)",
                       'vector': False},
              'gain_com': {'analysis': 'accom',
                           'depends': [],
                           'expression': 'ndx=m.IatXval(np.abs(scale()), '
                                         '10.0)[0]\n'
                                         "__result=m.XatI(m.ACmag(m.ACtf(v('out'), "
                                         '1.0)), ndx)',
                           'vector': False},
              'gain_vdd': {'analysis': 'acvdd',
                           'depends': [],
                           'expression': 'ndx=m.IatXval(np.abs(scale()), '
                                         '10.0)[0]\n'
                                         "__result=m.XatI(m.ACmag(m.ACtf(v('out'), "
                                         '1.0)), ndx)',
                           'vector': False},
              'gain_vss': {'analysis': 'acvss',
                           'depends': [],
                           'expression': 'ndx=m.IatXval(np.abs(scale()), '
                                         '10.0)[0]\n'
                                         "__result=m.XatI(m.ACmag(m.ACtf(v('out'), "
                                         '1.0)), ndx)',
                           'vector': False},
              'in1kmn2': {'analysis': 'noise',
                          'depends': [],
                          'expression': "m.XatI(ns('input', ipath('xmn2', "
                                        "'x1', 'm0')), m.IatXval(scale(), "
                                        '1e3)[0])',
                          'vector': False},
              'in1kmn2id': {'analysis': 'noise',
                            'depends': [],
                            'expression': "m.XatI(ns('input', ipath('xmn2', "
                                          "'x1', 'm0'), 'id'), "
                                          'm.IatXval(scale(), 1e3)[0])',
                            'vector': False},
              'in1kmn2rd': {'analysis': 'noise',
                            'depends': [],
                            'expression': "m.XatI(ns('input', ipath('xmn2', "
                                          "'x1', 'm0'), 'rd'), "
                                          'm.IatXval(scale(), 1e3)[0])',
                            'vector': False},
              'inoise1k': {'analysis': 'noise',
                           'depends': [],
                           'expression': "m.XatI(ns('input'), "
                                         'm.IatXval(scale(), 1e3)[0])',
                           'vector': False},
              'isup': {'analysis': 'op',
                       'depends': [],
                       'expression': "isup=-i('vdd1')",
                       'vector': False},
              'onoise1k': {'analysis': 'noise',
                           'depends': [],
                           'expression': "m.XatI(ns('output'), "
                                         'm.IatXval(scale(), 1e3)[0])',
                           'vector': False},
              'out_op': {'analysis': 'op',
                         'depends': [],
                         'expression': "v('out')",
                         'vector': False},
              'overshdn': {'analysis': 'tran',
                           'depends': [],
                           'expression': "m.Tundershoot(v('out'), scale(), "
                                         "t1=param['tstart'], "
                                         "t2=(param['pw']+param['tstart']+param['tr']))",
                           'vector': False},
              'overshup': {'analysis': 'tran',
                           'depends': [],
                           'expression': "m.Tovershoot(v('out'), scale(), "
                                         "t1=(param['pw']+param['tstart']+param['tr']))",
                           'vector': False},
              'phase_slope': {'analysis': 'ac',
                              'depends': [],
                              'expression': '# Transfer function\n'
                                            "tf=m.ACtf(v('out'), v('inp', "
                                            "'inn'))\n"
                                            '# Phase slope in deg/dec\n'
                                            'slope=m.dYdX(m.ACphase(tf), '
                                            'np.log10(scale()))\n'
                                            '# Look only at points where '
                                            'gain>0dB\n'
                                            'mask=m.ACmag(tf)>0\n'
                                            '# Max slope in region defined by '
                                            'mask\n'
                                            '__result=(slope*mask).max()\n',
                              'vector': False},
              'pm': {'analysis': 'ac',
                     'depends': [],
                     'expression': "m.ACphaseMargin(m.ACtf(v('out'), v('inp', "
                                   "'inn')))",
                     'vector': False},
              'psrr_vdd': {'analysis': 'blank',
                           'depends': ['gain', 'gain_vdd'],
                           'expression': "result['gain'][cornerName]-result['gain_vdd'][cornerName]",
                           'vector': False},
              'psrr_vss': {'analysis': 'blank',
                           'depends': ['gain_vss', 'gain'],
                           'expression': "result['gain'][cornerName]-result['gain_vss'][cornerName]",
                           'vector': False},
              'slewdn': {'analysis': 'translew',
                         'depends': [],
                         'expression': "m.TslewRate('falling', v('out'), "
                                       "scale(), t1=param['tstart'], "
                                       "t2=(param['pw']+param['tstart']+param['tr']))",
                         'vector': False},
              'slewup': {'analysis': 'translew',
                         'depends': [],
                         'expression': "m.TslewRate('rising', v('out'), "
                                       'scale(), '
                                       "t1=(param['pw']+param['tstart']+param['tr']))",
                         'vector': False},
              'swing': {'analysis': 'dc',
                        'depends': [],
                        'expression': "m.DCswingAtGain(v('out'), v('inp', "
                                      "'inn'), 0.5, 'out')",
                        'vector': False},
              'tsetdn': {'analysis': 'tran',
                         'depends': [],
                         'expression': "m.TsettlingTime(v('out'), scale(), "
                                       "t1=param['tstart'], "
                                       "t2=(param['pw']+param['tstart']+param['tr']))",
                         'vector': False},
              'tsetup': {'analysis': 'tran',
                         'depends': [],
                         'expression': "m.TsettlingTime(v('out'), scale(), "
                                       "t1=(param['pw']+param['tstart'])+param['tr'])",
                         'vector': False},
              'ugbw': {'analysis': 'ac',
                       'depends': [],
                       'expression': "m.ACugbw(m.ACtf(v('out'), v('inp', "
                                     "'inn')), scale())",
                       'vector': False},
              'vds_drv': {'analysis': 'op',
                          'components': 'mosList',
                          'depends': [],
                          'expression': 'res=[]\n'
                                        '# Loop over all MOS instances in '
                                        'mosList\n'
                                        'for inst in mosList:\n'
                                        '\t# Generate full name for MOS '
                                        'instance\n'
                                        "\tfullName=ipath(inst, 'x1', 'm0')\n"
                                        '\t# Extract vds and vdsat from '
                                        'results\n'
                                        "\tvds=p(fullName, 'vds')\n"
                                        "\tvdsat=p(fullName, 'vdsat')\n"
                                        '\t# Compute difference and append to '
                                        'results list\n'
                                        '\tdiff=float(vds-vdsat)\n'
                                        '\tres.append(diff)\n'
                                        '# Return NumPy array\n'
                                        '__result=np.array(res)',
                          'vector': True},
              'vgs_drv': {'analysis': 'op',
                          'components': 'mosList',
                          'depends': [],
                          'expression': 'res=[]\n'
                                        '# Loop over all MOS instances in '
                                        'mosList\n'
                                        'for inst in mosList:\n'
                                        '\t# Generate full name for MOS '
                                        'instance\n'
                                        "\tfullName=ipath(inst, 'x1', 'm0')\n"
                                        '\t# Extract vgs and vth from results\n'
                                        "\tvgs=p(fullName, 'vgs')\n"
                                        "\tvth=p(fullName, 'vth')\n"
                                        '\t# Compute difference and append to '
                                        'results list\n'
                                        '\tdiff=float(vgs-vth)\n'
                                        '\tres.append(diff)\n'
                                        '\t# Uncomment to print a debug '
                                        'message during evaluation\n'
                                        '\t# m.debug("%s: vgs=%f vth=%f" % '
                                        '(fullName, vgs, vth))\n'
                                        '# Return NumPy array\n'
                                        '__result=np.array(res)',
                          'vector': True}},
 'mirrormap': {'cmos180n.lib': '.',
               'miller.inc': '.',
               'mosmm.inc': '.',
               'topdc.inc': '.',
               'toprr.inc': '.'},
 'opPar': {'temperature': {'hi': 100, 'lo': 0, 'nominal': 25},
           'vdd': {'hi': 2.0, 'lo': 1.7, 'nominal': 1.8}},
 'opParNames': ['vdd', 'temperature'],
 'statPar': {'gu0nmm': {'dist': 'Normal(0.0,1.0)'},
             'gu0pmm': {'dist': 'Normal(0.0,1.0)'},
             'gvtnmm': {'dist': 'Normal(0.0,1.0)'},
             'gvtpmm': {'dist': 'Normal(0.0,1.0)'},
             'mn1u0': {'dist': 'Normal(0.0,1.0)'},
             'mn1vt': {'dist': 'Normal(0.0,1.0)'},
             'mn2u0': {'dist': 'Normal(0.0,1.0)'},
             'mn2vt': {'dist': 'Normal(0.0,1.0)'},
             'mn3u0': {'dist': 'Normal(0.0,1.0)'},
             'mn3vt': {'dist': 'Normal(0.0,1.0)'},
             'mn4u0': {'dist': 'Normal(0.0,1.0)'},
             'mn4vt': {'dist': 'Normal(0.0,1.0)'},
             'mn5u0': {'dist': 'Normal(0.0,1.0)'},
             'mn5vt': {'dist': 'Normal(0.0,1.0)'},
             'mp1u0': {'dist': 'Normal(0.0,1.0)'},
             'mp1vt': {'dist': 'Normal(0.0,1.0)'},
             'mp2u0': {'dist': 'Normal(0.0,1.0)'},
             'mp2vt': {'dist': 'Normal(0.0,1.0)'},
             'mp3u0': {'dist': 'Normal(0.0,1.0)'},
             'mp3vt': {'dist': 'Normal(0.0,1.0)'}},
 'statParNames': ['mp1vt',
                  'mp1u0',
                  'mp2vt',
                  'mp2u0',
                  'mp3vt',
                  'mp3u0',
                  'mn1vt',
                  'mn1u0',
                  'mn2vt',
                  'mn2u0',
                  'mn3vt',
                  'mn3u0',
                  'mn4vt',
                  'mn4u0',
                  'mn5vt',
                  'mn5u0',
                  'gvtnmm',
                  'gu0nmm',
                  'gvtpmm',
                  'gu0pmm'],
 'variableNames': ['mosList', 'isNmos'],
 'variables': {'isNmos': '[1, 1, 1, 1, 1, 0, 0, 0]',
               'mosList': "['xmn1', 'xmn2', 'xmn3', 'xmn4', 'xmn5', 'xmp1', "
                          "'xmp2', 'xmp3']"}}

taskData={'cornerNames': ['nominal'],
 'corners': {('nominal', ('ngspice',)): {'modules': ['tm'],
                                         'params': {'gu0nmm': 0.0,
                                                    'gu0pmm': 0.0,
                                                    'gvtnmm': 0.0,
                                                    'gvtpmm': 0.0,
                                                    'mn1u0': 0.0,
                                                    'mn1vt': 0.0,
                                                    'mn2u0': 0.0,
                                                    'mn2vt': 0.0,
                                                    'mn3u0': 0.0,
                                                    'mn3vt': 0.0,
                                                    'mn4u0': 0.0,
                                                    'mn4vt': 0.0,
                                                    'mn5u0': 0.0,
                                                    'mn5vt': 0.0,
                                                    'mp1u0': 0.0,
                                                    'mp1vt': 0.0,
                                                    'mp2u0': 0.0,
                                                    'mp2vt': 0.0,
                                                    'mp3u0': 0.0,
                                                    'mp3vt': 0.0,
                                                    'temperature': 25,
                                                    'vdd': 1.8}}},
 'fixedParameterNames': ['mirr_w',
                         'mirr_wd',
                         'mirr_wo',
                         'mirr_l',
                         'mirr_ld',
                         'out_w',
                         'out_l',
                         'load_w',
                         'load_l',
                         'diff_w',
                         'diff_l',
                         'c_out',
                         'r_out'],
 'name': 'evaluate',
 'optParameterNames': [],
 'output': {'aggregatordebug': 0,
            'evaluatordebug': 0,
            'keepfiles': False,
            'optimizerdebug': 0,
            'saveallresults': False,
            'savewaveforms': 'verification',
            'simulatordebug': 0,
            'taskdebug': 1},
 'parameterNames': ['mirr_w',
                    'mirr_wd',
                    'mirr_wo',
                    'mirr_l',
                    'mirr_ld',
                    'out_w',
                    'out_l',
                    'load_w',
                    'load_l',
                    'diff_w',
                    'diff_l',
                    'c_out',
                    'r_out'],
 'parameters': {'c_out': {'hi': None,
                          'init': 4.071026755523457e-12,
                          'lo': None},
                'diff_l': {'hi': None,
                           'init': 1.962987801002768e-06,
                           'lo': None},
                'diff_w': {'hi': None,
                           'init': 9.10044504193757e-05,
                           'lo': None},
                'load_l': {'hi': None,
                           'init': 2.7467156903976463e-07,
                           'lo': None},
                'load_w': {'hi': None,
                           'init': 8.416284368753146e-06,
                           'lo': None},
                'mirr_l': {'hi': None,
                           'init': 1.0448731038654446e-06,
                           'lo': None},
                'mirr_ld': {'hi': None,
                            'init': 1.5642296416442112e-06,
                            'lo': None},
                'mirr_w': {'hi': None, 'init': 7.4265218039144e-05, 'lo': None},
                'mirr_wd': {'hi': None,
                            'init': 4.656258457594952e-05,
                            'lo': None},
                'mirr_wo': {'hi': None,
                            'init': 4.557470194454615e-05,
                            'lo': None},
                'out_l': {'hi': None,
                          'init': 5.074524593084138e-07,
                          'lo': None},
                'out_w': {'hi': None,
                          'init': 2.274205802361054e-05,
                          'lo': None},
                'r_out': {'hi': None, 'init': 1529.245354459235, 'lo': None}},
 'requirementNames': [],
 'requirements': {'exclude': [],
                  'lower': {},
                  'norm': {},
                  'tradeoff': {},
                  'upper': {}},
 'settings': {'aggregatorsettings': {},
              'evaluatorsettings': {},
              'failurepenalty': 1000000.0,
              'forwardsolution': True,
              'incrementalcorners': True,
              'initialstep': 0.25,
              'maxiter': None,
              'method': 'noneFull',
              'optimizersettings': {},
              'stopsatisfied': True,
              'stoptol': 1e-05,
              'tradeoffmultiplier': 0},
 'type': 'cbd'}

if __name__=='__main__':
  import numpy as np
  np.random.seed(0)

  if useMPI:
    from pyopus.parallel.mpi import MPI
    from pyopus.parallel.cooperative import cOS

    cOS.setDebug(mpiData['cosdebug'])
    if mpiData['mirror']:
      vm=MPI(mirrorMap=projData['mirrormap'], persistentStorage=mpiData['persistent'], debug=mpiData['vmdebug'])
    else:
      vm=MPI(debug=mpiData['vmdebug'])
    cOS.setVM(vm)

    hosts=MPI.vmStatus['hosts']
    slots=MPI.vmStatus['slots']
    DbgMsgOut('VM', 'Process list (total %d):' % (len(slots)))
    for host in hosts.keys():
      DbgMsgOut('VM', '  Host %s with %d process(es)' % (host, len(hosts[host]['slots'])))
      for slot in hosts[host]['slots']:
        DbgMsgOut('VM', '    slot %d: pid=0x%x (%d)' % (slot, slots[slot]['pid'], slots[slot]['pid']))

  from pyopus.design.sqlite import SQLiteDatabase
  sqld=SQLiteDatabase(os.path.join('..', taskData['name']+'.sqlite'))

  from pyopus.gui.tasks import taskRunner

  try:
    runner=taskRunner[taskData['type']]
    runner(projData, taskData, sqld)
  except Exception as e:
    DbgMsgOut('TASK', 'Task terminated due to exception.')
    DbgMsgOut('TASK', traceback.format_exc())
    sys.exit(1)

  if useMPI:
    cOS.finalize()
