from __future__ import absolute_import
import builtins
import contextlib
import io
import os
import posixpath
import shutil
import subprocess
import tempfile
import time
import unittest
import random
import string

from devil.utils import cmd_helper
from telemetry.core import linux_based_interface
from telemetry import decorators
from telemetry.testing import options_for_unittests
from telemetry.util import cmd_util

import mock

class LinuxBasedInterfaceHelperMethodsTest(unittest.TestCase):

  @mock.patch.object(cmd_util, 'GetAllCmdOutput')
  @decorators.Enabled('linux', 'chromeos')
  def testGetAllCmdOutputCallsAndDecodes(self, mock_get_output):
    mock_stdout = mock.create_autospec(bytes, instance=True)
    mock_stdout.decode.return_value = 'decoded stdout'
    mock_stderr = mock.create_autospec(bytes, instance=True)
    mock_stderr.decode.return_value = 'decoded stderr'
    mock_get_output.return_value = (mock_stdout, mock_stderr)

    stdout, stderr = linux_based_interface.GetAllCmdOutput(['forward', 'me'])

    self.assertEqual(stdout, 'decoded stdout')
    self.assertEqual(stderr, 'decoded stderr')

    mock_stdout.decode.assert_called_once_with('utf-8')
    mock_stderr.decode.assert_called_once_with('utf-8')

    mock_get_output.assert_called_once_with(['forward', 'me'], None, False)

    mock_get_output.reset_mock()
    linux_based_interface.GetAllCmdOutput(['forward', 'me'],
                                          quiet=True,
                                          cwd='some/dir')
    mock_get_output.assert_called_once_with(['forward', 'me'], 'some/dir', True)

  @mock.patch.object(cmd_util, 'StartCmd')
  @decorators.Enabled('linux', 'chromeos')
  def testStartCmdForwardsArgs(self, mock_start):
    ret = mock.Mock()
    mock_start.return_value = ret

    self.assertEqual(linux_based_interface.StartCmd('cmd'), ret)

    mock_start.assert_called_once_with('cmd',
                                       cwd=None,
                                       quiet=False,
                                       stdout=None,
                                       stderr=None,
                                       env=None)

    mock_start.reset_mock()
    self.assertEqual(
        linux_based_interface.StartCmd(
            'another cmd', quiet=True, cwd='some/other/dir'), ret)
    mock_start.assert_called_once_with('another cmd', cwd='some/other/dir',
                                       quiet=True,
                                       stdout=None,
                                       stderr=None,
                                       env=None)

  @decorators.Enabled('linux', 'chromeos')
  def testUnquoteRemovesExternalQuotes(self):
    # For some reason, this use-case is supported.
    self.assertEqual(linux_based_interface._Unquote(0), 0)
    self.assertEqual(linux_based_interface._Unquote({}), {})
    self.assertEqual(linux_based_interface._Unquote([]), [])

    self.assertEqual(linux_based_interface._Unquote("'foo\""), "foo")
    self.assertEqual(linux_based_interface._Unquote('foo"""""'), "foo")
    self.assertEqual(linux_based_interface._Unquote("'''''''foo'\"'"), "foo")

    # This will even work for alternating quotes, no matter how many.
    self.assertEqual(linux_based_interface._Unquote("'\"'\"'\"foo'\"'"), "foo")

class LinuxBasedInterfaceTest(unittest.TestCase):

  def _GetLBI(self, remote=None, remote_ssh_port=None, ssh_identity=None):
    return linux_based_interface.LinuxBasedInterface(remote, remote_ssh_port,
                                                     ssh_identity)

  def _GetLocalLBI(self):
    return linux_based_interface.LinuxBasedInterface()

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @decorators.Enabled('linux', 'chromeos')
  def testLocal(self, unused_mock):
    with self._GetLocalLBI() as lbi:
      self.assertTrue(lbi.local)
      self.assertIsNone(lbi.hostname)

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @decorators.Enabled('linux', 'chromeos')
  def testLocalIsFalseIfHostname(self, unused_mock):
    with self._GetLBI(remote='some address') as lbi:
      self.assertFalse(lbi.local)
      self.assertEqual(lbi.hostname, 'some address')

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @decorators.Enabled('linux', 'chromeos')
  def testCallsOpenConnectionOnInitRemote(self, mock_open):
    with self._GetLBI(remote='address'):
      mock_open.assert_called_once_with()

  @mock.patch.object(subprocess, 'call')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'FormSSHCommandLine')
  @decorators.Enabled('linux', 'chromeos')
  def testOpenConnection(self, mock_call, mock_form_ssh):
    with self._GetLocalLBI() as lbi:
      # Check that local will return immediately.
      self.assertTrue(lbi.local)
      lbi.OpenConnection()
      self.assertEqual(mock_call.call_count, 0)
      self.assertEqual(mock_form_ssh.call_count, 0)

    mock_call.reset_mock()
    mock_form_ssh.reset_mock()

    # Test remote case calls OpenConnection on start.
    with self._GetLBI(remote='address') as lbi:
      mock_form_ssh.assert_called_once()
      mock_call.assert_called_once()

      self.assertTrue(lbi._master_connection_open)

      # Assert no duplicate calls if already open.
      lbi.OpenConnection()
      self.assertEqual(mock_form_ssh.call_count, 1)
      self.assertEqual(mock_call.call_count, 1)

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @decorators.Enabled('linux', 'chromeos')
  def testFormSSHCommandLineLocal(self, unused_mock):
    with self._GetLocalLBI() as lbi:
      self.assertEqual(
          lbi.FormSSHCommandLine(['some', 'args']), ['sh', '-c', 'some args'])

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @decorators.Enabled('linux', 'chromeos')
  def testFormSSHCommandLineRemote(self, unused_conn):
    with self._GetLBI(remote='address') as lbi:
      lbi._DEFAULT_SSH_CONNECTION_TIMEOUT = 42
      lbi._DEFAULT_SSH_COMMAND = ['fizz', 'buzz']
      lbi._ssh_args = ['-o SomeOptions', '-o ToAdd']
      lbi._ssh_control_file = 'some_file'
      lbi._ssh_port = 8222
      lbi._ssh_identity = 'foo-bar'

      result = lbi.FormSSHCommandLine(['some', 'args'])
      formed = ' '.join(result)

      # Ensure the correct components are present
      # SSH command
      self.assertIn('fizz buzz', formed)
      # Default timeout
      self.assertIn('-o ConnectTimeout=42', formed)
      # Control file (if no port-forwarding)
      self.assertIn('-S some_file', formed)
      # SSH Args.
      self.assertIn('-o SomeOptions -o ToAdd', formed)
      # Check root and SSH port
      self.assertIn('root@address', formed)
      self.assertIn('-p8222', formed)
      # SSH Identity
      self.assertIn('-i foo-bar', formed)
      # args given.
      self.assertIn('some args', formed)

      # Timeout override, extra_args, and port_forward
      result = lbi.FormSSHCommandLine(
          ['some', 'args'],
          connect_timeout=57,
          port_forward=True,
          extra_ssh_args=['additional', 'ssh', 'args'])
      formed = ' '.join(result)
      # Default timeout
      self.assertIn('-o ConnectTimeout=57', formed)
      # Control file not present if  port-forwarding
      self.assertNotIn('-S some_file', formed)
      # extra args given.
      self.assertIn('additional ssh args', formed)

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @decorators.Enabled('linux', 'chromeos')
  def testRemoveSSHWarnings(self, unused_mock):
    with self._GetLBI() as lbi:
      filter_string = ('Warning: Permanently added something to '
                       'the list of known hosts.\n\n')
      test_string = filter_string + 'Output from some command'

      self.assertEqual(
          lbi._RemoveSSHWarnings(test_string), 'Output from some command')

      test_string = filter_string.replace(
          'something', 'another address with whitespace') + 'foo'
      self.assertEqual(lbi._RemoveSSHWarnings(test_string), 'foo')

      # Does not remove.
      test_string = filter_string.replace('something to', 'something') + 'foo'
      self.assertEqual(lbi._RemoveSSHWarnings(test_string), test_string)

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'FormSSHCommandLine')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     '_RemoveSSHWarnings')
  @mock.patch.object(linux_based_interface, 'GetAllCmdOutput')
  @decorators.Enabled('linux', 'chromeos')
  def testRunCmdOnDeviceUsesArgsCorrectly(self, mock_get_output,
                                          mock_remove_warnings, mock_form_ssh,
                                          unused_mock):
    with self._GetLBI() as lbi:
      mock_form_ssh.return_value = ['some', 'args']
      mock_get_output.return_value = ('stdout', 'stderr')
      mock_remove_warnings.return_value = 'filtered stderr'

      stdout, stderr = lbi.RunCmdOnDevice(['additional', 'args'],
                                          cwd='/some/dir',
                                          quiet=True,
                                          connect_timeout=57,
                                          port_forward=True)
      self.assertEqual(stdout, 'stdout')
      self.assertEqual(stderr, 'filtered stderr')

      mock_form_ssh.assert_called_once_with(['additional', 'args'],
                                            connect_timeout=57,
                                            port_forward=True,
                                            env=None)
      mock_get_output.assert_called_once_with(['some', 'args'],
                                              cwd='/some/dir',
                                              quiet=True)
      mock_remove_warnings.asset_called_once_with('stderr')

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'RunCmdOnDevice')
  @decorators.Enabled('linux', 'chromeos')
  def testTryLoginRunsEcho(self, mock_run_cmd, unused_mock):
    with self._GetLBI(remote='address') as lbi:
      lbi._REMOTE_USER = 'foo_user'
      mock_run_cmd.return_value = ('foo_user\n', '')
      lbi.TryLogin()

      mock_run_cmd.assert_called_once_with(['echo', '$USER'],
                                           quiet=mock.ANY,
                                           connect_timeout=mock.ANY)

      mock_run_cmd.return_value = 'bad user', ''
      self.assertRaises(linux_based_interface.LoginException, lbi.TryLogin)

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'RunCmdOnDevice')
  @decorators.Enabled('linux', 'chromeos')
  def testTryLoginErrors(self, mock_run_cmd, unused_mock):
    with self._GetLBI(remote='address') as lbi:
      mock_run_cmd.return_value = ('', 'random error')

      self.assertRaisesRegex(linux_based_interface.LoginException,
                             'logging into address, got random error',
                             lbi.TryLogin)

      mock_run_cmd.return_value = ('', lbi._HOST_KEY_ERROR)
      self.assertRaisesRegex(linux_based_interface.LoginException,
                             'address host key verification failed',
                             lbi.TryLogin)
      mock_run_cmd.return_value = ('', lbi._TIMEOUT_ERROR)
      self.assertRaisesRegex(linux_based_interface.LoginException,
                             '[tT]imed out', lbi.TryLogin)
      mock_run_cmd.return_value = ('', lbi._PRIV_KEY_PROTECTIONS_ERROR)
      self.assertRaisesRegex(linux_based_interface.LoginException,
                             '[pP]ermissions.*are too open', lbi.TryLogin)
      mock_run_cmd.return_value = ('', lbi._SSH_AUTH_ERROR)
      self.assertRaisesRegex(linux_based_interface.LoginException,
                             '[nN]eed to set up ssh auth', lbi.TryLogin)
      mock_run_cmd.return_value = ('', lbi._HOSTNAME_RESOLUTION_ERROR)
      self.assertRaisesRegex(linux_based_interface.DNSFailureException,
                             '[uU]nable to resolve the hostname for: address',
                             lbi.TryLogin)

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'RunCmdOnDevice', return_value=('',''))
  @decorators.Enabled('linux', 'chromeos')
  def testTestFileAssertAnExistenceCondition(self, unused_mock_run,
                                             unused_mock):
    with self._GetLBI(remote='address') as lbi:
      self.assertRaises(AssertionError, lbi.TestFile, 'foo')
      self.assertRaises(AssertionError, lbi.TestFile, 'foo',
                        is_file=True, is_dir=True)

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'RunCmdOnDevice', return_value=('', 'stderr'))
  @decorators.Enabled('linux', 'chromeos')
  def testTestFileThrowsErrorOnFailure(self, unused_mock_run, unused_mock):
    with self._GetLBI(remote='address') as lbi:
      self.assertRaises(OSError, lbi.TestFile, 'foo', exists=True)

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'RunCmdOnDevice')
  def testTestFileChecksResultCorrectly(self, mock_run, unused_mock):
    with self._GetLBI(remote='address') as lbi:
      mock_run.return_value = '1\n', ''
      self.assertTrue(lbi.TestFile('foo', exists=True))

      mock_run.return_value = 'Not 1\n', ''
      self.assertFalse(lbi.TestFile('foo', exists=True))

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'RunCmdOnDevice')
  @decorators.Enabled('linux', 'chromeos')
  def testTestFileUsesCorrectConditions(self, mock_run, unused_mock):
    with self._GetLBI(remote='address') as lbi:
      mock_run.return_value = '1\n', ''
      self.assertTrue(lbi.TestFile('foo', exists=True))

      mock_run.assert_called_once_with(
          'if test -e foo ; then echo 1 ; fi'.split())
      mock_run.reset_mock()

      self.assertTrue(lbi.TestFile('foo', is_file=True))
      mock_run.assert_called_once_with(
          'if test -f foo ; then echo 1 ; fi'.split())
      mock_run.reset_mock()

      self.assertTrue(lbi.TestFile('foo', is_dir=True))
      mock_run.assert_called_once_with(
          'if test -d foo ; then echo 1 ; fi'.split())

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'RunCmdOnDevice')
  @decorators.Enabled('linux', 'chromeos')
  def testFileExistsOnDevice(self, mock_run_cmd, unused_mock):
    with self._GetLBI(remote='address') as lbi:
      mock_run_cmd.return_value = ('1\n', '')
      self.assertTrue(lbi.FileExistsOnDevice('foo'))

      # Check that file existence is called.
      self.assertIn('test -e foo', ' '.join(mock_run_cmd.call_args[0][0]))

      # Check bad stdout returns False.
      mock_run_cmd.return_value = ('', '')
      self.assertFalse(lbi.FileExistsOnDevice('foo'))

      # Check that errors are raised if stderr.
      mock_run_cmd.return_value = ('1\n', 'some stderr boohoo')
      self.assertRaisesRegex(OSError, '[uU]nexpected error: some stderr boohoo',
                             lbi.FileExistsOnDevice, 'foo')

      # Specific failure case.
      mock_run_cmd.return_value = ('1\n', 'Connection timed out')
      self.assertRaisesRegex(OSError, 'wasn\'t responding to ssh',
                             lbi.FileExistsOnDevice, 'foo')

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @mock.patch.object(linux_based_interface, 'GetAllCmdOutput')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     '_FormSCPToRemote')
  @mock.patch.object(os.path, 'exists', return_value=True)
  @decorators.Enabled('linux', 'chromeos')
  def testPushFileLocal(self, unused_mock_exists, mock_form_scp, mock_run_cmd,
                        unused_mock):
    with self._GetLocalLBI() as lbi:
      self.assertTrue(lbi.local)
      mock_run_cmd.return_value = ('no error but who cares about stdout', '')

      lbi.PushFile('foo', 'remote_foo')

      self.assertRegex(' '.join(mock_run_cmd.call_args[0][0]),
                       r'cp.*foo\sremote_foo')
      self.assertEqual(mock_form_scp.call_count, 0)

      mock_run_cmd.return_value = ('error in stderr!', 'stderr')

      self.assertRaises(OSError, lbi.PushFile, 'foo', 'remote_foo')

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @mock.patch.object(linux_based_interface, 'GetAllCmdOutput')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     '_FormSCPToRemote')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     '_RemoveSSHWarnings')
  @mock.patch.object(os.path, 'abspath')
  @mock.patch.object(os.path, 'exists')
  @decorators.Enabled('linux', 'chromeos')
  def testPushFileRemote(self, mock_exists,
                         mock_abspath, mock_ssh_warnings, mock_form_scp,
                         mock_run_cmd, unused_mock):
    mock_exists.side_effect = [
        False,  # To ignore ssh_control_file check
        True, True]
    with self._GetLBI(remote='address') as lbi:
      self.assertFalse(lbi.local)
      mock_run_cmd.return_value = ('stdout do not care',
                                   'stderr but will get filtered')
      mock_abspath.return_value = '/some/abs/path/to/foo'
      mock_form_scp.return_value = 'the scp cmd'.split(' ')
      mock_ssh_warnings.return_value = ''

      lbi.PushFile('foo', 'remote_foo')

      # abspath is called in ctor
      mock_abspath.assert_has_calls([mock.call('foo')])
      mock_form_scp.assert_called_once_with(
          '/some/abs/path/to/foo', 'remote_foo', extra_scp_args=mock.ANY,
      user='root')
      mock_run_cmd.assert_called_once_with(
          'the scp cmd'.split(' '), quiet=mock.ANY)
      mock_ssh_warnings.assert_called_once_with('stderr but will get filtered')

      mock_ssh_warnings.return_value = 'error in stderr!'

      self.assertRaises(OSError, lbi.PushFile, 'foo', 'remote_foo')

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface, 'PushFile')
  @mock.patch.object(tempfile, 'NamedTemporaryFile')
  @decorators.Enabled('linux', 'chromeos')
  def testPushContents(self, mock_tempfile, mock_push_file, unused_mock):
    with self._GetLocalLBI() as lbi:

      class NamedStringIO(io.StringIO):

        def __init__(self, name):
          super().__init__()
          self.name = name

      output = NamedStringIO(name='the_temp_file_name')

      mock_tempfile.return_value.__enter__.return_value = output

      lbi.PushContents('foo contents', 'remote_file')
      # assert writeable.
      self.assertIn('w', mock_tempfile.call_args[1]['mode'])
      self.assertEqual(output.getvalue(), 'foo contents')
      mock_push_file.assert_called_once_with(output.name, 'remote_file')

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     '_FormSCPFromRemote')
  @mock.patch.object(linux_based_interface, 'GetAllCmdOutput')
  @mock.patch.object(os.path, 'abspath')
  @mock.patch.object(shutil, 'copyfile')
  @decorators.Enabled('linux', 'chromeos')
  def testGetFileLocal(self, mock_copyfile, mock_abspath, mock_cmd, mock_scp,
                       unused_mock):
    with self._GetLocalLBI() as lbi:
      self.assertTrue(lbi.local)
      mock_abspath.return_value = '/local/file/abspath'

      lbi.GetFile('remote/file', 'local/file')

      # Ensure there is no SCP'ing in local case.
      self.assertEqual(mock_scp.call_count, 0)
      self.assertEqual(mock_cmd.call_count, 0)

      # Verify copy is called.
      mock_abspath.assert_called_once_with('local/file')
      mock_copyfile.assert_called_once_with('remote/file',
                                            '/local/file/abspath')

      mock_copyfile.reset_mock()
      mock_abspath.reset_mock()

      mock_abspath.return_value = '/identical/file'
      # Assert raises error if identical files calling copy.
      self.assertRaises(OSError, lbi.GetFile, '/identical/file',
                        '/identical/file')

      mock_copyfile.reset_mock()
      mock_abspath.reset_mock()
      mock_abspath.return_value = '/local/file/dir'

      # Copying from one dir to local dir/relative dir should be possible.
      lbi.GetFile('/path/in/other/dir')

      # basename is used to call the abspath.
      mock_abspath.assert_called_once_with('dir')
      mock_copyfile.assert_called_once_with('/path/in/other/dir',
                                            '/local/file/dir')

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     '_FormSCPFromRemote')
  @mock.patch.object(linux_based_interface, 'GetAllCmdOutput')
  @mock.patch.object(os.path, 'abspath')
  @mock.patch.object(shutil, 'copyfile')
  @decorators.Enabled('linux', 'chromeos')
  def testGetFileRemote(self, mock_copyfile, mock_abspath, mock_cmd, mock_scp,
                        unused_mock):
    with self._GetLBI(remote='address') as lbi:
      self.assertFalse(lbi.local)
      mock_abspath.return_value = '/local/file/abspath'
      lbi._disable_strict_filenames = False
      mock_scp.return_value = 'some scp command'.split(' ')
      mock_cmd.return_value = ('no stderr', '')

      lbi.GetFile('remote/file', 'local/file')

      # Ensure there is no SCP'ing in local case.
      self.assertEqual(mock_copyfile.call_count, 0)

      mock_scp.assert_called_once_with(
          'remote/file', '/local/file/abspath', extra_scp_args=[],
          user='root')
      mock_cmd.assert_called_once_with(
          'some scp command'.split(' '), quiet=mock.ANY)

      mock_cmd.return_value = ('stderr incoming!', 'stderr')
      self.assertRaises(OSError, lbi.GetFile, 'does it matter', 'at all')

      mock_cmd.reset_mock()
      mock_scp.reset_mock()

      # Check that edge case with filename mismatch is dealt with.
      mock_cmd.side_effect = [('stderr incoming!',
                               'filename does not match request'),
                              ('stderr works!', '')]
      mock_scp.side_effect = [
          'first scp command'.split(' '), 'second scp command'.split(' ')
      ]

      self.assertFalse(lbi._disable_strict_filenames)
      lbi.GetFile('remote/file', 'local/file')
      self.assertTrue(lbi._disable_strict_filenames)

      mock_scp.assert_has_calls([
          mock.call('remote/file', '/local/file/abspath', extra_scp_args=[],
                    user='root'),
          mock.call(
              'remote/file', '/local/file/abspath', extra_scp_args=['-T'],
          user='root')
      ])
      mock_cmd.assert_has_calls([
          mock.call('first scp command'.split(' '), quiet=mock.ANY),
          mock.call('second scp command'.split(' '), quiet=mock.ANY),
      ])

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface, 'GetFile')
  @mock.patch.object(tempfile, 'NamedTemporaryFile')
  @mock.patch.object(builtins, 'open')
  @decorators.Enabled('linux', 'chromeos')
  def testGetFileContents(self, mock_open, mock_named_temp, mock_getfile,
                          unused_mock):
    with self._GetLBI(remote='address') as lbi:
      some_mock = mock.Mock()
      some_mock.name = 'foo'
      mock_named_temp.return_value.__enter__.return_value = some_mock

      fake_file = io.StringIO('these are file contents')

      mock_open.return_value.__enter__.return_value = fake_file

      self.assertEqual(
          lbi.GetFileContents('path/to/some/file'), 'these are file contents')

      # Check that we got a temp file created
      mock_named_temp.assert_called_once_with(mode='w')
      mock_getfile.assert_called_once_with('path/to/some/file', 'foo')
      # Check that it was opened for reading.
      mock_open.assert_called_once_with('foo', 'r', encoding=mock.ANY)

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'RunCmdOnDevice')
  @mock.patch.object(time, 'time')
  @decorators.Enabled('linux', 'chromeos')
  def testGetDeviceHostClockOffset(self, mock_time, mock_run_cmd, unused_mock):
    with self._GetLocalLBI() as lbi:
      self.assertIsNone(lbi._device_host_clock_offset)
      # Device time. Expects string.
      mock_run_cmd.return_value = '1053', 'ignored stderr'

      # Host time.
      mock_time.return_value = 1000

      self.assertEqual(lbi.GetDeviceHostClockOffset(), 53)

      # Offset is now cached.
      self.assertEqual(lbi._device_host_clock_offset, 53)

      # Offset cannot be updated. If it did, the offset would be 0.
      mock_time.return_value = 1053
      self.assertEqual(lbi.GetDeviceHostClockOffset(), 53)

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'RunCmdOnDevice')
  @decorators.Enabled('linux', 'chromeos')
  def testHasSystemD(self, mock_cmd, unused_mock):
    with self._GetLocalLBI() as lbi:
      mock_cmd.return_value = 'ignored', ''

      self.assertTrue(lbi.HasSystemd())

      mock_cmd.assert_called_once_with(['systemctl'], quiet=mock.ANY)

      mock_cmd.reset_mock()
      mock_cmd.return_value = 'ignored', 'some error'

      self.assertFalse(lbi.HasSystemd())

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'RunCmdOnDevice')
  @decorators.Enabled('linux', 'chromeos')
  def testListProcesses(self, mock_cmd, unused_mock):
    ps_output = """
    1       0 /sbin/init splash               S
    2       0 [kthreadd]                      S
    3       2 [rcu_gp]                        I
    4       2 [rcu_par_gp]                    I
    5       2 [netns]                         I
    7       2 [kworker/0:0H-events_highpri]   I
"""
    expected_procs_parsed = [
        (1, '/sbin/init splash', 0, 'S'),
        (2, '[kthreadd]', 0, 'S'),
        (3, '[rcu_gp]', 2, 'I'),
        (4, '[rcu_par_gp]', 2, 'I'),
        (5, '[netns]', 2, 'I'),
        (7, '[kworker/0:0H-events_highpri]', 2, 'I'),
    ]
    with self._GetLocalLBI() as lbi:
      mock_cmd.return_value = ps_output, ''

      self.assertEqual(lbi.ListProcesses(), expected_procs_parsed)
      self.assertIn('/bin/ps', mock_cmd.call_args[0][0])

      mock_cmd.return_value = ps_output, 'stderr'
      self.assertRaises(AssertionError, lbi.ListProcesses)

      mock_cmd.return_value = ps_output + '\nThis line will cause issues', ''
      self.assertRaises(AssertionError, lbi.ListProcesses)

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface, 'ListProcesses')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'RunCmdOnDevice')
  @decorators.Enabled('linux', 'chromeos')
  def testKillAllMatching(self, mock_run_cmd, mock_list, unused_mock):
    with self._GetLocalLBI() as lbi:
      mock_list.return_value = [
          (0, 'some cmd', 'unused', 'unused'),
          (1, 'some other cmd', 'unused', 'unused'),
          (2, 'some new cmd', 'unused', 'unused'),
          (3, 'cmd', 'unused', 'unused'),
      ]

      removed = []
      count = 0

      def predicate_kill_every_other(cmd):
        del cmd
        nonlocal count
        if count % 2:
          count += 1
          return True
        count += 1
        return False

      predicate_kill_all = lambda a: True
      predicate_kill_none = lambda a: False

      self.assertEqual(lbi.KillAllMatching(predicate_kill_none), 0)
      self.assertEqual(mock_run_cmd.call_count, 0)

      mock_run_cmd.reset_mock()
      self.assertEqual(lbi.KillAllMatching(predicate_kill_all), 4)
      mock_run_cmd.assert_called_once_with(['kill', '-KILL', '0', '1', '2',
                                            '3'],
                                           quiet=mock.ANY)

      mock_run_cmd.reset_mock()
      num_kills = lbi.KillAllMatching(predicate_kill_every_other)
      removed = ['1', '3']
      self.assertEqual(num_kills, len(removed))
      mock_run_cmd.assert_called_once_with(
          ['kill', '-KILL'] + removed, quiet=mock.ANY)

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'RunCmdOnDevice')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface, 'HasSystemd')
  @decorators.Enabled('linux', 'chromeos')
  def testIsServiceRunning(self, mock_systemd, mock_cmd, unused_mock):
    with self._GetLocalLBI() as lbi:
      # Test default case.
      mock_systemd.return_value = False

      self.assertRaisesRegex(AssertionError, 'system does not have systemd',
                             lbi.IsServiceRunning, 'foo-service')

      mock_systemd.assert_called_once_with()
      self.assertEqual(mock_cmd.call_count, 0)
      mock_systemd.reset_mock()

      # Test stderr from cmd will throw error.
      mock_systemd.return_value = True
      mock_cmd.return_value = 'MainPID=0', 'some stderr'
      self.assertRaisesRegex(AssertionError, 'some stderr',
                             lbi.IsServiceRunning, 'foo-service')
      mock_cmd.assert_called_once_with(
          ['systemctl', 'show', '-p', 'MainPID', 'foo-service'], quiet=mock.ANY)

      # Test PID=0 returns false
      mock_cmd.return_value = 'MainPID=0', ''
      self.assertFalse(lbi.IsServiceRunning('foo-service'))

      # Test PID!=0 returns True
      mock_cmd.return_value = 'MainPID=53', ''
      self.assertTrue(lbi.IsServiceRunning('foo-service'))

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'RunCmdOnDevice')
  @decorators.Enabled('linux', 'chromeos')
  def testGetRemotePort(self, mock_cmd, unused_mock):
    netstat_output = ("""Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 127.0.0.1:19080         0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.2:6697          0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:9557          0.0.0.0:*               LISTEN
""", 'ignored stderr')

    with self._GetLocalLBI() as lbi:
      lbi._reserved_ports = []
      mock_cmd.return_value = netstat_output

      # Port given will be largest port in use +1
      # This includes previously reserved ports
      self.assertEqual(lbi.GetRemotePort(), 19081)
      self.assertEqual(lbi._reserved_ports, [19081])
      mock_cmd.assert_called_once_with(['netstat', '-ant'])

      self.assertEqual(lbi.GetRemotePort(), 19082)

      lbi._reserved_ports.append(30000)
      self.assertEqual(lbi.GetRemotePort(), 30001)
      self.assertEqual(lbi._reserved_ports, [19081, 19082, 30000, 30001])

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'RunCmdOnDevice')
  @decorators.Enabled('linux', 'chromeos')
  def testIsHTTPServerRunningOnPort(self, mock_cmd, unused_mock):
    with self._GetLocalLBI() as lbi:
      mock_cmd.return_value = 'some stdout from wget', 'Connection refused'

      self.assertFalse(lbi.IsHTTPServerRunningOnPort(5000))

      # Don't care about timeout period being there.
      args = mock_cmd.call_args[0][0]
      self.assertIn('wget', args)
      self.assertIn('localhost:5000', args)

      mock_cmd.reset_mock()
      mock_cmd.return_value = ('Connection somewhere not refused',
                               'Connection NOT refused')

      self.assertTrue(lbi.IsHTTPServerRunningOnPort(8008))

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'RunCmdOnDevice')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'CanTakeScreenshot', return_value=True)
  @mock.patch.object(linux_based_interface.LinuxBasedInterface, 'GetFile')
  @decorators.Enabled('linux', 'chromeos')
  def testTakeScreenshotFailsIfBadStdout(
      self,
      unused_mock_get_file,
      unused_mock_take_screenshot,
      mock_run_cmd,
      unused_mock,
  ):
    with self._GetLocalLBI() as lbi:
      self.assertTrue(lbi.local)
      mock_run_cmd.side_effect = [
          ('making a directory', ''),
          # This line causes the failure => value!=0
          ('screenshot return value:25', ''),
          ('making a directory', ''),
          ('copying a file', ''),
      ]

      self.assertFalse(lbi.TakeScreenshot('/path/to/foo'))

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'RunCmdOnDevice')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'CanTakeScreenshot', return_value=True)
  @mock.patch.object(linux_based_interface.LinuxBasedInterface, 'GetFile')
  @decorators.Enabled('linux', 'chromeos')
  def testTakeScreenshotLocallyMakesDirectoryAndCopiesFile(
      self,
      unused_mock_get_file,
      unused_mock_can_take_screenshot,
      mock_run_cmd,
      unused_mock,
  ):
    with self._GetLocalLBI() as lbi:
      self.assertTrue(lbi.local)
      mock_run_cmd.side_effect = [
          ('making a directory', ''),
          ('screenshot return value:0', ''),
          ('making a directory', ''),
          ('copying a file', ''),
      ]

      self.assertTrue(lbi.TakeScreenshot('/path/to/foo'))

      mock_run_cmd.assert_has_calls([
          mock.call('mkdir -p /tmp/log/screenshots'.split(' ')),
          mock.call((lbi._SCREENSHOT_BINARY +
                     ' -f /tmp/log/screenshots/foo && echo').split(' ') +
                    ['screenshot return value:$?']),
          mock.call('mkdir -p /path/to'.split(' ')),
          mock.call('cp /tmp/log/screenshots/foo /path/to/foo'.split(' '))
      ])

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'RunCmdOnDevice')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'CanTakeScreenshot', return_value=True)
  @mock.patch.object(linux_based_interface.LinuxBasedInterface, 'GetFile')
  @mock.patch.object(os.path, 'exists')
  @mock.patch.object(os, 'makedirs')
  @decorators.Enabled('linux', 'chromeos')
  def testTakeScreenshotRemoteMakesDirectoryAndCopiesFile(
      self, mock_mkdirs, mock_exists, mock_get_file,
      unused_mock_take_screenshot, mock_run_cmd, unused_mock):
    for dir_exists_case in [True, False]:
      with self.subTest(dir_exists=dir_exists_case):
        mock_mkdirs.reset_mock()
        mock_get_file.reset_mock()
        mock_exists.reset_mock()
        mock_run_cmd.reset_mock()
        mock_exists.side_effect = [False, dir_exists_case]
        with self._GetLBI(remote='address') as lbi:
          self.assertFalse(lbi.local)
          mock_run_cmd.side_effect = [
              ('making a directory', ''),
              ('screenshot return value:0', ''),
          ]
          mock_exists.return_value = dir_exists_case

          self.assertTrue(lbi.TakeScreenshot('/path/to/foo'))

          mock_run_cmd.assert_has_calls([
              mock.call('mkdir -p /tmp/log/screenshots'.split(' ')),
              mock.call((lbi._SCREENSHOT_BINARY +
                         ' -f /tmp/log/screenshots/foo && echo').split(' ') +
                        ['screenshot return value:$?']),
          ])
          # Check that it created the directory if it didn't exist.
          mock_exists.assert_has_calls([mock.call('/path/to')])
          if dir_exists_case:
            mock_mkdirs.assert_not_called()
          else:
            mock_mkdirs.assert_called_once_with('/path/to')
          mock_get_file.assert_called_once_with('/tmp/log/screenshots/foo',
                                                '/path/to/foo')

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'TakeScreenshot')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'RunCmdOnDevice')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'FileExistsOnDevice')
  @decorators.Enabled('linux', 'chromeos')
  def testTakeScreenshotWithPrefixSucceeds(self, mock_file_exists, mock_run_cmd,
                                           mock_screenshot, unused_mock):
    with self._GetLocalLBI() as lbi:
      mock_file_exists.return_value = False

      self.assertTrue(lbi.TakeScreenshotWithPrefix('test-prefix'))

      screenshot_file = '/tmp/telemetry/screenshots/test-prefix-0.png'
      mock_file_exists.assert_called_once_with(screenshot_file)
      mock_screenshot.assert_called_once_with(screenshot_file)
      mock_run_cmd.assert_called_once_with(
          ['mkdir', '-p', '/tmp/telemetry/screenshots/'])

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'TakeScreenshot')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'RunCmdOnDevice')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'FileExistsOnDevice')
  @decorators.Enabled('linux', 'chromeos')
  def testTakeScreenshotWithPrefixFailsIfFull(self, mock_file_exists,
                                              mock_run_cmd, mock_screenshot,
                                              unused_mock):
    with self._GetLocalLBI() as lbi:
      # Simulate as if there were too many screenshots.
      mock_file_exists.side_effect = [True, True]

      self.assertFalse(lbi.TakeScreenshotWithPrefix('test-prefix'))

      mock_run_cmd.assert_called_once_with(
          ['mkdir', '-p', '/tmp/telemetry/screenshots/'])

      # Assert there were no screenshots - disc is "full"
      self.assertEqual(mock_screenshot.call_count, 0)

      screenshot_file = '/tmp/telemetry/screenshots/test-prefix-%d.png'
      mock_file_exists.assert_has_calls(
          [mock.call(screenshot_file % 0),
           mock.call(screenshot_file % 1)])

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'RunCmdOnDevice')
  @decorators.Enabled('linux', 'chromeos')
  def testGetArchName(self, mock_cmd, unused_mock):
    with self._GetLocalLBI() as lbi:
      mock_cmd.return_value = 'foo-arch\n', 'ignored stderr'
      self.assertEqual(lbi.GetArchName(), 'foo-arch')
      mock_cmd.assert_called_once_with(['uname', '-m'])

      # Check that its cached.
      self.assertIsNotNone(lbi._arch_name)
      mock_cmd.return_value = 'buzz-arch\n', 'ignored stderr'
      self.assertEqual(lbi.GetArchName(), 'foo-arch')
      mock_cmd.assert_called_once_with(['uname', '-m'])

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'GetFileContents')
  @decorators.Enabled('linux', 'chromeos')
  def testLsbReleaseValue(self, mock_contents, unused_mock):
    example_contents = """DISTRIB_CODENAME=buzzian
DISTRIB_DESCRIPTION="Debian GNU/Linux buzzian"
DISTRIB_ID=Debian
DISTRIB_RELEASE=buzzian
ANOTHER_PROPERTY=foobuntu
"""
    with self._GetLocalLBI() as lbi:
      mock_contents.return_value = example_contents
      self.assertEqual(
          lbi.LsbReleaseValue('DISTRIB_DESCRIPTION', 'default'),
          '"Debian GNU/Linux buzzian"')
      mock_contents.assert_called_once_with('/etc/lsb-release')
      self.assertEqual(
          lbi.LsbReleaseValue('DISTRIB_CODENAME', 'default'), 'buzzian')
      self.assertEqual(lbi.LsbReleaseValue('DISTRIB_ID', 'default'), 'Debian')
      self.assertEqual(
          lbi.LsbReleaseValue('DISTRIB_RELEASE', 'default'), 'buzzian')
      self.assertEqual(
          lbi.LsbReleaseValue('ANOTHER_PROPERTY', 'default'), 'foobuntu')
      self.assertEqual(
          lbi.LsbReleaseValue('DNE_PROPERTY', 'default'), 'default')

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'CloseConnection')
  @decorators.Enabled('linux', 'chromeos')
  def testOpenAndCloseAreCalled(self, mock_close, mock_open):
    with self._GetLBI(remote='address'):
      mock_open.assert_called_once_with()
      self.assertEqual(mock_close.call_count, 0)

    mock_open.assert_called_once_with()
    mock_close.assert_called_once_with()

  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'OpenConnection')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'RunCmdOnDevice')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'GetDeviceHostClockOffset')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'IsDir')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'FileExistsOnDevice')
  @mock.patch.object(linux_based_interface.LinuxBasedInterface,
                     'GetFile')
  @mock.patch.object(os, 'utime')
  @mock.patch.object(os.path, 'exists')
  @decorators.Enabled('linux', 'chromeos')
  def testPullDumps(
      self, mock_local_exists, mock_utime, mock_get_file, mock_file_exists,
      mock_is_dir, mock_offset, mock_cmd, unused_mock_open):
    mock_local_exists.side_effect = lambda x: 'path_exists_on_host' in x
    with self._GetLBI(remote='address') as lbi:
      # Time offset used later.
      mock_offset.return_value = 100
      mock_file_exists.side_effect = lambda x: 'bar.lock' in x
      mock_is_dir.side_effect = lambda x: 'this_will_be_a_dir' in x

      mock_cmd.side_effect = [
          ('root', ''),
          ('\n'.join((
              'foo.dat',  # Ignored extension
              'bar.lock',  # Ignored extension
              'bar',  # Ignored b/c lock exists for it.
              'this_will_be_a_dir',  # Will return True is on IsDir
              'path_exists_on_host',  # Will exist on host
              'actual_good_file_to_pull',  # Will get copied
          )), ''),
          # Additional calls for each file.
          ('-rw-r----- 1 fizz_buzz primarygroup    0 4200 __init__.py', ''),
          ('-rw-r----- 1 fizz_buzz primarygroup    0 4200 __init__.py', ''),
          ('-rw-r----- 1 fizz_buzz primarygroup    0 4200 __init__.py', ''),
          ('-rw-r----- 1 fizz_buzz primarygroup    0 4200 __init__.py', ''),
          ('-rw-r----- 1 fizz_buzz primarygroup    0 4200 __init__.py', ''),
          ('-rw-r----- 1 fizz_buzz primarygroup    0 4200 __init__.py', ''),
          ('-rw-r----- 1 fizz_buzz primarygroup    0 4200 __init__.py', ''),
      ]

      original_dir = os.path.join('tmp', 'foo', 'bar')
      lbi.PullDumps(original_dir)

      mock_get_file.assert_called_once_with(
          cmd_helper.SingleQuote(posixpath.join(lbi.MINIDUMP_DIR,
                                                'actual_good_file_to_pull')),
          os.path.join(original_dir, 'actual_good_file_to_pull'))

      mock_utime.assert_called_once_with(
          os.path.join(original_dir, 'actual_good_file_to_pull'),
          (4200-100, 4200-100))

_GLOBAL_LBI = None

class LinuxBasedInterfaceIntegrationTest(unittest.TestCase):
  """Tests linux-based interface functionality on local and remote platforms."""

  @classmethod
  def _GetLBI(cls, remote=None, remote_ssh_port=None, ssh_identity=None):
    # pylint: disable=global-statement
    global _GLOBAL_LBI
    # pylint: enable=global-statement
    if _GLOBAL_LBI:
      return _GLOBAL_LBI

    remote = remote or options_for_unittests.GetCopy().remote
    remote_ssh_port = remote_ssh_port or options_for_unittests.GetCopy(
    ).remote_ssh_port
    ssh_identity = ssh_identity or options_for_unittests.GetCopy(
    ).ssh_identity

    _GLOBAL_LBI = linux_based_interface.LinuxBasedInterface(remote,
                                                            remote_ssh_port,
                                                            ssh_identity)
    return _GLOBAL_LBI

  @classmethod
  def setUpClass(cls):
    cls.lbi = cls._GetLBI()
    cls.tmp_test_dir = None

  @classmethod
  def tearDownClass(cls):
    cls.lbi.CloseConnection()

  @decorators.Enabled('linux', 'chromeos')
  def testRunCmdRunsBasicCommands(self):
    self.assertEqual(0, linux_based_interface.RunCmd(['echo', '"Hello World"']))

    with tempfile.TemporaryDirectory() as dir_:
      tmp_file = os.path.join(dir_, 'foo')
      self.assertFalse(os.path.isfile(tmp_file))
      # File does not exist, so this should fail.
      self.assertNotEqual(0, linux_based_interface.RunCmd(['ls', tmp_file]))

      self.assertEqual(0, linux_based_interface.RunCmd(['touch', tmp_file]))
      self.assertEqual(0, linux_based_interface.RunCmd(['ls', tmp_file]))

      self.assertTrue(os.path.isfile(tmp_file))

  @decorators.Enabled('linux', 'chromeos')
  def testRunCmdRunsChangesDir(self):
    with tempfile.TemporaryDirectory() as dir_:
      tmp_file = os.path.join(dir_, 'foo')
      self.assertFalse(os.path.isfile(tmp_file))
      self.assertEqual(0, linux_based_interface.RunCmd(['touch', tmp_file]))

      # Not in the directory.
      self.assertNotEqual(0, linux_based_interface.RunCmd(['ls', 'foo']))

      # In this directory.
      self.assertEqual(0, linux_based_interface.RunCmd(['ls', 'foo'], cwd=dir_))

  @contextlib.contextmanager
  def _PopulateTmpFileWithCommands(self, commands):
    with tempfile.NamedTemporaryFile(mode='w') as tmp_file:
      tmp_file.write('\n'.join(commands))
      tmp_file.flush()
      yield tmp_file

  @decorators.Enabled('linux', 'chromeos')
  def testGetAllCmdOutputGetsStdoutAndStderr(self):
    self.assertEqual(('Hello world!\n', ''),
                     linux_based_interface.GetAllCmdOutput(
                         ['echo', 'Hello world!']))

    # Check stderr can be extracted.
    cmds = ['echo output to stdout', 'echo output to stderr >> /dev/stderr']
    with self._PopulateTmpFileWithCommands(cmds) as tmp_file:
      self.assertEqual(('output to stdout\n', 'output to stderr\n'),
                     linux_based_interface.GetAllCmdOutput(['bash',
                                                            tmp_file.name]))

  @decorators.Enabled('linux', 'chromeos')
  def testGetAllCmdOutputChangesDirectories(self):
    # Check stderr can be extracted.
    cmds = ['echo output to stdout', 'echo output to stderr >> /dev/stderr']
    with self._PopulateTmpFileWithCommands(cmds) as tmp_file:
      tmp_file_dir, tmp_file_base = os.path.split(tmp_file.name)

      self.assertNotEqual(0, ['ls', tmp_file_base])
      self.assertEqual(('output to stdout\n', 'output to stderr\n'),
                     linux_based_interface.GetAllCmdOutput(['bash',
                                                            tmp_file_base],
                                                           cwd=tmp_file_dir))

  @decorators.Enabled('linux', 'chromeos')
  def testStartCmdExecutesAsyncCommand(self):
    proc = linux_based_interface.StartCmd(['echo', 'hello world'])
    proc.wait()
    self.assertEqual(proc.poll(), 0)

    # Capture output.
    cmds = ['echo output to stdout', 'echo output to stderr >> /dev/stderr']
    with self._PopulateTmpFileWithCommands(cmds) as tmp_file:
      proc = linux_based_interface.StartCmd(
          ['bash', tmp_file.name], stdout=subprocess.PIPE,
          stderr=subprocess.PIPE)
      proc.wait()
      self.assertEqual(proc.poll(), 0)
      stdout, stderr = proc.communicate()
      self.assertEqual(stdout.decode().strip(), 'output to stdout')
      self.assertEqual(stderr.decode().strip(), 'output to stderr')

  @decorators.Enabled('linux', 'chromeos')
  def testTryLoginSucceeds(self):
    if self.lbi.local:
      raise unittest.SkipTest('Cannot run TryLogin on local DUT')
    self.assertFalse(self.lbi.local)
    self.lbi.TryLogin()

  def _exists(self, dir_):
    rc, _, _ = self.lbi.RunCmdOnDeviceWithRC(['ls', dir_])
    return rc == 0

  @decorators.Enabled('linux', 'chromeos')
  def testMkdTempWithPrefix(self):
    dir_ = self.lbi.MkdTemp(prefix='/tmp/foo_XXXXXXX')

    self.assertIn('/tmp/foo', dir_[:len('/tmp/foo')])

    self.assertTrue(self._exists(dir_))

    # Delete.
    rc, _, _ = self.lbi.RunCmdOnDeviceWithRC(['rm', '-rf', dir_])
    self.assertEqual(rc, 0)

    self.assertFalse(self._exists(dir_))

  def _createTempFile(self, file_name, touch=False):
    if not self.tmp_test_dir or not self._exists(self.tmp_test_dir):
      self.tmp_test_dir = self.lbi.MkdTemp(prefix='/tmp/test_run_XXXXXX')

    test_file = self.lbi.path.join(self.tmp_test_dir, file_name)

    if touch:
      self.lbi.RunCmdOnDevice(['touch', test_file])
      self.assertTrue(self.lbi.IsFile(test_file))
    elif self.lbi.IsFile(test_file):
      self.lbi.RmRF(test_file)

    return test_file

  @decorators.Enabled('linux', 'chromeos')
  def testPushContentsPushesContentsToFile(self):
    test_file = self._createTempFile('bar.txt')
    self.assertFalse(self._exists(test_file))

    self.lbi.PushContents('some file contents\nanother line',
                     test_file)
    self.assertTrue(self._exists(test_file))

    # Verify contents are correct.
    stdout, stderr = self.lbi.RunCmdOnDevice(['cat', test_file])
    self.assertEqual(stdout, 'some file contents\nanother line')
    self.assertEqual(stderr, '')

  @decorators.Enabled('linux', 'chromeos')
  def testPushFileFailsIfFileDoesNotExistLocally(self):
    test_file = self._createTempFile('bar.txt')
    self.assertFalse(self._exists(test_file))
    local_path = 'some/local/file.txt'
    self.assertFalse(os.path.exists(local_path))

    self.assertRaises(AssertionError, self.lbi.PushFile, local_path, test_file)

  @decorators.Enabled('linux', 'chromeos')
  def testPushFileFailsIfDestinationDoesNotExist(self):
    local_path = 'file.txt'
    with open(local_path, 'w') as f:
      f.write('hello')

    remote_path = 'fake/path/will/not/exist'

    self.assertRaises(OSError, self.lbi.PushFile, local_path,
                      remote_path)

  @decorators.Enabled('linux', 'chromeos')
  def testGetFileContentsReturnsFileContents(self):
    test_file = self._createTempFile('foo.txt')
    self.assertFalse(self._exists(test_file))
    self.lbi.PushContents('some file contents\nanother line',
                     test_file)

    contents = self.lbi.GetFileContents(test_file)
    self.assertEqual(contents, 'some file contents\nanother line')

  @decorators.Enabled('linux', 'chromeos')
  def testGetFileCopiesFileToLocalDestFile(self):
    test_file = self._createTempFile('foo.txt')
    self.lbi.PushContents('random file contents', test_file)

    with tempfile.TemporaryDirectory() as dir_:
      dest_file = os.path.join(dir_, 'foo.txt')
      self.lbi.GetFile(test_file, dest_file)

      with open(dest_file, 'r') as f:
        self.assertEqual(f.read(), 'random file contents')

  @decorators.Enabled('linux', 'chromeos')
  def testTestFileUtils(self):
    path = self._createTempFile('foo', touch=True)
    self.assertTrue(self._exists(path))

    self.assertTrue(self.lbi.TestFile(path, exists=True))
    self.assertTrue(self.lbi.FileExistsOnDevice(path))

    self.assertTrue(self.lbi.TestFile(path, is_file=True))
    self.assertTrue(self.lbi.IsFile(path))

    # Delete file.
    self.lbi.RmRF(path)
    self.assertFalse(self._exists(path))
    self.assertFalse(self.lbi.TestFile(path, exists=True))
    self.assertFalse(self.lbi.FileExistsOnDevice(path))

    self.assertFalse(self.lbi.TestFile(path, is_file=True))
    self.assertFalse(self.lbi.IsFile(path))

    dir_name = self.lbi.path.dirname(path)
    self.assertTrue(self.lbi.TestFile(dir_name, is_dir=True))
    self.assertTrue(self.lbi.IsDir(dir_name))

    # Delete dir.
    self.lbi.RmRF(dir_name)
    self.assertFalse(self._exists(dir_name))
    self.assertFalse(self.lbi.TestFile(dir_name, is_dir=True))
    self.assertFalse(self.lbi.IsDir(dir_name))

  @decorators.Enabled('linux', 'chromeos')
  def testRunCmdOnDevice(self):
    stdout, _ = self.lbi.RunCmdOnDevice(['echo', '$USER'])

    if not self.lbi.local:
      self.assertEqual(stdout.strip(), 'root')
    else:
      self.assertEqual(stdout.strip(), os.getenv('USER'))

  @decorators.Enabled('linux', 'chromeos')
  def testGetDeviceHostClockOffset(self):
    offset = self.lbi.GetDeviceHostClockOffset()
    second_offset = self.lbi.GetDeviceHostClockOffset()
    self.assertEqual(offset, second_offset)

    # Can only really tell if its offset to itself, with some margin of the
    # call being made.
    if self.lbi.local:
      self.assertAlmostEqual(offset, 0, places=1)

  @decorators.Enabled('linux', 'chromeos')
  def testRmRF(self):
    tmp_dir = self.lbi.MkdTemp(prefix='/tmp/foo_bar_XXXXXX')
    self.assertTrue(self._exists(tmp_dir))
    # Add a file to show its rm -rf'able
    self.lbi.RunCmdOnDevice(['touch', self.lbi.path.join(tmp_dir, 'foo.txt')])

    self.lbi.RmRF(tmp_dir)

    self.assertFalse(self._exists(tmp_dir))

  @decorators.Enabled('linux', 'chromeos')
  def testTakeScreenshots(self):
    if not self.lbi.CanTakeScreenshot():
      raise unittest.SkipTest('Cannot take screenshots. Skipping test')

    prefix = ''.join([random.choice(string.ascii_letters) for i in range(8)])
    temp_file = self._createTempFile(f'{prefix}.png')
    self.assertFalse(self.lbi.FileExistsOnDevice(temp_file))
    self.assertTrue(self.lbi.TakeScreenshot(temp_file))

    self.assertTrue(self.lbi.FileExistsOnDevice(temp_file))

    # Test with prefix.
    prefix = ''.join([random.choice(string.ascii_letters) for i in range(8)])

    # Cleanup if the file already exists.
    path_created = f'/tmp/telemetry/screenshots/{prefix}-0.png'
    if self.lbi.FileExistsOnDevice(path_created):
      self.lbi.RmRF(path_created)
    print('Creating screenshot file: %s'  %path_created)

    try:
      self.assertTrue(self.lbi.TakeScreenshotWithPrefix(prefix))
      self.assertTrue(self.lbi.FileExistsOnDevice(path_created))
    finally:
      self.lbi.RmRF(path_created)

  @decorators.Enabled('linux', 'chromeos')
  def testGetArchNameCalls(self):
    arch_name = self.lbi.GetArchName()
    self.assertTrue(arch_name)

  @decorators.Enabled('linux')
  def testLsbReleaseValue(self):
    # Should parse, and not fallback to default.
    codename = self.lbi.LsbReleaseValue('DISTRIB_CODENAME', 'foo')
    self.assertNotEqual(codename, 'foo')

    # Get Default value for unknown key.
    self.assertEqual('value not found', self.lbi.LsbReleaseValue(
        'FAKE KEY',
        'value not found'))

  @decorators.Enabled('linux', 'chromeos')
  def testExpandUserExpandsInPath(self):
    home, _ = self.lbi.RunCmdOnDevice(['echo', '$HOME'])
    home = home.strip()

    self.assertEqual(self.lbi.ExpandUser('~/foo/bar'), f'{home}/foo/bar')


# First On Scene Identifier tool for Camano Island Fire Department
# This tool will process a call records document and return that
# document with some columns added. These columns will show which
# units were the first on scene for that incident. There will be
# one column where string values of "yes" or "no" will dictate
# whether the unit of that row was the first on scene. Another
# column will display the unit that is first on scene, and the
# next column will display the turnout time of that unit. This
# will only do this for the row of that unit, all other rows for
# that incident will be left blank.

import pandas as pd
import numpy as np

from datetime import timedelta
from itertools import compress

try:
    header_index = 2

    # gather inputs from user
    print('We will ask you for three inputs.')
    while True:
        # read input
        path = input("Copy/ paste file path: ")
        if path == "":
            print("File path missing value, please double check filepath")
            continue

        # cleaning
        path = path.rstrip()

        path = path.replace('"', '')

        # read in file

        try:
            df = pd.read_excel(path, header = header_index)
        except:
            print("Error with file path, please double check filepath")
            continue
        break

    # process excel spreadsheet
    print("Determining First On Scene Units...")

    try:
        df = pd.read_excel(path, header = header_index)

        df = df.iloc[0:len(df) - header_index]

        # create dictionary of incident numbers with that incident's first on scene unit
        fos_units = {}

        def arrival_rank(incident_number, apparatus):
            try:
                ordered_list = list(df[df['Incident Number'] == incident_number].sort_values(by = ['Arrival Date'])['Apparatus Name'].values)
                return int(ordered_list.index(apparatus) + 1)
            except:
                return None

        df['Rank of Arrival'] = [arrival_rank(df.loc[i, 'Incident Number'], df.loc[i, 'Apparatus Name']) for i in df.index]

        df['Number Apparatuses Involved'] = [len(df[df['Incident Number'] == df.loc[i, 'Incident Number']]) for i in df.index]

        for i in df["Incident Number"]:
            time_list = list(df[df['Incident Number'] == i]['Arrival Date'])
            bool_list = [not b for b in list(pd.isnull(time_list))]
            time_list = list(compress(time_list, bool_list))
            try:
                min_time = min(time_list)
            except:
                min_time = None
            unit = df[(df['Arrival Date'] == min_time) & (df['Incident Number'] == i)]['Apparatus Name'].to_numpy()
            fos_units[i] = unit

        print("Processing Document...")

        filler = [None for i in df.index]

        df['Turn Out (seconds)'] = filler
        df['Response Time (seconds)'] = filler
        df['Travel Time (seconds)'] = filler

        df['FOS unit'] = filler
        df['FOS Turn Out (seconds)'] = filler
        df['FOS Response Time (seconds)'] = filler
        df['FOS Travel Time (seconds)'] = filler
        df['Is FOS'] = filler
        df['Incident Turn Out Goal Met'] = filler

        goal = 9 * 60 + 30

        for i in df.index:
            inum = df.loc[i, 'Incident Number']
            try:
                df['Turn Out (seconds)'] = [pd.Timedelta((df.loc[i, 'En Route Date']- df.loc[i, 'Dispatched Date'])).seconds for i in df.index]
                df['Response Time (seconds)'] = [pd.Timedelta((df.loc[i, 'Arrival Date'] - df.loc[i, 'Dispatched Date'])).seconds for i in df.index]
                df['Travel Time (seconds)'] = [pd.Timedelta((df.loc[i, 'Arrival Date'] - df.loc[i, 'En Route Date'])).seconds for i in df.index]

                fos = fos_units[inum][0]
                df_slice = df[(df['Incident Number'] == inum) & (df['Apparatus Name'] == fos)]

                if df.loc[i, 'Apparatus Name'] == fos:
                    df.loc[i, 'FOS unit'] = fos
                    df.loc[i, 'FOS Turn Out (seconds)'] = df_slice['Turn Out (seconds)'].to_numpy()[0]
                    df.loc[i, 'FOS Response Time (seconds)'] = df_slice['Response Time (seconds)'].to_numpy()[0]
                    df.loc[i, 'FOS Travel Time (seconds)'] = df_slice['Travel Time (seconds)'].to_numpy()[0]
                    df.loc[i, 'Is FOS'] = 'YES'
                    if df.loc[i, 'FOS Response Time (seconds)'] <= goal:
                        df.loc[i, 'Incident Turn Out Goal Met'] = 'YES'
                    else:
                        df.loc[i, 'Incident Turn Out Goal Met'] = 'NO'
                else:
                    df.loc[i, 'Is FOS'] = 'NO'
            except:
                pass
    except Exception as e:
        print(e)

    while True:
        file_name = input("What would you like the file called? ")
        if file_name == "":
            print("File name empty, please enter a value.")
            continue

        destination = input("Where would you like the file to go? ")
        if destination == "":
            print("File path missing value, please double check destination filepath and re-enter file name and destination filepath")
            continue

        # cleaning

        destination = destination.rstrip()

        destination = destination.replace('"', '')

        if not destination.endswith("\\"):
            destination = destination + "\\"

        file_name = file_name.rstrip()

        if file_name.endswith(".xls"):
            file_name.remove(".xls")

        if ".xlsx" not in file_name:
            file_name = file_name + ".xlsx"

        try:
            df.to_excel(f"{destination + file_name}")
        except Exception as e:
            print(e)
            print("An error has occurred. Please re-enter the folder destination and file name.")
            continue

        break

    name = (f'{destination + file_name}')

    writer = pd.ExcelWriter(f'{name}', engine = 'xlsxwriter')

    df.to_excel(writer, index = False)

    writer.save()

    print("Done!")
except Exception as e:
    print(e)


import os
import traceback

from qgis.PyQt.QtCore import (
    QAbstractListModel,
    Qt
)
from qgis.PyQt.QtWidgets import (
    QTreeView
)

class FramesModel(QAbstractListModel):

    def __init__(self, tb, parent=None):
        QAbstractListModel.__init__(self, parent)
        if isinstance(tb, list):
            self.tb = None
            self.entries = tb
        else:
            self.tb = tb
            self.entries = traceback.extract_tb(tb)

    def rowCount(self, parent):
        return len(self.entries)

    def data(self, index, role):
        if not index.isValid():
            return

        if role == Qt.DisplayRole:
            entry = self.entries[index.row()]
            return "%s [%s:%d]" % (entry[2], os.path.basename(entry[0]), entry[1])
        elif role == Qt.ToolTipRole:
            entry = self.entries[index.row()]
            return "Method: %s\n
\nLine: %d\n

\nPath:
\n%s" % (entry[2], entry[1], entry[0])

    def headerData(self, section, orientation, role):
        if section == 0 and orientation == Qt.Horizontal and role == Qt.DisplayRole:
            return "Traceback (most recent call last)"  # "Frames"

class FramesView(QTreeView):
    def __init__(self, parent=None):
        QTreeView.__init__(self, parent)
        self.setRootIsDecorated(False)

    def setTraceback(self, tb):
        self.setModel(FramesModel(tb, self))


from ..utils import DataikuException
from ..dss.managedfolder import DSSManagedFolder
import logging
import os
import sys
import tempfile
import shutil
from base64 import b64encode

class MLflowHandle:
    def __init__(self, client, project, managed_folder, host=None):
        """ Add the MLflow-plugin parts of dataikuapi to MLflow local setup.

        This method deals with
        1. importing dynamically the DSS MLflow plugin:
        MLflow uses entrypoints==0.3 to load entrypoints from plugins at import time.
        We add dss-mlflow-plugin entrypoints dynamically by adding them in sys.path
        at call time.

        2. Setup the correct environment variables to setup the plugin to work
        with DSS backend as the tracking backend and enable using DSS managed folder
        as artifact location.
        """
        self.project = project
        self.project_key = project.project_key
        self.client = client
        self.mlflow_env = {}

        # Load DSS as the plugin
        self.tempdir = tempfile.mkdtemp()
        plugin_dir = os.path.join(self.tempdir, "dss-plugin-mlflow.egg-info")
        if not os.path.isdir(plugin_dir):
            os.makedirs(plugin_dir)
        with open(os.path.join(plugin_dir, "entry_points.txt"), "w") as f:
            f.write(
                "[mlflow.request_header_provider]\n"
                "unused=dataikuapi.dss_plugin_mlflow.header_provider:PluginDSSHeaderProvider\n"
                "[mlflow.artifact_repository]\n"
                "dss-managed-folder=dataikuapi.dss_plugin_mlflow.artifact_repository:PluginDSSManagedFolderArtifactRepository\n"
            )
        sys.path.insert(0, self.tempdir)

        # Reload the artifact_repository_registry in case MLflow was imported beforehand
        if sys.version_info > (3, 4):
            from importlib import reload
        import mlflow
        reload(mlflow.store.artifact.artifact_repository_registry)
        mlflow.set_tracking_uri(None)  # if user has changed tracking backend manually before
        mlflow.end_run()  # if user already created a run with another tracking backend

        # Setup authentication
        if client._session.auth is not None:
            self.mlflow_env.update({
                "DSS_MLFLOW_HEADER": "Authorization",
                "DSS_MLFLOW_TOKEN": "Basic {}".format(
                    b64encode("{}:".format(self.client._session.auth.username).encode("utf-8")).decode("utf-8")),
                "DSS_MLFLOW_APIKEY": self.client.api_key
            })
        elif client.internal_ticket:
            self.mlflow_env.update({
                "DSS_MLFLOW_HEADER": "X-DKU-APITicket",
                "DSS_MLFLOW_TOKEN": self.client.internal_ticket,
                "DSS_MLFLOW_INTERNAL_TICKET": self.client.internal_ticket
            })

        if not client._session.verify:
            self.mlflow_env.update({"MLFLOW_TRACKING_INSECURE_TLS": "true"})
        elif isinstance(client._session.verify, str):
            self.mlflow_env.update({"MLFLOW_TRACKING_SERVER_CERT_PATH": client._session.verify})

        mf_full_id = None
        if isinstance(managed_folder, DSSManagedFolder):
            mf_full_id = managed_folder.project.project_key + "." + managed_folder.id
        elif isinstance(managed_folder, str):
            mf_full_id = managed_folder
        else:
            try:
                from dataiku import Folder
                if isinstance(managed_folder, Folder):
                    mf_full_id = managed_folder.get_id()
            except ImportError:
                pass

        if not mf_full_id:
            raise TypeError('Type of managed_folder must be "str", "DSSManagedFolder" or "dataiku.Folder".')

        if "." not in mf_full_id:
            mf_full_id = self.project_key + "." + mf_full_id

        mf_project = mf_full_id.split(".")[0]
        mf_id = mf_full_id.split(".")[1]

        try:
            client.get_project(mf_project).get_managed_folder(mf_id).get_definition()
        except DataikuException as e:
            if "NotFoundException" in str(e):
                logging.error('The managed folder "%s" does not exist, please create it in your project flow before running this command.' % (mf_full_id))
            raise

        # Set host, tracking URI, project key and managed_folder_id
        self.mlflow_env.update({
            "DSS_MLFLOW_PROJECTKEY": self.project_key,
            "MLFLOW_TRACKING_URI": self.client.host + "/dip/publicapi" if host is None else host,
            "DSS_MLFLOW_HOST": self.client.host,
            "DSS_MLFLOW_MANAGED_FOLDER_ID": mf_full_id
        })

        os.environ.update(self.mlflow_env)

    def clear(self):
        shutil.rmtree(self.tempdir)
        for variable in self.mlflow_env:
            os.environ.pop(variable, None)

    def import_mlflow(self):
        import mlflow
        return mlflow

    def __enter__(self):
        return self.import_mlflow()

    def __exit__(self, exc_type, exc_value, traceback):
        self.clear()


import dj_database_url

from .base import *
from config.settings import setup_sentry_logging

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql_psycopg2",
    }
}

DATABASES['default'] = dj_database_url.config()

INSTALLED_APPS += ('raven.contrib.django.raven_compat',)

SENTRY_DSN = os.environ['SENTRY_DSN']

# Settings for Raven (Sentry reporting service)
RAVEN_CONFIG = {
    'dsn': SENTRY_DSN,
}

setup_sentry_logging(LOGGING)


#!/usr/bin/env python

import json
import os
import csv
import atexit

from flask import Flask, request, make_response, send_from_directory, render_template, jsonify
# for reference: http://flask.pocoo.org/docs/0.11/quickstart/
import flask_excel as excel
from googleapiclient import discovery
from oauth2client.client import GoogleCredentials
from classifier import classify_comments, Model, LemmaTokenizer

# Flask app should start in global layout
app = Flask(__name__, static_url_path='')
in_memory_db = {}
message_db = {}

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/js/<path:path>')
def send_js(path):
    return send_from_directory('js', path)

def analyse_entities(comment):
    credentials = GoogleCredentials.get_application_default()
    service = discovery.build('language', 'v1', credentials=credentials)

    service_request = service.documents().analyzeEntities(
        body = {
            'document': {
                'type': 'PLAIN_TEXT',
                'content': comment,
            }
        }
    )
    response = service_request.execute()

    r = make_response(json.dumps(response, indent=4))
    r.headers['Content-Type'] = 'application/json'
    return r

def analyse_sentences(comment):
    # comment = request.args.get('comment')
    credentials = GoogleCredentials.get_application_default()
    service = discovery.build('language', 'v1', credentials=credentials)

    service_request = service.documents().analyzeSentiment(
        body = {
            'document': {
                'type': 'PLAIN_TEXT',
                'content': comment,
            }
        }
    )
    response = service_request.execute()
    response['text'] = comment

    return response

# @app.route('/classify', methods=['GET'])
# def classify():
#     data = json.loads(classify_comments('/Users/michen/Python-Projects/ZapHax0rs/server/test.csv'))
#     print(data)
#     return make_response(json.dumps(data, indent=4))

@app.route('/demo', methods=['POST'])
def upload_demo():
    print(request)
    phrase = request.form.get('demo')
    print(phrase)
    google_response = analyse_sentences(phrase)
    inhouse_response = json.loads(classify_comments(phrase))
    # print(inhouse_response['Photos']['0'])
    # print(google_response)
    google_response['photos'] = inhouse_response['Photos']['0']
    r = make_response(json.dumps(google_response, indent=4))
    r.headers['Content-Type'] = 'application/json'
    return r

@app.route('/upload', methods=['POST'])
def upload_file():
    print('hello from upload_file')
    print(request)
    print('form')
    print(request.form)
    print('array')
    arr_of_arr = request.get_array(field_name='file')
    print(arr_of_arr)

    res_arr = []
    for i in range(len(arr_of_arr)):
        print(arr_of_arr[i])
        inhouse_response = json.loads(classify_comments(arr_of_arr[i][0]))
        print(inhouse_response)
        google_response = analyse_sentences(arr_of_arr[i][0])
        google_response['photos'] = inhouse_response['Photos']['0']
        res_arr.append(google_response)
    r = make_response(json.dumps(res_arr, indent=4))
    r.headers['Content-Type'] = 'application/json'
    return r

# example stuff, can ignore

@app.route('/export', methods=['GET'])
def export_records():
    return excel.make_response_from_array([[1,2], [3, 4]], 'csv', file_name='export_data')

@app.route('/example_post', methods=['POST'])
def webhook():
    req = request.get_json(silent=True, force=True)

    print('Request:')
    print((json.dumps(req, indent=4)))

    res = { 'sample': 'text' }

    res = json.dumps(res, indent=4)

    r = make_response(res)
    r.headers['Content-Type'] = 'application/json'
    return r

@app.route('/user/<username>')
def show_user_profile(username):
    # show the user profile for that user
    return 'User %s' % username

@app.route('/post/<int:post_id>')
def show_post(post_id):
    # show the post with the given id, the id is an integer
    return 'Post %d' % post_id

def init():
    print('initializing')

@atexit.register
def goodbye():
    print('You are now leaving the Python sector.')

# end examples

# main

if __name__ == '__main__':
    port = int(os.getenv('PORT', 5000))
    print('Starting app on port %d' % port)
    init()
    app.run(debug=True, port=port, host='0.0.0.0')


import re
from Utils.StringManip import bracket_matching

# ∧∨⊃

# Determine if the input is an atomic well-formed string
def is_atom(x):
    if re.match("^~*[PQR]\'*$",x):
        return True
    return False

# Create well-formed strings
def AND(x,y):
    return f"<{x}∧{y}>"

def OR(x,y):
    return f"<{x}∨{y}>"

def IMPLIES(x,y):
    return f"<{x}⊃{y}>"

def NOT(x):
    return f"~{x}"

def left_string(x):
    braks = bracket_matching(x,"<","⊃∧∨",overlap=True,inner=True,warn=False)
    for i in braks:
        if i[1] == 1:
            return i

def split(x):
    L,lo,hi = left_string(x)
    R = x[hi+2:-1]
    return L,R

# Maybe works?
def is_well_formed(x):

    if is_atom(x):
        print(f"{x} is an atom")
        return True
    else:
        #try to split left and right and try again
        while x[0] == "~":
            x = x[1:]
        if x[0] != "<":
            print(f"{x} is invalid")
            return False

        try:
            L,lo,hi = left_string(x)
        except:
            print(f"{x} caused an error")
            return False

        R = x[hi+2:-1]

        print(f"recur on {L} and {R}")

        ltrue = is_well_formed(L)
        rtrue = is_well_formed(R)

        return ltrue and rtrue

if __name__ == '__main__':

    P = "P"
    Qp = "Q'"
    print(P)
    print(NOT(P))
    print(NOT(NOT(P)))
    print(Qp)
    print(AND(P,NOT(Qp)))
    print(split(AND("P",NOT("Q'"))))

    ss = ["<~<P∧~Q'>∨<~<~P∧R>⊃Q'>>",
          "<~<P∧~'Q>∨<~<~P∧R>⊃Q'>>",
          "<~<P∧~Q'∧R>∨<~<~P∧R>⊃Q'>>",
          "<~<P∧~Q'∧R><~<~P∧R>⊃Q'>>",
          "<<<P∧~Q'>∨<~<~P∧R>⊃Q'>>",]
    print("\n")
    for s in ss:
        print(f"\n\n{s}")
        print(is_well_formed(s))


from django.shortcuts import render, redirect

from datetime import datetime, date, timedelta
from functools import reduce
from django.utils.dateformat import DateFormat
from django.utils import timezone
from django.utils.formats import get_format
from .forms import CategoryForm, TaskForm

from .models import Task, Category

def monday(date):
    """
    Get the monday from a Date
    args:
        date (Date): Date to get monday
    return:
        Date: The monday
    """
    return date - timedelta(days=date.weekday())

def taskInfo(task):
    """
    Task info to display
    args:
        task (Task): Task to store
    return:
        Dictionary: dictionary containing the task information
    """
    df = DateFormat(task.date.astimezone(timezone.get_current_timezone()))

    htmlInfo = {
        "icon": task.category.icon,
        "color": task.category.color,
        "h": "h"+df.format("H")
    }
    tInfo = {
        "id": task.id,
        "title": task.title,
        "category": task.category.name,
        "description": task.description,
        "date": df.format("l b d Y - H:i"),
        "complete": task.complete,
        "htmlInfo": htmlInfo
    }
    return tInfo

def reduceTasks(accumulator, task):
    """
    stores the tasks in the dictionary created by createWeeks(startMonday, numWeeks)
    args:
        accumulator (Dict): Dictionary to store the task
        task (Task): Task to store
    return:
        Dictionary: Task grouped by hours, days and weeks
    """
    tInfo = taskInfo(task)
    taskDate = task.date.astimezone(timezone.get_current_timezone())
    hourInfo = DateFormat(monday(taskDate)).format("b d Y")
    hours = accumulator[hourInfo]["week"][taskDate.weekday()]["hours"]
    if tInfo["htmlInfo"]["h"] in hours:
        hours[tInfo["htmlInfo"]["h"]].append(tInfo)
    else:
        accumulator[hourInfo]["week"][taskDate.weekday()]["hours"][tInfo["htmlInfo"]["h"]] =  [tInfo]

    return accumulator

def createWeeks(startMonday, numWeeks):
    """
    create a dictionary to group days by weeks from a start date to a number of weeks
    args:
        startMonday (date): First date
        numWeeks (int): Number of weeks
    return:
        Dictionary: Days grouped by weeks
    """
    w = 0
    monday = startMonday
    weeks = {}
    while w <= numWeeks:
        name = "Semana actual" if w == 0 else "Semana " + str(w+1)
        wid =  "week" + str(w+1)
        weekInfo = {"week": {}, "name":name, "index": w, "id":wid}
        for r in range(7):
            day = (monday + timedelta(days=r))
            df = DateFormat(day)
            weekInfo["week"][r] = {"hours":{}, "weekday":r, "name":df.format("D"), "date":df.format("b/d")}

        weeks[DateFormat(monday).format("b d Y")] = weekInfo
        monday = (monday + timedelta(days=7))
        w += 1
    return weeks

def schedulerView(request):
    """ Task Scheduler View """
    data = {}
    data['hours'] = map(lambda x: {'h': x if x > 9 else '0'+str(x), 'i': x+3}, range(24))

    now = datetime.now()
    today = date.today()
    iDate = today - timedelta(days=today.weekday())
    tasksList = Task.objects.filter(date__gte=iDate).order_by('date')

    firstTask = tasksList.first()
    lastTask = tasksList.last()
    weeks = (1 + ( monday(lastTask.date) - monday(firstTask.date)).days) / 7 if tasksList.count() > 0 and (firstTask.id != lastTask) else 0

    weeksInfo = createWeeks(monday(firstTask.date), weeks) if tasksList.count() > 0 else createWeeks(monday(today), weeks)

    tasks = reduce(reduceTasks, tasksList, weeksInfo)
    data["weeks"] = tasks
    data['datetext'] = DateFormat(now).format("l b d Y")

    summary = {}
    summary["complete"] = Task.objects.filter(complete=True).count()
    summary["pending"] = Task.objects.filter(date__gte=iDate).filter(complete=False).count()
    summary["lost"] = Task.objects.filter(date__lt=iDate).filter(complete=False).count()
    data["summary"] = summary

    data["forms"] = {
        "newTask": TaskForm(),
        "newCategory": CategoryForm()
    }

    data["categories"] = Category.objects.all()
    return render(request, 'scheduler.html', data)

def checkTask(request, id, week=""):
    """
    Change the completion status of a task
    args:
        id (int): Task id
        week (slug): Task week. ex: week2
    return:
        HttpResponseRedirect: redirect to  task scheluder view
    """
    task = Task.objects.get(id=id)
    task.complete = not task.complete
    task.save()
    rUrl = '/#' + week if week != "" else '/'
    return redirect(rUrl)

def newTask(request):
    if request.method == "POST":
        form = TaskForm(request.POST)
        if form.is_valid():
            form.save()
    return redirect("/")

def newCategory(request):
    if request.method == "POST":
        form = CategoryForm(request.POST)
        if form.is_valid():
            form.save()
    return redirect("/")


# --------------------------------------------------------
# get face key points
# Licensed under The MIT License [see LICENSE for details]
# Written by YaoWendi
# --------------------------------------------------------
import face_alignment
import cv2
import numpy as np
import time
import sys

#This function can detect face landmarks from video
#videopath is the path of the video
#if LandmarksType is 3D then can detect 3D landmarks
#if LandmarksType is 2D then can detect 2D landmarks
def face_detect(videopath,LandmarksType):

    start = time.time()
    if LandmarksType == '3D' or LandmarksType == '3d':
        landmarkstype = face_alignment.LandmarksType._3D
        print('开始进行3D关键点检测')
    elif LandmarksType =='2D' or LandmarksType =='2d':
        landmarkstype = face_alignment.LandmarksType._2D
        print('开始进行2D关键点检测')
    else:
        print("Error!Please put '3D' or '2D' !")
        sys.exit(0)

    fa = face_alignment.FaceAlignment(landmarkstype, device='cuda', flip_input=True,face_detector='blazeface')
    cap = cv2.VideoCapture(videopath)
    fps = cap.get(cv2.CAP_PROP_FPS)
    landmarks = []
    nonDetectFr = []
    my_figsize, my_dpi = (20, 10), 80
    totalIndx = 0
    fourcc = cv2.VideoWriter_fourcc(*'XVID') # create VideoWriter object
    totalFrame = np.int32(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    print("Total frames: ", totalFrame)

    while(cap.isOpened()):
        frameIndex = np.int32(cap.get(cv2.CAP_PROP_POS_FRAMES))
        print("Processing frame ", frameIndex, "...")
        ret, frame = cap.read()
        if ret==True:
        # operations on the frame
            try:
                # generate face bounding box and track 2D landmarks for current frame
                frame_landmarks = fa.get_landmarks(frame)[-1]
            except:
                print("Landmarks in frame ", frameIndex, " (", frameIndex/fps, " s) could not be detected.")
                nonDetectFr.append(frameIndex/fps)
                continue
            landmarks.append(frame_landmarks)
            totalIndx = totalIndx + 1
        else:
            break
    cap.release()
    end = time.time()
    print("processing time:" + str(end - start))
    return(landmarks)


import torch
import numpy as np
import matplotlib.pyplot as plt

from matplotlib.colors import LogNorm
from torch.utils.data import DataLoader

from models.parameter_estimators import EllipseParametersRegressor
from svg_dataset.ellipse_dataloader import SVGDataset, svg_code_to_pil_image
from ellipse_generator.svg_ellipse import Ellipse, EllipseImageHandler, \
    rgb_to_hex, hex_color_to_rgb

PARAMETER_NAMES = ['cx', 'cy', 'rx', 'ry', 'fill', 'opacity', 'angle']

def model_output_dict_to_ellipses(output_dict, num_ellipses_in_image):
    ellipses = []
    for shape in range(num_ellipses_in_image):
        shape_params = {param: output_dict[param][0][shape].item()
                        for param in PARAMETER_NAMES if param != 'fill'}
        shape_params['fill'] = rgb_to_hex(
            output_dict['fill'][0][shape].tolist())

        ellipses.append(Ellipse(**shape_params))
    return ellipses

def ellipses_to_svg_code(ellipses: list):
    svg_lines = []
    for ellipse in ellipses:
        svg_lines.append(ellipse.to_svg_line())
    handler = EllipseImageHandler()
    svg_code = handler.warp_shapes_in_svg_header('\n'.join(svg_lines))
    return svg_code

model = EllipseParametersRegressor(num_shapes_in_image=3, channels=4)
model.load_state_dict(
    torch.load('results/single_image_results/3_ellipses/regression_model.pth'))
rand_outputs = model(torch.rand(1, 4, 256, 256))
ellipses = model_output_dict_to_ellipses(rand_outputs, 3)
rand_svg_code = ellipses_to_svg_code(ellipses)
with open('rand_input_single_image.svg', 'w') as f:
    f.write(rand_svg_code)

dataset = SVGDataset('results/single_image_results/3_ellipses/original_image/')
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)
image = next(iter(dataloader))['image']
image_output = model(image)
ellipses = model_output_dict_to_ellipses(image_output, 3)
image_svg_code = ellipses_to_svg_code(ellipses)
with open('original_input_single_image.svg', 'w') as f:
    f.write(image_svg_code)

with open(
    'results/single_image_results/3_ellipses/original_image/ORIGINAL_IMAGE.svg',
    'r') as f: original_code = f.read()

original_pil_image = svg_code_to_pil_image(original_code)
gen_from_image = svg_code_to_pil_image(image_svg_code)
gen_from_noise = svg_code_to_pil_image(rand_svg_code)

plt.clf()
plt.title('original image')
plt.imshow(original_pil_image)
plt.xticks([])
plt.yticks([])
plt.tight_layout()
plt.savefig('01_original.png')

plt.clf()
plt.title('generated from original image')
plt.imshow(gen_from_image)
plt.xticks([])
plt.yticks([])
plt.tight_layout()
plt.savefig('02_gen_from_original.png')

plt.clf()
plt.title('generated from random noise image')
plt.imshow(gen_from_noise)
plt.xticks([])
plt.yticks([])
plt.tight_layout()
plt.savefig('03_gen_from_noise.png')

plt.clf()
plt.subplot(3, 1, 1)
plt.title('original image')
plt.imshow(original_pil_image)
plt.xticks([])
plt.yticks([])

plt.subplot(3, 3, 4)
plt.title('generated from original image')
plt.imshow(gen_from_image)
plt.xticks([])
plt.yticks([])
plt.subplot(3, 3, 5)
plt.title('rgb channels difference')
plt.imshow(np.abs(
    np.array(gen_from_image).astype(np.float32) -
    np.array(original_pil_image).astype(np.float32))[..., :-1].mean(axis=-1),
           norm=LogNorm(vmin=0.01, vmax=100))
plt.colorbar()
plt.xticks([])
plt.yticks([])
plt.subplot(3, 3, 6)
plt.title('alpha channels (abs) difference')
plt.imshow(np.abs(
    np.array(gen_from_image).astype(np.float32) -
    np.array(original_pil_image).astype(np.float32))[..., -1],
           norm=LogNorm(vmin=0.01, vmax=100))
plt.colorbar()
plt.xticks([])
plt.yticks([])

plt.subplot(3, 3, 4 + 3)
plt.title('generated from noise')
plt.imshow(gen_from_noise)
plt.xticks([])
plt.yticks([])
plt.subplot(3, 3, 5 + 3)
plt.title('rgb channels difference')
plt.imshow(np.abs(
    np.array(gen_from_noise).astype(np.float32) -
    np.array(original_pil_image).astype(np.float32))[..., :-1].mean(axis=-1),
           norm=LogNorm(vmin=0.01, vmax=100))
plt.colorbar()
plt.xticks([])
plt.yticks([])
plt.subplot(3, 3, 6 + 3)
plt.title('alpha channels (abs) difference')
plt.imshow(np.abs(
    np.array(gen_from_noise).astype(np.float32) -
    np.array(original_pil_image).astype(np.float32))[..., -1],
           norm=LogNorm(vmin=0.01, vmax=100))
plt.colorbar()
plt.xticks([])
plt.yticks([])
fig = plt.gcf()
fig.set_size_inches((12, 8))
plt.tight_layout()
plt.savefig('all in one.png')


#!/usr/bin/env python3
# a class that

import rospy
from my_robot_tutorial.srv import TurnCamera, TurnCameraResponse
import numpy as np
import os
import cv2
from cv_bridge import CvBridge

class TurnCameraClass:
    """TurnCameraClass ummary.

    Attributes
    ----------
    available_angles : type
        Description of attribute `available_angles`.
    ros_service : type
        Description of attribute `ros_service`.
    send_image : type
        Description of attribute `send_image`.

    """
    def __init__(self):
        """__init__ summary.
        Initialising the avaialable parameters for the camera
        """
        self.available_angles = [-30, -15, 0, 15, 30]
        self.ros_service = rospy.Service("turn_camera", TurnCamera, self.send_image)

    def read_in_image_by_file_name(self, file_name):
        """read_in_image_by_file_name summary.

        Parameters
        ----------
        file_name : type
            Description of parameter `file_name`.

        Returns
        -------
        type
            Description of returned object.

        """
        dir_name = os.path.dirname(__file__)
        file_location = dir_name + "/Images/" + file_name
        image = cv2.imread(file_location)
        return image

    def get_image(self, angle):
        """get_image summary.

        Parameters
        ----------
        angle : type
            Description of parameter `angle`.

        Returns
        -------
        type
            Description of returned object.

        """
        closest_angle = min(self.available_angles, key=lambda x:abs(x-angle))
        return self.read_in_image_by_file_name(str(closest_angle) + ".png")

    def send_image(self, req):
        """send_image summary.

        Parameters
        ----------
        req : type
            Description of parameter `req`.

        Returns
        -------
        type
            Description of returned object.

        """
        image = self.get_image(req.turn_degrees)
        image_msg = CvBridge().cv2_to_imgmsg(image)
        return TurnCameraResponse(image_msg)

if __name__ == '__main__':
    try:
        rospy.init_node("turn_camera_service_node")
        TurnCameraClass()
        print("Turn Camera Service is Running")
        rospy.spin()

    except rospy.ROSInterruptException:
        pass


# imports
import pygame as pg
import random
from os import path
import time

# game options/settings
TITLE = "Asteroids"
WIDTH = 800
HEIGHT = 600
FPS = 60
FONT_NAME = pg.font.match_font("ariel")
SPRITESHEET = "simpleSpace_sheet.png"
NUMSTARS = 200
NUMMETEORS = 2
BULLETRAD = 3
METEOR_DELAY = 5000
METEOR_SPEED = 3

# define colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
cfBLUE = (100, 149, 237)
BGCOLOR = BLACK

#player settings
PLAYER_GRAV = 0.0
PLAYER_ACC = 0.1
PLAYER_ROT_SPEED = 5
PLAYER_FRICTION = -.01


#!/etc/dev/dnschecker/mon/bin/python3
import json
import logging
import os
import random
import sys
from threading import Thread
import urllib.request
import requests
import re
from backend.accessdb import AccessDB, Base, enginer
from backend.geoavailable import Available
from initconf import getconf
from run import get_list

count = 0

class Scrapper:
    def __init__(self, _CONF, geobase):
        self.count = int(_CONF['GEO']['initcount'])
        self.geobase = geobase

    def getnslist(self, url):
        response = urllib.request.urlopen(url)
        data = json.loads(response.read())
        return data

    def scrap(self, url):
        geobase = []
        data = Scrapper.getnslist(self, url)
        random.shuffle(data)
        i = 0
        for one in data:
            if i >= self.count: break
            ip = one['ip']
            if ip in self.geobase:
                continue
            try:
                location, ip = Scrapper.geocheck(self, ip)
                if location and ip:
                    country = location["country"]
                    city = location["city"]
                    coordinates = location["coordinates"]
                    if coordinates and re.match('^[0-9]+.[0-9]+.[0-9]+.[0-9]+$', ip):
                        geobase.append({
                            'ip': ip,
                            'latitude': coordinates[0],
                            'longitude': coordinates[1],
                            'country': country,
                            'city': city
                        })
                        print('NEW:', country, city, ip)
                        i+=1
            except Exception as e:
                logging.exception('GEO SCRAP')
        return geobase

    def geocheck(self, ip):
        token = _token
        url = f'http://ipinfo.io/{ip}?token={token}'
        response = requests.get(url)
        data = response.json()
        #print(json.dumps(data, indent=4))
        if "loc" in data and "city" in data and "country" in data:
            location = {
                "coordinates": data["loc"].split(','),
                "city": data["city"],
                "country": data["country"]
            }
            return location, data["ip"]
        return None, None

if __name__ == "__main__":
    try:
        thisdir = os.path.dirname(os.path.abspath(__file__))
        _CONF = getconf(thisdir+'/config.conf')
        _DEBUG = _CONF['GENERAL']['debug']
        _token = sys.argv[1]
    except IndexError:
        print('Specify ipinfo.io API token')
        sys.exit()

    try:
        Base.metadata.create_all(enginer(_CONF))
        DB = AccessDB(_CONF)
        geobase = Available.get(None,DB.start(onlygeo=True))
        geobase = [server['ip'] for line in geobase for city in geobase[line] for server in geobase[line][city]]
        geobase = set(geobase)
    except:
        logging.exception('DB INIT:')
        sys.exit()

    try:
        urllist = get_list(_CONF['FILES']['publicns'])
    except:
        logging.exception('GET DATA FROM CONF')
        sys.exit()

    S = Scrapper(_CONF, geobase)
    geostorage = {}
    geostorage['initgeo'] = []
    for url in urllist:
        geostorage['initgeo'].append(S.scrap(url))
        pass
    geostorage['initgeo'] = [data for data in geostorage['initgeo'] for data in data]
    #print(geostorage['initgeo'])
    DB.parse(geostorage)


import AppKit
import os
from PIL import Image
import pyautogui as gui
import pyocr
import pyocr.builders
import sys

def mean(a, b):
    return int((a+b)/2)

if __name__ == "__main__":
    # 事前準備
    tmp_img_path = 'res/screen_tmp.png'
    os.makedirs('res', exist_ok=True)

    # 座標の大きさにズレがあるっぽいので、0~1 の相対座標にしてみる。

    # 参考： https://boook24.com/?p=348
    print('中断するにはCrt+Cを入力してください。')

    points = []
    try:
        for i in range(2):
            x = input(f"{i+1}点目にマウスを移動 → Enterキー押してください。\n")
            points.append(gui.position())
            print(f"OK!\n座標：{points[i]}\n")

    except KeyboardInterrupt:
        print('\n終了')
        sys.exit()

    # 矩形 を計算する。
    x_min = min(points[0][0], points[1][0])
    y_min = min(points[0][1], points[1][1])

    # スクショ
    # 参考： https://qiita.com/eito_2/items/1974f3cfa1f4d101378d
    # スクリーンショット（全体）を取得する。
    img = gui.screenshot()

    # gui.position() の最大値
    screen_x, screen_y = gui.size()
    print(screen_x, screen_y)
    # gui.position()  と  gui.screenshot()  の縮尺の違いを吸収する。
    ratio_x = (img.width / screen_x)
    ratio_y = (img.height / screen_y)

    # スクリーンショットした画像は表示しきれないので画像リサイズ
    x = int(x_min * ratio_x) #+ mean(points[0][0], points[1][0])
    y = int(y_min * ratio_y) # + mean(points[0][1], points[1][1])
    w_adj = int(abs(points[0][0] - points[1][0]) * ratio_x)
    h_adj = int(abs(points[0][1] - points[1][1]) * ratio_y)

    # region = (left_x, top_y, width, height)
    print(f'(left_x, top_y, width, height) = ({x}, {y}, {w_adj}, {h_adj})')
    screenshot = gui.screenshot(region=(x, y, w_adj, h_adj))
    screenshot.save(tmp_img_path)

    # img = Image.open(tmp_img_path)
    # img.show()

    # Tesseract OCR
    # 参考：https://chusotsu-program.com/python-tesseract-pyocr/
    # 切り出した領域に OCRする。（Tesseract OCR）
    tools = pyocr.get_available_tools()
    if len(tools) == 0:
        print("No OCR tool found")
        sys.exit(1)

    tool = tools[0]
    # print("Will use tool '%s'" % (tool.get_name()))

    txt = tool.image_to_string(
        Image.open(tmp_img_path),
        lang="jpn",
        builder = pyocr.builders.TextBuilder(tesseract_layout=6)
    )
    print(txt.replace(' ', ''))

    # ファイルに保存
    with open('res/ocr.txt', 'w') as f:
        f.write(txt)

    # 削除
    import shutil
    shutil.rmtree('res')


from os.path import dirname, basename, isfile
import glob

from PyDSS.pyPostprocessor import PostprocessScripts

modules = glob.glob(PostprocessScripts.__path__[0]+"/*.py")
pythonFiles = [basename(f)[:-3] for f in modules if isfile(f) and not f.endswith('__init__.py')]

POST_PROCESSES = {}
for file in pythonFiles:
    exec('from PyDSS.pyPostprocessor.PostprocessScripts import {}'.format(file))
    exec('POST_PROCESSES["{}"] = {}.{}'.format(file, file, file))

def Create(project, scenario, ppInfo, dssInstance, dssSolver, dssObjects, dssObjectsByClass, simulationSettings, Logger):
    test = None
    PostProcessorClass = None
    ScriptName = ppInfo.script
    assert (ScriptName in pythonFiles), \
        f"Definition for '{ScriptName}' post process script not found. \n" \
        "Please define the controller in PyDSS/pyPostprocessor/PostprocessScripts"
    PostProcessor = POST_PROCESSES[ScriptName](
        project,
        scenario,
        ppInfo,
        dssInstance,
        dssSolver,
        dssObjects,
        dssObjectsByClass,
        simulationSettings,
        Logger,
    )
    return PostProcessor