U

�������g�|����������������������@���s����d�Z�dddgZddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlZddlZddl
ZddlZddlmZmZmZ�G�dd��de�ZG�dd��de�Zed�Zed	�Zed
�Zdd��ZG�d
d��d�Zdd��Zdd��ZdS�)z�!Defines the Revital class which manipulates tcvitals files.

This module deals with rewriting TCVitals files to remove errors,
change Invests to storms, and other such operations.  �Revital�RevitalError�RevitalInitError�����N)�great_arc_dist�to_fraction�to_timedeltac�������������������@���s���e�Zd�ZdZdS�)r���z2!Base class of errors related to rewriting vitals.N��__name__�
__module__�__qualname__�__doc__��r
���r
����;/lfs/h1/ops/prod/packages/hafs.v2.0.7/ush/tcutil/revital.pyr������s���c�������������������@���s���e�Zd�ZdZdS�)r���zU!This exception is raised when an argument to the Revital
    constructor is invalid.Nr���r
���r
���r
���r���r������s���i���i`T��c�����������������C���s���|�|k|�|k��S�)z# Python3 does not have cmp funtion r
�����a�br
���r
���r����cmp&���s����r���c����������������	���@���s����e�Zd�ZdZd?dd�Zdd	��Zd
d��Zdd
��Zd@dd�ZdAdd�Z	dd��Z
dd��ZdBdd�Zdd��Z
dCdd�Zdd��Zdd ��Zd!d"��Zd#d$��Zd%d&��Zd'd(��Zd)d*��Zd+d,��Zd-d.��Zd/d0��ZdDd1d2�ZdEd4d5�Zd6d7��Zd8d9��Zd:d;��Zd<d=��Zd>d9��ZdS�)Fr���zP!This class reads one or more tcvitals files and rewrites them
    as requested.NF������jATc
�����������������C���s>��|	dk	r�|	j�|	j|	j|	jf\|�_�|�_|�_|�_|	j|	j|	j��|�_|�_|�_t��|�_|	j�	��D�]8\}
}t��|�j|
<�|�	��D�]\}}
|
�
��|�j|
�|<�qvqZt|	j�|�_dd��|	j
D��|�_
dS�t|�|�_�|dkr�tn||�_||�_|o�|dk	|�_t|�|�_||�_|dk	�rtj�|��std|f���t��|�_t��|�_t��|�_
d|�_dS�)a��!Creates a Revital object:

        @param logger A logging.Logger object for logging or None to
            disable.  Default: None
        @param invest_number_name Rename storms to have the last
            non-INVEST name seen
        @param stormid Ignored.
        @param adeckdir Directory with A deck files.  This is used to
            read the storm type information from CARQ entries and
            append them to produce vitals with the storm type from
            vitals that lack it.
        @param renumberlog Ignored.
        @param search_dx Search radius in km for deciding whether two
            storms are the same.
        @param search_dt Search timespan for finding two storms that are
            the same.
        @param debug If True, enables DEBUG level logging.
        @param copy Used by copy() to make a shallow copy of a
            Revital.  If specified, the other arguments are ignored, and
            the copy's contents are copied.  Do not use this argument.
            If you need a copy, use copy() instead.Nc�����������������S���s���g�|�]}|�����qS�r
�����copy)�.0�vr
���r
���r����
<listcomp>P���s�����z$Revital.__init__.<locals>.<listcomp>z*Specified directory %s is not a directory.F)�	search_dx�	search_dt�logger�debug�invest_number_name�adeckdir�
is_cleaned�dict�carqdat�itemsr����set�carqfail�vitals�float�	six_hours�bool�os�path�isdirr����list)�selfr���r����stormidr����renumberlogr���r���r���r����key�cdatZymdh�cardr
���r
���r����__init__-���s>������


��zRevital.__init__c�����������������C���s&���t�|tjj�std��|�j�|��dS�)zc!Appends a vital entry to self.vitals.
        @param vital an tcutil.storminfo.StormInfo to appendzDThe argument to Revital.append must be an tcutil.storminfo.StormInfoN)�
isinstance�tcutil�	storminfo�	StormInfo�	TypeErrorr%����append�r-����vitalr
���r
���r���r9�������s����zRevital.appendc�����������������C���s���|�j��|��d|�_dS�)z�!Given the specified iterable object, appends its contents
        to my own.
        @param vitals an iterable object filled with tcutil.storminfo.StormInfoFN)r%����extendr���)r-���r%���r
���r
���r���r<�������s����zRevital.extendc�����������������C���s
���t�|�d�S�)z_!Returns a deep copy of this Revital.  Modifying the copy
        will not modify the original.r���)r����r-���r
���r
���r���r�������s����zRevital.copyc�����������������C���s����t�|�dkr|�j�d��n|�j�d|dd�����|�j�tjj|||�jd���d|�_	|�jdk	r||�j
r||�j�
dt�|�j�f���|�S�)	a���!Same as readfiles except the tcvitals have already been
           parsed and the vitals are being passed in, not the
           filelist.  This was created to handle the multistorm fake
           storm.  This is being used to validate any self generated
           vitals by the fake storm.
           @param vitalslist a list of strings with tcvitals data
           @param raise_all if True, raise exceptions for any parsing errors.
           @returns selfr���z1No parsed tcvitals provided to revital.readvitalsz%Processing parsed tcvitals, line1: %sN������	raise_allr���F�line count: %d)�lenr����error�infor%���r<���r5���r6����parse_tcvitalsr���r���)r-���Z
vitalslistr@���r
���r
���r����
readvitals����s����
���zRevital.readvitalsc�����������������C���sD��t�|t�r|g}t��}d}|D�]�}|�jdk	r>|�j�d|f���z,t|d��}|�|�����W�5�Q�R�X�d}W�q�tk
r��}�zV|j	t	j
ks�|j	t	jkr�|�j�|d�t|����|r΂�n|�j�|d�t|������W�5�d}~X�Y�qX�q|s�|�j�
d��|�j�tjj|||�jd���d|�_|�jdk	�r@|�j�r@|�j�d	t|�j�f���dS�)
a:��!Reads the list of files and parses them as tcvitals files.
        @param filelist a list of string filenames
        @param raise_all if True, all exceptions are raised.  If False,
           then exceptions are ignored, and the function will attempt to
           process all files, even if earlier ones failed.FNz
read file: %s�rtTz: cannot open: zANo message files or tcvitals files provided to revital.readfiles.r?���rA���)r4����strr,���r���rD����openr<����	readlines�EnvironmentError�errno�ENOENTZEISDIR�warningrC���r%���r5���r6���rE���r���r���rB���)r-����filelistr@����lines�opened�tcvitals�f�er
���r
���r����	readfiles����s8����

����zRevital.readfilesc�����������������C���s����t�|dd�}t�|dd�}|dks@|dk�s@|dks@|dk�s@|dkrDdS�tjd�}d}||�|�|�}|d|��}|t�|��}	|t�|��t�|j|���}
|j|	�|j|
�fS�)	a��!Returns a tuple containing the latitude and longitude of
        the storm at a different position according to the storm
        motion vector.
        @param vital the tcutil.storminfo.StormInfo for the storm fix being extrapolated
        @param dt the time difference in hours�
stormspeedN�stormdirr���)NNg������f@g���@�TXAg������V@)�getattr�math�pi�sin�cos�lat�lon)r-���r;����dtrV���rW���Zpi180ZRearth�kZ	moveangleZdlatZdlonr
���r
���r����move_latlon����s������
zRevital.move_latlonc��������������	���C���s����||�j�krdS�tj�|�jd|f��}tj�|�r@tj�|�dkrP|�j��|��dS�t|d��}dd��|�	��D��}W�5�Q�R�X�t
jj||�j
d�}t��}|D�]}|||j<�q�||�j|<�dS�)ar��!Tries to find the CARQ data for the specified storm.  Reads
        it into the self.carqdat array, or adds the stormid to
        self.carqfail if the data cannot be read in.
        @param longstormid the long stormid of the storm to read
        @post the self.carqfail will contain longstormid OR
          self.carqdat[longstormid] will contain data for that stormNza%s.datr���rG���c�����������������S���s���g�|�]}|�qS�r
���r
���)r����liner
���r
���r���r�������s�����z$Revital.readcarq.<locals>.<listcomp>)r���)r$���r)���r*����joinr����exists�getsize�addrI���rJ���r5���r6���Z
parse_carqr���r ����YMDHr!���)r-����longstormid�filenamerS����data�carqr1���r2���r
���r
���r����readcarq����s����
�zRevital.readcarqc�����������������C���s"���t�jj|�j|||d�|�_d|�_dS�)aS��!Calls the tcutil.storminfo.clean_up_vitals on this object's
        vitals.  The optional arguments are passed to
        tcutil.storminfo.clean_up_vitals.

        @param name_number_checker a function like
          tcutil.storminfo.name_number_okay() for validating the storm
          name and number
        @param vitals_cmp a cmp-like function for ordering tcutil.storminfo.StormInfo objects
        @param basin_center_checker a function like
          tcutil.storminfo.basin_center_okay() for checking the storm
          basin and forecast center (RSMC)

        @post is_cleaned=True)�name_number_checker�basin_center_checker�
vitals_cmpTN)r5���r6����clean_up_vitalsr%���r���)r-���rm���rn���ro���r
���r
���r���rp�������s������zRevital.clean_up_vitalsc�����������������C���s���d}|�j�o|�jdk	}|�j}|dks&t�|dks2t�|dkrz|��|d|��\}	}
|�j�r�|	dk	r�|
dk	r�|�j��d|	|
f���n|j|j�}	}
|r�|	dks�|
dkr�|r�|��d��dS�|�j}|�j�o�|dk	}d}t|����D��]�}||�}|�r$t|dd�}
|
dk�r$|j	|k��r$|r�|��d	|j
|jf���q�|�r<|��d
|jf���|j|j�}|t
k��rX|�}|t
k�rdq�|tk�r�|�r~|��d��||=�q�||�jk�r�|r�|��d��q�|�r�|��d
��|j�r`|j|jkr�|j|jkr�|�r�|��d|j|jf���|�j�r|�dt|j�|jf���|�|j|j��|�t|jdd�����d}|�rT|��d|jf���|||j<�q�|dk��r�|��|d|��\}}|�r�|dk	�r�|dk	�r�|��d||f���n|j|j�}}|dk�s�|dk�r�|r�|��d��q�t|
|	||�}||�jk��r|tk�s|r�|��d|d�f���q�|�r4|��d|jf���|�j�rV|�dt|j�|jf���|�|j|j��|�t|jdd�����d}|�r�|��d|jf���|||j<�q�|�r�|��dt|�f���|S�)af��!Internal function that handles renumbering of storms.

        @protected
        This is an internal implementation function that should
        never be called directly.  It handles part of the work of
        renumbering storms in the list of vitals.  You should call
        "renumber" instead.
        @param vital the vital being renumbered
        @param lastvit the last vital seen
        @param vit_motion time since vital
        @param other_motion time since other storms vital
        @param threshold cold start threshold, used to decide when to
           stop connecting an invest to a non-investFNr���g����� �@z    -- lat=%.3f lon=%.3fz    -- no lat,lon for search�	old_stnum�Z���z@Old %s vit was a low intensity invest, so not considering it: %sz vs.  %sz    -- age out othervitz    -- dt is too largez    -- within dtz#    -- continue renumbering (%s) %sz
INVEST%02d%1s����Tz NOW  %sz    -- vs lat=%.3f lon=%.3fz3    -- cannot get other vitals location; moving on.z&    -- not kinda near (distance %f km)g�����@�@z*    -- within dx: renumber to %s and storez    - renumbered = %s)r���r����AssertionErrorra���r]���r^���r,����keysrX����wmax�old_stormid3rb����when�	zero_time�two_daysr���Z
has_old_stnumrq����stnum�basin1�stormid3r����rename_storm�intZchange_basinZ	pubbasin2Zrenumber_stormr���r���r'����repr)r-���r;����lastvitZ
vit_motionZother_motion�	threshold�
renumberedr���r���r]���r^���r.���ZothervitZold_idr_���ZotherlatZotherlon�distr
���r
���r����renumber_one
��s������
�����

�
�
�
�

�
��

����������zRevital.renumber_oner���c�����������
������C���s���|�j�s|�����d|�_�|sd}t|�}t��}|�jo8|�jdk	}|�j}t|�j�D�]�}|rd|�d|jf���|j	}	|j
dkr�|j
dk�r�qJn:|j
dk�r�|||j	<�qJn"|��||dd|�r�|rJ|�d��qJ|r�|�d��|��||dd	|�r�qJ|r�|�d
��|��||dd|��rqJ|�r|�d��|��||d
d|�rJqJqJ|�r6|�����|�r�|�sd|�rd|dk	�r\|�
d��|�����|dk	�rx|�
d��tj�|�j�|�_dS�)a���!Renumbers storms with numbers 90-99, if possible, to have
        the same number as later 1-49 numbered storms.

        Loops over all vitals from last to first, renumbering 90-99
        storms to have the same storm number as later 1-49 storms.

        @param threshold If a threshold is given, then a cycle will
        only be considered for renumbering if it is either above that
        threshold, or is not an Invest.
        @param unrenumber If unrenumber is True, the original storm
        numbers are restored after renumbering.
        @param discard_duplicate If True, discard invests that are
          duplicates of non-invests.  This feature is disabled if
          unrenumber is enabled or cleaning is disabled.
        @param clean If clean is True (the default), then
        self.clean_up_vitals is called, which will (among other
        things) delete vitals lines that have the same time and storm
        ID.  The cleaning is done after unrenumbering, so if both
        options are turned on, the result will contain only one entry
        per storm ID per time, but with all storm IDs that are
        available for a given storm at any one time.Fr���NzVITAL %s�2���rr���z     -- done renumbering this onez7 - SEARCH AGAIN: subtract storm motion from later cyclei����z2 - SEARCH AGAIN: add storm motion to earlier cycle����z; - SEARCH AGAIN: add half motion to later and earlier cycle���������z2Delete Invests that are duplicates of non-Invests.z.Clean up the vitals again after renumbering...)r���rp���r���r ���r���r����reversedr%���rb���r}���r{���r�����swap_numbersrD����delete_invest_duplicatesr5���r6���)
r-����
unrenumber�cleanr����Zdiscard_duplicatesr����r���r���r;���r0���r
���r
���r����renumber���sd�������

�
���



zRevital.renumberc�����������������C���s����t��t�}|�jD�]8}|jdk�rt|jd��t|jd��f}|||j�|<�q|�jD�]F}|jdkrPt|jd��t|jd��f}|||j�krP|||j�|<�qPt	��}|�
��D�]}|�
��D�]}|�|��q�q�||�_dS�)z[!Deletes Invest entries that have the same location and time
        as non-invest entries.r��������rr���N)�collections�defaultdictr ���r%���r{���r���r]���r^���rg���r,����valuesr9���)r-����or���r`����lZyvr
���r
���r���r�������s����




z Revital.delete_invest_duplicatesc�����������������C���s���|�j�D�]}|����qd|�_dS�)z@!Calls swap_numbers on all vitals to swap old and new storm IDs.FN)r%���r����r���r:���r
���r
���r���r�������s����

zRevital.swap_numbersc�����������������C���sD���t���}|�jD�]&}|�|��d|jkr|�|�����q||�_d|�_dS�)z�!Duplicates all vitals that have been renumbered, creating
        one StormInfo with the old number and one with the new
        number.rw���FN)r,���r%���r9����__dict__�oldr���)r-����newvitr;���r
���r
���r����mirror_renumbered_vitals���s����


z Revital.mirror_renumbered_vitalsc�����������������C���s.���t���}|�jD�]}||�r|�|��q||�_dS�)aP��!Discards all vitals except those for which the
        keep_condition function returns True.

        @param keep_condition A function that receives a StormInfo
        object as its only argument, returning True if the vital
        should be kept and False if not.
        @note The list will be unmodified if an exception is thrown.N)r,���r%���r9���)r-����keep_conditionr�����vitr
���r
���r����discard_except���s
����
zRevital.discard_exceptc�����������������C���s,���|�j�D�] }t|d�r|j|j�|_|_qdS�)zT!This subroutine undoes the effect of renaming by swapping
        old and new names�
old_stormnameN)r%����hasattr�	stormnamer����r:���r
���r
���r����
swap_names��s����


�zRevital.swap_namesc�����������������C���s����|�j�}|�jo|dk	}t��}t|�j�D�]p}|j}||kr�||�}|j|kr�|r`|�d||jf���|�|��|r�|�d|jf���q$|jdd��||<�q$dS�)zd!This subroutine renames storms so that they have the last name seen
        for their storm number.NzRename to %s: %szNow: %sr����	���)	r���r���r ���r����r%���r}���r����rb���r~���)r-���r���r����lastnamer;���r0����namer
���r
���r����rename��s����

�zRevital.renamec�����������������C���s����|�j�}|�jo|dk	}|�jD�]�}|j���}|j}||�jkrB|��|��||�jkrp|dk	rd|�d|f���|�	d��q|�j|�}||kr�|dk	r�|�d||f���|�	d��q|�	||���qdS�)zJ!Add the storm type parameter from the CARQ entries in the A
        deck.Nz2storm %s: no CARQ data found.  Using stormtype XX.ZXXzDstorm %s cycle %s: no CARQ data for this cycle.  Using stormtype XX.)
r���r���r%���rh����lowerrg���r!���rl���rN���Z
set_stormtype)r-���r���r���r;���Zlsidrx���rk���r
���r
���r����
add_stormtype!��s.����




�

�
zRevital.add_stormtypec�����������������C���s���t�|�jt�|�d�|�_dS�)z�!Resorts the vitals using the specified cmp-like function.
        @param cmpfun a cmp-like function for comparing tcutil.storminfo.StormInfo objects)r0���N)�sortedr%����	functools�
cmp_to_key)r-���Zcmpfunr
���r
���r����sort_by_function;��s����zRevital.sort_by_functionc�����������������C���s���t�|�jtjjd�|�_dS�)zi!Resorts the vitals by storm instead of date.  See
        tcutil.storminfo.vit_cmp_by_storm for details.)r���N)r����r%���r5���r6���Zvit_cmp_by_stormr=���r
���r
���r����
sort_by_stormA��s����zRevital.sort_by_stormc�����������������c���s���|�j�D�]
}|V��qdS�)zK!Iterates over all vitals, yielding StormInfo objects for
        each one.N)r%���)r-����xr
���r
���r����__iter__E��s����
�zRevital.__iter__c�����������������#���s������dkrdd��}n�t���������t�d���rH��fdd�}|r���fdd�}nft�d���rr��fd	d�}|r���fd
d�}n<t�d���r���fdd�}|r���fd
d�}ntdt�t�f���|�jD�]&}||�r�|V��q�|r�||�r�|V��q�dS�)ay��!Iterates over all vitals that match the specified stormid.
        If no stormid is given, iterates over all vitals.

        @param stormid the storm ID to search for.  This can be
          a stormid3, stormid4 or longstormid.
        @param old If old=True, also searches the old_ copy of the
        stormid.  Any of stormid3, stormid4 or longstormid are
        accepted.Nc�����������������S���s���dS�)NTr
����r;���r
���r
���r����selectedU�������zRevital.each.<locals>.selectedz\A\d\d[a-zA-Z]\Zc��������������������s
���|�j���kS��N)r}���r�����r.���r
���r���r����Y��r����c��������������������s���d|�j�ko|�j��kS�)Nrw���)r����rw���r����r����r
���r����old_selected[��s����
�z"Revital.each.<locals>.old_selectedz\A[a-zA-Z]{2}\d\d\Zc��������������������s
���|�j���kS�r����)Zstormid4r����r����r
���r���r����_��r����c��������������������s���d|�j�ko|�j��kS�)N�old_stormid4)r����r����r����r����r
���r���r����a��s����
�z\A[a-zA-Z]{2}\d{6}\Zc��������������������s
���|�j���kS�r����)rh���r����r����r
���r���r����e��r����c��������������������s���d|�j�ko|�j��kS�)N�old_longstormid)r����r����r����r����r
���r���r����g��s����
�zNInvalid storm id %s.  It must be one of these three formats: 04L AL04 AL042013)rH����upper�re�searchr����valr%���)r-���r.���r����r����r����r����r
���r����r����eachI��s0����
�
zRevital.eachrb���c�����������������C���s���|�j�||d�D�]�}|dk	rh|j}t|d|�}|j}	t|d|	�}
|�d|j|||
dd��|	dd��f���|dkr�t|���|d	��q|d
kr�|���}t|d|j�}t|d|j�}
td||
|f�|d	��q|dkr�td
|j�	��|jf�|d	��qt|j
|d	��qdS�)a���!Print the vitals to the given stream in a specified format.

        @param stream The stream (eg.: opened file) to receive the vitals.
        @param format Either "tcvitals" to reformat as tcvitals (cleaning up
         any errors); or "line" to simply print the original data for each
         line; or "HHS" to use the HHS output format.  (Do not use the "HHS"
         option unless you are HHS.)
        @param renumberlog If given, sends information about renaming and
        renumbering of the vitals to a second stream.
        @param stormid The "stormid" argument is used to restrict
        printing to only a certain stormid.
        @param old If True, then vitals with an old_stormid that matches are
          also printed.)r.���r����Nrw���r����z%10s %3s %3s %-9s %-9s
r���r����rR���)�fileZrenumberingz
%3s %9s => %sZHHSz%s %s "TCVT")r����r}���rX���r�����writerg����print�as_tcvitalsrh���r����rb���)r-����streamr/����formatr.���r����r����Z	xstormid3Zoldidr�����oldname�sr
���r
���r����print_vitalsv��s&�����zRevital.print_vitalsc�����������
������C���s����t�|dd�}t�|dd�}|jdkr&dnd}|jdkr8dnd}|jdkrJdnd}|jdkr\dnd}t||�p�t||�p�t||�p�t|j|j��p�|jdkr�|jdkr�t|j|j�p�|jdko�|jdko�t|j|j��}	|	S�)am��!A drop-in replacement for "cmp" that can be used for sorting or
        comparison.  Returns -1 if a<b, 1 if a>b or 0 if a=b.  Decision is
        made in this order:

        Edited by GJA on 08-29-2017 -- Added logic to prefer Atlantic storm
        over East Pacific storm if the class (i.e., invest vs. non-invest)
        is the same.

        1) User priority (a.userprio): lower (priority 1) is "more
        important" than higher numbers (priority 9999 is fill value).

        2) Invest vs. non-invest: invest is less important

        3) Atlantic vs. East Pacific: Atlantic is more important

        4) wind: stronger wind is more important than weaker wind

        5) North Atlantic (L) storms: farther west is more important

        6) North East Pacific (E) storms: farther East is more important

        If all of the above values are equal, 0 is returned.�userprio�'���INVESTr>���r����E�L)rX���r����r|���r���rv���r^���)
r-���r���r����
a_userprio�
b_userprio�a_invest�b_investZa_basinZb_basin�cr
���r
���r����hrd_multistorm_sorter���s$����
��� �"�zRevital.hrd_multistorm_sorterc�����������������C���s���dS��z!Does nothing.Nr
���r=���r
���r
���r����multistorm_priority���s����zRevital.multistorm_priorityc�����������������C���s
���t�||�S�r����)�hrd_multistorm_cmp)r-���r���r���r
���r
���r���r�������s����zRevital.hrd_multistorm_cmpc�����������������C���s
���t��t�S�r����)r����r����r����)r-���r���r
���r
���r����hrd_multistorm_key���s����zRevital.hrd_multistorm_keyc�����������������C���s���dS�r����r
���r=���r
���r
���r���r�������s����)	NFNNNr���NTN)T)T)NNN)FTr���T)NF)Nrb���NF)r	���r
���r���r���r3���r9���r<���r���rF���rU���ra���rl���rp���r����r����r����r����r����r����r����r����r����r����r����r����r����r����r����r����r����r����r
���r
���r
���r���r���*���sV���������������
Y

!�����
t���
H
-���
#&c�����������������C���s���|�|k�rdS�|�|krdS�dS�)N�����r>���r���r
���r���r
���r
���r����oldcmp���s
������r����c�����������������C���s����t�|�dd�}t�|dd�}|�jdkr&dnd}|jdkr8dnd}t||�p�t||�p�t|�j|j��p�|�jdkr�|jdkr�t|�j|j�p�|�jdko�|jdko�t|�j|j��}|S�)a���!A compares two storminfo objects for use in sorting or comparison.
    Returns -1 if a<b, 1 if a>b or 0 if a=b.  Decision is made in this
    order:

    1. User priority (a.userprio): lower (priority 1) is "more
       important" than higher numbers (priority 9999 is fill value).

    2.  Invest vs. non-invest: invest is less important

    3.  wind: stronger wind is more important than weaker wind

    4.  North Atlantic (L) storms: farther west is more important

    5.  North East Pacific (E) storms: farther East is more important

    If all of the above values are equal, 0 is returned.
    @returns -1, 0 or 1
    @param a,b the vitals to compare

    r����r����r����r>���r���r����r����)rX���r����r����rv���r|���r^���)r���r���r����r����r����r����r����r
���r
���r���r�������s����
�� �"�r����)r����__all__�logging�datetime�getopt�sys�os.pathr)���r����rY���rL���r����r�����tcutil.storminfor5����tcutil.numericsr���r���r����	Exceptionr���r���ry���rz���r'���r���r���r����r����r
���r
���r
���r����<module>���s&���
H�����(