text: """This file and its contents are licensed under the Apache License 2.0. Please see the included NOTICE for copyright information and LICENSE for a copy of the license.
  """
  import sys
  import logging
  import socket
  import pathlib
  import os
  import io
  import json
  import getpass
  
  from colorama import init, Fore
  if sys.platform == 'win32':
      init(convert=True)
  
  # on windows there will be problems with sqlite and json1 support, so fix it
  from label_studio.core.utils.windows_sqlite_fix import windows_dll_fix
  windows_dll_fix()
  
  from django.core.management import call_command
  from django.db import IntegrityError
  from django.core.wsgi import get_wsgi_application
  from django.db.migrations.executor import MigrationExecutor
  from django.db import connections, DEFAULT_DB_ALIAS
  
  from label_studio.core.argparser import parse_input_args
  from label_studio.core.utils.params import get_env
  
  logger = logging.getLogger(__name__)
  
  
  LS_PATH = str(pathlib.Path(__file__).parent.absolute())
  DEFAULT_USERNAME = 'default_user@localhost'
  
  
  def _setup_env():
      sys.path.insert(0, LS_PATH)
      os.environ.setdefault("DJANGO_SETTINGS_MODULE", "label_studio.core.settings.label_studio")
      application = get_wsgi_application()
  
  
  def _app_run(host, port):
      http_socket = '{}:{}'.format(host, port)
      call_command('runserver', '--noreload', http_socket)
  
  
  def is_database_synchronized(database):
      connection = connections[database]
      connection.prepare_database()
      executor = MigrationExecutor(connection)
      targets = executor.loader.graph.leaf_nodes()
      return not executor.migration_plan(targets)
  
  
  def _apply_database_migrations():
      if not is_database_synchronized(DEFAULT_DB_ALIAS):
          print('Initializing database..')
          call_command('migrate', '--no-color', verbosity=0)
  
  
  def _get_config(config_path):
      with io.open(os.path.abspath(config_path), encoding='utf-8') as c:
          config = json.load(c)
      return config
  
  
  def _create_project(title, user, label_config=None, sampling=None, description=None):
      from projects.models import Project
      from organizations.models import Organization
  
      project = Project.objects.filter(title=title).first()
      if project is not None:
          print('Project with title "{}" already exists'.format(title))
      else:
          org = Organization.objects.first()
          org.add_user(user)
          project = Project.objects.create(title=title, created_by=user, organization=org)
          print('Project with title "{}" successfully created'.format(title))
  
      if label_config is not None:
          with open(os.path.abspath(label_config)) as c:
              project.label_config = c.read()
  
      if sampling is not None:
          project.sampling = sampling
  
      if description is not None:
          project.description = description
  
      project.save()
      return project
  
  
  def _get_user_info(username):
      from users.models import User
      from users.serializers import UserSerializer
      if not username:
          username = DEFAULT_USERNAME
  
      user = User.objects.filter(email=username)
      if not user.exists():
          print({'status': 'error', 'message': f"user {username} doesn't exist"})
          return
  
      user = user.first()
      user_data = UserSerializer(user).data
      user_data['token'] = user.auth_token.key
      user_data['status'] = 'ok'
      print('=> User info:')
      print(user_data)
      return user_data
  
  
  def _create_user(input_args, config):
      from users.models import User
      from organizations.models import Organization
  
      username = input_args.username or config.get('username') or get_env('USERNAME')
      password = input_args.password or config.get('password') or get_env('PASSWORD')
      token = input_args.user_token or config.get('user_token') or get_env('USER_TOKEN')
  
      if not username:
          user = User.objects.filter(email=DEFAULT_USERNAME).first()
          if user is not None:
              if password and not user.check_password(password):
                  user.set_password(password)
                  user.save()
                  print(f'User {DEFAULT_USERNAME} password changed')
              return user
          print(f'Please enter default user email, or press Enter to use {DEFAULT_USERNAME}')
          username = input('Email: ')
          if not username:
              username = DEFAULT_USERNAME
      if not password:
          password = getpass.getpass(f'Default user password {DEFAULT_USERNAME}: ')
  
      try:
          user = User.objects.create_user(email=username, password=password)
          user.is_staff = True
          user.is_superuser = True
          user.save()
  
          if token and len(token) > 5:
              from rest_framework.authtoken.models import Token
              Token.objects.filter(key=user.auth_token.key).update(key=token)
          else:
              print(f"Token {token} is not applied to user {DEFAULT_USERNAME} "
                    f"because it's empty or len(token) < 5")
  
      except IntegrityError:
          print('User {} already exists'.format(username))
  
      user = User.objects.get(email=username)
      org = Organization.objects.first()
      if not org:
          Organization.create_organization(created_by=user, title='Label Studio')
      else:
          org.add_user(user)
  
      return user
  
  
  def _init(input_args, config):
      if not _project_exists(input_args.project_name):
          from projects.models import Project
          sampling_map = {'sequential': Project.SEQUENCE, 'uniform': Project.UNIFORM,
                          'prediction-score-min': Project.UNCERTAINTY}
          user = _create_user(input_args, config)
          _create_project(
              title=input_args.project_name,
              user=user,
              label_config=input_args.label_config,
              description=input_args.project_desc,
              sampling=sampling_map.get(input_args.sampling, 'sequential')
          )
      else:
          print('Project "{0}" already exists'.format(input_args.project_name))
  
  
  def _reset_password(input_args):
      from users.models import User
  
      username = input_args.username
      if not username:
          username = input('Username: ')
  
      user = User.objects.filter(email=username).first()
      if user is None:
          print('User with username {} not found'.format(username))
          return
  
      password = input_args.password
      if not password:
          password = getpass.getpass('New password:')
  
      if not password:
          print('Can not set empty password')
          return
  
      if user.check_password(password):
          print('Entered password is the same as current')
          return
  
      user.set_password(password)
      user.save()
      print('Password successfully changed')
  
  
  def check_port_in_use(host, port):
      logger.info('Checking if host & port is available :: ' + str(host) + ':' + str(port))
      host = host.replace('https://', '').replace('http://', '')
      with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
          return s.connect_ex((host, port)) == 0
  
  
  def _get_free_port(port, debug):
      # check port is busy
      if not debug:
          original_port = port
          # try up to 1000 new ports
          while check_port_in_use('localhost', port):
              old_port = port
              port = int(port) + 1
              if port - original_port >= 1000:
                  raise ConnectionError(
                      '\n*** WARNING! ***\n Could not find an available port\n'
                      + ' to launch label studio. \n Last tested port was '
                      + str(port)
                      + '\n****************\n'
                  )
              print(
                  '\n*** WARNING! ***\n* Port '
                  + str(old_port)
                  + ' is in use.\n'
                  + '* Trying to start at '
                  + str(port)
                  + '\n****************\n'
              )
      return port
  
  
  def _project_exists(project_name):
      from projects.models import Project
  
      return Project.objects.filter(title=project_name).exists()
  
  
  def main():
      input_args = parse_input_args()
  
      # setup logging level
      if input_args.log_level:
          os.environ.setdefault("LOG_LEVEL", input_args.log_level)
  
      if input_args.database:
          database_path = pathlib.Path(input_args.database)
          os.environ.setdefault("DATABASE_NAME", str(database_path.absolute()))
  
      if input_args.data_dir:
          data_dir_path = pathlib.Path(input_args.data_dir)
          os.environ.setdefault("LABEL_STUDIO_BASE_DATA_DIR", str(data_dir_path.absolute()))
  
      config = _get_config(input_args.config_path)
  
      # set host name
      host = input_args.host or config.get('host', '')
      if not get_env('HOST'):
          os.environ.setdefault('HOST', host)  # it will be passed to settings.HOSTNAME as env var
  
      _setup_env()
      _apply_database_migrations()
  
      from label_studio.core.utils.common import collect_versions
      versions = collect_versions()
  
      if input_args.command == 'reset_password':
          _reset_password(input_args)
          return
  
      if input_args.command == 'shell':
          call_command('shell_plus')
          return
  
      # print version
      if input_args.command == 'version':
          from label_studio import __version__
          print('\nLabel Studio version:', __version__, '\n')
          print(json.dumps(versions, indent=4))
  
      # init
      elif input_args.command == 'user' or getattr(input_args, 'user', None):
          _get_user_info(input_args.username)
          return
  
      # init
      elif input_args.command == 'init' or getattr(input_args, 'init', None):
          _init(input_args, config)
  
          print('')
          print('Label Studio has been successfully initialized.')
          if input_args.command != 'start':
              print('Start the server: label-studio start ' + input_args.project_name)
              return
  
      # start with migrations from old projects, '.' project_name means 'label-studio start' without project name
      elif input_args.command == 'start' and input_args.project_name != '.':
          from label_studio.core.old_ls_migration import migrate_existing_project
          from projects.models import Project
          sampling_map = {'sequential': Project.SEQUENCE, 'uniform': Project.UNIFORM,
                          'prediction-score-min': Project.UNCERTAINTY}
  
          if not _project_exists(input_args.project_name):
              migrated = False
              project_path = pathlib.Path(input_args.project_name)
              if project_path.exists():
                  print('Project directory from previous verion of label-studio found')
                  print('Start migrating..')
                  config_path = project_path / 'config.json'
                  config = _get_config(config_path)
                  user = _create_user(input_args, config)
                  label_config_path = project_path / 'config.xml'
                  project = _create_project(
                      title=input_args.project_name,
                      user=user,
                      label_config=label_config_path,
                      sampling=sampling_map.get(config.get('sampling', 'sequential'), Project.UNIFORM),
                      description=config.get('description', ''),
                  )
                  migrate_existing_project(project_path, project, config)
                  migrated = True
  
                  print(
                      Fore.LIGHTYELLOW_EX +
                      '\n*** WARNING! ***\n'
                      + f'Project {input_args.project_name} migrated to Label Studio Database\n'
                      + "YOU DON'T NEED THIS FOLDER ANYMORE"
                      + '\n****************\n' +
                      Fore.WHITE
                  )
              if not migrated:
                  print(
                      'Project "{project_name}" not found. '
                      'Did you miss create it first with `label-studio init {project_name}` ?'.format(
                          project_name=input_args.project_name
                      )
                  )
                  return
  
      # on `start` command, launch browser if --no-browser is not specified and start label studio server
      if input_args.command == 'start' or input_args.command is None:
          from label_studio.core.utils.common import start_browser
  
          if get_env('USERNAME') and get_env('PASSWORD') or input_args.username:
              _create_user(input_args, config)
  
          # ssl not supported from now
          cert_file = input_args.cert_file or config.get('cert')
          key_file = input_args.key_file or config.get('key')
          if cert_file or key_file:
              logger.error("Label Studio doesn't support SSL web server with cert and key.\n"
                           'Use nginx or other servers for it.')
              return
  
          # internal port and internal host for server start
          internal_host = input_args.internal_host or config.get('internal_host', '0.0.0.0')
          internal_port = input_args.port or get_env('PORT') or config.get('port', 8080)
          internal_port = int(internal_port)
          internal_port = _get_free_port(internal_port, input_args.debug)
  
          # save selected port to global settings
          from django.conf import settings
          settings.INTERNAL_PORT = str(internal_port)
  
          # browser
          url = ('http://localhost:' + str(internal_port)) if not host else host
          start_browser(url, input_args.no_browser)
  
          _app_run(host=internal_host, port=internal_port)
  
  
  if __name__ == "__main__":
      sys.exit(main())
  