import logging
import os

import atest_configs
import atest_error
import atest_utils
import constants

from test_finders import test_info
from test_finders import test_finder_base
from test_finders import test_finder_utils
from test_runners import atest_tf_test_runner
from test_runners import robolectric_test_runner
from test_runners import vts_tf_test_runner

_ANDROID_MK = 'Android.mk'

# These are suites in LOCAL_COMPATIBILITY_SUITE that aren't really suites so
# we can ignore them.
_SUITES_TO_IGNORE = frozenset({'general-tests', 'device-tests', 'tests'})

class ModuleFinder(test_finder_base.TestFinderBase):
    """Module finder class."""
    NAME = 'MODULE'
    _TEST_RUNNER = atest_tf_test_runner.AtestTradefedTestRunner.NAME
    _ROBOLECTRIC_RUNNER = robolectric_test_runner.RobolectricTestRunner.NAME
    _VTS_TEST_RUNNER = vts_tf_test_runner.VtsTradefedTestRunner.NAME

    def __init__(self, module_info=None):
        super().__init__()
        self.root_dir = os.environ.get(constants.ANDROID_BUILD_TOP)
        self.module_info = module_info

    def _determine_testable_module(self, path, file_path=None):
        """Determine which module the user is trying to test.

        Returns the module to test. If there are multiple possibilities, will
        ask the user. Otherwise will return the only module found.

        Args:
            path: String path of module to look for.
            file_path: String path of input file.

        Returns:
            A list of the module names.
        """
        testable_modules = []
        # A list to save those testable modules but srcs information is empty.
        testable_modules_no_srcs = []
        for mod in self.module_info.get_module_names(path):
            mod_info = self.module_info.get_module_info(mod)
            # Robolectric tests always exist in pairs of 2, one module to build
            # the test and another to run it. For now, we are assuming they are
            # isolated in their own folders and will return if we find one.
            if self.module_info.is_robolectric_test(mod):
                # return a list with one module name if it is robolectric.
                return [mod]
            if self.module_info.is_testable_module(mod_info):
                # If test module defined srcs, input file_path should be defined
                # in the src list of module.
                module_srcs = mod_info.get(constants.MODULE_SRCS, [])
                if file_path and os.path.relpath(
                    file_path, self.root_dir) not in module_srcs:
                    logging.debug('Skip module: %s for %s', mod, file_path)
                    # Collect those modules if they don't have srcs information
                    # in module-info, use this list if there's no other matched
                    # module with src information.
                    if not module_srcs:
                        testable_modules_no_srcs.append(
                            mod_info.get(constants.MODULE_NAME))
                    continue
                testable_modules.append(mod_info.get(constants.MODULE_NAME))
        if not testable_modules:
            testable_modules.extend(testable_modules_no_srcs)
        return test_finder_utils.extract_test_from_tests(testable_modules)

    def _is_vts_module(self, module_name):
        """Returns True if the module is a vts10 module, else False."""
        mod_info = self.module_info.get_module_info(module_name)
        suites = []
        if mod_info:
            suites = mod_info.get('compatibility_suites', [])
        # Pull out all *ts (cts, tvts, etc) suites.
        suites = [suite for suite in suites if suite not in _SUITES_TO_IGNORE]
        return len(suites) == 1 and 'vts10' in suites

    def _update_to_vts_test_info(self, test):
        """Fill in the fields with vts10 specific info.

        We need to update the runner to use the vts10 runner and also find the
        test specific dependencies.

        Args:
            test: TestInfo to update with vts10 specific details.

        Return:
            TestInfo that is ready for the vts10 test runner.
        """
        test.test_runner = self._VTS_TEST_RUNNER
        config_file = os.path.join(self.root_dir,
                                   test.data[constants.TI_REL_CONFIG])
        # Need to get out dir (special logic is to account for custom out dirs).
        # The out dir is used to construct the build targets for the test deps.
        out_dir = os.environ.get(constants.ANDROID_HOST_OUT)
        custom_out_dir = os.environ.get(constants.ANDROID_OUT_DIR)
        # If we're not an absolute custom out dir, get no-absolute out dir path.
        if custom_out_dir is None or not os.path.isabs(custom_out_dir):
            out_dir = os.path.relpath(out_dir, self.root_dir)
        vts_out_dir = os.path.join(out_dir, 'vts10', 'android-vts10', 'testcases')
        # Parse dependency of default staging plans.
        xml_paths = test_finder_utils.search_integration_dirs(
            constants.VTS_STAGING_PLAN,
            self.module_info.get_paths(constants.VTS_TF_MODULE))
        vts_xmls = set()
        vts_xmls.add(config_file)
        for xml_path in xml_paths:
            vts_xmls |= test_finder_utils.get_plans_from_vts_xml(xml_path)
        for config_file in vts_xmls:
            # Add in vts10 test build targets.
            test.build_targets |= test_finder_utils.get_targets_from_vts_xml(
                config_file, vts_out_dir, self.module_info)
        test.build_targets.add('vts-test-core')
        test.build_targets.add(test.test_name)
        return test

    def _update_to_robolectric_test_info(self, test):
        """Update the fields for a robolectric test.

        Args:
          test: TestInfo to be updated with robolectric fields.

        Returns:
          TestInfo with robolectric fields.
        """
        test.test_runner = self._ROBOLECTRIC_RUNNER
        test.test_name = self.module_info.get_robolectric_test_name(test.test_name)
        return test

    def _process_test_info(self, test):
        """Process the test info and return some fields updated/changed.

        We need to check if the test found is a special module (like vts10) and
        update the test_info fields (like test_runner) appropriately.

        Args:
            test: TestInfo that has been filled out by a find method.

        Return:
            TestInfo that has been modified as needed and return None if
            this module can't be found in the module_info.
        """
        module_name = test.test_name
        mod_info = self.module_info.get_module_info(module_name)
        if not mod_info:
            return None
        test.module_class = mod_info['class']
        test.install_locations = test_finder_utils.get_install_locations(
            mod_info['installed'])
        # Check if this is only a vts10 module.
        if self._is_vts_module(test.test_name):
            return self._update_to_vts_test_info(test)
        if self.module_info.is_robolectric_test(test.test_name):
            return self._update_to_robolectric_test_info(test)
        rel_config = test.data[constants.TI_REL_CONFIG]
        test.build_targets = self._get_build_targets(module_name, rel_config)
        # For device side java test, it will use
        # com.android.compatibility.testtype.DalvikTest as test runner in
        # cts-dalvik-device-test-runner.jar
        if self.module_info.is_auto_gen_test_config(module_name):
            if constants.MODULE_CLASS_JAVA_LIBRARIES in test.module_class:
                test.build_targets.update(test_finder_utils.DALVIK_TEST_DEPS)
        # Update test name if the test belong to extra config which means it's
        # test config name is not the same as module name. For extra config, it
        # index will be greater or equal to 1.
        try:
            if (mod_info.get(constants.MODULE_TEST_CONFIG, []).index(rel_config)
                    > 0):
                config_test_name = os.path.splitext(os.path.basename(
                    rel_config))[0]
                logging.debug('Replace test_info.name(%s) to %s',
                              test.test_name, config_test_name)
                test.test_name = config_test_name
        except ValueError:
            pass
        return test

    def _get_build_targets(self, module_name, rel_config):
        """Get the test deps.

        Args:
            module_name: name of the test.
            rel_config: XML for the given test.

        Returns:
            Set of build targets.
        """
        targets = set()
        if not self.module_info.is_auto_gen_test_config(module_name):
            config_file = os.path.join(self.root_dir, rel_config)
            targets = test_finder_utils.get_targets_from_xml(config_file,
                                                             self.module_info)
        if constants.VTS_CORE_SUITE in self.module_info.get_module_info(
                module_name).get(constants.MODULE_COMPATIBILITY_SUITES, []):
            targets.add(constants.VTS_CORE_TF_MODULE)
        for suite in self.module_info.get_module_info(
            module_name).get(constants.MODULE_COMPATIBILITY_SUITES, []):
            targets.update(constants.SUITE_DEPS.get(suite, []))
        for module_path in self.module_info.get_paths(module_name):
            mod_dir = module_path.replace('/', '-')
            targets.add(constants.MODULES_IN + mod_dir)
        # (b/156457698) Force add vts_kernel_tests as build target if our test
        # belong to REQUIRED_KERNEL_TEST_MODULES due to required_module option
        # not working for sh_test in soong.
        if module_name in constants.REQUIRED_KERNEL_TEST_MODULES:
            targets.add('vts_kernel_tests')
        # (b/184567849) Force adding module_name as a build_target. This will
        # allow excluding MODULES-IN-* and prevent from missing build targets.
        if module_name and self.module_info.is_module(module_name):
            targets.add(module_name)
        return targets

    def _get_module_test_config(self, module_name, rel_config=None):
        """Get the value of test_config in module_info.

        Get the value of 'test_config' in module_info if its
        auto_test_config is not true.
        In this case, the test_config is specified by user.
        If not, return rel_config.

        Args:
            module_name: A string of the test's module name.
            rel_config: XML for the given test.

        Returns:
            A list of string of test_config path if found, else return rel_config.
        """
        default_all_config = not (atest_configs.GLOBAL_ARGS and
                                  atest_configs.GLOBAL_ARGS.test_config_select)
        mod_info = self.module_info.get_module_info(module_name)
        if mod_info:
            test_configs = []
            test_config_list = mod_info.get(constants.MODULE_TEST_CONFIG, [])
            if test_config_list:
                # multiple test configs
                if len(test_config_list) > 1:
                    test_configs = test_finder_utils.extract_test_from_tests(
                        test_config_list, default_all=default_all_config)
                else:
                    test_configs = test_config_list
            if test_configs:
                return test_configs
            # Double check if below section is needed.
            if (not self.module_info.is_auto_gen_test_config(module_name)
                    and len(test_configs) > 0):
                return test_configs
        return [rel_config] if rel_config else []

    # pylint: disable=too-many-branches
    # pylint: disable=too-many-locals
    def _get_test_info_filter(self, path, methods, **kwargs):
        """Get test info filter.

        Args:
            path: A string of the test's path.
            methods: A set of method name strings.
            rel_module_dir: Optional. A string of the module dir no-absolute to
                root.
            class_name: Optional. A string of the class name.
            is_native_test: Optional. A boolean variable of whether to search
                for a native test or not.

        Returns:
            A set of test info filter.
        """
        _, file_name = test_finder_utils.get_dir_path_and_filename(path)
        ti_filter = frozenset()
        if kwargs.get('is_native_test', None):
            ti_filter = frozenset([test_info.TestFilter(
                test_finder_utils.get_cc_filter(
                    kwargs.get('class_name', '*'), methods), frozenset())])
        # Path to java file.
        elif file_name and constants.JAVA_EXT_RE.match(file_name):
            full_class_name = test_finder_utils.get_fully_qualified_class_name(
                path)
            # If input class is parameterized java class, adding * to the end of
            # method filter string to make sure the generated method name could
            # be run.
            if test_finder_utils.is_parameterized_java_class(path):
                update_methods = []
                for method in methods:
                    update_methods.append(method + '*')
                methods = frozenset(update_methods)
            ti_filter = frozenset(
                [test_info.TestFilter(full_class_name, methods)])
        # Path to cc file.
        elif file_name and constants.CC_EXT_RE.match(file_name):
            # TODO (b/173019813) Should setup correct filter for an input file.
            if not test_finder_utils.has_cc_class(path):
                raise atest_error.MissingCCTestCaseError(
                    "Can't find CC class in %s" % path)
            # Extract class_name, method_name and parameterized_class from
            # the given cc path.
            file_classes, _, file_para_classes = (
                test_finder_utils.get_cc_test_classes_methods(path))
            cc_filters = []
            # When instantiate tests found, recompose the class name in
            # $(InstantiationName)/$(ClassName)
            for file_class in file_classes:
                if file_class in file_para_classes:
                    file_class = '*/%s' % file_class
                cc_filters.append(
                    test_info.TestFilter(
                        test_finder_utils.get_cc_filter(file_class, methods),
                        frozenset()))
            ti_filter = frozenset(cc_filters)
        # If input path is a folder and have class_name information.
        elif (not file_name and kwargs.get('class_name', None)):
            ti_filter = frozenset(
                [test_info.TestFilter(kwargs.get('class_name', None), methods)])
        # Path to non-module dir, treat as package.
        elif (not file_name
              and kwargs.get('rel_module_dir', None) !=
              os.path.relpath(path, self.root_dir)):
            dir_items = [os.path.join(path, f) for f in os.listdir(path)]
            for dir_item in dir_items:
                if constants.JAVA_EXT_RE.match(dir_item):
                    package_name = test_finder_utils.get_package_name(dir_item)
                    if package_name:
                        # methods should be empty frozenset for package.
                        if methods:
                            raise atest_error.MethodWithoutClassError(
                                '%s: Method filtering requires class'
                                % str(methods))
                        ti_filter = frozenset(
                            [test_info.TestFilter(package_name, methods)])
                        break
        logging.debug('_get_test_info_filter() ti_filter: %s', ti_filter)
        return ti_filter

    def _get_rel_config(self, test_path):
        """Get config file's no-absolute path.

        Args:
            test_path: A string of the test absolute path.

        Returns:
            A string of config's no-absolute path, else None.
        """
        test_dir = os.path.dirname(test_path)
        rel_module_dir = test_finder_utils.find_parent_module_dir(
            self.root_dir, test_dir, self.module_info)
        if rel_module_dir:
            return os.path.join(rel_module_dir, constants.MODULE_CONFIG)
        return None

    def _get_test_infos(self, test_path, rel_config, module_name, test_filter):
        """Get test_info for test_path.

        Args:
            test_path: A string of the test path.
            rel_config: A string of rel path of config.
            module_name: A string of the module name to use.
            test_filter: A test info filter.

        Returns:
            A list of TestInfo namedtuple if found, else None.
        """
        if not rel_config:
            rel_config = self._get_rel_config(test_path)
            if not rel_config:
                return None
        if module_name:
            module_names = [module_name]
        else:
            module_names = self._determine_testable_module(
                os.path.dirname(rel_config),
                test_path if self._is_comparted_src(test_path) else None)
        test_infos = []
        if module_names:
            for mname in module_names:
                # The real test config might be record in module-info.
                rel_configs = self._get_module_test_config(
                    mname, rel_config=rel_config)
                for rel_cfg in rel_configs:
                    mod_info = self.module_info.get_module_info(mname)
                    tinfo = self._process_test_info(test_info.TestInfo(
                        test_name=mname,
                        test_runner=self._TEST_RUNNER,
                        build_targets=set(),
                        data={constants.TI_FILTER: test_filter,
                              constants.TI_REL_CONFIG: rel_cfg},
                        compatibility_suites=mod_info.get(
                            constants.MODULE_COMPATIBILITY_SUITES, [])))
                    if tinfo:
                        test_infos.append(tinfo)
        return test_infos

    def find_test_by_module_name(self, module_name):
        """Find test for the given module name.

        Args:
            module_name: A string of the test's module name.

        Returns:
            A list that includes only 1 populated TestInfo namedtuple
            if found, otherwise None.
        """
        tinfos = []
        mod_info = self.module_info.get_module_info(module_name)
        if self.module_info.is_testable_module(mod_info):
            # path is a list with only 1 element.
            rel_config = os.path.join(mod_info['path'][0],
                                      constants.MODULE_CONFIG)
            rel_configs = self._get_module_test_config(module_name,
                                                       rel_config=rel_config)
            for rel_config in rel_configs:
                tinfo = self._process_test_info(test_info.TestInfo(
                    test_name=module_name,
                    test_runner=self._TEST_RUNNER,
                    build_targets=set(),
                    data={constants.TI_REL_CONFIG: rel_config,
                          constants.TI_FILTER: frozenset()},
                    compatibility_suites=mod_info.get(
                        constants.MODULE_COMPATIBILITY_SUITES, [])))
                if tinfo:
                    tinfos.append(tinfo)
            if tinfos:
                return tinfos
        return None

    def find_test_by_kernel_class_name(self, module_name, class_name):
        """Find kernel test for the given class name.

        Args:
            module_name: A string of the module name to use.
            class_name: A string of the test's class name.

        Returns:
            A list of populated TestInfo namedtuple if test found, else None.
        """

        class_name, methods = test_finder_utils.split_methods(class_name)
        test_configs = self._get_module_test_config(module_name)
        if not test_configs:
            return None
        tinfos = []
        for test_config in test_configs:
            test_config_path = os.path.join(self.root_dir, test_config)
            mod_info = self.module_info.get_module_info(module_name)
            ti_filter = frozenset(
                [test_info.TestFilter(class_name, methods)])
            if test_finder_utils.is_test_from_kernel_xml(test_config_path, class_name):
                tinfo = self._process_test_info(test_info.TestInfo(
                    test_name=module_name,
                    test_runner=self._TEST_RUNNER,
                    build_targets=set(),
                    data={constants.TI_REL_CONFIG: test_config,
                          constants.TI_FILTER: ti_filter},
                    compatibility_suites=mod_info.get(
                        constants.MODULE_COMPATIBILITY_SUITES, [])))
                if tinfo:
                    tinfos.append(tinfo)
        if tinfos:
            return tinfos
        return None

    def find_test_by_class_name(self, class_name, module_name=None,
                                rel_config=None, is_native_test=False):
        """Find test files given a class name.

        If module_name and rel_config not given it will calculate it determine
        it by looking up the tree from the class file.

        Args:
            class_name: A string of the test's class name.
            module_name: Optional. A string of the module name to use.
            rel_config: Optional. A string of module dir no-absolute to repo root.
            is_native_test: A boolean variable of whether to search for a
            native test or not.

        Returns:
            A list of populated TestInfo namedtuple if test found, else None.
        """
        class_name, methods = test_finder_utils.split_methods(class_name)
        search_class_name = class_name
        # For parameterized gtest, test class will be automerged to
        # $(class_prefix)/$(base_class) name. Using $(base_class) for searching
        # matched TEST_P to make sure test class is matched.
        if '/' in search_class_name:
            search_class_name = str(search_class_name).split('/')[-1]
        if rel_config:
            search_dir = os.path.join(self.root_dir,
                                      os.path.dirname(rel_config))
        else:
            search_dir = self.root_dir
        test_paths = test_finder_utils.find_class_file(search_dir, search_class_name,
                                                       is_native_test, methods)
        if not test_paths and rel_config:
            logging.info('Did not find class (%s) under module path (%s), '
                         'researching from repo root.', class_name, rel_config)
            test_paths = test_finder_utils.find_class_file(self.root_dir,
                                                           search_class_name,
                                                           is_native_test,
                                                           methods)
        test_paths = test_paths if test_paths is not None else []
        # If we already have module name, use path in module-info as test_path.
        if not test_paths:
            if not module_name:
                return None
            # Use the module path as test_path.
            module_paths = self.module_info.get_paths(module_name)
            test_paths = []
            for rel_module_path in module_paths:
                test_paths.append(os.path.join(self.root_dir, rel_module_path))
        tinfos = []
        for test_path in test_paths:
            test_filter = self._get_test_info_filter(
                test_path, methods, class_name=class_name,
                is_native_test=is_native_test)
            test_infos = self._get_test_infos(
                test_path, rel_config, module_name, test_filter)
            # If input include methods, check if tinfo match.
            if test_infos and len(test_infos) > 1 and methods:
                test_infos = self._get_matched_test_infos(test_infos, methods)
            if test_infos:
                tinfos.extend(test_infos)
        return tinfos if tinfos else None

    def _get_matched_test_infos(self, test_infos, methods):
        """Get the test_infos matched the given methods.

        Args:
            test_infos: A list of TestInfo obj.
            methods: A set of method name strings.

        Returns:
            A list of matched TestInfo namedtuple, else None.
        """
        matched_test_infos = set()
        for tinfo in test_infos:
            test_config, test_srcs = test_finder_utils.get_test_config_and_srcs(
                tinfo, self.module_info)
            if test_config:
                filter_dict = atest_utils.get_android_junit_config_filters(
                    test_config)
                # Always treat the test_info is matched if no filters found.
                if not filter_dict.keys():
                    matched_test_infos.add(tinfo)
                    continue
                for method in methods:
                    if self._is_srcs_match_method_annotation(method, test_srcs,
                                                             filter_dict):
                        logging.debug('For method:%s Test:%s matched '
                                      'filter_dict: %s', method,
                                      tinfo.test_name, filter_dict)
                        matched_test_infos.add(tinfo)
        return list(matched_test_infos)

    def _is_srcs_match_method_annotation(self, method, srcs, annotation_dict):
        """Check if input srcs matched annotation.

        Args:
            method: A string of test method name.
            srcs: A list of source file of test.
            annotation_dict: A dictionary record the include and exclude
                             annotations.

        Returns:
            True if input method matched the annotation of input srcs, else
            None.
        """
        include_annotations = annotation_dict.get(
            constants.INCLUDE_ANNOTATION, [])
        exclude_annotations = annotation_dict.get(
            constants.EXCLUDE_ANNOTATION, [])
        for src in srcs:
            include_methods = set()
            src_path = os.path.join(self.root_dir, src)
            # Add methods matched include_annotations.
            for annotation in include_annotations:
                include_methods.update(
                    test_finder_utils.get_annotated_methods(
                        annotation, src_path))
            if exclude_annotations:
                # For exclude annotation, get all the method in the input srcs,
                # and filter out the matched annotation.
                exclude_methods = set()
                all_methods = test_finder_utils.get_java_methods(src_path)
                for annotation in exclude_annotations:
                    exclude_methods.update(
                        test_finder_utils.get_annotated_methods(
                            annotation, src_path))
                include_methods = all_methods - exclude_methods
            if method in include_methods:
                return True
        return False

    def find_test_by_module_and_class(self, module_class):
        """Find the test info given a MODULE:CLASS string.

        Args:
            module_class: A string of form MODULE:CLASS or MODULE:CLASS#METHOD.

        Returns:
            A list of populated TestInfo namedtuple if found, else None.
        """
        if ':' not in module_class:
            return None
        module_name, class_name = module_class.split(':')
        # module_infos is a list with at most 1 element.
        module_infos = self.find_test_by_module_name(module_name)
        module_info = module_infos[0] if module_infos else None
        if not module_info:
            return None
        find_result = None
        # If the target module is NATIVE_TEST, search CC classes only.
        if not self.module_info.is_native_test(module_name):
            # Find by java class.
            find_result = self.find_test_by_class_name(
                class_name, module_info.test_name,
                module_info.data.get(constants.TI_REL_CONFIG))
        # kernel target test is also define as NATIVE_TEST in build system.
        # TODO (b/157210083) Update find_test_by_kernel_class_name method to
        # support gen_rule use case.
        if not find_result:
            find_result = self.find_test_by_kernel_class_name(
                module_name, class_name)
        # Find by cc class.
        if not find_result:
            find_result = self.find_test_by_cc_class_name(
                class_name, module_info.test_name,
                module_info.data.get(constants.TI_REL_CONFIG))
        return find_result

    def find_test_by_package_name(self, package, module_name=None,
                                  rel_config=None):
        """Find the test info given a PACKAGE string.

        Args:
            package: A string of the package name.
            module_name: Optional. A string of the module name.
            ref_config: Optional. A string of rel path of config.

        Returns:
            A list of populated TestInfo namedtuple if found, else None.
        """
        _, methods = test_finder_utils.split_methods(package)
        if methods:
            raise atest_error.MethodWithoutClassError('%s: Method filtering '
                                                      'requires class' % (
                                                          methods))
        # Confirm that packages exists and get user input for multiples.
        if rel_config:
            search_dir = os.path.join(self.root_dir,
                                      os.path.dirname(rel_config))
        else:
            search_dir = self.root_dir
        package_paths = test_finder_utils.run_find_cmd(
            test_finder_utils.FIND_REFERENCE_TYPE.PACKAGE, search_dir, package)
        package_paths = package_paths if package_paths is not None else []
        # Package path will be the full path to the dir represented by package.
        if not package_paths:
            if not module_name:
                return None
            module_paths = self.module_info.get_paths(module_name)
            for rel_module_path in module_paths:
                package_paths.append(os.path.join(self.root_dir, rel_module_path))
        test_filter = frozenset([test_info.TestFilter(package, frozenset())])
        test_infos = []
        for package_path in package_paths:
            tinfo = self._get_test_infos(package_path, rel_config,
                                         module_name, test_filter)
            if tinfo:
                test_infos.extend(tinfo)
        return test_infos if test_infos else None

    def find_test_by_module_and_package(self, module_package):
        """Find the test info given a MODULE:PACKAGE string.

        Args:
            module_package: A string of form MODULE:PACKAGE

        Returns:
            A list of populated TestInfo namedtuple if found, else None.
        """
        module_name, package = module_package.split(':')
        # module_infos is a list with at most 1 element.
        module_infos = self.find_test_by_module_name(module_name)
        module_info = module_infos[0] if module_infos else None
        if not module_info:
            return None
        return self.find_test_by_package_name(
            package, module_info.test_name,
            module_info.data.get(constants.TI_REL_CONFIG))

    def find_test_by_path(self, rel_path):
        """Find the first test info matching the given path.

        Strategy:
            path_to_java_file --> Resolve to CLASS
            path_to_cc_file --> Resolve to CC CLASS
            path_to_module_file -> Resolve to MODULE
            path_to_module_dir -> Resolve to MODULE
            path_to_dir_with_class_files--> Resolve to PACKAGE
            path_to_any_other_dir --> Resolve as MODULE

        Args:
            rel_path: A string of the relative path to $BUILD_TOP.

        Returns:
            A list of populated TestInfo namedtuple if test found, else None
        """
        logging.debug('Finding test by path: %s', rel_path)
        path, methods = test_finder_utils.split_methods(rel_path)
        # TODO: See if this can be generalized and shared with methods above
        # create absolute path from cwd and remove symbolic links
        path = os.path.realpath(path)
        if not os.path.exists(path):
            return None
        if (methods and
                not test_finder_utils.has_method_in_file(path, methods)):
            return None
        dir_path, _ = test_finder_utils.get_dir_path_and_filename(path)
        # Module/Class
        rel_module_dir = test_finder_utils.find_parent_module_dir(
            self.root_dir, dir_path, self.module_info)
        if not rel_module_dir:
            # Try to find unit-test for input path.
            path = os.path.relpath(
                os.path.realpath(rel_path),
                os.environ.get(constants.ANDROID_BUILD_TOP, ''))
            unit_tests = test_finder_utils.find_host_unit_tests(
                self.module_info, path)
            if unit_tests:
                tinfos = []
                for unit_test in unit_tests:
                    tinfo = self._get_test_infos(path, constants.MODULE_CONFIG,
                                                 unit_test, frozenset())
                    if tinfo:
                        tinfos.extend(tinfo)
                return tinfos
            return None
        rel_config = os.path.join(rel_module_dir, constants.MODULE_CONFIG)
        test_filter = self._get_test_info_filter(path, methods,
                                                 rel_module_dir=rel_module_dir)
        return self._get_test_infos(path, rel_config, None, test_filter)

    def find_test_by_cc_class_name(self, class_name, module_name=None,
                                   rel_config=None):
        """Find test files given a cc class name.

        If module_name and rel_config not given, test will be determined
        by looking up the tree for files which has input class.

        Args:
            class_name: A string of the test's class name.
            module_name: Optional. A string of the module name to use.
            rel_config: Optional. A string of module dir no-absolute to repo root.

        Returns:
            A list of populated TestInfo namedtuple if test found, else None.
        """
        # Check if class_name is prepended with file name. If so, trim the
        # prefix and keep only the class_name.
        if '.' in class_name:
            # Assume the class name has a format of file_name.class_name
            class_name = class_name[class_name.rindex('.')+1:]
            logging.info('Search with updated class name: %s', class_name)
        return self.find_test_by_class_name(
            class_name, module_name, rel_config, is_native_test=True)

    def get_testable_modules_with_ld(self, user_input, ld_range=0):
        """Calculate the edit distances of the input and testable modules.

        The user input will be calculated across all testable modules and
        results in integers generated by Levenshtein Distance algorithm.
        To increase the speed of the calculation, a bound can be applied to
        this method to prevent from calculating every testable modules.

        Guessing from typos, e.g. atest atest_unitests, implies a tangible range
        of length that Atest only needs to search within it, and the default of
        the bound is 2.

        Guessing from keywords however, e.g. atest --search Camera, means that
        the uncertainty of the module name is way higher, and Atest should walk
        through all testable modules and return the highest possibilities.

        Args:
            user_input: A string of the user input.
            ld_range: An integer that range the searching scope. If the length
                      of user_input is 10, then Atest will calculate modules of
                      which length is between 8 and 12. 0 is equivalent to
                      unlimited.

        Returns:
            A List of LDs and possible module names. If the user_input is "fax",
            the output will be like:
            [[2, "fog"], [2, "Fix"], [4, "duck"], [7, "Duckies"]]

            Which means the most lilely names of "fax" are fog and Fix(LD=2),
            while Dickies is the most unlikely one(LD=7).
        """
        atest_utils.colorful_print('\nSearching for similar module names using '
                                   'fuzzy search...', constants.CYAN)
        testable_modules = sorted(self.module_info.get_testable_modules(),
                                  key=len)
        lower_bound = len(user_input) - ld_range
        upper_bound = len(user_input) + ld_range
        testable_modules_with_ld = []
        for module_name in testable_modules:
            # Dispose those too short or too lengthy.
            if ld_range != 0:
                if len(module_name) < lower_bound:
                    continue
                if len(module_name) > upper_bound:
                    break
            testable_modules_with_ld.append(
                [test_finder_utils.get_levenshtein_distance(
                    user_input, module_name), module_name])
        return testable_modules_with_ld

    def get_fuzzy_searching_results(self, user_input):
        """Give results which have no more than allowance of edit distances.

        Args:
            user_input: the target module name for fuzzy searching.

        Return:
            A list of guessed modules.
        """
        modules_with_ld = self.get_testable_modules_with_ld(
            user_input, ld_range=constants.LD_RANGE)
        guessed_modules = []
        for _distance, _module in modules_with_ld:
            if _distance <= abs(constants.LD_RANGE):
                guessed_modules.append(_module)
        return guessed_modules

    def find_test_by_config_name(self, config_name):
        """Find test for the given config name.

        Args:
            config_name: A string of the test's config name.

        Returns:
            A list that includes only 1 populated TestInfo namedtuple
            if found, otherwise None.
        """
        for module_name, mod_info in self.module_info.name_to_module_info.items():
            test_configs = mod_info.get(constants.MODULE_TEST_CONFIG, [])
            for test_config in test_configs:
                test_config_name = os.path.splitext(
                    os.path.basename(test_config))[0]
                if test_config_name == config_name:
                    tinfo = test_info.TestInfo(
                        test_name=test_config_name,
                        test_runner=self._TEST_RUNNER,
                        build_targets=self._get_build_targets(module_name,
                                                              test_config),
                        data={constants.TI_REL_CONFIG: test_config,
                              constants.TI_FILTER: frozenset()},
                        compatibility_suites=mod_info.get(
                            constants.MODULE_COMPATIBILITY_SUITES, []))
                    if tinfo:
                        # There should have only one test_config with the same
                        # name in source tree.
                        return [tinfo]
        return None

    def _is_comparted_src(self, path):
        """Check if the input path need to match srcs information in module.

        If path is a folder or android build file, we don't need to compart
        with module's srcs.

        Args:
            path: A string of the test's path.

        Returns:
            True if input path need to match with module's src info, else False.
        """
        if os.path.isdir(path):
            return False
        if atest_utils.is_build_file(path):
            return False
        return True


# Do not modify these lines
__winc_id__ = '63ce21059cf34d3d8ffef497ede7e317'
__human_name__ = 'comments'

# Add your code after this line
answer = 42
question = "How many roads?" # Here's an end-of-line comment.
answer = 43
question = "How many houses?" # Here's an end-of-line comment.

"""
LinuxThingy version 1.6.5

Parameters:

-t (--text): show the text interface
-h (--help): display this help
"""


def is_prime(num):
    if num == 1:
        return False

    for j in range(2, num + 1):
        if j*j <= num and num % j == 0:
            return False

    return True

if __name__ == '__main__':
    n = int(input())
    list_n = list(map(int, input().split()))
    cnt = 0
    for i in range(len(list_n)):
        if is_prime(list_n[i]):
            cnt += 1
    print(cnt)


"""Stormpath EmailTemplate resource mappings."""

from .base import (
    CollectionResource,
    DictMixin,
    Resource,
    SaveMixin,
)

class EmailTemplate(Resource, DictMixin, SaveMixin):
    """Stormpath EmailTemplate resource.

    More info in documentation:
    http://docs.stormpath.com/rest/product-guide/#directory-password-policy
    """

    MIME_TYPE_PLAIN_TEXT = 'text/plain'
    MIME_TYPE_HTML = 'text/html'

    writable_attrs = (
        'description',
        'from_email_address',
        'from_name',
        'html_body',
        'mime_type',
        'name',
        'subject',
        'text_body',
    )

class EmailTemplateList(CollectionResource):
    """EmailTemplate resource list."""
    resource_class = EmailTemplate

class DefaultModelEmailTemplate(EmailTemplate):
    """Stormpath DefaultModelEmailTemplate resource.

    More info in documentation:
    http://docs.stormpath.com/rest/product-guide/#directory-password-policy
    (Password Reset Workflow for Directory's Accounts section)
    """

    writable_attrs = EmailTemplate.writable_attrs + ('default_model', )

    def get_link_base_url(self):
        """
        Gets link_base_url from default_model.
        :return: Value of "linkBaseUrl" key in defaultModel dict.
        """
        return self.default_model.get('linkBaseUrl')

    def set_link_base_url(self, value):
        """
        Sets link_base_url from default_model dict..
        :param value: Value to which "linkBaseUrl" key will be set.
        """
        self.default_model['linkBaseUrl'] = value

class DefaultModelEmailTemplateList(CollectionResource):
    """DefaultModelEmailTemplate resource list."""
    resource_class = DefaultModelEmailTemplate


from odoo import api, fields, models

class IncomingQtyWizard(models.TransientModel):
    _name = "incoming.qty.wizard"
    _description = 'Incoming Qty'

    product_id = fields.Many2one(
        'product.product', 'Product', readonly=True, required=True)
    product_tmpl_id = fields.Many2one(
        'product.template', string='Product Template',
        readonly=False)
    incoming_qty_ids = fields.One2many('incoming.qty.lines.wizard', 'incoming_qty_id', string="Incoming Qty Lines")

    @api.model
    def default_get(self, fields):
        res = super(IncomingQtyWizard, self).default_get(fields)
        active_model = self._context.get('active_model')
        company = self.env.company
        warehouse = self.env['stock.warehouse'].search(
            [('warehouse_type', '!=', 'ocean'), ('company_id', '=', company.id)])
        vals = []
        prod_obj = self.env[active_model].browse(self.env.context.get('active_id'))
        if active_model == 'product.template':
            product_tmpl_id = prod_obj.id
            product_id = prod_obj.product_variant_id
        else:
            product_tmpl_id = prod_obj.product_tmpl_id.id
            product_id = prod_obj
        for ware in warehouse:
            incoming = product_id.with_context(warehouse=ware.id).incoming_qty
            if incoming > 0:
                vals.append((0, 0, {'warehouse_id': ware, 'incoming_qty': incoming}))
            res.update({'incoming_qty_ids': vals, 'product_tmpl_id': product_tmpl_id, 'product_id': product_id.id})
        return res

class IncomingQty(models.TransientModel):
    _name = "incoming.qty.lines.wizard"
    _description = 'Incoming Qty lines'

    warehouse_id = fields.Many2one('stock.warehouse', 'Warehouse')
    incoming_qty = fields.Float('Incoming Qty')
    incoming_qty_id = fields.Many2one('incoming.qty.wizard', 'Incoming')

class OutgoingQtyWizard(models.TransientModel):
    _name = "outgoing.qty.wizard"
    _description = 'Outgoing Qty'

    product_id = fields.Many2one(
        'product.product', 'Product', readonly=True, required=True)
    product_tmpl_id = fields.Many2one(
        'product.template', string='Product Template',
        readonly=False)
    outgoing_qty_ids = fields.One2many('outgoing.qty.lines.wizard', 'outgoing_qty_id', string="Outgoing Qty Lines")

    @api.model
    def default_get(self, fields):
        res = super(OutgoingQtyWizard, self).default_get(fields)
        active_model = self._context.get('active_model')
        company = self.env.company
        warehouse = self.env['stock.warehouse'].search([('company_id', '=', company.id)])
        vals = []
        prod_obj = self.env[active_model].browse(self.env.context.get('active_id'))
        if active_model == 'product.template':
            product_tmpl_id = prod_obj.id
            product_id = prod_obj.product_variant_id
        else:
            product_tmpl_id = prod_obj.product_tmpl_id.id
            product_id = prod_obj
        for ware in warehouse:
            outgoing = product_id.with_context(warehouse=ware.id).outgoing_qty
            if outgoing > 0:
                vals.append((0, 0, {'warehouse_id': ware, 'outgoing_qty': outgoing}))
            res.update({'outgoing_qty_ids': vals, 'product_tmpl_id': product_tmpl_id, 'product_id': product_id})
        return res

class OutgoingQty(models.TransientModel):
    _name = "outgoing.qty.lines.wizard"
    _description = 'Outgoing Qty lines'

    warehouse_id = fields.Many2one('stock.warehouse', 'Warehouse')
    outgoing_qty = fields.Float('Outgoing Qty')
    outgoing_qty_id = fields.Many2one('outgoing.qty.wizard', 'Outgoing')


#!/usr/bin/env python3
def main():
    n, k = map(int,input().split())
    ans = 0
    r = 1 / n

    for i in range(1, n+1):
        score = i
        cnt = 0
        while score < k:
            score *= 2
            cnt += 1

        ans += r * (0.5)**(cnt)

    return ans

print(main())

# self AC


from random import shuffle
from card import Card

class DeckOfCards:

    all_cards = []

    def __init__(self):
        self.restart_deck_of_cards()

    def give_a_card(self):
        selected_card = self.all_cards.pop()
        return selected_card

    #Shuffle the deck
    def shuffle_cards(self):
        shuffle(self.all_cards)

    #All cards become availiable again
    def restart_deck_of_cards(self):
        suits = ['Spades', 'Diamonds', 'Hearts', 'Clubs']
        for x in range(0, 4):
            for y in range(2, 11):
                card_rank = str(y)
                card_suit = suits[x]
                new_card = Card(card_rank, card_suit)
                self.all_cards.append(new_card)
            for z in range(11, 14):
                if z == 11:
                    card_rank = 'Jack'
                    card_suit = suits[x]
                    new_card = Card(card_rank, card_suit)
                    self.all_cards.append(new_card)
                if z == 12:
                    card_rank = 'Queen'
                    card_suit = suits[x]
                    new_card = Card(card_rank, card_suit)
                    self.all_cards.append(new_card)
                if z == 13:
                    card_rank = 'King'
                    card_suit = suits[x]
                    new_card = Card(card_rank, card_suit)
                    self.all_cards.append(new_card)
            #The Aces creation
            card_rank = 'Ace'
            card_suit = suits[x]
            new_card = Card(card_rank, card_suit)
            self.all_cards.append(new_card)

        self.shuffle_cards()


import numpy as np
import pydot

def write_mcts_as_png(search_paths, max_search_depth=float('inf'), path_to_file=''):
  graph = pydot.Dot(graph_type='graph')

  args = {'label': 'default',
          'penwidth': 1,
          'style': '',
          'color': 'green',
          'fontsize': 15,
          'fontname': 'times',
          'dir': '',
          'arrow': ''}

  unique_nodes = set(n for p in search_paths for n in p)

  seen_nodes = []
  chosen_nodes = []
  for path in search_paths:
    search_depth = 0
    for i, node in enumerate(path):
      if node not in seen_nodes:
        if node.visit_count > 1:
          if i == 0:
            root_args = args.copy()
            c, v = node.visit_count, node.value()
            root_args['label'] = "c:{}, v:{:.2f}".format(c, v)
            root_args['penwidth'] = 4
            graph.add_node(pydot.Node(str(node), **root_args))
            chosen_nodes.append(node)

          parent_id = str(node)
          _, chosen_action = max([(child.visit_count, action)
                                  for action, child in node.children.items()])
          for action, child in node.children.items():
            child_id = str(child)

            node_args = args.copy()
            edge_args = args.copy()

            node_args['label'] = 'nv'
            edge_args['label'] = 'p:{:.2f}'.format(child.prior)
            edge_args['fontsize'] = 10

            if child.visit_count > 0:
              c, v = child.visit_count, child.value()
              node_args['label'] = "c:{}, v:{:.2f}".format(c, v)
              edge_args['label'] += ', r:{:.2f}'.format(child.reward)
              node_args['arrow'] = 'forward'
              edge_args['style'] = 'filled'
            else:
              node_args['color'] = 'red'
              edge_args['color'] = 'red'
              edge_args['style'] = 'dotted'

            if node in chosen_nodes and action == chosen_action:
              node_args['fontname'] = 'times bold'
              edge_args['fontname'] = 'times bold'
              node_args['style'] = 'bold'
              edge_args['style'] = 'bold'
              node_args['penwidth'] = 4
              edge_args['penwidth'] = 2
              chosen_nodes.append(node.children[chosen_action])

            graph.add_node(pydot.Node(child_id, **node_args))
            graph.add_edge(pydot.Edge(parent_id, child_id, **edge_args))

        seen_nodes.append(node)

      search_depth += 1
      if search_depth > max_search_depth:
        break

  image = graph.write_png(path_to_file)


# using list comprehensions for texts

mysentence = 'Random fact I am a fan of jam'
words = mysentence.split()

print(words)

ending_m = [word for word in words if word[-1] == 'm']

print(ending_m)


import os
import re
from setuptools import setup, find_packages

readme = os.path.join(os.path.dirname(__file__), "README.rst")
LONG_DESCRIPTION = open(readme).read()

def read_module_contents():
    with open("product_listings_manager/__init__.py") as init:
        return init.read()

def read_requirements(filename):
    specifiers = []
    dep_links = []
    with open(filename, "r") as f:
        for line in f:
            if line.startswith("-r") or line.strip() == "":
                continue
            if line.startswith("git+"):
                dep_links.append(line.strip())
            else:
                specifiers.append(line.strip())
    return specifiers, dep_links

setup_py_path = os.path.dirname(os.path.realpath(__file__))
install_requires, _ = read_requirements(os.path.join(setup_py_path, "requirements.txt"))
tests_requires, _ = read_requirements(
    os.path.join(setup_py_path, "test-requirements.txt")
)

module_file = read_module_contents()
metadata = dict(re.findall(r'__([a-z]+)__\s*=\s*"([^"]+)"', module_file))
version = metadata["version"]

setup(
    name="product-listings-manager",
    version=version,
    description="query product listings data in composedb",
    classifiers=[
        "Development Status :: 5 - Production/Stable",
        "License :: OSI Approved :: MIT License",
        "Intended Audience :: Developers",
        "Operating System :: POSIX",
        "Programming Language :: Python",
        "Programming Language :: Python :: 3",
        "Topic :: Software Development",
    ],
    keywords="product compose",
    author="Ken Dreyer",
    author_email="kdreyer@redhat.com",
    url="https://github.com/release-engineering/product-listings-manager",
    license="MIT",
    long_description=LONG_DESCRIPTION,
    packages=find_packages(exclude=["tests"]),
    install_requires=install_requires,
    tests_require=tests_requires,
)


import subprocess as sp
lst = ["","X"," "," "," "," "," "," "," "," "]
def board():
	print('Current board')
	print("1 | 2 | 3     "+lst[1]+" | "+lst[2]+" | "+lst[3])
	print("---------     ---------")
	print("4 | 5 | 6     "+lst[4]+" | "+lst[5]+" | "+lst[6])
	print("---------     ---------")
	print("7 | 8 | 9     "+lst[7]+" | "+lst[8]+" | "+lst[9]+"\n")
def win():
	flag = 0
	for i in range(1,8,3):
		if lst[i]==lst[i+1]==lst[i+2]=='X':
			print('---YOU LOST---')
			flag = 1
		elif lst[i]==lst[i+1]==lst[i+2]=='O':
			print('---YOU WON---')
			flag = 1
	if flag == 0:
		for i in range(1,4):
			if lst[i]==lst[i+3]==lst[i+6]=='X':
				print('---YOU LOST---')
				flag = 1
			elif lst[i]==lst[i+3]==lst[i+6]=='O':
				print('---YOU WON---')
				flag = 1
	if flag == 0:
		if lst[1]==lst[5]==lst[9]=='X' or lst[3]==lst[5]==lst[7]=='X':
			print('---YOU LOST---')
			flag = 1
		elif lst[1]==lst[5]==lst[9]=='X' or lst[3]==lst[5]==lst[7]=='O':
			print('---YOU WON---')
			flag = 1
	if flag == 1:
		return True
	else:
		return False
for i in range(1,10):
	if i == 9:
		print('---TIE---')
		board()
		break
	if i%2 == 1:
		board()
		inp = int(input('Enter position:'))
		if inp > 1 and inp < 10 and lst[inp] == ' ':
			lst[inp] = 'O'
		else:
			while True:
				inp = int(input('INCORRECT!!! Enter position again:'))
				if inp > 1 and inp < 10 and lst[inp] == ' ':
					lst[inp] = 'O'
					break
		if win():
			board()
			break
		sp.call('cls',shell=True)
	if i == 2:
		if lst[2] == 'O':
			lst[5] = 'X'
		elif lst[3] != 'O':
			lst[3] = 'X'
		elif lst[9] != 'O':
			lst[9] = 'X'
	elif i == 4:
		if lst[3] == 'X' and lst[2] != 'O':
			lst[2] = 'X'
		elif lst[3] == 'X' and lst[2] == 'O' and lst[7] != 'O' and lst[5] != 'O' and lst[9] != 'O':
			lst[5] = 'X'
		elif lst[3] == 'X' and lst[2] == 'O' and lst[7] == 'O':
			lst[9] = 'X'
		elif lst[3] == 'X' and lst[2] == 'O' and lst[9] == 'O':
			lst[7] = 'X'
		elif lst[9] == 'X' and lst[5] != 'O':
			lst[5] = 'X'
		elif lst[9] == 'X' and lst[5] == 'O':
			lst[7] = 'X'
		elif lst[5] == 'X' and lst[9] != 'O':
			lst[9] = 'X'
		elif lst[5] == 'X' and lst[9] == 'O':
			lst[7] = 'X'
		elif lst[5] == 'O' and lst[2] != 'O':
			lst[2] = 'X'
		elif lst[5] == 'O' and lst[2] == 'O':
			lst[8] = 'X'
	elif i == 6:
		if lst[3] == 'X' and lst[2] == 'O' and lst[5] == 'X':
			if lst[9] != 'O':
				lst[9] = 'X'
			else:
				lst[7] = 'X'
		elif lst[3] == 'X' and lst[2] == 'O' and lst[7] == 'O' and lst[9] == 'X':
			if lst[5] != 'O':
				lst[5] = 'X'
			else:
				lst[6] = 'X'
		elif lst[9] == 'X' and lst[5] == 'O' and lst[7] == 'X':
			if lst[4] != 'O':
				lst[4] = 'X'
			else:
				lst[8] = 'X'
		elif lst[5] == 'X' and lst[9] == 'O' and lst[7] == 'X':
			if lst[4] != 'O':
				lst[4] = 'X'
			else:
				lst[3] = 'X'
		elif lst[3] == 'X' and lst[9] == 'O' and lst[7] == 'X':
			if lst[4] != 'O':
				lst[4] = 'X'
			else:
				lst[5] = 'X'
		elif lst[5] == 'O' and lst[2] == 'O' and lst[8] == 'X':
			if lst[4] == 'O':
				lst[6] = 'X'
			elif lst[6] == 'O':
				lst[4] = 'X'
			elif lst[7] == 'O':
				lst[6] = 'X'
			else:
				lst[4] = 'X'
	elif i == 8:
		for i in range(2,10):
			if lst[i] != 'O' and lst[i] != 'X':
				lst[i] = 'X'
	if win():
		board()
		break


from .Config import Config
from enum import Enum

class FlowType(Enum):
    VF = 1
    MF = 2
    DF = 3

#FlowType = Enum('FlowType', 'VF MF DF')
PatternType = Enum('PatternType', 'CXN AMP')

__all__ = ['FlowType','PatternType','Flows']

class Flows(object):
    """Abstract class to represent flows. Flows have the
    following properties:

    Attributes:
        name: A string representing the name.
        flowType: Enum for type of flow - vf, mf or df
        patternType: Enum for type of design pattern - cxn or amp
        config = {} : dictionary of common configuration properties
    """

    def __init__(self, name, flowType:FlowType, config:Config, patternType:PatternType = 'AMP'):
        """Return a flow object """
        self.name = name
        self.flowType = flowType
        self.config = config
        self.patternType = patternType

    def generate(self, name):
        """Generate the appropriate flow

        """

    def validate(self, name):
        """validate the flow
        """


from typing import Optional

import simple_pid

class Controller:
    """This class wraps an internal PID controller.

    This class is used to control the drone's descent."""

    def __init__(
            self,
            kp: float = 0,
            ki: float = 0,
            kd: float = 0,
            target: float = 0,
            upper_limit: float = 0,
            lower_limit: float = 0,
            update_rate: float = 0,
            scalar: float = 0):
        """
        :param kp: The proportional coefficient of the PID
        :param ki: The integral coefficient of the PID
        :param kd: The derivative coefficient of the PID
        :param target: The initial target value which the PID will approach
        :param upper_limit: The largest value which the PID should output
        :param lower_limit: The smallest value which the PID should output
        :param update_rate: The (approximate) time in seconds between each call to enable.
        :param scalar: A value to offset the result of each update by."""
        self.kp = kp
        self.ki = ki
        self.kd = kd
        self.target = target
        self.upper_limit = upper_limit
        self.lower_limit = lower_limit
        self.update_rate = update_rate
        self.scalar = scalar
        self.pid = simple_pid.PID(
            Kp=self.kp,
            Ki=self.ki,
            Kd=self.kd,
            setpoint=self.target,
            output_limits=(self.lower_limit, self.upper_limit),
            sample_time=self.update_rate,
            auto_mode=False)

    def enable(
            self,
            l_output: Optional[float] = None):
        """Start the pid controller, with an optional last output of the
        previous controller.

        This function is used to transition from another controller to
        this PID controller. It must be called before the update method."""
        self.pid.set_auto_mode(True, last_output=l_output)

    def update(
            self,
            input: float) -> float:
        """Feed a new input value into the controller.

        Be sure to call the enable method prior to this method.

        :param input: The new input value"""
        output = self.pid(input) + self.scalar
        return output

    def set_target(
            self,
            new_target: float):
        """Set the target value for the pid.

        :param new_target: The new target value"""
        self.target = new_target
        self.pid.setpoint = self.target

    def reset(self):
        """Reset the PID's values to all zeros.

        Useful for eliminating integral windup."""
        self.pid.reset()


from .extension import Extension

class MathJax(Extension):
    def run(self, code, path):
        return mathjaxify(code)

def mathjaxify(code):
    splitted = code.split("$$")
    result = ""
    for i, section in enumerate(splitted):
        if i % 2:
            section = section \
                .replace('<em>', '*') \
                .replace('</em>', '*') \
                .replace('<', '<') \
                .replace('>', '>') \
                .replace("&", "&") \
                .replace("\\left{", "\\left[") \
                .replace("\\right.", "\\right]") \
                .replace("\\\n", "\\\\\n")
            result += "<script type='math/tex'>"
            result += section
            result += "</script>"
        else:
            result += section
    return result


from .command import Command
import json

class UpdateNoteCommand(Command):
    def __init__(self, args):
        super().__init__(args)
        self.id = args.id
        self.content = args.content

    def run(self):
        result = self.do_activity({
            "type": "Update",
            "object": {
                "type": "Note",
                "id": self.id,
                "content": self.content,
            }
        })
        print(json.dumps(result, indent=4))


size = int(input('Введите размер списка:'))

def fill_list(size):
    list = []

    for i in range(1, size + 1):
        list.append(int(i))
    return list

def multyply_paired_elements(list):
    new_list = []
    length_list1 = len(list) // 2
    length_list2 = len(list)

    for i in range(length_list1):
        first_element = list[i]
        last_element = list[length_list2 - 1 - i]
        multuply = first_element * last_element
        new_list.append(multuply)
    if length_list2 % 2 != 0:
        first_element = list[i + 1]
        multuply = first_element ** 2
        new_list.append(multuply)
    return new_list

list = fill_list(size)
print(list)
print(multyply_paired_elements(list))


from functools import reduce
import sys

__all__ = [
    'FEATS_10',
    'FEATS_14',
    'FEATS_16',
    'FEATURE_SET_MAP',
    'score_analysis_uniform'
]

_BACKOFF_PENALTY = float(f'1e-{sys.float_info.dig}')

# 10 features described in Khalifa et al., 2020
# Morphological Analysis and Disambiguation for Gulf Arabic: The Interplay
# between Resources and Methods
FEATS_10 = [
    'pos', 'per', 'form_gen', 'form_num', 'asp', 'prc0', 'prc1', 'prc2',
    'prc3', 'enc0'
]

FEATS_14 = [
    'pos', 'per', 'form_gen', 'form_num', 'asp', 'mod', 'vox', 'stt', 'cas',
    'prc0', 'prc1', 'prc2', 'prc3', 'enc0'
]

FEATS_16 = [
    'pos', 'per', 'form_gen', 'form_num', 'asp', 'mod', 'vox', 'stt', 'cas',
    'prc0', 'prc1', 'prc2', 'prc3', 'enc0', 'enc1', 'enc2'
]

FEATURE_SET_MAP = {
    'feats_10': FEATS_10,
    'feats_14': FEATS_14,
    'feats_16': FEATS_16,
}

def score_analysis_uniform(analysis, reference, mle_model=None,
                           tie_breaker=None, features=FEATS_16):
    """Calculate the score of matches given the predictions from the classifier
    and the analyses from the morphological analyzer.
    """

    # for GLF and LEV analyzers that use num for form_num, and gen for form_gen
    if 'form_num' not in analysis.keys():
        analysis['form_num'] = analysis['num']
    if 'form_gen' not in analysis.keys():
        analysis['form_gen'] = analysis['gen']

    score = sum(
        analysis.get(feat, '') == reference.get(feat, '') for feat in features
    )

    if tie_breaker == 'tag':
        score += _tie_breaker_tag(analysis, reference, mle_model)

    if analysis['source'] == 'backoff':
        score -= _BACKOFF_PENALTY

    return score

def _tie_breaker_tag(analysis, reference, mle_model):
    """Calculate the tie breaker score using factored tag and unfactored tag
    probabilities in the training data.
    """

    ordered_feats = mle_model['info']['features']
    score_factored_tag = reduce(lambda x, y: x*y,
                                [mle_model[x].get(analysis.get(x, ''), 0)
                                for x in ordered_feats])
    unfactored_tag = ' '.join(
        f'{x}:{analysis.get(x, "")}' for x in ordered_feats
    )

    score_unfactored_tag = mle_model['unfactored'].get(unfactored_tag, 0)

    return (score_factored_tag + score_unfactored_tag) / 2


import requests
from bs4 import BeautifulSoup
import pandas as pd
from datetime import datetime

# 台北票房觀測站(年度週末冠軍)
def movie_weekend_champion_crawler(year):
    url = "http://www.taipeibo.com/yearly/{}".format(year)
    response = requests.get(url)
    response.encoding ="utf-8"
    soup = BeautifulSoup(response.text, 'lxml')
    crawling_time = datetime.now().strftime('%Y-%m-%d-%H:%M:%S')

    all_rows = soup.table.find_all("tr") # 找出所有 tr 的標籤，並存成 list

    column_name_tag = all_rows[0] # 標題名稱的標籤就是 all_rows 的第一筆資料
    column_name = [text for text in column_name_tag.stripped_strings] # 使用 strpped_strings 找出 tag 底下所有的文字
    movie_df = pd.DataFrame(columns = column_name)
    for i, row in enumerate(all_rows[1:]): # 從第二個 row 開始 iterate (因為第一個 row 是標題)
        data_want = [s for s in row.stripped_strings]
        movie_df.loc[i] = data_want # 設定 DataFrame 的第 i 個 row 是我們抓下來的資訊

    movie_df.columns.values[7] = "冠軍比例"
    movie_df.insert(1, "年度", str(year))
    movie_df['crawling_time'] = crawling_time
    movie_df['crawling_time'] = pd.to_datetime(movie_df['crawling_time'])
    movie_df.columns = [u'週次', u'年度', u'日期', u'週末票房總和', u'漲跌幅', u'冠軍片名', u'英文片名', u'週末票房冠軍', u'冠軍比例', 'crawling_time']
    return(movie_df)
    # 冠軍比例 = 冠軍週末票房 / 北市週末總票房

# 呼叫函數
champion_2017 = movie_weekend_champion_crawler(year = 2017)
champion_2016 = movie_weekend_champion_crawler(year = 2016)
current_year_champion = champion_2017.append(champion_2016)

# 結果存成 CSV
current_year_champion.to_csv("csv_results/movie_weekend_champion.csv", index = False, encoding = "utf-8")

# 結果存進資料庫
import sqlite3
with sqlite3.connect('movie.db') as db:
    current_year_champion.to_sql('weekend_champion', con = db, if_exists = 'replace')

# 從資料庫讀取資料到 DataFrame
with sqlite3.connect('movie.db') as db:
    df = pd.read_sql_query('select * from weekend_champion', con = db)


# Corrutina
def minimize():
    try:
        # La primera vez que se llame a next(), el generador arrancará y se ejecutará hasta encontrar un yield.
        # La llamada a next() es equivalente a send(none), de manera que se guardará None en current,
        # y entonces parará, a esperas de la siguiente llamada
        current = yield

        # El resto de llamadas después del primer next() entrarán en el bucle. Con yield current recogemos el valor que nos llegue cada vez.
        while True:
            value = yield current
            current = min(value, current)

    except GeneratorExit:
        # Cuando alguien llame a close, implícita o explícitamente (ej: al terminar el programa),
        # se lanzará la excepción GeneratorExit dentro del generador. Por supuesto, nosotros
        # podemos capturar dicha excepción, y ejecutar cualquier tarea de limpieza necesaria dentro
        # de nuestro generador
        print("Terminando corrutina")

# Construimos corrutina
it = minimize()

# La iniciamos
next(it)

# Le enviamos valores
print(it.send(10))      # min: 10
print(it.send(1))       # min: 1
print(it.send(1055))    # min: 1
print(it.send(-4))      # min: -4

it.close()  # Llamada explicita a close, aunque no es necesaria


import sys
import theano
import theano.tensor as T
import numpy as np
import cPickle
from data_utils import read_lm_data

sys.path.append("/home/akashb/Desktop/Acads/Summer/Leibnetz/Leibnetz")
sys.path.append("/home/akashb/Desktop/Acads/Summer/Leibnetz/Leibnetz/datasets")

from layers import *
from recurrent_layers import *
from model import *
from optimizers import *
from dataset_utils import *
from regularizers import *
from constraints import *
from model import *

class LangModel(Model):

    def __init__(self, vocab, w_emb_dim, lstm_hidden, model_name="example_lang_model", learning_rate=0.01,
                 init_type='glorot_uniform', use_biases=True,
                 with_batch=False,
                 leak_slope=0.01, clip_threshold=5.0,

                 train_embeddings=True,
                 embedding_constraint=None, embedding_regularizer=None,

                 layer_W_regularizer=None,
                 layer_W_constraint=None, layer_b_regularizer=None, layer_b_constraint=None,
                 layer_activation='softmax',

                 peephole_f=True, peephole_i=True,
                 peephole_o=True, gate_activation='sigmoid',

                 w_hf_regularizer=None, w_xf_regularizer=None, w_cf_regularizer=None, b_f_regularizer=None,
                 w_hu_regularizer=None, w_xu_regularizer=None, b_u_regularizer=None,
                 w_hi_regularizer=None, w_xi_regularizer=None, w_ci_regularizer=None, b_i_regularizer=None,
                 w_ho_regularizer=None, w_xo_regularizer=None, w_co_regularizer=None, b_o_regularizer=None,

                 w_hf_constraint=None, w_xf_constraint=None, w_cf_constraint=None, b_f_constraint=None,
                 w_hu_constraint=None, w_xu_constraint=None, b_u_constraint=None,
                 w_hi_constraint=None, w_xi_constraint=None, w_ci_constraint=None, b_i_constraint=None,
                 w_ho_constraint=None, w_xo_constraint=None, w_co_constraint=None, b_o_constraint=None,
                 lstm_activation='tanh'
                 ):
        super(LangModel, self).__init__()
        assert isinstance(vocab, list), "Vocabulary must be a list of words!"

        # Global model parameters
        self.model_name = model_name
        self.vocab = vocab
        self.w_emb_dim = w_emb_dim
        self.lstm_hidden = lstm_hidden
        self.ip_one_hot = len(vocab)
        self.learning_rate = learning_rate
        self.init_type = init_type
        self.use_biases = use_biases
        self.with_batch = with_batch
        self.leak_slope = leak_slope
        self.clip_threshold = clip_threshold

        # Embedding layer parameters
        self.train_embeddings = train_embeddings
        self.embedding_regularizer = embedding_regularizer
        self.embedding_constraint = embedding_constraint

        # Layer parameters
        self.layer_W_regularizer = layer_W_regularizer
        self.layer_W_constraint = layer_W_constraint
        self.layer_b_regularizer = layer_b_regularizer
        self.layer_b_constraint = layer_b_constraint
        self.layer_activation = layer_activation

        # LSTM specific parameters
        self.peephole_f = peephole_f
        self.peephole_i = peephole_i
        self.peephole_o = peephole_o
        self.gate_activation = gate_activation
        self.lstm_activation = lstm_activation

        self.w_hf_regularizer = w_hf_regularizer
        self.w_xf_regularizer = w_xf_regularizer
        self.w_cf_regularizer = w_cf_regularizer
        self.b_f_regularizer = b_f_regularizer
        self.w_hu_regularizer = w_hu_regularizer
        self.w_xu_regularizer = w_xu_regularizer
        self.b_u_regularizer = b_u_regularizer
        self.w_hi_regularizer = w_hi_regularizer
        self.w_xi_regularizer = w_xi_regularizer
        self.w_ci_regularizer = w_ci_regularizer
        self.b_i_regularizer = b_i_regularizer
        self.w_ho_regularizer = w_ho_regularizer
        self.w_xo_regularizer = w_xo_regularizer
        self.w_co_regularizer = w_co_regularizer
        self.b_o_regularizer = b_o_regularizer

        self.w_hf_constraint = w_hf_constraint
        self.w_xf_constraint = w_xf_constraint
        self.w_cf_constraint = w_cf_constraint
        self.b_f_constraint = b_f_constraint
        self.w_hu_constraint = w_hu_constraint
        self.w_xu_constraint = w_xu_constraint
        self.b_u_constraint = b_u_constraint
        self.w_hi_constraint = w_hi_constraint
        self.w_xi_constraint = w_xi_constraint
        self.w_ci_constraint = w_ci_constraint
        self.b_i_constraint = b_i_constraint
        self.w_ho_constraint = w_ho_constraint
        self.w_xo_constraint = w_xo_constraint
        self.w_co_constraint = w_co_constraint
        self.b_o_constraint = b_o_constraint

        self.optimizer = None

    def build_train(self,

                    embeddings=None,

                    layer_weights=None, layer_biases=None,

                    weights_hf=None, weights_xf=None, weights_cf=None, biases_f=None,
                    weights_hi=None, weights_xi=None, weights_ci=None, biases_i=None,
                    weights_hu=None, weights_xu=None, biases_u=None,
                    weights_ho=None, weights_xo=None, weights_co=None, biases_o=None,

                    rnd_seed=1234
                    ):

        if self.with_batch:
            # self.inputs = T.itensor3("batch_inputs")
            self.inputs = T.imatrix("batch_word_indices")
            self.outputs = T.itensor3("batch_outputs")
        else:
            # self.inputs = T.imatrix("sgd_inputs")
            self.inputs = T.ivector("sgd_word_indices")
            self.outputs = T.imatrix("sgd_outputs")

        self.embed_layer = EmbeddingLayer(layer_name=self.model_name+"_embed_layer",
                                          vocab_size=self.ip_one_hot, embed_size=self.w_emb_dim,
                                          init_type=self.init_type, learning_rate=self.learning_rate,
                                          clip_threshold=self.clip_threshold,
                                          pretrained_embeddings=embeddings,
                                          embedding_constraint=self.embedding_constraint,
                                          embedding_regularizer=self.embedding_regularizer, rnd_seed=rnd_seed,
                                          trainable=self.train_embeddings)
        rnd_seed += 9182

        self.train_ip_projections = self.embed_layer.link(self.inputs, is_train=True)

        self.lstm = LSTM(name=self.model_name+"_batch_lstm", hidden_dim=self.lstm_hidden, input_dim=self.w_emb_dim,
                         peephole_f=self.peephole_f, peephole_i=self.peephole_i,
                         peephole_o=self.peephole_o, gate_activation=self.gate_activation,
                         activation=self.lstm_activation, init_type=self.init_type, with_batch=self.with_batch,
                         leak_slope=self.leak_slope, clip_threshold=self.clip_threshold,
                         weights_hf=weights_hf, weights_xf=weights_xf, weights_cf=weights_cf, biases_f=biases_f,
                         weights_hi=weights_hi, weights_xi=weights_xi, weights_ci=weights_ci, biases_i=biases_i,
                         weights_hu=weights_hu, weights_xu=weights_xu, biases_u=biases_u,
                         weights_ho=weights_ho, weights_xo=weights_xo, weights_co=weights_co, biases_o=biases_o,

                         w_hf_regularizer=self.w_hf_regularizer, w_xf_regularizer=self.w_xf_regularizer,
                         w_cf_regularizer=self.w_cf_regularizer, b_f_regularizer=self.b_f_regularizer,

                         w_hu_regularizer=self.w_hu_regularizer, w_xu_regularizer=self.w_xu_regularizer,
                         b_u_regularizer=self.b_u_regularizer,

                         w_hi_regularizer=self.w_hi_regularizer, w_xi_regularizer=self.w_xi_regularizer,
                         w_ci_regularizer=self.w_ci_regularizer, b_i_regularizer=self.b_i_regularizer,

                         w_ho_regularizer=self.w_ho_regularizer, w_xo_regularizer=self.w_xo_regularizer,
                         w_co_regularizer=self.w_co_regularizer, b_o_regularizer=self.b_o_regularizer,

                         w_hf_constraint=self.w_hf_constraint, w_xf_constraint=self.w_xf_constraint,
                         w_cf_constraint=self.w_cf_constraint,
                         b_f_constraint=self.b_f_constraint,
                         w_hu_constraint=self.w_hu_constraint, w_xu_constraint=self.w_xu_constraint,
                         b_u_constraint=self.b_f_constraint,
                         w_hi_constraint=self.w_hi_constraint, w_xi_constraint=self.w_xi_constraint,
                         w_ci_constraint=self.w_ci_constraint, b_i_constraint=self.b_i_constraint,
                         w_ho_constraint=self.w_ho_constraint, w_xo_constraint=self.w_xo_constraint,
                         w_co_constraint=self.w_co_constraint, b_o_constraint=self.b_o_constraint,

                         use_biases=True, rnd_seed=rnd_seed, trainable=True)

        self.lstm_hids, self.lstm_cs = self.lstm.link(input=self.train_ip_projections, is_train=False)

        rnd_seed+=1349

        self.pred_layer = DenseLayer(name=self.model_name+"_pred_layer", output_dim=self.ip_one_hot,
                                     input_dim=self.lstm_hidden,
                                     activation=self.layer_activation, init_type=self.init_type,
                                     learning_rate=self.learning_rate, leak_slope=self.leak_slope,
                                     clip_threshold=self.clip_threshold, weights=layer_weights, biases=layer_biases,
                                     W_regularizer=self.layer_W_regularizer,
                                     W_constraint=self.layer_W_constraint, b_regularizer=self.layer_b_regularizer,
                                     b_constraint=self.layer_b_constraint, use_bias=self.use_biases, rnd_seed=rnd_seed,
                                     trainable=True)

        self.predictions = self.pred_layer.link(input=self.lstm_hids, is_train=True)

        # Registering components

        self.register_component(self.embed_layer)
        self.register_component(self.lstm)
        self.register_component(self.pred_layer)

        # Configuring train inputs
        self.add_train_input(input_name=self.inputs.name, train_input_tensor=self.inputs)
        # Configuring gold train inputs
        self.add_gold_train_output(output_name=self.pred_layer.layer_name, gold_train_output_tensor=self.outputs)
        # Configuring train model outputs
        self.add_train_output(output_name=self.pred_layer.layer_name, train_output_tensor=self.predictions)

        self.built = True

    def build_test(self):
        """
        Builds the test version of the model. This can differ from the train version of a model if things like dropout
        layers are used. It also compiles the test function.
        """

        assert self.built, "Please build the train version of the model before building the test version!"

        """
        At test time, the input at train time is instead replaced by the output from the previous time step
        """
        if self.with_batch:
            self.test_hid = T.dmatrix("batch_test_hids")
            self.test_c = T.dmatrix("batch_test_cs")
        else:
            self.test_hid = T.dvector("sgd_test_hids")
            self.test_c = T.dvector("sgd_test_cs")

        self.test_ip_projections = self.embed_layer.link(self.inputs, is_train=False)

        self.lstm_test_hids, self.lstm_test_cs = self.lstm.link(input=self.train_ip_projections,
                                                                init_hidden = self.test_hid, init_context = self.test_c,
                                                                is_train=False)

        # self.test_predictions = T.argmax(self.pred_layer.link(input=self.lstm_test_hids, is_train=False))
        self.test_predictions = self.pred_layer.link(input=self.lstm_test_hids, is_train=False)

        # Registering test inputs
        self.add_test_input(input_name=self.inputs.name, test_input_tensor=self.inputs)
        self.add_test_input(input_name=self.test_hid.name, test_input_tensor=self.test_hid)
        self.add_test_input(input_name=self.test_c.name, test_input_tensor=self.test_c)

        # Registering test outputs
        self.add_test_output(output_name=self.lstm.layer_name+"_hids", test_output_tensor=self.lstm_test_hids)
        self.add_test_output(output_name=self.lstm.layer_name+"_contexts", test_output_tensor=self.lstm_test_cs)
        self.add_test_output(output_name=self.pred_layer.layer_name, test_output_tensor=self.test_predictions)

        ordered_test_inputs = self.get_ordered_test_input_tensors()
        ordered_test_outputs = self.get_ordered_test_output_tensors()

        self.model_test_fn = theano.function(inputs=self.get_ordered_test_input_tensors(),
                                             outputs=self.get_ordered_test_output_tensors()
                                             )

        # This test function can now be used to simulate a single step of the decoding process. Since along with the
        # predicted word probabilities, the hidden state and context are also provided, you can seed the states of
        # subsequent states appropriately.

    def train_model(self, train_inputs, train_outputs, val_inputs=None, val_outputs=None,optimizer='batch_gradient_descent', n_epochs=100,
                    clip_threshold=None, rnd_seed=np.random.randint(low=1, high=1000000)):
        batch_size = None
        assert self.built, "Please build the model (at least build the train version) before trying to optimize!"
        assert optimizer=='batch_gradient_descent', "Optimizers other than SGD aren't supported!"

        if clip_threshold is not None:
            assert isinstance(clip_threshold, float) or isinstance(clip_threshold, int) and clip_threshold > 0., \
                "Clip threshold must be a strictly positive value!"

        validate = False
        if all(val is not None for val in [val_inputs, val_outputs]):
            validate = True

        if self.optimizer is None:
            print("Configure the optimizer for the first time")
            batch_optimizer = BatchGradientDescent(model=self, clip_threshold=clip_threshold)
        else:
            batch_optimizer = self.optimizer

        rnd = np.random.RandomState(rnd_seed)
        batch_optimizer.configure_train_inputs(
            input_name_to_input_mat_dict={
                                            self.inputs.name: train_inputs,
                    }
        )

        batch_optimizer.configure_costs_and_gold_outputs(
            output_name_to_cost_gold_mat_dict={
                    self.pred_layer.layer_name  : ("categorical_crossentropy", train_outputs)
                    }
        )

        if validate:
            batch_optimizer.configure_val_inputs(
                val_input_name_to_input_mat_dict={
                    self.inputs.name: train_inputs
                       }
            )

            batch_optimizer.configure_val_outputs(
                val_output_name_to_gold_op_mat_dict={
                    self.pred_layer.layer_name  : train_outputs
                    }
            )

        [self.model_train_fn, self.model_val_fn] = batch_optimizer.train(batch_size=batch_size, n_epochs=n_epochs,
                                                   compile_validation_fn=True, validate=validate,
                                                   rnd=rnd, skip_compile=self.optimizer is not None)

        self.train_fn = batch_optimizer.train_model
        self.optimizer = batch_optimizer

    # def validate(self):
    #     pass

    def apply_model(self, n_steps=10, mode='sample', first_word=0):
        assert (first_word is None or isinstance(first_word, int)), "Supplied first word must be an index into the " \
                "vocabulary or must be unspecified!"
        if self.with_batch:
            ip = np.array(
                [
                    [first_word]
                ] , dtype=np.int32
            )
            hidden = np.array(
                [
                    np.zeros(shape=(self.lstm_hidden,))
                ]
            )
            context = np.array(
                [
                    np.zeros(shape=(self.lstm_hidden,))
                ]
            )
        else:
            ip = np.array(
                [first_word], dtype=np.int32
            )
            hidden =  np.zeros(shape=(self.lstm_hidden,))
            context =  np.zeros(shape=(self.lstm_hidden,))

        step_output = {
                        self.inputs.name  : ip,
                        self.test_hid.name: hidden,
                        self.test_c.name  : context
                      }

        decoded_sequence = []

        for i in range(n_steps):
            output = self.get_ordered_test_output_data(self.model_test_fn(*self.get_ordered_test_input_data({
                self.inputs.name: step_output[self.inputs.name],
                self.test_hid.name   : step_output[self.test_hid.name],
                self.test_c.name    : step_output[self.test_c.name]
            })))

            if mode == 'max':
                pred_id = np.argmax(output[self.pred_layer.layer_name], axis=-1)
                decoded_sequence.append(pred_id)

                if pred_id == len(vocab) - 1:
                    break

                step_output[self.inputs.name] = np.array(
                                                            pred_id, dtype=np.int32
                                                            # [pred_id] if self.with_batch else pred_id, dtype=np.int32
                                                        )
            elif mode == "sample":
                pred_vec = np.random.multinomial(1,output[self.pred_layer.layer_name][-1][-1] if self.with_batch
                                                  else output[self.pred_layer.layer_name][-1] , size=None)
                pred_id = np.argmax(pred_vec)
                decoded_sequence.append(pred_id)

                if pred_id == len(vocab) - 1:
                    break

                step_output[self.inputs.name] = np.array(
                                                                [[pred_id]] if self.with_batch else [pred_id], dtype=np.int32
                                                             )

            step_output[self.test_hid.name] = output[self.lstm.layer_name + "_hids"][:,-1, :] if self.with_batch \
                                                else np.array(output[self.lstm.layer_name + "_hids"][-1])
            step_output[self.test_c.name] = output[self.lstm.layer_name + "_contexts"][:, -1, :] if self.with_batch \
                                                else np.array(output[self.lstm.layer_name + "_contexts"][-1])

        word_sequence = " ".join([self.vocab[i] for i in decoded_sequence])

        return word_sequence

# Instantiating the language model

# vocab = ["<s>","His","Her","name","is","Akash","Deepika","<\s>"]

w_emb_dim = 50
lstm_hidden = 50
n_epochs = 1000
gate_activation = "sigmoid"
init_type='glorot_uniform'

use_batch = True
learning_rate = 10.0 if not use_batch else 1.0
vocab_dict, inv_vocab_dict, composite_data = read_lm_data("./lm_text_data.txt", retain_seq_len_batch=use_batch)
vocab = [inv_vocab_dict[w_index] for w_index in range(len(vocab_dict.keys()))]
# First vocab word is expected to be the start word while the last one is the end word

my_lm = LangModel(vocab=vocab, w_emb_dim=w_emb_dim, lstm_hidden=lstm_hidden,
                  model_name="my_first_lm", learning_rate=learning_rate,
                  peephole_f=True, peephole_i=True,
                  peephole_o=True, gate_activation=gate_activation,
                  init_type=init_type, use_biases=True,
                  with_batch=use_batch,
                  leak_slope=0.01, clip_threshold=5.0,

                  train_embeddings=True,
                  embedding_constraint=None, embedding_regularizer=None,

                  layer_W_regularizer=None,
                  layer_W_constraint=None, layer_b_regularizer=None, layer_b_constraint=None,
                  layer_activation='softmax',

                  w_hf_regularizer=None, w_xf_regularizer=None, w_cf_regularizer=None, b_f_regularizer=None,
                  w_hu_regularizer=None, w_xu_regularizer=None, b_u_regularizer=None,
                  w_hi_regularizer=None, w_xi_regularizer=None, w_ci_regularizer=None, b_i_regularizer=None,
                  w_ho_regularizer=None, w_xo_regularizer=None, w_co_regularizer=None, b_o_regularizer=None,

                  w_hf_constraint=None, w_xf_constraint=None, w_cf_constraint=None, b_f_constraint=None,
                  w_hu_constraint=None, w_xu_constraint=None, b_u_constraint=None,
                  w_hi_constraint=None, w_xi_constraint=None, w_ci_constraint=None, b_i_constraint=None,
                  w_ho_constraint=None, w_xo_constraint=None, w_co_constraint=None, b_o_constraint=None,
                  lstm_activation='tanh')

my_lm.build_train(embeddings=None,

                  layer_weights=None, layer_biases=None,

                  weights_hf=None, weights_xf=None, weights_cf=None, biases_f=None,
                  weights_hi=None, weights_xi=None, weights_ci=None, biases_i=None,
                  weights_hu=None, weights_xu=None, biases_u=None,
                  weights_ho=None, weights_xo=None, weights_co=None, biases_o=None,

                  rnd_seed=1234)
my_lm.build_test()

if not use_batch:
    # toy_inputs = np.array([0,1,3,4,5,7], dtype=np.int32)
    # toy_inputs = np.array(
    #                         [[0, 1, 3, 4, 5, 7],
    #                          [0, 2, 3, 4, 6, 7]]
    #                         , dtype=np.int32
    #                     )
    toy_inputs = [np.array(composite_data_item[0], dtype=np.int32) for composite_data_item in composite_data]
else:
    # toy_inputs = np.array(
    #                         [[0,1,3,4,5,7],
    #                          [0,2,3,4,6,7],
    #                           [0,2,3,4,6,7],
    #                           [0,2,3,4,6,7]]
    #     , dtype=np.int32
    #                      )
    toy_inputs = []
    for seq_len in composite_data.keys():
        toy_inputs.append(np.array([np.array(composite_item[0], dtype=np.int32)
                                                for composite_item in composite_data[seq_len]],
                                   dtype=np.int32))
    # toy_inputs = np.array(toy_inputs, dtype=np.int32)

if not use_batch:
    # toy_outputs = np.array(
    #         [
    #             [[0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0],
    #              [0, 0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 0, 0, 1]],
    #             [[0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0],
    #              [0, 0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 0, 0, 1]]
    #         ],
    #         dtype=np.int32
    #     )
    toy_outputs = [np.array(composite_data_item[1], dtype=np.int32) for composite_data_item in composite_data]
else:
    # toy_outputs = np.array(
    #     [
    #         [[0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0],
    #          [0, 0, 0, 0, 0, 0, 0, 1], [0,0,0,0,0,0,0,1]],
    #         [[0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0],
    #          [0, 0, 0, 0, 0, 0, 0, 1], [0,0,0,0,0,0,0,1]],
    #         [[0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0],
    #          [0, 0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 0, 0, 1]],
    #         [[0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0],
    #          [0, 0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 0, 0, 1]]
    #     ],
    #     dtype=np.int32
    # )

    toy_outputs = []
    for seq_len in composite_data.keys():
        toy_outputs.append(np.array([np.array(composite_item[1], dtype=np.int32)
                                                for composite_item in composite_data[seq_len]],
                                    dtype=np.int32))
    # toy_outputs = np.array(toy_outputs, dtype=np.int32)

# Note: There is a problem when you you use any number o finputs other than 2

assert len(toy_inputs) == len(toy_outputs), "Mismatch between outputs and inputs!"

N = len(toy_inputs)

shuffle_vec = range(len(toy_inputs))

if(use_batch):
    # my_lm.train_model(train_inputs=toy_inputs, train_outputs=toy_outputs, val_inputs=toy_inputs,
    #                   val_outputs=toy_outputs,
    #                   optimizer='batch_gradient_descent', n_epochs=n_epochs,
    #                   clip_threshold=None, rnd_seed=np.random.randint(low=1, high=1000000))
    for epoch in range(n_epochs):
        print("Epoch %d"%(epoch))
        np.random.shuffle(shuffle_vec)
        for index_ind, index in enumerate(shuffle_vec):
            my_lm.train_model(train_inputs=toy_inputs[index], train_outputs=toy_outputs[index],
                              val_inputs=toy_inputs[shuffle_vec[(index_ind+1)%N]],
                              val_outputs=toy_outputs[shuffle_vec[(index_ind+1)%N]],
                          optimizer='batch_gradient_descent', n_epochs=1,
                          clip_threshold=None, rnd_seed=np.random.randint(low=1, high=1000000))
else:
    for epoch in range(n_epochs):
        np.random.shuffle(shuffle_vec)
        print("Epoch %d"%(epoch))
        # for index, toy_input in enumerate(toy_inputs):
        for index_ind, index in enumerate(shuffle_vec):
            toy_input = toy_inputs[index]
            toy_output = toy_outputs[index]
            my_lm.train_model(train_inputs=toy_input, train_outputs=toy_output,
                              val_inputs=toy_inputs[shuffle_vec[(index_ind+1)%N]],
                              val_outputs=toy_outputs[shuffle_vec[(index+1)%N]],
                              optimizer='batch_gradient_descent', n_epochs=1,
                              clip_threshold=None, rnd_seed=np.random.randint(low=1, high=1000000))

print("\n\nDone Training!\n\n")

print("Enter a start word among " , vocab_dict.keys())
word = raw_input("Enter first word:")
while(word is not None):
    assert vocab_dict.has_key(word), "No such word in vocab!"
    print("Sampled sentence starting with " + word + " is:")
    print(my_lm.apply_model(n_steps=10, mode='sample', first_word=vocab_dict[word]))
    print("Greedy max decoding is:")
    print(my_lm.apply_model(n_steps=10, mode='max', first_word=vocab_dict[word]))
    print("Enter a start word among ", vocab_dict.keys())
    word = raw_input("Enter next word or # to end")
    if word == "#":
        word = None

# TO DO:
# 1. Fix the batching issue! Even when restricting to a single train sample, result of SGD is not replicated!
# 2. Implement parallel samplers for n start words, i.e. batch mode sampling!


class Solution:
    def numSubarrayProductLessThanK(self, nums: List[int], k: int) -> int:
        # Initialize the left pointer, result, and value counter

        if k<2:

            return 0

        # Initialize the left pointer, result, and value counter
        left=0
        result=1
        val=0

        # Loop through each element in nums
        for right in range(len(nums)):

            # Update the result to include the current element
            result*=nums[right]

            # While the result is greater than or equal to k,
            # divide it by the leftmost element and move the left pointer               to the right
            while result>=k:

                result/=nums[left]

                left+=1

            # Increment the value counter by the number of subarrays that               end at the current index
            # (i.e. the length of the window from left to right)
            val+=right-left+1

        # Return the total number of subarrays with a product less than k
        return val


#!/usr/bin/env python3
import boto3

INSTANCES = ['i-abcd5678', 'i-abcd1234']
AWS_REGION = 'us-west-2'

ec2_resource = boto3.resource('ec2', region_name=AWS_REGION)
ec2_client = boto3.client('ec2', region_name=AWS_REGION)

# List all specified instances
ec2_instances = ec2_resource.instances.filter(
    InstanceIds=INSTANCES
)

for instance in ec2_instances:

    print('\n===== Checking', instance.id, '=====')

    # Get the current AZ to enable FSR
    az = instance.placement['AvailabilityZone']
    print(instance.placement['AvailabilityZone'])

    # Get the current block device mappings
    for device in instance.block_device_mappings:
        print(device['DeviceName'], device['Ebs']['VolumeId'])

    # Create a snapshot for all volumes
    for volume in instance.volumes.all():
        snapshot = volume.create_snapshot(
            Description= 'for instance ' + instance.id,
            TagSpecifications=[
                {
                    'ResourceType': 'snapshot',
                    'Tags': [
                        {
                            'Key': 'instance',
                            'Value': instance.id
                        },
                    ]
                },
            ]
        )
        print('Snapshot', snapshot.id, 'is created for', snapshot.volume_id)
        enable_fsr = ec2_client.enable_fast_snapshot_restores(
            AvailabilityZones=[
                az
            ],
            SourceSnapshotIds=[
                snapshot.id
            ]
        )
        if enable_fsr['Successful']:
            print('Snapshot', snapshot.id, 'enabled FSR on', az)
        else:
            print('Something went wrong! Exiting...')
            break

'''

Example result

===== Checking i-abcd1234 =====
us-west-2a
/dev/xvda vol-xxx
Snapshot snap-yyy is created for vol-xxx
Snapshot snap-yyy enabled FSR on us-west-2a

===== Checking i-abcd5678 =====
us-west-2c
/dev/xvda vol-aaa
/dev/sdb vol-bbb
Snapshot snap-aaa is created for vol-aaa
Snapshot snap-aaa enabled FSR on us-west-2c
Snapshot snap-bbb is created for vol-bbb
Snapshot snap-bbb enabled FSR on us-west-2c

'''


import re,math
import hashlib
from PIL import Image,ImageDraw
import HSL

# https://avatars2.githubusercontent.com/u/62230282?s=400&v=5
# https://cdn.v2ex.com/gravatar/8a426e1ecdc693b9c9e528b1465cefad?s=73&d=retro

# 62230282		216	41	80		789acd		85014617f14d6f9 131fb8f8d3995f391
# 62071247		97	40	86		a4db83		764eca8765bfa13 1037d372c34567e52
# 61263923		182	32	88		99dee1		49ffc41ce302043 80e584364181c880d

defaults = {
    "background": (240, 240, 240, 255),
    "margin":     1/12,
    "size":       420,
    "saturation": 0.46,
    "brightness": 0.637
}

def gen_icon(text):
    hash = hashlib.md5(text.encode()).hexdigest()
    # print(text,hash)
    size       = defaults["size"]
    baseMargin = math.floor(size * defaults["margin"])
    cell       = math.floor((size - (baseMargin * 2)) / 5)
    margin     = math.floor((size - cell * 5) / 2)

    hue = int(hash[-7:],16) / 0xfffffff
    foreground = HSL.hsl2rgb([hue, defaults["saturation"], defaults["brightness"]])
    icon = Image.new(mode="RGBA",size=(size,size),color=defaults["background"])
    draw = ImageDraw.Draw(icon)
    for i in range(15):
        if int(hash[i],16) % 2 == 0:
            if i < 5:
                draw.rectangle((2 * cell + margin,i * cell + margin,3 * cell + margin,(i + 1) * cell + margin),fill=foreground)
            elif i < 10:
                draw.rectangle((1 * cell + margin,(i - 5) * cell + margin,2 * cell + margin,(i - 4) * cell + margin),fill=foreground)
                draw.rectangle((3 * cell + margin,(i - 5) * cell + margin,4 * cell + margin,(i - 4) * cell + margin),fill=foreground)
            else:
                draw.rectangle((0 * cell + margin,(i - 10) * cell + margin,1 * cell + margin,(i - 9) * cell + margin),fill=foreground)
                draw.rectangle((4 * cell + margin,(i - 10) * cell + margin,5 * cell + margin,(i - 9) * cell + margin),fill=foreground)
    icon.save("gen/"+text+".png")

flag = "flag{ZhEnDeShAnGtOu}"
for txt in re.findall(r'.{2}',flag):
    gen_icon(txt)
# gen_icon("62230282")