예제 #1
0
    def __init__(self, config, server, sandbox, quiet=False):
        self.config = config
        self.quiet = quiet
        self.amt_services_wrapper = MTurkServicesWrapper(config=config, sandbox=sandbox)

        self.sandbox = sandbox
        self.tunnel = TunnelServices()

        self.sandbox_hits = 0
        self.live_hits = 0

        if not quiet:
            self.update_hit_tally()
        PsiturkShell.__init__(self, config, server, quiet)

        # Prevents running of commands by abbreviation
        self.abbrev = False
        self.debug = True
        self.help_path = os.path.join(os.path.dirname(__file__), "shell_help/")
        self.psiturk_header = 'psiTurk command help:'
        self.super_header = 'basic CMD command help:'
예제 #2
0
 def __init__(self, config=None, web_services=None, tunnel=None, sandbox=None):
     
     if not config:
         config = PsiturkConfig()
         config.load_config()
     self.config = config
     
     if web_services:
         self._cached_web_services = web_services
     
     if not tunnel:
         tunnel = TunnelServices(config)
     self.tunnel = tunnel
 
     if not sandbox:
         sandbox = config.getboolean('Shell Parameters', 'launch_in_sandbox_mode')
     self.sandbox = sandbox
예제 #3
0
    def __init__(self, config, server, sandbox, quiet=False):
        self.config = config
        self.quiet = quiet
        self.amt_services_wrapper = MTurkServicesWrapper(config=config, sandbox=sandbox)        
        
        self.sandbox = sandbox
        self.tunnel = TunnelServices()
        
        self.sandbox_hits = 0
        self.live_hits = 0
        
        if not quiet:
            self.update_hit_tally()
        PsiturkShell.__init__(self, config, server, quiet)

        # Prevents running of commands by abbreviation
        self.abbrev = False
        self.debug = True
        self.help_path = os.path.join(os.path.dirname(__file__), "shell_help/")
        self.psiturk_header = 'psiTurk command help:'
        self.super_header = 'basic CMD command help:'
예제 #4
0
class PsiturkNetworkShell(PsiturkShell):
    ''' Extends PsiturkShell class to include online psiTurk.org features '''

    _cached_web_services = None

    @property
    def web_services(self):
        if not self._cached_web_services:
            self._cached_web_services = PsiturkOrgServices(
                self.config.get('psiTurk Access', 'psiturk_access_key_id'),
                self.config.get('psiTurk Access', 'psiturk_secret_access_id'))
            self.amt_services_wrapper.set_web_services(
                self._cached_web_services)
        return self._cached_web_services

    def __init__(self, config, server, sandbox, quiet=False):
        self.config = config
        self.quiet = quiet
        self.amt_services_wrapper = MTurkServicesWrapper(config=config,
                                                         sandbox=sandbox)

        self.sandbox = sandbox
        self.tunnel = TunnelServices()

        self.sandbox_hits = 0
        self.live_hits = 0

        if not quiet:
            self.update_hit_tally()
        PsiturkShell.__init__(self, config, server, quiet)

        # Prevents running of commands by abbreviation
        self.abbrev = False
        self.debug = True
        self.help_path = os.path.join(os.path.dirname(__file__), "shell_help/")
        self.psiturk_header = 'psiTurk command help:'
        self.super_header = 'basic CMD command help:'

    def do_quit(self, _):
        '''Override do_quit for network clean up.'''
        if (self.server.is_server_running() == 'yes'
                or self.server.is_server_running() == 'maybe'):
            user_input = raw_input("Quitting shell will shut down experiment "
                                   "server. Really quit? y or n: ")
            if user_input == 'y':
                self.server_off()
            else:
                return False
        return True

    def server_off(self):
        if (self.server.is_server_running() == 'yes'
                or self.server.is_server_running() == 'maybe'):
            self.server.shutdown()
            print 'Please wait. This could take a few seconds.'
            self.clean_up()
            while self.server.is_server_running() != 'no':
                time.sleep(0.5)
        else:
            print 'Your server is already off.'

    def server_restart(self):
        ''' Restart server '''
        self.server_off()
        self.clean_up()
        self.server_on()

    def clean_up(self):
        ''' Clean up child and orphaned processes. '''
        if self.tunnel.is_open:
            print 'Closing tunnel...'
            self.tunnel.close()
            print 'Done.'
        else:
            pass

    # +-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.
    #   basic command line functions
    # +-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.

    def get_intro_prompt(self):
        ''' Overloads intro prompt with network-aware version if you can reach
        psiTurk.org, request system status message'''
        server_msg = self.web_services.get_system_status()
        return server_msg + colorize(
            'psiTurk version ' + version_number +
            '\nType "help" for more information.', 'green', False)

    def color_prompt(self):  # overloads prompt with network info
        prompt = '[' + colorize('psiTurk', 'bold')
        server_string = ''
        server_status = self.server.is_server_running()
        if server_status == 'yes':
            server_string = colorize('on', 'green')
        elif server_status == 'no':
            server_string = colorize('off', 'red')
        elif server_status == 'maybe':
            server_string = colorize('status unknown', 'yellow')
        elif server_status == 'blocked':
            server_string = colorize('blocked', 'red')
        prompt += ' server:' + server_string
        if self.sandbox:
            prompt += ' mode:' + colorize('sdbx', 'bold')
        else:
            prompt += ' mode:' + colorize('live', 'bold')
        if self.tunnel.is_open:
            prompt += ' tunnel:' + colorize('✓', 'green')
        if self.sandbox:
            prompt += ' #HITs:' + str(self.sandbox_hits)
        else:
            prompt += ' #HITs:' + str(self.live_hits)
        prompt += ']$ '
        self.prompt = prompt

    def server_on(self):
        self.server.startup()
        time.sleep(0.5)

    def do_status(self, arg):  # overloads do_status with AMT info
        super(PsiturkNetworkShell, self).do_status(arg)
        # server_status = self.server.is_server_running()  # Not used
        self.update_hit_tally()
        if self.sandbox:
            print 'AMT worker site - ' + colorize('sandbox', 'bold') + ': ' \
            + str(self.sandbox_hits) + ' HITs available'
        else:
            print 'AMT worker site - ' + colorize('live', 'bold') + ': ' \
            + str(self.live_hits) + ' HITs available'

    def update_hit_tally(self):
        ''' Tally hits '''
        if not self.quiet:
            num_hits = self.amt_services_wrapper.tally_hits()
            if self.sandbox:
                self.sandbox_hits = num_hits
            else:
                self.live_hits = num_hits

    # +-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.
    #   hit management
    # +-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.
    def do_amt_balance(self, _):
        ''' Get MTurk balance '''
        print self.amt_services_wrapper.amt_balance()

    def help_amt_balance(self):
        ''' Get help for amt_balance. '''
        with open(self.help_path + 'amt.txt', 'r') as help_text:
            print help_text.read()

    @docopt_cmd
    def do_db(self, arg):
        """
        Usage:
          db get_config
          db use_local_file [<filename>]
          db use_aws_instance [<instance_id>]
          db aws_list_regions
          db aws_get_region
          db aws_set_region [<region_name>]
          db aws_list_instances
          db aws_create_instance [<instance_id> <size> <username> <password>
                                  <dbname>]
          db aws_delete_instance [<instance_id>]
          db help
        """
        if arg['get_config']:
            self.db_get_config()
        elif arg['use_local_file']:
            self.db_use_local_file(arg, filename=arg['<filename>'])
        elif arg['use_aws_instance']:
            self.db_use_aws_instance(arg['<instance_id>'], arg)
        elif arg['aws_list_regions']:
            self.db_aws_list_regions()
        elif arg['aws_get_region']:
            self.db_aws_get_region()
        elif arg['aws_set_region']:
            self.db_aws_set_region(arg['<region_name>'])
        elif arg['aws_list_instances']:
            self.db_aws_list_instances()
        elif arg['aws_create_instance']:
            self.db_create_aws_db_instance(arg['<instance_id>'], arg['<size>'],
                                           arg['<username>'],
                                           arg['<password>'], arg['<dbname>'])
        elif arg['aws_delete_instance']:
            self.db_aws_delete_instance(arg['<instance_id>'])
        else:
            self.help_db()

    db_commands = ('get_config', 'use_local_file', 'use_aws_instance',
                   'aws_list_regions', 'aws_get_region', 'aws_set_region',
                   'aws_list_instances', 'aws_create_instance',
                   'aws_delete_instance', 'help')

    def complete_db(self, text, line, begidx, endidx):
        ''' Tab-complete db command '''
        return  [i for i in PsiturkNetworkShell.db_commands if \
                 i.startswith(text)]

    def help_db(self):
        ''' DB help '''
        with open(self.help_path + 'db.txt', 'r') as help_text:
            print help_text.read()

    # +-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.
    #   Basic shell commands
    # +-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.
    @docopt_cmd
    def do_mode(self, arg):
        """
        Usage: mode
               mode <which>
        """
        restart_server = False
        if self.server.is_server_running(
        ) == 'yes' or self.server.is_server_running() == 'maybe':
            r = raw_input(
                "Switching modes requires the server to restart. Really "
                "switch modes? y or n: ")
            if r != 'y':
                return
            restart_server = True
        if arg['<which>'] is None:
            if self.sandbox:
                arg['<which>'] = 'live'
            else:
                arg['<which>'] = 'sandbox'
        if arg['<which>'] == 'live':
            self.set_sandbox(False)
            self.update_hit_tally()
            print 'Entered %s mode' % colorize('live', 'bold')
        else:
            self.set_sandbox(True)
            self.update_hit_tally()
            print 'Entered %s mode' % colorize('sandbox', 'bold')
        if restart_server:
            self.server_restart()

    def help_mode(self):
        ''' Help '''
        with open(self.help_path + 'mode.txt', 'r') as help_text:
            print help_text.read()

    def set_sandbox(self, is_sandbox):
        self.sandbox = is_sandbox
        self.amt_services_wrapper.set_sandbox(is_sandbox)

    @docopt_cmd
    def do_tunnel(self, arg):
        """
        Usage: tunnel open
               tunnel change
               tunnel status
        """
        if arg['open']:
            self.tunnel_open()
        elif arg['change']:
            self.tunnel_change()
        elif arg['status']:
            self.tunnel_status()

    # def help_tunnel(self):
    #     with open(self.help_path + 'tunnel.txt', 'r') as helpText:
    #         print helpText.read()

    @docopt_cmd
    def do_hit(self, arg):
        """
        Usage:
          hit create [<numWorkers> <reward> <duration>]
          hit extend <HITid> [(--assignments <number>)] [(--expiration <minutes>)]
          hit expire (--all | <HITid> ...)
          hit dispose (--all | <HITid> ...)
          hit list [--active | --reviewable] [--all-studies]
          hit help
        """

        if arg['create']:
            self.hit_create(arg['<numWorkers>'], arg['<reward>'],
                            arg['<duration>'])
            self.update_hit_tally()
        elif arg['extend']:
            self.amt_services_wrapper.hit_extend(arg['<HITid>'],
                                                 arg['<number>'],
                                                 arg['<minutes>'])
        elif arg['expire']:
            self.amt_services_wrapper.hit_expire(arg['--all'], arg['<HITid>'])
            self.update_hit_tally()
        elif arg['dispose']:
            self.amt_services_wrapper.hit_dispose(arg['--all'], arg['<HITid>'])
            self.update_hit_tally()
        elif arg['list']:
            self.hit_list(arg['--active'], arg['--reviewable'],
                          arg['--all-studies'])
        else:
            self.help_hit()

    hit_commands = ('create', 'extend', 'expire', 'dispose', 'list')

    def complete_hit(self, text, line, begidx, endidx):
        ''' Tab-complete hit command. '''
        return  [i for i in PsiturkNetworkShell.hit_commands if \
                 i.startswith(text)]

    def help_hit(self):
        ''' HIT help '''
        with open(self.help_path + 'hit.txt', 'r') as help_text:
            print help_text.read()

    @docopt_cmd
    def do_worker(self, arg):
        """
        Usage:
          worker approve (--all | --hit <hit_id> ... | <assignment_id> ...) [--all-studies] [--force]
          worker reject (--hit <hit_id> | <assignment_id> ...)
          worker unreject (--hit <hit_id> | <assignment_id> ...)
          worker bonus  (--amount <amount> | --auto) (--hit <hit_id> | <assignment_id> ...)
          worker list [--submitted | --approved | --rejected] [(--hit <hit_id>)] [--all-studies]
          worker help
        """
        if arg['approve']:
            self.worker_approve(arg['--all'], arg['<hit_id>'],
                                arg['<assignment_id>'], arg['--all-studies'],
                                arg['--force'])
        elif arg['reject']:
            self.amt_services_wrapper.worker_reject(arg['<hit_id>'],
                                                    arg['<assignment_id>'])
        elif arg['unreject']:
            self.amt_services_wrapper.worker_unreject(arg['<hit_id>'],
                                                      arg['<assignment_id>'])
        elif arg['list']:
            self.worker_list(arg['--submitted'], arg['--approved'],
                             arg['--rejected'], arg['<hit_id>'],
                             arg['--all-studies'])
        elif arg['bonus']:
            self.amt_services_wrapper.worker_bonus(arg['<hit_id>'],
                                                   arg['--auto'],
                                                   arg['<amount>'], '',
                                                   arg['<assignment_id>'])
        else:
            self.help_worker()

    worker_commands = ('approve', 'reject', 'unreject', 'bonus', 'list',
                       'help')

    def complete_worker(self, text, line, begidx, endidx):
        ''' Tab-complete worker command. '''
        return  [i for i in PsiturkNetworkShell.worker_commands if \
                 i.startswith(text)]

    def help_worker(self):
        ''' Help for worker command. '''
        with open(self.help_path + 'worker.txt', 'r') as help_text:
            print help_text.read()

    @docopt_cmd
    def do_debug(self, arg):
        """
        Usage: debug [options]

        -p, --print-only        just provides the URL, doesn't attempt to
                                launch browser
        """
        revproxy_url = False
        if self.config.has_option('Server Parameters',
                                  'adserver_revproxy_host'):
            if self.config.has_option('Server Parameters',
                                      'adserver_revproxy_port'):
                port = self.config.get('Server Parameters',
                                       'adserver_revproxy_port')
            else:
                port = 80
            revproxy_url = "http://{}:{}/ad".format(
                self.config.get('Server Parameters', 'adserver_revproxy_host'),
                port)

        if revproxy_url:
            base_url = revproxy_url
        elif 'OPENSHIFT_SECRET_TOKEN' in os.environ:
            base_url = "http://" + self.config.get('Server Parameters',
                                                   'host') + "/ad"
        else:
            if arg['--print-only']:
                my_ip = get_my_ip()
                base_url = "http://" + my_ip + ":" + \
                    self.config.get('Server Parameters', 'port') + "/ad"
            else:
                base_url = "http://" + self.config.get('Server Parameters',
                                                   'host') + \
                ":" + self.config.get('Server Parameters', 'port') + "/ad"


        launch_url = base_url + "?assignmentId=debug" + \
            str(self.random_id_generator()) \
            + "&hitId=debug" + str(self.random_id_generator()) \
            + "&workerId=debug" + str(self.random_id_generator() \
            + "&mode=debug")

        if arg['--print-only']:
            print("Here's your randomized debug link, feel free to request " \
                  "another:\n\t" + launch_url)

        else:
            print("Launching browser pointed at your randomized debug link, " \
                  "feel free to request another.\n\t" + launch_url)
            webbrowser.open(launch_url, new=1, autoraise=True)

    # Modified version of standard cmd help which lists psiturk commands first.
    def do_help(self, arg):
        if arg:
            try:
                func = getattr(self, 'help_' + arg)
            except AttributeError:
                try:
                    doc = getattr(self, 'do_' + arg).__doc__
                    if doc:
                        self.stdout.write("%s\n" % str(doc))
                        return
                except AttributeError:
                    pass
                self.stdout.write("%s\n" % str(self.nohelp % (arg, )))
                return
            func()
        else:
            # Modifications start here
            names = dir(PsiturkNetworkShell)
            super_names = dir(Cmd)
            new_names = [m for m in names if m not in super_names]
            help_struct = {}
            cmds_psiTurk = []
            cmds_super = []
            for name in names:
                if name[:5] == 'help_':
                    help_struct[name[5:]] = 1
            names.sort()
            prevname = ''
            for name in names:
                if name[:3] == 'do_':
                    if name == prevname:
                        continue
                    prevname = name
                    cmd = name[3:]
                    if cmd in help_struct:
                        del help_struct[cmd]
                    if name in new_names:
                        cmds_psiTurk.append(cmd)
                    else:
                        cmds_super.append(cmd)
            self.stdout.write("%s\n" % str(self.doc_leader))
            self.print_topics(self.psiturk_header, cmds_psiTurk, 15, 80)
            self.print_topics(self.misc_header, help_struct.keys(), 15, 80)
            self.print_topics(self.super_header, cmds_super, 15, 80)

    # +-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.
    #   tunnel
    # +-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.

    def tunnel_open(self):
        ''' Open tunnel '''
        if (self.server.is_server_running() == 'no'
                or self.server.is_server_running() == 'maybe'):
            print(
                "Error: Sorry, you need to have the server running to open a "
                "tunnel.  Try 'server on' first.")
        else:
            self.tunnel.open()

    def tunnel_status(self):
        ''' Get tunnel status '''
        if self.tunnel.is_open:
            print "For tunnel status, navigate to http://127.0.0.1:4040"
            print "Hint: In OSX, you can open a terminal link using cmd + click"
        else:
            print(
                "Sorry, you need to open a tunnel to check the status. Try"
                "'tunnel open' first.")

    def tunnel_change(self):
        ''' Change tunnel url '''
        print('Tearing down old tunnel if present...')
        self.tunnel.change_tunnel_ad_url()
        print("New tunnel ready. Run 'tunnel open' to start.")

    def cmdloop(self):
        while True:
            stop = Cmd._cmdloop(self)
            if not stop:
                self.intro = ''
                self.color_prompt()
                print "^C"
            else:
                break
예제 #5
0
class PsiturkNetworkShell(PsiturkShell):
    ''' Extends PsiturkShell class to include online psiTurk.org features '''

    _cached_web_services = None
    
    @property
    def web_services(self):
        if not self._cached_web_services:
            self._cached_web_services = PsiturkOrgServices(
                self.config.get('psiTurk Access', 'psiturk_access_key_id'),
                self.config.get('psiTurk Access', 'psiturk_secret_access_id')) 
            self.amt_services_wrapper.set_web_services(self._cached_web_services)
        return self._cached_web_services
    
    def __init__(self, config, server, sandbox, quiet=False):
        self.config = config
        self.quiet = quiet
        self.amt_services_wrapper = MTurkServicesWrapper(config=config, sandbox=sandbox)        
        
        self.sandbox = sandbox
        self.tunnel = TunnelServices()
        
        self.sandbox_hits = 0
        self.live_hits = 0
        
        if not quiet:
            self.update_hit_tally()
        PsiturkShell.__init__(self, config, server, quiet)

        # Prevents running of commands by abbreviation
        self.abbrev = False
        self.debug = True
        self.help_path = os.path.join(os.path.dirname(__file__), "shell_help/")
        self.psiturk_header = 'psiTurk command help:'
        self.super_header = 'basic CMD command help:'

    def do_quit(self, _):
        '''Override do_quit for network clean up.'''
        if (self.server.is_server_running() == 'yes' or
                self.server.is_server_running() == 'maybe'):
            user_input = raw_input("Quitting shell will shut down experiment " 
                                    "server. Really quit? y or n: ")
            if user_input == 'y':
                self.server_off()
            else:
                return False
        return True

    def server_off(self):
        if (self.server.is_server_running() == 'yes' or
                self.server.is_server_running() == 'maybe'):
            self.server.shutdown()
            print 'Please wait. This could take a few seconds.'
            self.clean_up()
            while self.server.is_server_running() != 'no':
                time.sleep(0.5)
        else:
            print 'Your server is already off.'

    def server_restart(self):
        ''' Restart server '''
        self.server_off()
        self.clean_up()
        self.server_on()

    def clean_up(self):
        ''' Clean up child and orphaned processes. '''
        if self.tunnel.is_open:
            print 'Closing tunnel...'
            self.tunnel.close()
            print 'Done.'
        else:
            pass


    # +-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.
    #   basic command line functions
    # +-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.

    def get_intro_prompt(self):
        ''' Overloads intro prompt with network-aware version if you can reach
        psiTurk.org, request system status message'''
        server_msg = self.web_services.get_system_status()
        return server_msg + colorize('psiTurk version ' + version_number +
                                     '\nType "help" for more information.',
                                     'green', False)

    def color_prompt(self):  # overloads prompt with network info
        prompt = '[' + colorize('psiTurk', 'bold')
        server_string = ''
        server_status = self.server.is_server_running()
        if server_status == 'yes':
            server_string = colorize('on', 'green')
        elif server_status == 'no':
            server_string = colorize('off', 'red')
        elif server_status == 'maybe':
            server_string = colorize('status unknown', 'yellow')
        elif server_status == 'blocked':
            server_string = colorize('blocked', 'red')
        prompt += ' server:' + server_string
        if self.sandbox:
            prompt += ' mode:' + colorize('sdbx', 'bold')
        else:
            prompt += ' mode:' + colorize('live', 'bold')
        if self.tunnel.is_open:
            prompt += ' tunnel:' + colorize('✓', 'green')
        if self.sandbox:
            prompt += ' #HITs:' + str(self.sandbox_hits)
        else:
            prompt += ' #HITs:' + str(self.live_hits)
        prompt += ']$ '
        self.prompt = prompt

    def server_on(self):
        self.server.startup()
        time.sleep(0.5)

    def do_status(self, arg): # overloads do_status with AMT info
        super(PsiturkNetworkShell, self).do_status(arg)
        # server_status = self.server.is_server_running()  # Not used
        self.tally_hits()
        if self.sandbox:
            print 'AMT worker site - ' + colorize('sandbox', 'bold') + ': ' \
            + str(self.sandbox_hits) + ' HITs available'
        else:
            print 'AMT worker site - ' + colorize('live', 'bold') + ': ' \
            + str(self.live_hits) + ' HITs available'

    def update_hit_tally(self):
        ''' Tally hits '''
        if not self.quiet:            
            num_hits = self.amt_services_wrapper.tally_hits()
            if self.sandbox:
                self.sandbox_hits = num_hits
            else:
                self.live_hits = num_hits

    # +-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.
    #   hit management
    # +-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.
    def do_amt_balance(self, _):
        ''' Get MTurk balance '''
        print self.amt_services_wrapper.amt_balance()

    def help_amt_balance(self):
        ''' Get help for amt_balance. '''
        with open(self.help_path + 'amt.txt', 'r') as help_text:
            print help_text.read()

    

    @docopt_cmd
    def do_db(self, arg):
        """
        Usage:
          db get_config
          db use_local_file [<filename>]
          db use_aws_instance [<instance_id>]
          db aws_list_regions
          db aws_get_region
          db aws_set_region [<region_name>]
          db aws_list_instances
          db aws_create_instance [<instance_id> <size> <username> <password>
                                  <dbname>]
          db aws_delete_instance [<instance_id>]
          db help
        """
        if arg['get_config']:
            self.db_get_config()
        elif arg['use_local_file']:
            self.db_use_local_file(arg, filename=arg['<filename>'])
        elif arg['use_aws_instance']:
            self.db_use_aws_instance(arg['<instance_id>'], arg)
        elif arg['aws_list_regions']:
            self.db_aws_list_regions()
        elif arg['aws_get_region']:
            self.db_aws_get_region()
        elif arg['aws_set_region']:
            self.db_aws_set_region(arg['<region_name>'])
        elif arg['aws_list_instances']:
            self.db_aws_list_instances()
        elif arg['aws_create_instance']:
            self.db_create_aws_db_instance(arg['<instance_id>'], arg['<size>'],
                                           arg['<username>'],
                                           arg['<password>'], arg['<dbname>'])
        elif arg['aws_delete_instance']:
            self.db_aws_delete_instance(arg['<instance_id>'])
        else:
            self.help_db()

    db_commands = ('get_config', 'use_local_file', 'use_aws_instance',
                   'aws_list_regions', 'aws_get_region', 'aws_set_region',
                   'aws_list_instances', 'aws_create_instance',
                   'aws_delete_instance', 'help')

    def complete_db(self, text, line, begidx, endidx):
        ''' Tab-complete db command '''
        return  [i for i in PsiturkNetworkShell.db_commands if \
                 i.startswith(text)]

    def help_db(self):
        ''' DB help '''
        with open(self.help_path + 'db.txt', 'r') as help_text:
            print help_text.read()

    # +-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.
    #   Basic shell commands
    # +-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.
    @docopt_cmd
    def do_mode(self, arg):
        """
        Usage: mode
               mode <which>
        """
        restart_server = False
        if self.server.is_server_running() == 'yes' or self.server.is_server_running() == 'maybe':
            r = raw_input("Switching modes requires the server to restart. Really "
                          "switch modes? y or n: ")
            if r != 'y':
                return
            restart_server = True
        if arg['<which>'] is None:
            if self.sandbox:
                arg['<which>'] = 'live'
            else:
                arg['<which>'] = 'sandbox'
        if arg['<which>'] == 'live':
            self.set_sandbox(False)
            self.update_hit_tally()
            print 'Entered %s mode' % colorize('live', 'bold')
        else:
            self.set_sandbox(True)
            self.update_hit_tally()
            print 'Entered %s mode' % colorize('sandbox', 'bold')
        if restart_server:
            self.server_restart()
    def help_mode(self):
        ''' Help '''
        with open(self.help_path + 'mode.txt', 'r') as help_text:
            print help_text.read()
    
    def set_sandbox(self, is_sandbox):
        self.sandbox = is_sandbox
        self.amt_services_wrapper.set_sandbox(is_sandbox)
            
    @docopt_cmd
    def do_tunnel(self, arg):
        """
        Usage: tunnel open
               tunnel change
               tunnel status
        """
        if arg['open']:
            self.tunnel_open()
        elif arg['change']:
            self.tunnel_change()
        elif arg['status']:
            self.tunnel_status()

    # def help_tunnel(self):
    #     with open(self.help_path + 'tunnel.txt', 'r') as helpText:
    #         print helpText.read()

    @docopt_cmd
    def do_hit(self, arg):
        """
        Usage:
          hit create [<numWorkers> <reward> <duration>]
          hit extend <HITid> [(--assignments <number>)] [(--expiration <minutes>)]
          hit expire (--all | <HITid> ...)
          hit dispose (--all | <HITid> ...)
          hit list [--active | --reviewable] [--all-studies]
          hit help
        """

        if arg['create']:
            self.hit_create(arg['<numWorkers>'], arg['<reward>'],
                            arg['<duration>'])
            self.update_hit_tally()
        elif arg['extend']:
            self.amt_services_wrapper.hit_extend(arg['<HITid>'], arg['<number>'], arg['<minutes>'])
        elif arg['expire']:
            self.amt_services_wrapper.hit_expire(arg['--all'], arg['<HITid>'])
            self.update_hit_tally()
        elif arg['dispose']:
            self.amt_services_wrapper.hit_dispose(arg['--all'], arg['<HITid>'])
            self.update_hit_tally()
        elif arg['list']:
            self.hit_list(arg['--active'], arg['--reviewable'], arg['--all-studies'])
        else:
            self.help_hit()

    hit_commands = ('create', 'extend', 'expire', 'dispose', 'list')

    def complete_hit(self, text, line, begidx, endidx):
        ''' Tab-complete hit command. '''
        return  [i for i in PsiturkNetworkShell.hit_commands if \
                 i.startswith(text)]

    def help_hit(self):
        ''' HIT help '''
        with open(self.help_path + 'hit.txt', 'r') as help_text:
            print help_text.read()


    @docopt_cmd
    def do_worker(self, arg):
        """
        Usage:
          worker approve (--all | --hit <hit_id> ... | <assignment_id> ...) [--all-studies] [--force]
          worker reject (--hit <hit_id> | <assignment_id> ...)
          worker unreject (--hit <hit_id> | <assignment_id> ...)
          worker bonus  (--amount <amount> | --auto) (--hit <hit_id> | <assignment_id> ...)
          worker list [--submitted | --approved | --rejected] [(--hit <hit_id>)] [--all-studies]
          worker help
        """
        if arg['approve']:
            self.worker_approve(arg['--all'], arg['<hit_id>'], arg['<assignment_id>'], arg['--all-studies'], arg['--force'])
        elif arg['reject']:
            self.amt_services_wrapper.worker_reject(arg['<hit_id>'], arg['<assignment_id>'])
        elif arg['unreject']:
            self.amt_services_wrapper.worker_unreject(arg['<hit_id>'], arg['<assignment_id>'])
        elif arg['list']:
            self.worker_list(arg['--submitted'], arg['--approved'], arg['--rejected'], arg['<hit_id>'], arg['--all-studies'])
        elif arg['bonus']:
            self.amt_services_wrapper.worker_bonus(arg['<hit_id>'], arg['--auto'], arg['<amount>'], '',
                              arg['<assignment_id>'])
        else:
            self.help_worker()

    worker_commands = ('approve', 'reject', 'unreject', 'bonus', 'list', 'help')

    def complete_worker(self, text, line, begidx, endidx):
        ''' Tab-complete worker command. '''
        return  [i for i in PsiturkNetworkShell.worker_commands if \
                 i.startswith(text)]

    def help_worker(self):
        ''' Help for worker command. '''
        with open(self.help_path + 'worker.txt', 'r') as help_text:
            print help_text.read()

    @docopt_cmd
    def do_debug(self, arg):
        """
        Usage: debug [options]

        -p, --print-only        just provides the URL, doesn't attempt to
                                launch browser
        """
        revproxy_url = False
        if self.config.has_option('Server Parameters','adserver_revproxy_host'):
            if self.config.has_option( 'Server Parameters', 'adserver_revproxy_port'):
                port = self.config.get( 'Server Parameters', 'adserver_revproxy_port')
            else:
                port = 80
            revproxy_url = "http://{}:{}/ad".format(self.config.get('Server Parameters', 
                                                                    'adserver_revproxy_host'),
                                                    port)

        if revproxy_url:
            base_url = revproxy_url
        elif 'OPENSHIFT_SECRET_TOKEN' in os.environ:
            base_url = "http://" + self.config.get('Server Parameters', 'host') + "/ad"
        else:
            if arg['--print-only']:
                my_ip = get_my_ip()
                base_url = "http://" + my_ip + ":" + \
                    self.config.get('Server Parameters', 'port') + "/ad"
            else:
                base_url = "http://" + self.config.get('Server Parameters',
                                                   'host') + \
                ":" + self.config.get('Server Parameters', 'port') + "/ad"


        launch_url = base_url + "?assignmentId=debug" + \
            str(self.random_id_generator()) \
            + "&hitId=debug" + str(self.random_id_generator()) \
            + "&workerId=debug" + str(self.random_id_generator() \
            + "&mode=debug")

        if arg['--print-only']:
            print("Here's your randomized debug link, feel free to request " \
                  "another:\n\t" + launch_url)

        else:
            print("Launching browser pointed at your randomized debug link, " \
                  "feel free to request another.\n\t" + launch_url)
            webbrowser.open(launch_url, new=1, autoraise=True)

    # Modified version of standard cmd help which lists psiturk commands first.
    def do_help(self, arg):
        if arg:
            try:
                func = getattr(self, 'help_' + arg)
            except AttributeError:
                try:
                    doc = getattr(self, 'do_' + arg).__doc__
                    if doc:
                        self.stdout.write("%s\n" % str(doc))
                        return
                except AttributeError:
                    pass
                self.stdout.write("%s\n" % str(self.nohelp % (arg,)))
                return
            func()
        else:
            # Modifications start here
            names = dir(PsiturkNetworkShell)
            super_names = dir(Cmd)
            new_names = [m for m in names if m not in super_names]
            help_struct = {}
            cmds_psiTurk = []
            cmds_super = []
            for name in names:
                if name[:5] == 'help_':
                    help_struct[name[5:]]=1
            names.sort()
            prevname = ''
            for name in names:
                if name[:3] == 'do_':
                    if name == prevname:
                        continue
                    prevname = name
                    cmd = name[3:]
                    if cmd in help_struct:
                        del help_struct[cmd]
                    if name in new_names:
                        cmds_psiTurk.append(cmd)
                    else:
                        cmds_super.append(cmd)
            self.stdout.write("%s\n" % str(self.doc_leader))
            self.print_topics(self.psiturk_header, cmds_psiTurk, 15, 80)
            self.print_topics(self.misc_header, help_struct.keys(), 15, 80)
            self.print_topics(self.super_header, cmds_super, 15, 80)

    # +-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.
    #   tunnel
    # +-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.+-+.

    def tunnel_open(self):
        ''' Open tunnel '''
        if (self.server.is_server_running() == 'no' or
                self.server.is_server_running() == 'maybe'):
            print("Error: Sorry, you need to have the server running to open a "
                  "tunnel.  Try 'server on' first.")
        else:
            self.tunnel.open()

    def tunnel_status(self):
        ''' Get tunnel status '''
        if self.tunnel.is_open:
            print "For tunnel status, navigate to http://127.0.0.1:4040"
            print "Hint: In OSX, you can open a terminal link using cmd + click"
        else:
            print("Sorry, you need to open a tunnel to check the status. Try" 
                  "'tunnel open' first.")

    def tunnel_change(self):
        ''' Change tunnel url '''
        print('Tearing down old tunnel if present...')
        self.tunnel.change_tunnel_ad_url()
        print("New tunnel ready. Run 'tunnel open' to start.")

    def cmdloop(self):
        while True:
            stop = Cmd._cmdloop(self) 
            if not stop:
                self.intro = ''
                self.color_prompt()
                print "^C"
            else:
                break