def main(argparseOptions):
    
    global c, rOpt, appnamePrefix, rClient
    rOpt = argparseOptions
    c = string_ops.Printer(rOpt.enableColor)
    runningApps = []
    timestamps = []
    
    try:
        with open(os.devnull, 'w') as devnull:
            subprocess.check_call(['notify-send', '--version'], stdout=devnull)
    except:
        print(c.RED("Unable to launch notify-send command!",
                    "We cannot notify you of events without libnotify installed"))
        sys.exit(2)
    
    try:
        with open(os.path.expanduser(rOpt.configFile)) as f:
            cfg = yaml.safe_load(f)
    except:
        print(c.yellow(
            "Note: unable to read configFile '{}'; using defaults"
            .format(rOpt.configFile)))
        nick = user = passwd = messg = events = None
    else:
        nick   = cfg.get('nickname', None)
        user   = cfg.get('ravelloUser', None)
        passwd = cfg.get('ravelloPass', None)
        messg  = cfg.get('unableToLoginAdditionalMsg', None)
        events = cfg.get('eventsOfInterest', None)
    
    if rOpt.kerberos:
        appnamePrefix = 'k:' + rOpt.kerberos + '__'
    elif nick:
        appnamePrefix = 'k:' + nick + '__'
    else:
        appnamePrefix = ''
    
    lackingCreds = False
    
    if not rOpt.ravelloUser:
        if user:
            rOpt.ravelloUser = user
        elif sys.stdout.isatty():
            rOpt.ravelloUser = get_username(c.CYAN("Enter Ravello username: "))
        else:
            lackingCreds = True
    
    if not rOpt.ravelloPass:
        if passwd:
            rOpt.ravelloPass = passwd
        elif sys.stdout.isatty():
            rOpt.ravelloPass = get_passphrase(c.CYAN("Enter Ravello passphrase: "))
        else:
            lackingCreds = True
    
    if lackingCreds:
        cmd = [
            'notify-send', '--urgency', 'critical',
            "rav-notify missing Ravello credentials!",
            "You must either populate ~/.ravshello/ravshello.conf, run " +
            "rav-notify with -u & -p options, or run rav-notify from a " +
            "terminal so it can prompt you for user/pass.",
            ]
        subprocess.check_call(cmd)
        sys.exit(3)
    
    rClient = ravello_sdk.RavelloClient()
    try:
        # Try to log in.
        rClient.login(rOpt.ravelloUser, rOpt.ravelloPass)
    except:
        if sys.stdout.isatty():
            print(c.RED("Logging in to Ravello failed!"))
            print("\nRe-check your username and password.")
            if messg: print(messg)
        else:
            cmd = [
                'notify-send', '--urgency', 'critical',
                "rav-notify failed to log in to Ravello!",
                "Re-check your username and password.",
                ]
            subprocess.check_call(cmd)
        sys.exit(5)
    
    cmd = [
        'notify-send', '--urgency', 'low',
        "rav-notify monitoring Ravello events",
        "Any events of interest (app timeouts or deletions, vms being " +
        "started or stopped) will trigger further notifications",
        ]
    subprocess.check_call(cmd)
    
    if events:
        eventsOfInterest = events
    else:
        eventsOfInterest = [
            'APP_TIMEOUT_AUTO_STOPPING',
            'APP_TIMEOUT_AUTO_STOPPED',
            'APPLICATION_TIMER_RESET',
            'APPLICATION_DELETED',
            'VM_STOPPED',
            'VM_STARTED',
            'VM_SNAPSHOTTING_AFTER_STOP',
            'VM_FINISHED_SNAPSHOTTING',
            ]
    
    debug("Event triggers:\n{}\n".format("\n".join(eventsOfInterest)))
    
    urgency = {
        'INFO': "low",
        'WARN': "normal",
        'ERROR': "critical",
        }
    
    # Build a list of app ids we should pay attention to.
    myAppIds = update_myAppIds()
    
    for appId in myAppIds:
        app = rClient.get_application(appId, aspect='properties')
        try:
            # Grab expiration time for all of my deployed apps.
            expirationTime = app['deployment']['expirationTime']
        except:
            continue
        else:
            a = {
                'id': appId,
                'name': app['name'].replace(appnamePrefix, ''),
                'expirationTime': sanitize_timestamp(expirationTime),
                }
            runningApps.append(a)
    
    # Run forever-loop to watch for notifications or expiring apps.
    while 1:
        
        # Run check to see if any apps are about to expire.
        act_on_imminent_app_expiration(runningApps)
        
        myEvents = []
        # Set lower bound to 5 minutes ago, upper bound to right now.
        # Unusual manipulation present because Ravello expects timestamps to
        # include thousandths of a sec, but not as floating-point.
        start = time.time() - (5*60 + rOpt.refreshInterval)
        start = int("{:.3f}".format(start).replace('.', ''))
        end = int("{:.3f}".format(time.time()).replace('.', ''))
        query = {
            'dateRange': {
                'startTime': start,
                'endTime': end,
                },
            }
        try:
            # Perform our search.
            results = rClient.search_notifications(query)
        except ravello_sdk.RavelloError as e:
            if e.args[0] == 'request timeout':
                # Timeout, so try one more time.
                results = rClient.search_notifications(query)
        try:
            # Results are returned in reverse-chronological order.
            for event in reversed(results['notification']):
                try:
                    # Only deal with events we have not seen before that relate
                    # to one of myAppIds.
                    if (any(appId == event['appId'] for appId in myAppIds) and 
                            event['eventTimeStamp'] not in timestamps):
                        myEvents.append(event)
                except:
                    pass
        except:
            pass
        
        # Iterate over events relevant to my apps.
        for event in myEvents:
            
            if any(etype in event['eventType'] for etype in eventsOfInterest):
                # Get application data if event of interest.
                try:
                    app = rClient.get_application(
                        event['appId'], aspect='properties')
                except KeyError:
                    # Will fail if event is not about an app, i.e.: on user login.
                    continue
            else:
                continue
            
            # Add unique timestamp for this event to our list, to prevent acting
            # on it in a subsequent loop.
            timestamps.append(event['eventTimeStamp'])
            
            try:
                appName = app['name'].replace(appnamePrefix, '')
            except __HOLE__:
                # Will fail if app was deleted.
                appName = ''
            
            if event['eventType'] == 'APPLICATION_TIMER_RESET':
                try:
                    # Grab expiration time if app is deployed.
                    expirationTime = app['deployment']['expirationTime']
                except:
                    # (app isn't deployed)
                    pass
                else:
                    expirationTime = sanitize_timestamp(expirationTime)
                    for a in runningApps:
                        # Try to find the app by id in our existing list.
                        if a['id'] == app['id']:
                            # Update the app's expirationTime timestamp.
                            a['expirationTime'] = expirationTime
                            break
                    else:
                        # If the appId for the APPLICATION_TIMER_RESET event isn't
                        # present in our runningApps list, we need to add it.
                        a = {
                            'id': app['id'],
                            'name': appName,
                            'expirationTime': expirationTime,
                            }
                        runningApps.append(a)
            else:
                # Event type is anything but APPLICATION_TIMER_RESET.
                tstamp = datetime.fromtimestamp(
                    sanitize_timestamp(timestamps[-1])
                    ).strftime("%H:%M:%S")
                if appName:
                    appName = " ({})".format(appName)
                msg = event['eventProperties'][0]['value'].replace(appnamePrefix, '')
                cmd = [
                    'notify-send',
                    '--urgency',
                    urgency[event['notificationLevel']],
                    "{}{}".format(event['eventType'], appName),
                    "[{}] {}".format(tstamp, msg),
                    ]
                subprocess.check_call(cmd)
        
        if rOpt.enableDebug and sys.stdout.isatty():
            i = rOpt.refreshInterval
            while i >= 0:
                print(c.REVERSE("{}".format(i)), end='')
                sys.stdout.flush()
                time.sleep(1)
                print('\033[2K', end='')
                i -= 1
            print()
        else:
            time.sleep(rOpt.refreshInterval)

        myAppIds = update_myAppIds(myAppIds)
dataset/ETHPy150Open ryran/ravshello/rav-notify.py/main