<commit_before>import os
import djcelery
djcelery.setup_loader()

_ = gettext = lambda s: s

DEBUG = True
TEMPLATE_DEBUG = DEBUG
TASTYPIE_FULL_DEBUG = True

PRODUCTION_DOMAIN = 'readthedocs.org'
USE_SUBDOMAIN = False

ADMINS = (
    ('Charlie Leifer', 'coleifer@gmail.com'),
    ('Eric Holscher', 'eric@ericholscher.com'),
)

MANAGERS = ADMINS

SITE_ROOT = '/'.join(os.path.dirname(__file__).split('/')[0:-2])
DOCROOT = os.path.join(SITE_ROOT, 'user_builds')
UPLOAD_ROOT = os.path.join(SITE_ROOT, 'user_uploads')
CNAME_ROOT = os.path.join(SITE_ROOT, 'cnames')
LOGS_ROOT = os.path.join(SITE_ROOT, 'logs')

MEDIA_ROOT = '%s/media/' % (SITE_ROOT)
MEDIA_URL = '/media/'
ADMIN_MEDIA_PREFIX = '/media/admin/'
# For 1.4
STATIC_ROOT = os.path.join(SITE_ROOT, 'media/static/')
STATIC_URL = '/static/'
#STATICFILES_DIRS = ()
#STATICFILES_FINDERS = ()

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
        'PREFIX': 'docs',
    }
}

CACHE_MIDDLEWARE_SECONDS = 60

LOGIN_REDIRECT_URL = '/dashboard/'
FORCE_WWW = False
#APPEND_SLASH = False

TIME_ZONE = 'America/Chicago'
LANGUAGE_CODE = 'en-us'
LANGUAGES = (
    ('en', gettext('English')),
    ('nb', gettext('Norwegian')),
    ('fr', gettext('French')),
)

USE_I18N = True
USE_L10N = True
SITE_ID = 1
SECRET_KEY = 'asciidick'

ACCOUNT_ACTIVATION_DAYS = 7

TEMPLATE_LOADERS = (
    'django.template.loaders.filesystem.Loader',
    'django.template.loaders.app_directories.Loader',
)

MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.locale.LocaleMiddleware',
    'django.middleware.common.CommonMiddleware',
    'djangosecure.middleware.SecurityMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'pagination.middleware.PaginationMiddleware',
    # Hack
    # 'core.underscore_middleware.UnderscoreMiddleware',
    'core.middleware.SubdomainMiddleware',
    'corsheaders.middleware.CorsMiddleware',
    #'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
)

CORS_ORIGIN_REGEX_WHITELIST = ('^http://(.+)\.readthedocs\.org$', '^https://(.+)\.readthedocs\.org$')
# So people can post to their accounts
CORS_ALLOW_CREDENTIALS = True
ROOT_URLCONF = 'urls'

TEMPLATE_DIRS = (
    '%s/readthedocs/templates/' % SITE_ROOT,
)

TEMPLATE_CONTEXT_PROCESSORS = (
    "django.contrib.auth.context_processors.auth",
    "django.core.context_processors.debug",
    "django.core.context_processors.i18n",
    "django.core.context_processors.media",
    "django.core.context_processors.request",
    "core.context_processors.readthedocs_processor",
)

INSTALLED_APPS = [
    'django.contrib.auth',
    'django.contrib.admin',
    'django.contrib.contenttypes',
    'django.contrib.markup',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.staticfiles',

    # third party apps
    'pagination',
    'registration',
    'profiles',
    'taggit',
    'south',
    'basic.flagging',
    'djangosecure',
    'guardian',
    'django_gravatar',
    'django_nose',
    'rest_framework',
    'corsheaders',

    # Celery bits
    'djcelery',
    'celery_haystack',

    # daniellindsleyrocksdahouse
    'haystack',
    'tastypie',

    # our apps
    'projects',
    'builds',
    'core',
    'rtd_tests',
    'websupport',
]

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAdminUser',),
    'PAGINATE_BY': 10
}

if DEBUG:
    INSTALLED_APPS.append('django_extensions')

#CARROT_BACKEND = "ghettoq.taproot.Database"
CELERY_ALWAYS_EAGER = True
CELERYD_TASK_TIME_LIMIT = 60*60  # 60 minutes
CELERY_SEND_TASK_ERROR_EMAILS = True
CELERYD_HIJACK_ROOT_LOGGER = False
HAYSTACK_SIGNAL_PROCESSOR = 'celery_haystack.signals.CelerySignalProcessor'

CELERY_ROUTES = {
    'celery_haystack.tasks.CeleryHaystackSignalHandler': {
        'queue': 'celery_haystack',
    },
    'projects.tasks.fileify': {
        'queue': 'celery_haystack',
    },
}

DEFAULT_FROM_EMAIL = "no-reply@readthedocs.org"
SESSION_COOKIE_DOMAIN = 'readthedocs.org'

HAYSTACK_CONNECTIONS = {
    'default': {
        'ENGINE': 'haystack.backends.simple_backend.SimpleEngine',
    },
}

# Elasticsearch settings.
ES_HOSTS = ['127.0.0.1:9200']
ES_DEFAULT_NUM_REPLICAS = 0
ES_DEFAULT_NUM_SHARDS = 5

AUTH_PROFILE_MODULE = "core.UserProfile"
SOUTH_TESTS_MIGRATE = False

ABSOLUTE_URL_OVERRIDES = {
    'auth.user': lambda o: "/profiles/%s/" % o.username
}

INTERNAL_IPS = ('127.0.0.1',)

IMPORT_EXTERNAL_DATA = True

backup_count = 1000
maxBytes = 500 * 100 * 100
if DEBUG:
    backup_count = 2
    maxBytes = 500 * 100 * 10

# Guardian Settings
GUARDIAN_RAISE_403 = True
ANONYMOUS_USER_ID = -1

# RTD Settings
REPO_LOCK_SECONDS = 30
ALLOW_PRIVATE_REPOS = False

LOG_FORMAT = "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s"

LOGGING = {
    'version': 1,
    'disable_existing_loggers': True,
    'formatters': {
        'standard': {
            'format': LOG_FORMAT,
            'datefmt': "%d/%b/%Y %H:%M:%S"
        },
    },
    'filters': {
         'require_debug_false': {
             '()': 'django.utils.log.RequireDebugFalse'
         }
     },
    'handlers': {
        'null': {
            'level': 'DEBUG',
            'class': 'django.utils.log.NullHandler',
        },
        'exceptionlog': {
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': os.path.join(LOGS_ROOT, "exceptions.log"),
            'maxBytes': maxBytes,
            'backupCount': backup_count,
            'formatter': 'standard',
        },
        'errorlog': {
            'level': 'INFO',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': os.path.join(LOGS_ROOT, "rtd.log"),
            'maxBytes': maxBytes,
            'backupCount': backup_count,
            'formatter': 'standard',
        },
        'postcommit': {
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': os.path.join(LOGS_ROOT, "postcommit.log"),
            'maxBytes': maxBytes,
            'backupCount': backup_count,
            'formatter': 'standard',
        },
        'middleware': {
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': os.path.join(LOGS_ROOT, "middleware.log"),
            'maxBytes': maxBytes,
            'backupCount': backup_count,
            'formatter': 'standard',
        },
        'restapi': {
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': os.path.join(LOGS_ROOT, "api.log"),
            'maxBytes': maxBytes,
            'backupCount': backup_count,
            'formatter': 'standard',
        },
        'db': {
            'level': 'INFO',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': os.path.join(LOGS_ROOT, "db.log"),
            'maxBytes': maxBytes,
            'backupCount': backup_count,
            'formatter': 'standard',
        },
        'mail_admins': {
            'level': 'ERROR',
             'filters': ['require_debug_false'],
            'class': 'django.utils.log.AdminEmailHandler',
        },
        'console': {
            'level': 'INFO',
            'class': 'logging.StreamHandler',
            'formatter': 'standard'
        },
    },
    'loggers': {
        'django': {
            'handlers': ['console', 'errorlog'],
            'propagate': True,
            'level': 'WARN',
        },
        'django.db.backends': {
            'handlers': ['db'],
            'level': 'DEBUG',
            'propagate': False,
        },
        'core.views.post_commit': {
            'handlers': ['postcommit'],
            'level': 'DEBUG',
            'propagate': False,
        },
        'core.middleware': {
            'handlers': ['middleware'],
            'level': 'DEBUG',
            'propagate': False,
        },
        'restapi': {
            'handlers': ['restapi'],
            'level': 'DEBUG',
            'propagate': False,
        },
        'django.request': {
            'handlers': ['mail_admins', 'exceptionlog'],
            'level': 'ERROR',
            'propagate': False,
        },
        # Uncomment if you want to see Elasticsearch queries in the console.
        #'elasticsearch.trace': {
        #    'level': 'DEBUG',
        #    'handlers': ['console'],
        #},

        # Default handler for everything that we're doing. Hopefully this
        # doesn't double-print the Django things as well. Not 100% sure how
        # logging works :)
        '': {
            'handlers': ['console', 'errorlog'],
            'level': 'DEBUG',
        },
    }
}
<commit_msg>Changes for 1.6<commit_after>import os
import djcelery
djcelery.setup_loader()

_ = gettext = lambda s: s

DEBUG = True
TEMPLATE_DEBUG = DEBUG
TASTYPIE_FULL_DEBUG = True

PRODUCTION_DOMAIN = 'readthedocs.org'
USE_SUBDOMAIN = False

ADMINS = (
    ('Charlie Leifer', 'coleifer@gmail.com'),
    ('Eric Holscher', 'eric@ericholscher.com'),
)

MANAGERS = ADMINS

SITE_ROOT = '/'.join(os.path.dirname(__file__).split('/')[0:-2])
DOCROOT = os.path.join(SITE_ROOT, 'user_builds')
UPLOAD_ROOT = os.path.join(SITE_ROOT, 'user_uploads')
CNAME_ROOT = os.path.join(SITE_ROOT, 'cnames')
LOGS_ROOT = os.path.join(SITE_ROOT, 'logs')

MEDIA_ROOT = '%s/media/' % (SITE_ROOT)
MEDIA_URL = '/media/'
ADMIN_MEDIA_PREFIX = '/media/admin/'
# For 1.4
STATIC_ROOT = os.path.join(SITE_ROOT, 'media/static/')
STATIC_URL = '/static/'
#STATICFILES_DIRS = ()
#STATICFILES_FINDERS = ()

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
        'PREFIX': 'docs',
    }
}

CACHE_MIDDLEWARE_SECONDS = 60

LOGIN_REDIRECT_URL = '/dashboard/'
FORCE_WWW = False
#APPEND_SLASH = False

TIME_ZONE = 'America/Chicago'
LANGUAGE_CODE = 'en-us'
LANGUAGES = (
    ('en', gettext('English')),
    ('nb', gettext('Norwegian')),
    ('fr', gettext('French')),
)

USE_I18N = True
USE_L10N = True
SITE_ID = 1
SECRET_KEY = 'asciidick'

ACCOUNT_ACTIVATION_DAYS = 7

TEMPLATE_LOADERS = (
    'django.template.loaders.filesystem.Loader',
    'django.template.loaders.app_directories.Loader',
)

MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.locale.LocaleMiddleware',
    'django.middleware.common.CommonMiddleware',
    'djangosecure.middleware.SecurityMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'pagination.middleware.PaginationMiddleware',
    # Hack
    # 'core.underscore_middleware.UnderscoreMiddleware',
    'core.middleware.SubdomainMiddleware',
    'corsheaders.middleware.CorsMiddleware',
    #'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
)

CORS_ORIGIN_REGEX_WHITELIST = ('^http://(.+)\.readthedocs\.org$', '^https://(.+)\.readthedocs\.org$')
# So people can post to their accounts
CORS_ALLOW_CREDENTIALS = True
ROOT_URLCONF = 'urls'

TEMPLATE_DIRS = (
    '%s/readthedocs/templates/' % SITE_ROOT,
)

TEMPLATE_CONTEXT_PROCESSORS = (
    "django.contrib.auth.context_processors.auth",
    "django.core.context_processors.debug",
    "django.core.context_processors.i18n",
    "django.core.context_processors.media",
    "django.core.context_processors.request",
    "core.context_processors.readthedocs_processor",
)

INSTALLED_APPS = [
    'django.contrib.auth',
    'django.contrib.admin',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.staticfiles',

    # third party apps
    'pagination',
    'registration',
    'profiles',
    'taggit',
    'south',
    'basic.flagging',
    'djangosecure',
    'guardian',
    'django_gravatar',
    'django_nose',
    'rest_framework',
    'corsheaders',

    # Celery bits
    'djcelery',
    'celery_haystack',

    # daniellindsleyrocksdahouse
    'haystack',
    'tastypie',

    # our apps
    'projects',
    'builds',
    'core',
    'rtd_tests',
    'websupport',
]

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAdminUser',),
    'PAGINATE_BY': 10
}

if DEBUG:
    INSTALLED_APPS.append('django_extensions')

#CARROT_BACKEND = "ghettoq.taproot.Database"
CELERY_ALWAYS_EAGER = True
CELERYD_TASK_TIME_LIMIT = 60*60  # 60 minutes
CELERY_SEND_TASK_ERROR_EMAILS = True
CELERYD_HIJACK_ROOT_LOGGER = False
HAYSTACK_SIGNAL_PROCESSOR = 'celery_haystack.signals.CelerySignalProcessor'

CELERY_ROUTES = {
    'celery_haystack.tasks.CeleryHaystackSignalHandler': {
        'queue': 'celery_haystack',
    },
    'projects.tasks.fileify': {
        'queue': 'celery_haystack',
    },
}

DEFAULT_FROM_EMAIL = "no-reply@readthedocs.org"
SESSION_COOKIE_DOMAIN = 'readthedocs.org'

HAYSTACK_CONNECTIONS = {
    'default': {
        'ENGINE': 'haystack.backends.simple_backend.SimpleEngine',
    },
}

# Elasticsearch settings.
ES_HOSTS = ['127.0.0.1:9200']
ES_DEFAULT_NUM_REPLICAS = 0
ES_DEFAULT_NUM_SHARDS = 5

AUTH_PROFILE_MODULE = "core.UserProfile"
SOUTH_TESTS_MIGRATE = False

ABSOLUTE_URL_OVERRIDES = {
    'auth.user': lambda o: "/profiles/%s/" % o.username
}

INTERNAL_IPS = ('127.0.0.1',)

IMPORT_EXTERNAL_DATA = True

backup_count = 1000
maxBytes = 500 * 100 * 100
if DEBUG:
    backup_count = 2
    maxBytes = 500 * 100 * 10

# Guardian Settings
GUARDIAN_RAISE_403 = True
ANONYMOUS_USER_ID = -1

# RTD Settings
REPO_LOCK_SECONDS = 30
ALLOW_PRIVATE_REPOS = False

LOG_FORMAT = "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s"

LOGGING = {
    'version': 1,
    'disable_existing_loggers': True,
    'formatters': {
        'standard': {
            'format': LOG_FORMAT,
            'datefmt': "%d/%b/%Y %H:%M:%S"
        },
    },
    'filters': {
         'require_debug_false': {
             '()': 'django.utils.log.RequireDebugFalse'
         }
     },
    'handlers': {
        'null': {
            'level': 'DEBUG',
            'class': 'django.utils.log.NullHandler',
        },
        'exceptionlog': {
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': os.path.join(LOGS_ROOT, "exceptions.log"),
            'maxBytes': maxBytes,
            'backupCount': backup_count,
            'formatter': 'standard',
        },
        'errorlog': {
            'level': 'INFO',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': os.path.join(LOGS_ROOT, "rtd.log"),
            'maxBytes': maxBytes,
            'backupCount': backup_count,
            'formatter': 'standard',
        },
        'postcommit': {
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': os.path.join(LOGS_ROOT, "postcommit.log"),
            'maxBytes': maxBytes,
            'backupCount': backup_count,
            'formatter': 'standard',
        },
        'middleware': {
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': os.path.join(LOGS_ROOT, "middleware.log"),
            'maxBytes': maxBytes,
            'backupCount': backup_count,
            'formatter': 'standard',
        },
        'restapi': {
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': os.path.join(LOGS_ROOT, "api.log"),
            'maxBytes': maxBytes,
            'backupCount': backup_count,
            'formatter': 'standard',
        },
        'db': {
            'level': 'INFO',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': os.path.join(LOGS_ROOT, "db.log"),
            'maxBytes': maxBytes,
            'backupCount': backup_count,
            'formatter': 'standard',
        },
        'mail_admins': {
            'level': 'ERROR',
             'filters': ['require_debug_false'],
            'class': 'django.utils.log.AdminEmailHandler',
        },
        'console': {
            'level': 'INFO',
            'class': 'logging.StreamHandler',
            'formatter': 'standard'
        },
    },
    'loggers': {
        'django': {
            'handlers': ['console', 'errorlog'],
            'propagate': True,
            'level': 'WARN',
        },
        'django.db.backends': {
            'handlers': ['db'],
            'level': 'DEBUG',
            'propagate': False,
        },
        'core.views.post_commit': {
            'handlers': ['postcommit'],
            'level': 'DEBUG',
            'propagate': False,
        },
        'core.middleware': {
            'handlers': ['middleware'],
            'level': 'DEBUG',
            'propagate': False,
        },
        'restapi': {
            'handlers': ['restapi'],
            'level': 'DEBUG',
            'propagate': False,
        },
        'django.request': {
            'handlers': ['mail_admins', 'exceptionlog'],
            'level': 'ERROR',
            'propagate': False,
        },
        # Uncomment if you want to see Elasticsearch queries in the console.
        #'elasticsearch.trace': {
        #    'level': 'DEBUG',
        #    'handlers': ['console'],
        #},

        # Default handler for everything that we're doing. Hopefully this
        # doesn't double-print the Django things as well. Not 100% sure how
        # logging works :)
        '': {
            'handlers': ['console', 'errorlog'],
            'level': 'DEBUG',
        },
    }
}
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
# vim:fenc=utf-8
#
# Copyright © 2019 Shlomi Fish <shlomif@cpan.org>
#
# Distributed under the terms of the Expat license.

import platform

from cffi import FFI

class BlackHoleSolver(object):
    # TEST:$num_befs_weights=5;
    NUM_BEFS_WEIGHTS = 5
    FCS_STATE_SUSPEND_PROCESS = 5
    BHS__BLACK_HOLE__BITS_PER_COL = 2
    BHS__BLACK_HOLE__MAX_NUM_CARDS_IN_COL = 3
    BHS__BLACK_HOLE__NUM_COLUMNS = 17

    def __init__(self, ffi=None, lib=None):
        if ffi:
            self.ffi = ffi
            self.lib = lib
        else:
            self.ffi = FFI()
            self.lib = self.ffi.dlopen(
                "libblack_hole_solver." + (
                    "dll" if (platform.system() == 'Windows') else "so"))
            self.ffi.cdef('''
typedef struct
{
    unsigned long nothing;
} black_hole_solver_instance_t;
int black_hole_solver_create(
black_hole_solver_instance_t **ret_instance);

int black_hole_solver_read_board(
black_hole_solver_instance_t *instance, const char *board_string,
int *error_line_number, unsigned int num_columns,
unsigned int max_num_cards_in_col, unsigned int bits_per_column);

int black_hole_solver_set_max_iters_limit(
black_hole_solver_instance_t *instance, unsigned long limit);

int black_hole_solver_enable_place_queens_on_kings(
black_hole_solver_instance_t *instance, bool enabled_status);

int black_hole_solver_enable_wrap_ranks(
black_hole_solver_instance_t *instance, bool enabled_status);

int black_hole_solver_enable_rank_reachability_prune(
black_hole_solver_instance_t *instance, bool enabled_status);

#define BLACK_HOLE_SOLVER__API__REQUIRES_SETUP_CALL 1
int black_hole_solver_config_setup(
black_hole_solver_instance_t *instance);
int black_hole_solver_setup(
black_hole_solver_instance_t *instance);

int black_hole_solver_run(
black_hole_solver_instance_t *instance);

int black_hole_solver_recycle(
black_hole_solver_instance_t *instance);

int black_hole_solver_free(
black_hole_solver_instance_t *instance);

void black_hole_solver_init_solution_moves(
black_hole_solver_instance_t *instance);
int black_hole_solver_get_next_move(
black_hole_solver_instance_t *instance, int *col_idx_ptr,
int *card_rank_ptr, int *card_suit_ptr /* Will return H=0, C=1, D=2, S=3 */
);

unsigned long black_hole_solver_get_num_states_in_collection(
black_hole_solver_instance_t *instance);

unsigned long black_hole_solver_get_iterations_num(
black_hole_solver_instance_t *instance);

int black_hole_solver_get_current_solution_board(
black_hole_solver_instance_t *instance, char *output);

const char *black_hole_solver_get_lib_version(void);
''')
        self.user = self.ffi.new('black_hole_solver_instance_t * *')
        self.error_on_line = self.ffi.new('int *')
        assert 0 == self.lib.black_hole_solver_create(self.user)
        self.lib.black_hole_solver_enable_rank_reachability_prune(
            self.user[0], 1)
        self.lib.black_hole_solver_enable_wrap_ranks(self.user[0], 1)
        self.lib.black_hole_solver_enable_place_queens_on_kings(
            self.user[0], 1)
        self.lib.black_hole_solver_config_setup(self.user[0])

    def new_bhs_user_handle(self):
        return self.__class__(ffi=self.ffi, lib=self.lib)

    def ret_code_is_suspend(self, ret_code):
        """docstring for ret_code_is_suspend"""
        return ret_code == self.FCS_STATE_SUSPEND_PROCESS

    def get_next_move(self):
        move = self.ffi.new('fcs_move_t *')
        num_moves = self.lib.freecell_solver_user_get_moves_left(self.user)
        if not num_moves:
            return None
        ret = self.lib.freecell_solver_user_get_next_move(self.user, move)
        success = 0
        return (move if ret == success else None)

    def input_cmd_line(self, cmd_line_args):
        last_arg = self.ffi.new('int *')
        error_string = self.ffi.new('char * *')
        known_params = self.ffi.new('char * *')
        opened_files_dir = self.ffi.new('char [32001]')

        prefix = 'freecell_solver_user_cmd_line'
        func = 'parse_args_with_file_nesting_count'

        getattr(self.lib, prefix + '_' + func)(
            self.user,  # instance
            len(cmd_line_args),    # argc
            [self.ffi.new('char[]', bytes(s, 'UTF-8')) \
             for s in cmd_line_args],  # argv
            0,   # start_arg
            known_params,  # known_params
            self.ffi.NULL,   # callback
            self.ffi.NULL,   # callback_context
            error_string,  # error_string
            last_arg,   # last_arg
            -1,  # file_nesting_count
            opened_files_dir
        )

        return {'last_arg': last_arg[0],
                'cmd_line_args_len': len(cmd_line_args)}

    def __del__(self):
        self.lib.black_hole_solver_free(self.user[0])

    def read_board(self, board):
        ret = self.lib.black_hole_solver_read_board(
            self.user[0],
            bytes(board, 'UTF-8'),
            self.error_on_line,
            self.BHS__BLACK_HOLE__NUM_COLUMNS,
            self.BHS__BLACK_HOLE__MAX_NUM_CARDS_IN_COL,
            self.BHS__BLACK_HOLE__BITS_PER_COL,
        )
        assert ret == 0
        assert 0 == self.lib.black_hole_solver_setup(self.user[0])
        return ret

    def resume_solution(self):
        return self.lib.black_hole_solver_run(self.user[0])

    def limit_iterations(self, max_iters):
        self.lib.black_hole_solver_set_max_iters_limit(
            self.user[0],
            max_iters
        )

    def get_num_times(self):
        return self.lib.freecell_solver_user_get_num_times_long(
            self.user)

    def get_num_states_in_collection(self):
        return self.lib.freecell_solver_user_get_num_states_in_collection_long(
            self.user)

    def recycle(self):
        self.lib.freecell_solver_user_recycle(self.user)
<commit_msg>refactoring<commit_after># -*- coding: utf-8 -*-
# vim:fenc=utf-8
#
# Copyright © 2019 Shlomi Fish <shlomif@cpan.org>
#
# Distributed under the terms of the Expat license.

import platform

from cffi import FFI

class BlackHoleSolver(object):
    # TEST:$num_befs_weights=5;
    NUM_BEFS_WEIGHTS = 5
    FCS_STATE_SUSPEND_PROCESS = 5
    BHS__BLACK_HOLE__BITS_PER_COL = 2
    BHS__BLACK_HOLE__MAX_NUM_CARDS_IN_COL = 3
    BHS__BLACK_HOLE__NUM_COLUMNS = 17

    def __init__(self, ffi=None, lib=None):
        if ffi:
            self.ffi = ffi
            self.lib = lib
        else:
            self.ffi = FFI()
            self.lib = self.ffi.dlopen(
                "libblack_hole_solver." + (
                    "dll" if (platform.system() == 'Windows') else "so"))
            self.ffi.cdef('''
typedef struct
{
    unsigned long nothing;
} black_hole_solver_instance_t;
int black_hole_solver_create(
black_hole_solver_instance_t **ret_instance);

int black_hole_solver_read_board(
black_hole_solver_instance_t *instance, const char *board_string,
int *error_line_number, unsigned int num_columns,
unsigned int max_num_cards_in_col, unsigned int bits_per_column);

int black_hole_solver_set_max_iters_limit(
black_hole_solver_instance_t *instance, unsigned long limit);

int black_hole_solver_enable_place_queens_on_kings(
black_hole_solver_instance_t *instance, bool enabled_status);

int black_hole_solver_enable_wrap_ranks(
black_hole_solver_instance_t *instance, bool enabled_status);

int black_hole_solver_enable_rank_reachability_prune(
black_hole_solver_instance_t *instance, bool enabled_status);

#define BLACK_HOLE_SOLVER__API__REQUIRES_SETUP_CALL 1
int black_hole_solver_config_setup(
black_hole_solver_instance_t *instance);
int black_hole_solver_setup(
black_hole_solver_instance_t *instance);

int black_hole_solver_run(
black_hole_solver_instance_t *instance);

int black_hole_solver_recycle(
black_hole_solver_instance_t *instance);

int black_hole_solver_free(
black_hole_solver_instance_t *instance);

void black_hole_solver_init_solution_moves(
black_hole_solver_instance_t *instance);
int black_hole_solver_get_next_move(
black_hole_solver_instance_t *instance, int *col_idx_ptr,
int *card_rank_ptr, int *card_suit_ptr /* Will return H=0, C=1, D=2, S=3 */
);

unsigned long black_hole_solver_get_num_states_in_collection(
black_hole_solver_instance_t *instance);

unsigned long black_hole_solver_get_iterations_num(
black_hole_solver_instance_t *instance);

int black_hole_solver_get_current_solution_board(
black_hole_solver_instance_t *instance, char *output);

const char *black_hole_solver_get_lib_version(void);
''')
        self.user_container = self.ffi.new('black_hole_solver_instance_t * *')
        self.error_on_line = self.ffi.new('int *')
        assert 0 == self.lib.black_hole_solver_create(self.user_container)
        self.user = self.user_container[0]
        self.lib.black_hole_solver_enable_rank_reachability_prune(
            self.user, 1)
        self.lib.black_hole_solver_enable_wrap_ranks(self.user, 1)
        self.lib.black_hole_solver_enable_place_queens_on_kings(
            self.user, 1)
        self.lib.black_hole_solver_config_setup(self.user)

    def new_bhs_user_handle(self):
        return self.__class__(ffi=self.ffi, lib=self.lib)

    def ret_code_is_suspend(self, ret_code):
        """docstring for ret_code_is_suspend"""
        return ret_code == self.FCS_STATE_SUSPEND_PROCESS

    def get_next_move(self):
        move = self.ffi.new('fcs_move_t *')
        num_moves = self.lib.freecell_solver_user_get_moves_left(self.user)
        if not num_moves:
            return None
        ret = self.lib.freecell_solver_user_get_next_move(self.user, move)
        success = 0
        return (move if ret == success else None)

    def input_cmd_line(self, cmd_line_args):
        return {'last_arg': 0,
                'cmd_line_args_len': len(cmd_line_args)}

    def __del__(self):
        self.lib.black_hole_solver_free(self.user)

    def read_board(self, board):
        ret = self.lib.black_hole_solver_read_board(
            self.user,
            bytes(board, 'UTF-8'),
            self.error_on_line,
            self.BHS__BLACK_HOLE__NUM_COLUMNS,
            self.BHS__BLACK_HOLE__MAX_NUM_CARDS_IN_COL,
            self.BHS__BLACK_HOLE__BITS_PER_COL,
        )
        assert ret == 0
        assert 0 == self.lib.black_hole_solver_setup(self.user)
        return ret

    def resume_solution(self):
        return self.lib.black_hole_solver_run(self.user)

    def limit_iterations(self, max_iters):
        self.lib.black_hole_solver_set_max_iters_limit(
            self.user,
            max_iters
        )

    def get_num_times(self):
        return self.lib.freecell_solver_user_get_num_times_long(
            self.user)

    def get_num_states_in_collection(self):
        return self.lib.freecell_solver_user_get_num_states_in_collection_long(
            self.user)

    def recycle(self):
        self.lib.freecell_solver_user_recycle(self.user)
<|endoftext|>


<commit_before>"""Base Schema setup for api."""
from fm_database.base import get_session
from marshmallow_sqlalchemy import SQLAlchemyAutoSchema, SQLAlchemyAutoSchemaOpts

session = get_session()

# pylint: disable=too-few-public-methods
class BaseOpts(SQLAlchemyAutoSchemaOpts):
    """Define a BaseOpts with a common Session object.

    https://marshmallow-sqlalchemy.readthedocs.io/en/latest/recipes.html#base-schema-ii
    """

    def __init__(self, meta, ordered=False):
        """Add a sqla_session if it doesn't already exist."""
        if not hasattr(meta, "sqla_session"):
            meta.sqla_session = session()
        super().__init__(meta, ordered=ordered)

class BaseSchema(SQLAlchemyAutoSchema):
    """Define a BaseSchema with a common Session object.

    https://marshmallow-sqlalchemy.readthedocs.io/en/latest/recipes.html#base-schema-ii
    """

    OPTIONS_CLASS = BaseOpts
<commit_msg>ignore mypy error<commit_after>"""Base Schema setup for api."""
from fm_database.base import get_session
from marshmallow_sqlalchemy import SQLAlchemyAutoSchema, SQLAlchemyAutoSchemaOpts

session = get_session()

# pylint: disable=too-few-public-methods
class BaseOpts(SQLAlchemyAutoSchemaOpts):
    """Define a BaseOpts with a common Session object.

    https://marshmallow-sqlalchemy.readthedocs.io/en/latest/recipes.html#base-schema-ii
    """

    def __init__(self, meta, ordered=False):
        """Add a sqla_session if it doesn't already exist."""
        if not hasattr(meta, "sqla_session"):
            meta.sqla_session = session()
        super().__init__(meta, ordered=ordered)

class BaseSchema(SQLAlchemyAutoSchema):
    """Define a BaseSchema with a common Session object.

    https://marshmallow-sqlalchemy.readthedocs.io/en/latest/recipes.html#base-schema-ii
    """

    OPTIONS_CLASS = BaseOpts  # type: ignore
<|endoftext|>


<commit_before>"""
usage: sl firewall [<command>] [<args>...] [options]

Firewall rule and security management

The available commands are:
  add    Add a new firewall
  cancel Cancel an existing firewall
  detail Provide details about a particular firewall
  edit   Edit the rules of a particular firewall
  list   List active firewalls - both dedicated and shared

"""
# :license: MIT, see LICENSE for more details.

from SoftLayer import FirewallManager
from SoftLayer.CLI import CLIRunnable, Table, listing, resolve_id, confirm
from SoftLayer.CLI.helpers import blank, CLIAbort
from subprocess import call
import os
import tempfile

DELIMITER = "=========================================\n"

def print_package_info(package):
    """ Helper package to print the firewall price.

    :param dict package: A dictionary representing the firewall package
    """
    print "******************"
    print "Product: %s" % package[0]['description']
    print "Price: %s$ monthly" % package[0]['prices'][0]['recurringFee']
    print "******************"
    return

def has_firewall_component(server):
    """ Helper to determine whether or not a server has a firewall.

    :param dict server: A dictionary representing a server
    :returns: True if the Server has a firewall.
    """
    if server['status'] != 'no_edit':
        return True

    return False

def get_rules_table(rules):
    """ Helper to format the rules into a table

    :param list rules: A list containing the rules of the firewall
    :returns: a formatted table of the firewall rules
    """
    t = Table(['#', 'action', 'protocol', 'src_ip', 'src_mask', 'dest',
               'dest_mask'])
    t.sortby = '#'
    for rule in rules:
        t.add_row([
            rule['orderValue'],
            rule['action'],
            rule['protocol'],
            rule['sourceIpAddress'],
            rule['sourceIpSubnetMask'],
            '%s:%s-%s' % (rule['destinationIpAddress'],
                          rule['destinationPortRangeStart'],
                          rule['destinationPortRangeEnd']),
                          rule['destinationIpSubnetMask']])
    return t

def get_formatted_rule(rule=None):
    """ Helper to format the rule into a user friendly format
        for editing purposes

    :param dict rule: A dict containing one rule of the firewall
    :returns: a formatted string that get be pushed into the editor
    """
    rule = rule or {}
    return ('action: %s\n'
            'protocol: %s\n'
            'source_ip_address: %s\n'
            'source_ip_subnet_mask: %s\n'
            'destination_ip_address: %s\n'
            'destination_ip_subnet_mask: %s\n'
            'destination_port_range_start: %s\n'
            'destination_port_range_end: %s\n'
            'version: %s\n'
            % (rule.get('action', 'permit'),
               rule.get('protocol', 'tcp'),
               rule.get('sourceIpAddress', 'any'),
               rule.get('sourceIpSubnetMask', '255.255.255.255'),
               rule.get('destinationIpAddress', 'any'),
               rule.get('destinationIpSubnetMask', '255.255.255.255'),
               rule.get('destinationPortRangeStart', 1),
               rule.get('destinationPortRangeEnd', 1),
               rule.get('version', 4)))

def open_editor(rules=None, content=None):
    """ Helper to open an editor for editing the firewall rules
        This method takes two parameters, if content is provided,
        that means that submitting the rules failed and we are allowing
        the user to re-edit what they provided.
        If content is not provided, the rules retrieved from the firewall
        will be displayed to the user.

    :param list rules: A list containing the rules of the firewall
    :param string content: the content that the user provided in the editor
    :returns: a formatted string that get be pushed into the editor
    """

    # Let's get the default EDITOR of the environment,
    # use nano if none is specified
    editor = os.environ.get('EDITOR', 'nano')

    with tempfile.NamedTemporaryFile(suffix=".tmp") as tfile:

        if content:
            # if content is provided, just display it as is
            tfile.write(content)
            tfile.flush()
            call([editor, tfile.name])
            tfile.seek(0)
            data = tfile.read()
            return data

        if not rules:
            # if the firewall has no rules, provide a template
            tfile.write(DELIMITER)
            tfile.write(get_formatted_rule())
        else:
            # if the firewall has rules, display those to the user
            for rule in rules:
                tfile.write(DELIMITER)
                tfile.write(get_formatted_rule(rule))
        tfile.write(DELIMITER)
        tfile.flush()
        call([editor, tfile.name])
        tfile.seek(0)
        data = tfile.read()
        return data

    return

def parse_rules(content=None):
    """ Helper to parse the input from the user into a list of rules.

    :param string content: the content of the editor
    :returns: a list of rules
    """
    rules = content.split(DELIMITER)
    parsed_rules = list()
    order = 1
    for rule in rules:
        if rule.strip() == '':
            continue
        parsed_rule = {}
        lines = rule.split("\n")
        parsed_rule['orderValue'] = order
        order += 1
        for line in lines:
            if line.strip() == '':
                continue
            key_value = line.strip().split(':')
            key = key_value[0].strip()
            value = key_value[1].strip()
            if key == 'action':
                parsed_rule['action'] = value
            elif key == 'protocol':
                parsed_rule['protocol'] = value
            elif key == 'source_ip_address':
                parsed_rule['sourceIpAddress'] = value
            elif key == 'source_ip_subnet_mask':
                parsed_rule['sourceIpSubnetMask'] = value
            elif key == 'destination_ip_address':
                parsed_rule['destinationIpAddress'] = value
            elif key == 'destination_ip_subnet_mask':
                parsed_rule['destinationIpSubnetMask'] = value
            elif key == 'destination_port_range_start':
                parsed_rule['destinationPortRangeStart'] = int(value)
            elif key == 'destination_port_range_end':
                parsed_rule['destinationPortRangeEnd'] = int(value)
            elif key == 'version':
                parsed_rule['version'] = int(value)
        parsed_rules.append(parsed_rule)
    return parsed_rules

class FWList(CLIRunnable):
    """
usage: sl firewall list [options]

List active firewalls
"""
    action = 'list'

    def execute(self, args):
        mgr = FirewallManager(self.client)
        table = Table(['firewall id',
                       'type',
                       'features',
                       'server/vlan id'])

        fwvlans = mgr.get_firewalls()
        dedicatedfws = filter(lambda x: x['dedicatedFirewallFlag'], fwvlans)

        for vlan in dedicatedfws:
            features = []
            if vlan['highAvailabilityFirewallFlag']:
                features.append('HA')

            if features:
                feature_list = listing(features, separator=',')
            else:
                feature_list = blank()

            table.add_row([
                'vlan:%s' % vlan['networkVlanFirewall']['id'],
                'VLAN - dedicated',
                feature_list,
                vlan['id']
            ])

        shared_vlan = filter(lambda x: not x['dedicatedFirewallFlag'], fwvlans)
        for vlan in shared_vlan:
            fws = list(filter(has_firewall_component,
                              vlan['firewallGuestNetworkComponents']))

            for fw in fws:
                table.add_row([
                    'cci:%s' % fw['id'],
                    'CCI - standard',
                    '',
                    fw['guestNetworkComponent']['guest']['id']
                ])

            fws = list(filter(has_firewall_component,
                              vlan['firewallNetworkComponents']))
            for fw in fws:
                table.add_row([
                    'server:%s' % fw['id'],
                    'Server - standard',
                    '',
                    fw['networkComponent']['downlinkComponent']['hardwareId']
                ])

        return table

class FWCancel(CLIRunnable):
    """
usage: sl firewall cancel <identifier> [options]

Cancels a firewall

Options:
  --really     Whether to skip the confirmation prompt

"""
    action = 'cancel'
    options = ['really']

    def execute(self, args):
        mgr = FirewallManager(self.client)
        input_id = args.get('<identifier>')
        key_value = input_id.split(':')
        firewall_id = int(key_value[1])

        if args['--really'] or confirm("This action will cancel a firewall"
                                       " from your account. Continue?"):
            if key_value[0] in ['cci', 'server']:
                mgr.cancel_firewall(firewall_id, dedicated=False)
            elif key_value[0] == 'vlan':
                mgr.cancel_firewall(firewall_id, dedicated=True)
            return 'Firewall with id %s is being cancelled!' % input_id
        else:
            raise CLIAbort('Aborted.')

class FWAdd(CLIRunnable):
    """
usage: sl firewall add <identifier> (--cci | --vlan | --server) [options]

Adds a firewall of type either standard (cci or server) or dedicated(vlan)
Options:
  --cci     creates a standard firewall for a CCI
  --vlan    creates a dedicated firewall for a VLAN
  --server  creates a standard firewall for a server
  --ha      whether HA will be on or off - only for dedicated
  --really  whether to skip the confirmation prompt
"""
    action = 'add'
    options = ['really', 'ha']

    def execute(self, args):
        mgr = FirewallManager(self.client)
        input_id = resolve_id(
            mgr.resolve_ids, args.get('<identifier>'), 'firewall')
        ha = args.get('--ha', False)
        if not args['--really']:
            if args['--vlan']:
                pkg = mgr.get_dedicated_fwl_pkg(ha_enabled=ha)
            elif args['--cci']:
                pkg = mgr.get_std_fwl_pkg(input_id)
            elif args['--server']:
                pkg = mgr.get_std_fwl_pkg(input_id, is_cci=False)
            print_package_info(pkg)

            if not confirm("This action will incur charges on your account. "
                           "Continue?"):
                raise CLIAbort('Aborted.')

        if args['--vlan']:
            mgr.add_vlan_firewall(input_id, ha_enabled=ha)
        elif args['--cci']:
            mgr.add_standard_firewall(input_id, is_cci=True)
        elif args['--server']:
            mgr.add_standard_firewall(input_id, is_cci=False)

        return "Firewall is being created!"

class FWDetails(CLIRunnable):
    """
usage: sl firewall detail <identifier> [options]

Get firewall details
"""
    action = 'detail'

    def execute(self, args):
        mgr = FirewallManager(self.client)
        firewall_id = args.get('<identifier>')

        key_value = firewall_id.split(':')
        if key_value[0] == 'vlan':
            rules = mgr.get_dedicated_fwl_rules(key_value[1])
        else:
            rules = mgr.get_standard_fwl_rules(key_value[1])

        return get_rules_table(rules)

class FWEdit(CLIRunnable):
    """
usage: sl firewall edit <identifier> [options]

Edit the rules for a firewall
"""
    action = 'edit'

    def execute(self, args):
        mgr = FirewallManager(self.client)
        input_id = args.get('<identifier>')

        key_value = input_id.split(':')
        firewall_id = int(key_value[1])
        if key_value[0] == 'vlan':
            orig_rules = mgr.get_dedicated_fwl_rules(firewall_id)
        else:
            orig_rules = mgr.get_standard_fwl_rules(firewall_id)
        # open an editor for the user to enter their rules
        edited_rules = open_editor(rules=orig_rules)
        while True:
            try:
                rules = parse_rules(edited_rules)
                if key_value[0] == 'vlan':
                    rules = mgr.edit_dedicated_fwl_rules(firewall_id, rules)
                else:
                    rules = mgr.edit_standard_fwl_rules(firewall_id, rules)
                break
            except Exception as e:
                print "Unexpected error({%s})" % (e)
                if confirm("Would you like to continue editing the rules. "
                           "Continue?"):
                    edited_rules = open_editor(content=edited_rules)
                else:
                    raise CLIAbort('Aborted.')
        return 'Firewall updated!'
<commit_msg>Pep8 Issue - last one<commit_after>"""
usage: sl firewall [<command>] [<args>...] [options]

Firewall rule and security management

The available commands are:
  add    Add a new firewall
  cancel Cancel an existing firewall
  detail Provide details about a particular firewall
  edit   Edit the rules of a particular firewall
  list   List active firewalls - both dedicated and shared

"""
# :license: MIT, see LICENSE for more details.

from SoftLayer import FirewallManager
from SoftLayer.CLI import CLIRunnable, Table, listing, resolve_id, confirm
from SoftLayer.CLI.helpers import blank, CLIAbort
from subprocess import call
import os
import tempfile

DELIMITER = "=========================================\n"

def print_package_info(package):
    """ Helper package to print the firewall price.

    :param dict package: A dictionary representing the firewall package
    """
    print "******************"
    print "Product: %s" % package[0]['description']
    print "Price: %s$ monthly" % package[0]['prices'][0]['recurringFee']
    print "******************"
    return

def has_firewall_component(server):
    """ Helper to determine whether or not a server has a firewall.

    :param dict server: A dictionary representing a server
    :returns: True if the Server has a firewall.
    """
    if server['status'] != 'no_edit':
        return True

    return False

def get_rules_table(rules):
    """ Helper to format the rules into a table

    :param list rules: A list containing the rules of the firewall
    :returns: a formatted table of the firewall rules
    """
    t = Table(['#', 'action', 'protocol', 'src_ip', 'src_mask', 'dest',
               'dest_mask'])
    t.sortby = '#'
    for rule in rules:
        t.add_row([
            rule['orderValue'],
            rule['action'],
            rule['protocol'],
            rule['sourceIpAddress'],
            rule['sourceIpSubnetMask'],
            '%s:%s-%s' % (rule['destinationIpAddress'],
                          rule['destinationPortRangeStart'],
                          rule['destinationPortRangeEnd']),
            rule['destinationIpSubnetMask']])
    return t

def get_formatted_rule(rule=None):
    """ Helper to format the rule into a user friendly format
        for editing purposes

    :param dict rule: A dict containing one rule of the firewall
    :returns: a formatted string that get be pushed into the editor
    """
    rule = rule or {}
    return ('action: %s\n'
            'protocol: %s\n'
            'source_ip_address: %s\n'
            'source_ip_subnet_mask: %s\n'
            'destination_ip_address: %s\n'
            'destination_ip_subnet_mask: %s\n'
            'destination_port_range_start: %s\n'
            'destination_port_range_end: %s\n'
            'version: %s\n'
            % (rule.get('action', 'permit'),
               rule.get('protocol', 'tcp'),
               rule.get('sourceIpAddress', 'any'),
               rule.get('sourceIpSubnetMask', '255.255.255.255'),
               rule.get('destinationIpAddress', 'any'),
               rule.get('destinationIpSubnetMask', '255.255.255.255'),
               rule.get('destinationPortRangeStart', 1),
               rule.get('destinationPortRangeEnd', 1),
               rule.get('version', 4)))

def open_editor(rules=None, content=None):
    """ Helper to open an editor for editing the firewall rules
        This method takes two parameters, if content is provided,
        that means that submitting the rules failed and we are allowing
        the user to re-edit what they provided.
        If content is not provided, the rules retrieved from the firewall
        will be displayed to the user.

    :param list rules: A list containing the rules of the firewall
    :param string content: the content that the user provided in the editor
    :returns: a formatted string that get be pushed into the editor
    """

    # Let's get the default EDITOR of the environment,
    # use nano if none is specified
    editor = os.environ.get('EDITOR', 'nano')

    with tempfile.NamedTemporaryFile(suffix=".tmp") as tfile:

        if content:
            # if content is provided, just display it as is
            tfile.write(content)
            tfile.flush()
            call([editor, tfile.name])
            tfile.seek(0)
            data = tfile.read()
            return data

        if not rules:
            # if the firewall has no rules, provide a template
            tfile.write(DELIMITER)
            tfile.write(get_formatted_rule())
        else:
            # if the firewall has rules, display those to the user
            for rule in rules:
                tfile.write(DELIMITER)
                tfile.write(get_formatted_rule(rule))
        tfile.write(DELIMITER)
        tfile.flush()
        call([editor, tfile.name])
        tfile.seek(0)
        data = tfile.read()
        return data

    return

def parse_rules(content=None):
    """ Helper to parse the input from the user into a list of rules.

    :param string content: the content of the editor
    :returns: a list of rules
    """
    rules = content.split(DELIMITER)
    parsed_rules = list()
    order = 1
    for rule in rules:
        if rule.strip() == '':
            continue
        parsed_rule = {}
        lines = rule.split("\n")
        parsed_rule['orderValue'] = order
        order += 1
        for line in lines:
            if line.strip() == '':
                continue
            key_value = line.strip().split(':')
            key = key_value[0].strip()
            value = key_value[1].strip()
            if key == 'action':
                parsed_rule['action'] = value
            elif key == 'protocol':
                parsed_rule['protocol'] = value
            elif key == 'source_ip_address':
                parsed_rule['sourceIpAddress'] = value
            elif key == 'source_ip_subnet_mask':
                parsed_rule['sourceIpSubnetMask'] = value
            elif key == 'destination_ip_address':
                parsed_rule['destinationIpAddress'] = value
            elif key == 'destination_ip_subnet_mask':
                parsed_rule['destinationIpSubnetMask'] = value
            elif key == 'destination_port_range_start':
                parsed_rule['destinationPortRangeStart'] = int(value)
            elif key == 'destination_port_range_end':
                parsed_rule['destinationPortRangeEnd'] = int(value)
            elif key == 'version':
                parsed_rule['version'] = int(value)
        parsed_rules.append(parsed_rule)
    return parsed_rules

class FWList(CLIRunnable):
    """
usage: sl firewall list [options]

List active firewalls
"""
    action = 'list'

    def execute(self, args):
        mgr = FirewallManager(self.client)
        table = Table(['firewall id',
                       'type',
                       'features',
                       'server/vlan id'])

        fwvlans = mgr.get_firewalls()
        dedicatedfws = filter(lambda x: x['dedicatedFirewallFlag'], fwvlans)

        for vlan in dedicatedfws:
            features = []
            if vlan['highAvailabilityFirewallFlag']:
                features.append('HA')

            if features:
                feature_list = listing(features, separator=',')
            else:
                feature_list = blank()

            table.add_row([
                'vlan:%s' % vlan['networkVlanFirewall']['id'],
                'VLAN - dedicated',
                feature_list,
                vlan['id']
            ])

        shared_vlan = filter(lambda x: not x['dedicatedFirewallFlag'], fwvlans)
        for vlan in shared_vlan:
            fws = list(filter(has_firewall_component,
                              vlan['firewallGuestNetworkComponents']))

            for fw in fws:
                table.add_row([
                    'cci:%s' % fw['id'],
                    'CCI - standard',
                    '',
                    fw['guestNetworkComponent']['guest']['id']
                ])

            fws = list(filter(has_firewall_component,
                              vlan['firewallNetworkComponents']))
            for fw in fws:
                table.add_row([
                    'server:%s' % fw['id'],
                    'Server - standard',
                    '',
                    fw['networkComponent']['downlinkComponent']['hardwareId']
                ])

        return table

class FWCancel(CLIRunnable):
    """
usage: sl firewall cancel <identifier> [options]

Cancels a firewall

Options:
  --really     Whether to skip the confirmation prompt

"""
    action = 'cancel'
    options = ['really']

    def execute(self, args):
        mgr = FirewallManager(self.client)
        input_id = args.get('<identifier>')
        key_value = input_id.split(':')
        firewall_id = int(key_value[1])

        if args['--really'] or confirm("This action will cancel a firewall"
                                       " from your account. Continue?"):
            if key_value[0] in ['cci', 'server']:
                mgr.cancel_firewall(firewall_id, dedicated=False)
            elif key_value[0] == 'vlan':
                mgr.cancel_firewall(firewall_id, dedicated=True)
            return 'Firewall with id %s is being cancelled!' % input_id
        else:
            raise CLIAbort('Aborted.')

class FWAdd(CLIRunnable):
    """
usage: sl firewall add <identifier> (--cci | --vlan | --server) [options]

Adds a firewall of type either standard (cci or server) or dedicated(vlan)
Options:
  --cci     creates a standard firewall for a CCI
  --vlan    creates a dedicated firewall for a VLAN
  --server  creates a standard firewall for a server
  --ha      whether HA will be on or off - only for dedicated
  --really  whether to skip the confirmation prompt
"""
    action = 'add'
    options = ['really', 'ha']

    def execute(self, args):
        mgr = FirewallManager(self.client)
        input_id = resolve_id(
            mgr.resolve_ids, args.get('<identifier>'), 'firewall')
        ha = args.get('--ha', False)
        if not args['--really']:
            if args['--vlan']:
                pkg = mgr.get_dedicated_fwl_pkg(ha_enabled=ha)
            elif args['--cci']:
                pkg = mgr.get_std_fwl_pkg(input_id)
            elif args['--server']:
                pkg = mgr.get_std_fwl_pkg(input_id, is_cci=False)
            print_package_info(pkg)

            if not confirm("This action will incur charges on your account. "
                           "Continue?"):
                raise CLIAbort('Aborted.')

        if args['--vlan']:
            mgr.add_vlan_firewall(input_id, ha_enabled=ha)
        elif args['--cci']:
            mgr.add_standard_firewall(input_id, is_cci=True)
        elif args['--server']:
            mgr.add_standard_firewall(input_id, is_cci=False)

        return "Firewall is being created!"

class FWDetails(CLIRunnable):
    """
usage: sl firewall detail <identifier> [options]

Get firewall details
"""
    action = 'detail'

    def execute(self, args):
        mgr = FirewallManager(self.client)
        firewall_id = args.get('<identifier>')

        key_value = firewall_id.split(':')
        if key_value[0] == 'vlan':
            rules = mgr.get_dedicated_fwl_rules(key_value[1])
        else:
            rules = mgr.get_standard_fwl_rules(key_value[1])

        return get_rules_table(rules)

class FWEdit(CLIRunnable):
    """
usage: sl firewall edit <identifier> [options]

Edit the rules for a firewall
"""
    action = 'edit'

    def execute(self, args):
        mgr = FirewallManager(self.client)
        input_id = args.get('<identifier>')

        key_value = input_id.split(':')
        firewall_id = int(key_value[1])
        if key_value[0] == 'vlan':
            orig_rules = mgr.get_dedicated_fwl_rules(firewall_id)
        else:
            orig_rules = mgr.get_standard_fwl_rules(firewall_id)
        # open an editor for the user to enter their rules
        edited_rules = open_editor(rules=orig_rules)
        while True:
            try:
                rules = parse_rules(edited_rules)
                if key_value[0] == 'vlan':
                    rules = mgr.edit_dedicated_fwl_rules(firewall_id, rules)
                else:
                    rules = mgr.edit_standard_fwl_rules(firewall_id, rules)
                break
            except Exception as e:
                print "Unexpected error({%s})" % (e)
                if confirm("Would you like to continue editing the rules. "
                           "Continue?"):
                    edited_rules = open_editor(content=edited_rules)
                else:
                    raise CLIAbort('Aborted.')
        return 'Firewall updated!'
<|endoftext|>


<commit_before>__version__ = '1.9.8'

<commit_msg>bump version<commit_after>__version__ = '1.9.9'

<|endoftext|>


<commit_before>from dateutil.tz import tzutc, tzlocal
from lxml import etree
import simplejson

from django.core.urlresolvers import reverse
from django.contrib.gis.db import models
from django.conf import settings
from django.utils.translation import ugettext_lazy as _

from molly.external_media import resize_external_image
from molly.apps.places.models import Entity

FEED_TYPE_CHOICES = (
    ('n', 'news'),
    ('e', 'event'),
)

PROVIDER_CHOICES = tuple(
    (provider().class_path, provider().verbose_name)
        for app in settings.APPLICATIONS
        for provider in app.providers
        if app.application_name == 'molly.apps.feeds'
)

FORMAT_CHOICES = tuple((x, x) for x in (
    'lecture', 'class', 'tutorial', 'seminar', 'performance', 'workshop',
    'exhibition', 'meeting',
))

class EventsManager(models.Manager):
    def get_query_set(self):
        return super(EventsManager, self).get_query_set().filter(ptype='e')

class NewsManager(models.Manager):
    def get_query_set(self):
        return super(NewsManager, self).get_query_set().filter(ptype='n')

class Tag(models.Model):
    value = models.CharField(max_length=128)

    def __unicode__(self):
        return self.value

class Feed(models.Model):
    title = models.TextField(help_text=_("Feed title"))
    entity = models.ForeignKey(Entity, null=True, blank=True,
                               help_text=_('Place which this feed belongs to'))
    rss_url = models.URLField(help_text=_("URL of feed"))
    slug = models.SlugField(help_text=_("Slug of feed, e.g. oucs-news"))
    # this one is in UTC
    last_modified = models.DateTimeField(null=True, blank=True)
    language = models.CharField(max_length=10, choices=settings.LANGUAGES,
                                null=True)

    # Provider type
    ptype = models.CharField(max_length=1, choices=FEED_TYPE_CHOICES)
    provider = models.CharField(max_length=128, choices=PROVIDER_CHOICES)

    objects = models.Manager()
    events = EventsManager()
    news = NewsManager()

    tags = models.ManyToManyField(Tag, blank=True)

    def __unicode__(self):
        return self.title

    def get_absolute_url(self):
        if self.ptype == 'n':
            return reverse('news:item-list', args=[self.slug])
        else:
            return reverse('events:item-list', args=[self.slug])

    class Meta:
        ordering = ('title',)

class vCard(models.Model):
    uri = models.TextField()

    name = models.TextField(blank=True)
    address = models.TextField(blank=True)
    telephone = models.TextField(blank=True)
    location = models.PointField(null=True)
    entity = models.ForeignKey(Entity, null=True, blank=True)

class Series(models.Model):
    feed = models.ForeignKey(Feed)
    guid = models.TextField()
    title = models.TextField()
    unit = models.ForeignKey(vCard, null=True, blank=True)
    tags = models.ManyToManyField(Tag, blank=True)

class Item(models.Model):
    feed = models.ForeignKey(Feed)
    title = models.TextField(help_text=_("Title of feed item"))
    guid = models.TextField()
    description = models.TextField(help_text=_("Description of feed item"))
    link = models.URLField(help_text=_("URL to feed item"))
    last_modified = models.DateTimeField(null = True)  # this one is also in UTC

    ptype = models.CharField(max_length=16, choices=FEED_TYPE_CHOICES)

    organiser = models.ForeignKey(vCard, related_name='organising_set',
                                  null=True, blank=True)
    speaker = models.ForeignKey(vCard, related_name='speaking_set',
                                null=True, blank=True)
    venue = models.ForeignKey(vCard, related_name='venue_set',
                              null=True, blank=True)
    contact = models.ForeignKey(vCard, related_name='contact_set',
                                null=True, blank=True)

    series = models.ForeignKey(Series, null=True, blank=True)
    ordinal = models.IntegerField(null=True)
    track = models.TextField(blank=True)

    tags = models.ManyToManyField(Tag, blank=True)

    objects = models.Manager()
    events = EventsManager()
    news = NewsManager()

    dt_start = models.DateTimeField(null=True, blank=True)
    dt_end = models.DateTimeField(null=True, blank=True)
    dt_has_time = models.BooleanField(default=False)

    @property
    def location_mobile_url(self):
        return self.location_url.replace('/reviews/venue/',
                                         '/reviews/phone/venue/')

    @property
    def last_modified_local(self):
        try:
            return self.last_modified.replace(tzinfo=tzutc())\
                .astimezone(tzlocal())
        except Exception, e:
            return repr(e)

    def get_absolute_url(self):
        if self.ptype == 'n':
            return reverse('news:item-detail', args=[self.feed.slug, self.id])
        else:
            return reverse('events:item-detail',
                           args=[self.feed.slug, self.id])

    def get_description_display(self, device):
        html = etree.fromstring('
%s
' % self.description,
                                parser=etree.HTMLParser())
        for img in html.findall('.//img'):
            eis = resize_external_image(img.attrib['src'],
                                        device.max_image_width - 40)
            if eis != None:
                img.attrib['src'] = eis.get_absolute_url()
                img.attrib['width'] = '%d' % eis.width
                img.attrib['height'] = '%d' % eis.height
        return etree.tostring(html.find('.//div'), method="html")[5:-6]

    def save(self, *args, **kwargs):
        self.ptype = self.feed.ptype
        super(Item, self).save(*args, **kwargs)

    class Meta:
        ordering = ('-last_modified',)
<commit_msg>MOLLY-284 / feed url verbose name in admin interface (removed RSS as it should be generic)<commit_after>from dateutil.tz import tzutc, tzlocal
from lxml import etree

from django.core.urlresolvers import reverse
from django.contrib.gis.db import models
from django.conf import settings
from django.utils.translation import ugettext_lazy as _

from molly.external_media import resize_external_image
from molly.apps.places.models import Entity

FEED_TYPE_CHOICES = (
    ('n', 'news'),
    ('e', 'event'),
)

PROVIDER_CHOICES = tuple(
    (provider().class_path, provider().verbose_name)
        for app in settings.APPLICATIONS
        for provider in app.providers
        if app.application_name == 'molly.apps.feeds'
)

FORMAT_CHOICES = tuple((x, x) for x in (
    'lecture', 'class', 'tutorial', 'seminar', 'performance', 'workshop',
    'exhibition', 'meeting',
))

class EventsManager(models.Manager):
    def get_query_set(self):
        return super(EventsManager, self).get_query_set().filter(ptype='e')

class NewsManager(models.Manager):
    def get_query_set(self):
        return super(NewsManager, self).get_query_set().filter(ptype='n')

class Tag(models.Model):
    value = models.CharField(max_length=128)

    def __unicode__(self):
        return self.value

class Feed(models.Model):
    title = models.TextField(help_text=_("Feed title"))
    entity = models.ForeignKey(Entity, null=True, blank=True,
                               help_text=_('Place which this feed belongs to'))
    rss_url = models.URLField(help_text=_("URL of feed"),
            verbose_name=_("URL"))
    slug = models.SlugField(help_text=_("Slug of feed, e.g. oucs-news"))
    # this one is in UTC
    last_modified = models.DateTimeField(null=True, blank=True)
    language = models.CharField(max_length=10, choices=settings.LANGUAGES,
                                null=True)

    # Provider type
    ptype = models.CharField(max_length=1, choices=FEED_TYPE_CHOICES)
    provider = models.CharField(max_length=128, choices=PROVIDER_CHOICES)

    objects = models.Manager()
    events = EventsManager()
    news = NewsManager()

    tags = models.ManyToManyField(Tag, blank=True)

    def __unicode__(self):
        return self.title

    def get_absolute_url(self):
        if self.ptype == 'n':
            return reverse('news:item-list', args=[self.slug])
        else:
            return reverse('events:item-list', args=[self.slug])

    class Meta:
        ordering = ('title',)

class vCard(models.Model):
    uri = models.TextField()

    name = models.TextField(blank=True)
    address = models.TextField(blank=True)
    telephone = models.TextField(blank=True)
    location = models.PointField(null=True)
    entity = models.ForeignKey(Entity, null=True, blank=True)

class Series(models.Model):
    feed = models.ForeignKey(Feed)
    guid = models.TextField()
    title = models.TextField()
    unit = models.ForeignKey(vCard, null=True, blank=True)
    tags = models.ManyToManyField(Tag, blank=True)

class Item(models.Model):
    feed = models.ForeignKey(Feed)
    title = models.TextField(help_text=_("Title of feed item"))
    guid = models.TextField()
    description = models.TextField(help_text=_("Description of feed item"))
    link = models.URLField(help_text=_("URL to feed item"))
    last_modified = models.DateTimeField(null = True)  # this one is also in UTC

    ptype = models.CharField(max_length=16, choices=FEED_TYPE_CHOICES)

    organiser = models.ForeignKey(vCard, related_name='organising_set',
                                  null=True, blank=True)
    speaker = models.ForeignKey(vCard, related_name='speaking_set',
                                null=True, blank=True)
    venue = models.ForeignKey(vCard, related_name='venue_set',
                              null=True, blank=True)
    contact = models.ForeignKey(vCard, related_name='contact_set',
                                null=True, blank=True)

    series = models.ForeignKey(Series, null=True, blank=True)
    ordinal = models.IntegerField(null=True)
    track = models.TextField(blank=True)

    tags = models.ManyToManyField(Tag, blank=True)

    objects = models.Manager()
    events = EventsManager()
    news = NewsManager()

    dt_start = models.DateTimeField(null=True, blank=True)
    dt_end = models.DateTimeField(null=True, blank=True)
    dt_has_time = models.BooleanField(default=False)

    @property
    def location_mobile_url(self):
        return self.location_url.replace('/reviews/venue/',
                                         '/reviews/phone/venue/')

    @property
    def last_modified_local(self):
        try:
            return self.last_modified.replace(tzinfo=tzutc())\
                .astimezone(tzlocal())
        except Exception, e:
            return repr(e)

    def get_absolute_url(self):
        if self.ptype == 'n':
            return reverse('news:item-detail', args=[self.feed.slug, self.id])
        else:
            return reverse('events:item-detail',
                           args=[self.feed.slug, self.id])

    def get_description_display(self, device):
        html = etree.fromstring('
%s
' % self.description,
                                parser=etree.HTMLParser())
        for img in html.findall('.//img'):
            eis = resize_external_image(img.attrib['src'],
                                        device.max_image_width - 40)
            if eis != None:
                img.attrib['src'] = eis.get_absolute_url()
                img.attrib['width'] = '%d' % eis.width
                img.attrib['height'] = '%d' % eis.height
        return etree.tostring(html.find('.//div'), method="html")[5:-6]

    def save(self, *args, **kwargs):
        self.ptype = self.feed.ptype
        super(Item, self).save(*args, **kwargs)

    class Meta:
        ordering = ('-last_modified',)
<|endoftext|>


<commit_before>import inspect
from collections import OrderedDict
from json.decoder import JSONDecodeError
from typing import Optional, Tuple, Union
from urllib.parse import urljoin

import requests
from bs4 import BeautifulSoup

from recipe_scrapers.settings import settings

from ._schemaorg import SchemaOrg

# some sites close their content for 'bots', so user-agent must be supplied
HEADERS = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0) Gecko/20100101 Firefox/86.0"
}

class AbstractScraper:
    def __init__(
        self,
        url,
        proxies: Optional[str] = None,  # allows us to specify optional proxy server
        timeout: Optional[
            Union[float, Tuple, None]
        ] = None,  # allows us to specify optional timeout for request
        wild_mode: Optional[bool] = False,
    ):
        if settings.TEST_MODE:  # when testing, we load a file
            page_data = url.read()
            url = "https://test.example.com/"
        else:
            page_data = requests.get(
                url, headers=HEADERS, proxies=proxies, timeout=timeout
            ).content

        self.wild_mode = wild_mode
        self.soup = BeautifulSoup(page_data, "html.parser")
        self.url = url
        self.schema = SchemaOrg(page_data)

        # attach the plugins as instructed in settings.PLUGINS
        for name, func in inspect.getmembers(self, inspect.ismethod):
            current_method = getattr(self.__class__, name)
            for plugin in reversed(settings.PLUGINS):
                if plugin.should_run(self.host(), name):
                    current_method = plugin.run(current_method)
            setattr(self.__class__, name, current_method)

    @classmethod
    def host(cls) -> str:
        """get the host of the url, so we can use the correct scraper"""
        raise NotImplementedError("This should be implemented.")

    def canonical_url(self):
        canonical_link = self.soup.find("link", {"rel": "canonical", "href": True})
        if canonical_link:
            return urljoin(self.url, canonical_link["href"])
        return self.url

    def title(self):
        raise NotImplementedError("This should be implemented.")

    def total_time(self):
        """total time it takes to preparate the recipe in minutes"""
        raise NotImplementedError("This should be implemented.")

    def yields(self):
        """The number of servings or items in the recipe"""
        raise NotImplementedError("This should be implemented.")

    def image(self):
        raise NotImplementedError("This should be implemented.")

    def nutrients(self):
        raise NotImplementedError("This should be implemented.")

    def language(self):
        """
        Human language the recipe is written in.

        May be overridden by individual scrapers.
        """
        candidate_languages = OrderedDict()
        html = self.soup.find("html", {"lang": True})
        candidate_languages[html.get("lang")] = True

        # Deprecated: check for a meta http-equiv header
        # See: https://www.w3.org/International/questions/qa-http-and-lang
        meta_language = (
            self.soup.find(
                "meta",
                {
                    "http-equiv": lambda x: x and x.lower() == "content-language",
                    "content": True,
                },
            )
            if settings.META_HTTP_EQUIV
            else None
        )
        if meta_language:
            language = meta_language.get("content").split(",", 1)[0]
            if language:
                candidate_languages[language] = True

        # If other langs exist, remove 'en' commonly generated by HTML editors
        if len(candidate_languages) > 1:
            candidate_languages.pop("en", None)

        # Return the first candidate language
        return candidate_languages.popitem(last=False)[0]

    def ingredients(self):
        raise NotImplementedError("This should be implemented.")

    def instructions(self):
        raise NotImplementedError("This should be implemented.")

    def ratings(self):
        raise NotImplementedError("This should be implemented.")

    def author(self):
        raise NotImplementedError("This should be implemented.")

    def reviews(self):
        raise NotImplementedError("This should be implemented.")

    def links(self):
        invalid_href = {"#", ""}
        links_html = self.soup.findAll("a", href=True)

        return [link.attrs for link in links_html if link["href"] not in invalid_href]

    def site_name(self):
        meta = self.soup.find("meta", property="og:site_name")
        return meta.get("content") if meta else None
<commit_msg>Cleanup: unused import<commit_after>import inspect
from collections import OrderedDict
from typing import Optional, Tuple, Union
from urllib.parse import urljoin

import requests
from bs4 import BeautifulSoup

from recipe_scrapers.settings import settings

from ._schemaorg import SchemaOrg

# some sites close their content for 'bots', so user-agent must be supplied
HEADERS = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0) Gecko/20100101 Firefox/86.0"
}

class AbstractScraper:
    def __init__(
        self,
        url,
        proxies: Optional[str] = None,  # allows us to specify optional proxy server
        timeout: Optional[
            Union[float, Tuple, None]
        ] = None,  # allows us to specify optional timeout for request
        wild_mode: Optional[bool] = False,
    ):
        if settings.TEST_MODE:  # when testing, we load a file
            page_data = url.read()
            url = "https://test.example.com/"
        else:
            page_data = requests.get(
                url, headers=HEADERS, proxies=proxies, timeout=timeout
            ).content

        self.wild_mode = wild_mode
        self.soup = BeautifulSoup(page_data, "html.parser")
        self.url = url
        self.schema = SchemaOrg(page_data)

        # attach the plugins as instructed in settings.PLUGINS
        for name, func in inspect.getmembers(self, inspect.ismethod):
            current_method = getattr(self.__class__, name)
            for plugin in reversed(settings.PLUGINS):
                if plugin.should_run(self.host(), name):
                    current_method = plugin.run(current_method)
            setattr(self.__class__, name, current_method)

    @classmethod
    def host(cls) -> str:
        """get the host of the url, so we can use the correct scraper"""
        raise NotImplementedError("This should be implemented.")

    def canonical_url(self):
        canonical_link = self.soup.find("link", {"rel": "canonical", "href": True})
        if canonical_link:
            return urljoin(self.url, canonical_link["href"])
        return self.url

    def title(self):
        raise NotImplementedError("This should be implemented.")

    def total_time(self):
        """total time it takes to preparate the recipe in minutes"""
        raise NotImplementedError("This should be implemented.")

    def yields(self):
        """The number of servings or items in the recipe"""
        raise NotImplementedError("This should be implemented.")

    def image(self):
        raise NotImplementedError("This should be implemented.")

    def nutrients(self):
        raise NotImplementedError("This should be implemented.")

    def language(self):
        """
        Human language the recipe is written in.

        May be overridden by individual scrapers.
        """
        candidate_languages = OrderedDict()
        html = self.soup.find("html", {"lang": True})
        candidate_languages[html.get("lang")] = True

        # Deprecated: check for a meta http-equiv header
        # See: https://www.w3.org/International/questions/qa-http-and-lang
        meta_language = (
            self.soup.find(
                "meta",
                {
                    "http-equiv": lambda x: x and x.lower() == "content-language",
                    "content": True,
                },
            )
            if settings.META_HTTP_EQUIV
            else None
        )
        if meta_language:
            language = meta_language.get("content").split(",", 1)[0]
            if language:
                candidate_languages[language] = True

        # If other langs exist, remove 'en' commonly generated by HTML editors
        if len(candidate_languages) > 1:
            candidate_languages.pop("en", None)

        # Return the first candidate language
        return candidate_languages.popitem(last=False)[0]

    def ingredients(self):
        raise NotImplementedError("This should be implemented.")

    def instructions(self):
        raise NotImplementedError("This should be implemented.")

    def ratings(self):
        raise NotImplementedError("This should be implemented.")

    def author(self):
        raise NotImplementedError("This should be implemented.")

    def reviews(self):
        raise NotImplementedError("This should be implemented.")

    def links(self):
        invalid_href = {"#", ""}
        links_html = self.soup.findAll("a", href=True)

        return [link.attrs for link in links_html if link["href"] not in invalid_href]

    def site_name(self):
        meta = self.soup.find("meta", property="og:site_name")
        return meta.get("content") if meta else None
<|endoftext|>


<commit_before>__version__ = '2.0.0'

<commit_msg>bump version<commit_after>__version__ = '2.0.1'

<|endoftext|>


<commit_before>#!/usr/bin/env python
import time
import random
import math
import array

KEY_LEFT = 'left'
KEY_UP = 'up'
KEY_RIGHT = 'right'
KEY_DOWN = 'down'

INF = 100000000

moves = [KEY_DOWN, KEY_LEFT, KEY_UP, KEY_RIGHT]
moves_LR = [ KEY_LEFT, KEY_RIGHT ]
moves_UD = [ KEY_UP, KEY_DOWN ]
range4 = range(4)
range3 = range(3)

to_idx = dict((2**i, i) for i in range(16))
to_idx[None] = 0

def clone(grid):
    return [row[:] for row in grid]

def move_row(row):
    out = [None, None, None, None]
    oc = 0
    ic = 0
    while ic < 4:
        if row[ic] is None:
            ic += 1
            continue
        out[oc] = row[ic]
        oc += 1
        ic += 1

    ic = 0
    oc = 0
    while ic < 4:
        if out[ic] is None:
            break
        if ic == 3:
            out[oc] = out[ic]
            oc += 1
            break
        if out[ic] == out[ic+1]:
            out[oc] = 2*out[ic]
            ic += 1
        else:
            out[oc] = out[ic]
        ic += 1
        oc += 1
    while oc < 4:
        out[oc] = None
        oc += 1
    return out

class AI(object):
    def __init__(self):
        self.total_node = 0
        self.total_time = 0
        self.eval_count = 0
        self.table = {}
        self.move_table = {}
        self.move_table_r = {}
        self.build_move_table()

    def build_move_table(self):
        values = [None] + [2**x for x in range(1, 16)]
        for a in values:
            for b in values:
                for c in values:
                    for d in values:
                        row = a, b, c, d
                        assert row not in self.move_table
                        self.move_table[row] = move_row(row)
                        assert row not in self.move_table_r
                        self.move_table_r[row] = move_row(row[::-1])[::-1]

    def emptyGrid(self):
        return [[None,None,None,None],[None,None,None,None],
                [None,None,None,None],[None,None,None,None]]

    def rotateLeft(self, grid):
        g = grid
        return [
                [g[3][0], g[2][0], g[1][0], g[0][0]],
                [g[3][1], g[2][1], g[1][1], g[0][1]],
                [g[3][2], g[2][2], g[1][2], g[0][2]],
                [g[3][3], g[2][3], g[1][3], g[0][3]],
                ]

    def rotateRight(self, grid):
        g = grid
        return [
                [g[0][3], g[1][3], g[2][3], g[3][3]],
                [g[0][2], g[1][2], g[2][2], g[3][2]],
                [g[0][1], g[1][1], g[2][1], g[3][1]],
                [g[0][0], g[1][0], g[2][0], g[3][0]],
                ]

    def flip(self, grid):
        return [grid[3][::-1], grid[2][::-1], grid[1][::-1], grid[0][::-1]]

    def encode(self, grid):
        a = array.array('h')
        for x in range4:
            for y in range4:
                if grid[x][y]:
                    a.append(grid[x][y])
                else:
                    a.append(0)
        return a.tostring()

    def move(self, grid, direction):
        if direction == KEY_UP:
            rot = 1
        elif direction == KEY_RIGHT:
            rot = 2
        elif direction == KEY_DOWN:
            rot = 3
        else:
            rot = 0

        if rot == 3:
            tmp = [
                self.move_table_r[tuple(grid[0])][:],
                self.move_table_r[tuple(grid[1])][:],
                self.move_table_r[tuple(grid[2])][:],
                self.move_table_r[tuple(grid[3])][:],
                ]
            return tmp
        if rot == 1:
            pass
        elif rot == 0:
            grid = self.rotateRight(grid)
        elif rot == 3:
            grid = self.flip(grid)
        elif rot == 2:
            grid = self.rotateLeft(grid)

        out = [
                self.move_table[tuple(grid[0])][:],
                self.move_table[tuple(grid[1])][:],
                self.move_table[tuple(grid[2])][:],
                self.move_table[tuple(grid[3])][:],
                ]
        if rot == 0:
            out = self.rotateLeft(out)
        elif rot == 3:
            out = self.flip(out)
        elif rot == 2:
            out = self.rotateRight(out)

        return out

    def show(self, grid):
        for x in range(4):
            for y in range(4):
                if grid[x][y]:
                    print '%4d' % grid[x][y],
                else:
                    print '   .',
            print

    def canMove(self, grid, direction):
      return grid != self.move(grid, direction)

    def eval_monotone(self, grid):
      L = R = U = D = 0
      LR = UD = 0
      for x in range4:
        m = 0
        for y in range3:
          if grid[x][y] and grid[x][y] >= grid[x][y+1]:
            m += 1
            # 26090
            #L += m
            # 29281
            L += m ** 2 * 4
          else:
            # 20585
            #L -= abs(to_idx[grid[x][y]] - to_idx[grid[x][y+1]]) ** 2
            # 26090
            L -= abs((grid[x][y] or 0)- (grid[x][y+1] or 0)) * 1.5
            m = 0

        m = 0
        for y in range3:
          if grid[x][y] <= grid[x][y+1] and grid[x][y+1]:
            m += 1
            R += m ** 2 * 4
          else:
            #R -= abs(to_idx[grid[x][y]] - to_idx[grid[x][y+1]]) ** 2
            R -= abs((grid[x][y] or 0)- (grid[x][y+1] or 0)) * 1.5
            m = 0

      LR += max(L, R)
      L = R = 0

      for y in range4:
        m = 0
        for x in range3:
          if grid[x][y] and grid[x][y] >= grid[x+1][y]:
            m += 1
            U += m ** 2 * 4
          else:
            #U -= abs(to_idx[grid[x][y]] - to_idx[grid[x+1][y]]) ** 2
            U -= abs((grid[x][y] or 0)- (grid[x+1][y] or 0)) * 1.5
            m = 0

        m = 0
        for x in range3:
          if grid[x][y] <= grid[x+1][y] and grid[x+1][y]:
            m += 1
            D += m ** 2 * 4
          else:
            #D -= abs(to_idx[grid[x][y]] - to_idx[grid[x+1][y]]) ** 2
            D -= abs((grid[x][y] or 0)- (grid[x+1][y] or 0)) * 1.5
            m = 0

      UD += max(U, D)
      U = D = 0

      return LR + UD

    def eval_smoothness(self, grid):
        score_smooth = 0
        for x in range4:
            for y in range4:
                s = INF
                if x > 0: s = min(s, abs((grid[x][y] or 2) - (grid[x-1][y] or 2)))
                if y > 0: s = min(s, abs((grid[x][y] or 2) - (grid[x][y-1] or 2)))
                if x < 3: s = min(s, abs((grid[x][y] or 2) - (grid[x+1][y] or 2)))
                if y < 3: s = min(s, abs((grid[x][y] or 2) - (grid[x][y+1] or 2)))
                score_smooth -= s
        return score_smooth

    def eval_free(self, grid):
      free = 0
      for i in range4:
        for j in range4:
          if grid[i][j] is None:
            free += 1
      return -(16-free)**2

    def eval(self, grid):
      key = self.encode(grid)
      if key in self.table:
        return self.table[key]

      self.eval_count += 1

      score_monotone = self.eval_monotone(grid)
      score_smooth = self.eval_smoothness(grid)
      score_free = self.eval_free(grid)

      score = 0
      score += score_smooth
      score += score_monotone
      score += score_free

      self.table[key] = score
      return score

    def search_max(self, grid, depth, a, b, moves):
      for m in moves:
        g2 = self.move(grid, m)
        if g2 == grid:
          continue
        score = self.search_min(g2, depth - 1, a, b)
        #print 'search_max', m, score
        if score >= b:
          return b
        if score > a:
          a = score

      return a

    def search_min(self, grid, depth, a, b):
      if depth == 0:
        return self.eval(grid)

      key = self.encode(grid), depth
      if key in self.table:
        return self.table[key]

      #g = clone(grid)
      #assert g == grid
      #print '=' * 30
      #self.show(grid)
      for i in range4:
        for j in range4:
          if grid[i][j] is not None:
            continue

          for v in (2, 4):
            grid[i][j] = v
            score = self.search_max(grid, depth, a, b, moves)
            if score <= a:
              grid[i][j] = None
              return a
            if score < b:
              b = score

          grid[i][j] = None

      self.table[key] = b
      return b

    def reset(self):
      self.eval_count = 0
      self.table = {}

    def getNextMove(self, grid):
      best_score = -INF
      best_move = random.choice(moves)
      self.reset()

      t0 = time.time()
      for m in moves:
        #print 'move', m
        g2 = self.move(grid, m)
        if g2 == grid:
          continue
        #print grid
        #print g2
        score = self.search_min(g2, 3-1, -INF, INF)

        #print score, m
        if score > best_score:
          best_score = score
          best_move = m
        #print '-'
      t1 = time.time()

      self.total_time += t1 - t0
      self.total_node += self.eval_count
      print 't=%.2fs, node=%d, total_node=%d, %fnps' % (
          t1-t0, self.eval_count, self.total_node, self.total_node/self.total_time)

      return best_move

# vim:sw=4:expandtab
<commit_msg>optimize move (tuple)<commit_after>#!/usr/bin/env python
import time
import random
import math
import array

KEY_LEFT = 'left'
KEY_UP = 'up'
KEY_RIGHT = 'right'
KEY_DOWN = 'down'

INF = 100000000

moves = [KEY_DOWN, KEY_LEFT, KEY_UP, KEY_RIGHT]
moves_LR = [ KEY_LEFT, KEY_RIGHT ]
moves_UD = [ KEY_UP, KEY_DOWN ]
range4 = range(4)
range3 = range(3)

to_idx = dict((2**i, i) for i in range(16))
to_idx[None] = 0

def clone(grid):
    return [row[:] for row in grid]

def move_row(row):
    out = [None, None, None, None]
    oc = 0
    ic = 0
    while ic < 4:
        if row[ic] is None:
            ic += 1
            continue
        out[oc] = row[ic]
        oc += 1
        ic += 1

    ic = 0
    oc = 0
    while ic < 4:
        if out[ic] is None:
            break
        if ic == 3:
            out[oc] = out[ic]
            oc += 1
            break
        if out[ic] == out[ic+1]:
            out[oc] = 2*out[ic]
            ic += 1
        else:
            out[oc] = out[ic]
        ic += 1
        oc += 1
    while oc < 4:
        out[oc] = None
        oc += 1
    return out

class AI(object):
    def __init__(self):
        self.total_node = 0
        self.total_time = 0
        self.eval_count = 0
        self.table = {}
        self.move_table = {}
        self.move_table_r = {}
        self.build_move_table()

    def build_move_table(self):
        values = [None] + [2**x for x in range(1, 16)]
        for a in values:
            for b in values:
                for c in values:
                    for d in values:
                        row = a, b, c, d
                        self.move_table[row] = tuple(move_row(row))
                        self.move_table_r[row] = tuple(move_row(row[::-1])[::-1])

    def emptyGrid(self):
        return [[None,None,None,None],[None,None,None,None],
                [None,None,None,None],[None,None,None,None]]

    def rotateLeft(self, grid):
        g = grid
        return [
                (g[3][0], g[2][0], g[1][0], g[0][0]),
                (g[3][1], g[2][1], g[1][1], g[0][1]),
                (g[3][2], g[2][2], g[1][2], g[0][2]),
                (g[3][3], g[2][3], g[1][3], g[0][3]),
                ]

    def rotateRight(self, grid):
        g = grid
        return [
                (g[0][3], g[1][3], g[2][3], g[3][3]),
                (g[0][2], g[1][2], g[2][2], g[3][2]),
                (g[0][1], g[1][1], g[2][1], g[3][1]),
                (g[0][0], g[1][0], g[2][0], g[3][0]),
                ]

    def flip(self, grid):
        return [grid[3][::-1], grid[2][::-1], grid[1][::-1], grid[0][::-1]]

    def encode(self, grid):
        a = array.array('h')
        for x in range4:
            for y in range4:
                if grid[x][y]:
                    a.append(grid[x][y])
                else:
                    a.append(0)
        return a.tostring()

    def move(self, grid, direction):
        if direction == KEY_UP:
            rot = 1
        elif direction == KEY_RIGHT:
            rot = 2
        elif direction == KEY_DOWN:
            rot = 3
        else:
            rot = 0

        if rot == 3:
            tmp = [
                self.move_table_r[grid[0]],
                self.move_table_r[grid[1]],
                self.move_table_r[grid[2]],
                self.move_table_r[grid[3]],
                ]
            return tmp
        if rot == 1:
            pass
        elif rot == 0:
            grid = self.rotateRight(grid)
        elif rot == 3:
            grid = self.flip(grid)
        elif rot == 2:
            grid = self.rotateLeft(grid)

        out = [
                self.move_table[grid[0]],
                self.move_table[grid[1]],
                self.move_table[grid[2]],
                self.move_table[grid[3]],
                ]
        if rot == 0:
            out = self.rotateLeft(out)
        elif rot == 3:
            out = self.flip(out)
        elif rot == 2:
            out = self.rotateRight(out)

        return out

    def show(self, grid):
        for x in range(4):
            for y in range(4):
                if grid[x][y]:
                    print '%4d' % grid[x][y],
                else:
                    print '   .',
            print

    def canMove(self, grid, direction):
      return grid != self.move(grid, direction)

    def eval_monotone(self, grid):
      L = R = U = D = 0
      LR = UD = 0
      for x in range4:
        m = 0
        for y in range3:
          if grid[x][y] and grid[x][y] >= grid[x][y+1]:
            m += 1
            # 26090
            #L += m
            # 29281
            L += m ** 2 * 4
          else:
            # 20585
            #L -= abs(to_idx[grid[x][y]] - to_idx[grid[x][y+1]]) ** 2
            # 26090
            L -= abs((grid[x][y] or 0)- (grid[x][y+1] or 0)) * 1.5
            m = 0

        m = 0
        for y in range3:
          if grid[x][y] <= grid[x][y+1] and grid[x][y+1]:
            m += 1
            R += m ** 2 * 4
          else:
            #R -= abs(to_idx[grid[x][y]] - to_idx[grid[x][y+1]]) ** 2
            R -= abs((grid[x][y] or 0)- (grid[x][y+1] or 0)) * 1.5
            m = 0

      LR += max(L, R)
      L = R = 0

      for y in range4:
        m = 0
        for x in range3:
          if grid[x][y] and grid[x][y] >= grid[x+1][y]:
            m += 1
            U += m ** 2 * 4
          else:
            #U -= abs(to_idx[grid[x][y]] - to_idx[grid[x+1][y]]) ** 2
            U -= abs((grid[x][y] or 0)- (grid[x+1][y] or 0)) * 1.5
            m = 0

        m = 0
        for x in range3:
          if grid[x][y] <= grid[x+1][y] and grid[x+1][y]:
            m += 1
            D += m ** 2 * 4
          else:
            #D -= abs(to_idx[grid[x][y]] - to_idx[grid[x+1][y]]) ** 2
            D -= abs((grid[x][y] or 0)- (grid[x+1][y] or 0)) * 1.5
            m = 0

      UD += max(U, D)
      U = D = 0

      return LR + UD

    def eval_smoothness(self, grid):
        score_smooth = 0
        for x in range4:
            for y in range4:
                s = INF
                if x > 0: s = min(s, abs((grid[x][y] or 2) - (grid[x-1][y] or 2)))
                if y > 0: s = min(s, abs((grid[x][y] or 2) - (grid[x][y-1] or 2)))
                if x < 3: s = min(s, abs((grid[x][y] or 2) - (grid[x+1][y] or 2)))
                if y < 3: s = min(s, abs((grid[x][y] or 2) - (grid[x][y+1] or 2)))
                score_smooth -= s
        return score_smooth

    def eval_free(self, grid):
      free = 0
      for i in range4:
        for j in range4:
          if grid[i][j] is None:
            free += 1
      return -(16-free)**2

    def eval(self, grid):
      key = self.encode(grid)
      if key in self.table:
        return self.table[key]

      self.eval_count += 1

      score_monotone = self.eval_monotone(grid)
      score_smooth = self.eval_smoothness(grid)
      score_free = self.eval_free(grid)

      score = 0
      score += score_smooth
      score += score_monotone
      score += score_free

      self.table[key] = score
      return score

    def search_max(self, grid, depth, a, b, moves):
      for m in moves:
        g2 = self.move(grid, m)
        if g2 == grid:
          continue
        score = self.search_min(g2, depth - 1, a, b)
        #print 'search_max', m, score
        if score >= b:
          return b
        if score > a:
          a = score

      return a

    def search_min(self, grid, depth, a, b):
      if depth == 0:
        return self.eval(grid)

      key = self.encode(grid), depth
      if key in self.table:
        return self.table[key]

      #g = clone(grid)
      #assert g == grid
      #print '=' * 30
      #self.show(grid)
      for i in range4:
        for j in range4:
          if grid[i][j] is not None:
            continue

          tmp = list(grid[i])
          for v in (2, 4):
            tmp[j] = v
            grid[i] = tuple(tmp)
            score = self.search_max(grid, depth, a, b, moves)
            if score <= a:
              tmp[j] = None
              grid[i] = tuple(tmp)
              return a
            if score < b:
              b = score

          tmp[j] = None
          grid[i] = tuple(tmp)

      self.table[key] = b
      return b

    def reset(self):
      self.eval_count = 0
      self.table = {}

    def getNextMove(self, grid):
      best_score = -INF
      best_move = random.choice(moves)
      self.reset()

      t0 = time.time()
      grid = map(tuple, grid)
      for m in moves:
        #print 'move', m
        g2 = self.move(grid, m)
        if g2 == grid:
          continue
        #print grid
        #print g2
        score = self.search_min(g2, 3-1, -INF, INF)

        #print score, m
        if score > best_score:
          best_score = score
          best_move = m
        #print '-'
      t1 = time.time()

      self.total_time += t1 - t0
      self.total_node += self.eval_count
      print 't=%.2fs, node=%d, total_node=%d, %fnps' % (
          t1-t0, self.eval_count, self.total_node, self.total_node/self.total_time)

      return best_move

# vim:sw=4:expandtab
<|endoftext|>