<commit_before>import logging
import os
import re
from glob import glob

from toolbox.config.docker import CONFIG_KEYS, CRP_CONFIG_ITEM_KEYS, CAPABILITIES
from toolbox.utils import check_common_files, counted_error, validate_bool, validate_flag, validate_ports

from .utils import sorted_container_configs, yield_dockerfiles

def check_config(config: dict):  # pylint: disable=too-many-branches
    invalid_keys = set(config.keys()) - set(CONFIG_KEYS)
    if invalid_keys:
        counted_error('Invalid key(s) found in config.yml: %s', invalid_keys)

    first = True
    for _, item in sorted_container_configs(config['crp_config']):
        if not isinstance(item, dict):
            counted_error('Items of crp_config must be dictionaries.')

        invalid_keys = set(item.keys()) - set(CRP_CONFIG_ITEM_KEYS)
        if invalid_keys:
            counted_error('Invalid key(s) found in crp_config: %s', invalid_keys)

        if 'image' in item and item['image'].find('/') >= 0:
            counted_error('If the image is explicitly defined, it must be relative to the registry '
                          '- e.g. challenge:solvable.')

        if 'capabilities' in item:
            invalid_caps = set(item['capabilities']) - CAPABILITIES
            if invalid_caps:
                counted_error('Forbidden capabilities: %s\n\tAllowed capabilities: %s',
                              invalid_caps, CAPABILITIES)

        if 'mem_limit_mb' in item:
            if not str(item['mem_limit_mb']).isnumeric() or not 8 <= int(item['mem_limit_mb']) <= 1024:
                counted_error('Invalid mem_limit_mb: %s. It should be an integer between 8 and 1024 MegaBytes.',
                              item['mem_limit_mb'])

        if 'cpu_limit_ms' in item:
            if not str(item['cpu_limit_ms']).isnumeric() or not 100 <= int(item['cpu_limit_ms']) <= 4000:
                counted_error('Invalid cpu_limit_ms: %s. It should be an integer between 100 and 4000 CPU milliseconds.',
                              item['cpu_limit_ms'])

        if 'volumes' in item:
            if not first:
                counted_error('Only the first container [solvable, controller, ...] can set shared volumes.')
            else:
                logging.warning('Shared volumes are manually set. Is this what you want?')

        validate_bool('read_only', item.get('read_only', '0'))
        validate_ports(item.get('ports', []), item.get('buttons', None))
        first = False

    validate_flag(config)

def check_dockerfile(filename):
    repo_pattern = r'FROM ((docker\.io\/)?avatao|eu\.gcr\.io\/avatao-challengestore)\/'
    try:
        with open(filename, 'r') as f:
            d = f.read()
            if re.search(repo_pattern, d) is None:
                counted_error('Please, use avatao base images for your challenges. Our base images '
                              'are available at https://hub.docker.com/u/avatao/')
    except FileNotFoundError as e:
        counted_error('Could not open %s', e.filename)

    except Exception as e:
        counted_error('An error occurred while loading %s. \n\tDetails: %s', filename, e)

def check_misc():
    check_common_files()

    if not glob('src/*'):
        logging.warning('Missing or empty "src" directory. Please, place your source files there '
                        'if your challenge has any.')

def run(repo_path: str, repo_name: str, repo_branch: str, config: dict):
    os.chdir(repo_path)

    check_config(config)
    check_misc()

    for dockerfile, _ in yield_dockerfiles(repo_path, repo_branch, repo_name, config['crp_config']):
        check_dockerfile(dockerfile)
<commit_msg>Increase max memory limit for docker<commit_after>import logging
import os
import re
from glob import glob

from toolbox.config.docker import CONFIG_KEYS, CRP_CONFIG_ITEM_KEYS, CAPABILITIES
from toolbox.utils import check_common_files, counted_error, validate_bool, validate_flag, validate_ports

from .utils import sorted_container_configs, yield_dockerfiles

def check_config(config: dict):  # pylint: disable=too-many-branches
    invalid_keys = set(config.keys()) - set(CONFIG_KEYS)
    if invalid_keys:
        counted_error('Invalid key(s) found in config.yml: %s', invalid_keys)

    first = True
    for _, item in sorted_container_configs(config['crp_config']):
        if not isinstance(item, dict):
            counted_error('Items of crp_config must be dictionaries.')

        invalid_keys = set(item.keys()) - set(CRP_CONFIG_ITEM_KEYS)
        if invalid_keys:
            counted_error('Invalid key(s) found in crp_config: %s', invalid_keys)

        if 'image' in item and item['image'].find('/') >= 0:
            counted_error('If the image is explicitly defined, it must be relative to the registry '
                          '- e.g. challenge:solvable.')

        if 'capabilities' in item:
            invalid_caps = set(item['capabilities']) - CAPABILITIES
            if invalid_caps:
                counted_error('Forbidden capabilities: %s\n\tAllowed capabilities: %s',
                              invalid_caps, CAPABILITIES)

        if 'mem_limit_mb' in item:
            if not str(item['mem_limit_mb']).isnumeric() or not 8 <= int(item['mem_limit_mb']) <= 2048:
                counted_error('Invalid mem_limit_mb: %s. It should be an integer between 8 and 2048 MegaBytes.',
                              item['mem_limit_mb'])

        if 'cpu_limit_ms' in item:
            if not str(item['cpu_limit_ms']).isnumeric() or not 100 <= int(item['cpu_limit_ms']) <= 4000:
                counted_error('Invalid cpu_limit_ms: %s. It should be an integer between 100 and 4000 CPU milliseconds.',
                              item['cpu_limit_ms'])

        if 'volumes' in item:
            if not first:
                counted_error('Only the first container [solvable, controller, ...] can set shared volumes.')
            else:
                logging.warning('Shared volumes are manually set. Is this what you want?')

        validate_bool('read_only', item.get('read_only', '0'))
        validate_ports(item.get('ports', []), item.get('buttons', None))
        first = False

    validate_flag(config)

def check_dockerfile(filename):
    repo_pattern = r'FROM ((docker\.io\/)?avatao|eu\.gcr\.io\/avatao-challengestore)\/'
    try:
        with open(filename, 'r') as f:
            d = f.read()
            if re.search(repo_pattern, d) is None:
                counted_error('Please, use avatao base images for your challenges. Our base images '
                              'are available at https://hub.docker.com/u/avatao/')
    except FileNotFoundError as e:
        counted_error('Could not open %s', e.filename)

    except Exception as e:
        counted_error('An error occurred while loading %s. \n\tDetails: %s', filename, e)

def check_misc():
    check_common_files()

    if not glob('src/*'):
        logging.warning('Missing or empty "src" directory. Please, place your source files there '
                        'if your challenge has any.')

def run(repo_path: str, repo_name: str, repo_branch: str, config: dict):
    os.chdir(repo_path)

    check_config(config)
    check_misc()

    for dockerfile, _ in yield_dockerfiles(repo_path, repo_branch, repo_name, config['crp_config']):
        check_dockerfile(dockerfile)
<|endoftext|>


<commit_before>import tornado.web
import tornado.ioloop
import tornado.httpserver
from tornado.options import define,options
import os
import time
import subprocess
import glob
from subprocess import PIPE

define("port",default=8080,help="Frontend port",type=int)
options.parse_command_line()

current_port = [5000]

class Application(tornado.web.Application):
	def __init__(self):
		handlers = [
			(r"/", MainHandler),
			(r"/home", HomeHandler),
			(r"/video", VideoHandler),
			(r"/port", PortHandler),
		]

		settings = dict(
			debug = True,
			template_path = os.path.join(os.path.dirname(__file__),"templates"),
			static_path = os.path.join(os.path.dirname(__file__),"static"),
			login_url = "/auth",
			cookie_secret = "Settings.COOKIE_SECRET",
		)
		tornado.web.Application.__init__(self,handlers,**settings)

class BaseHandler(tornado.web.RequestHandler):
	def prepare(self):
		pass

class MainHandler(BaseHandler):
	def get(self):
		self.redirect("/home")

class HomeHandler(BaseHandler):
	def get(self):
		files = glob.glob("static/video/*.mp4")
		data = dict()
		data["files"] = []
		for file in files:
			if "background" not in file:
				data["files"].append(file)
		print data
		self.render("home.html",**data)

class VideoHandler(BaseHandler):
	def post(self):
		sdp_headers = self.get_argument('sdp',None)
		path = "static/video"
		with open('%s/stream.sdp' % path,'w') as f:
			f.write(sdp_headers)

		ts = time.strftime("%Y_%m_%d_%H_%M_%S")
		cmd = "ffmpeg -i {}/stream.sdp -vcodec libx264 -acodec aac -strict -2 -y {}/{}.mp4 && avconv -ss 00:00:02 -i %s/%s.mp4 -vsync 1 -t 0.01 %s/%s.jpg".format(path,path,path,ts,path,ts)
		subprocess.Popen(cmd,stdout=PIPE,stderr=PIPE,shell=True)

class PortHandler(BaseHandler):
	def get(self):
		data = "%s %s" %(current_port[0],current_port[0]+2)
		current_port[0] += 2
		if(current_port[0] >= 5500):
			current_port[0] = 5000
		self.write(data)

if __name__ == "__main__":
	http_server = tornado.httpserver.HTTPServer(Application())
	http_server.listen(options.port)
	tornado.ioloop.IOLoop.instance().start()

<commit_msg>Format<commit_after>import tornado.web
import tornado.ioloop
import tornado.httpserver
from tornado.options import define,options
import os
import time
import subprocess
import glob
from subprocess import PIPE

define("port",default=8080,help="Frontend port",type=int)
options.parse_command_line()

current_port = [5000]

class Application(tornado.web.Application):
	def __init__(self):
		handlers = [
			(r"/", MainHandler),
			(r"/home", HomeHandler),
			(r"/video", VideoHandler),
			(r"/port", PortHandler),
		]

		settings = dict(
			debug = True,
			template_path = os.path.join(os.path.dirname(__file__),"templates"),
			static_path = os.path.join(os.path.dirname(__file__),"static"),
			login_url = "/auth",
			cookie_secret = "Settings.COOKIE_SECRET",
		)
		tornado.web.Application.__init__(self,handlers,**settings)

class BaseHandler(tornado.web.RequestHandler):
	def prepare(self):
		pass

class MainHandler(BaseHandler):
	def get(self):
		self.redirect("/home")

class HomeHandler(BaseHandler):
	def get(self):
		files = glob.glob("static/video/*.mp4")
		data = dict()
		data["files"] = []
		for file in files:
			if "background" not in file:
				data["files"].append(file)
		print data
		self.render("home.html",**data)

class VideoHandler(BaseHandler):
	def post(self):
		sdp_headers = self.get_argument('sdp',None)
		path = "static/video"
		with open('%s/stream.sdp' % path,'w') as f:
			f.write(sdp_headers)

		ts = time.strftime("%Y_%m_%d_%H_%M_%S")
		cmd = "ffmpeg -i {}/stream.sdp -vcodec libx264 -acodec aac -strict -2 -y {}/{}.mp4 && \
				avconv -ss 00:00:02 -i %s/%s.mp4 -vsync 1 -t 0.01 %s/%s.jpg".format(path,path,ts,path,ts,path,ts)
		subprocess.Popen(cmd,stdout=PIPE,stderr=PIPE,shell=True)

class PortHandler(BaseHandler):
	def get(self):
		data = "%s %s" %(current_port[0],current_port[0]+2)
		current_port[0] += 2
		if(current_port[0] >= 5500):
			current_port[0] = 5000
		self.write(data)

if __name__ == "__main__":
	http_server = tornado.httpserver.HTTPServer(Application())
	http_server.listen(options.port)
	tornado.ioloop.IOLoop.instance().start()

<|endoftext|>


<commit_before>import atexit
import logging
import os
import subprocess
import time
from collections import OrderedDict, defaultdict
from copy import deepcopy
from posixpath import join
from typing import Any, Dict, List, Tuple
from uuid import uuid4

from toolbox.config.docker import ENABLE_CPU_LIMITS, FORWARD_PORTS
from toolbox.utils import parse_bool, fatal_error

from .utils import get_image_url, sorted_container_configs

BIND_ADDR = '127.0.0.1'
ULIMIT_NPROC = '2048:4096'
ULIMIT_NOFILE = '8192:16384'
SECRET = 'secret'

DEFAULT_CPU_LIMIT_MS = 1000  # 1 vCPU
DEFAULT_MEMORY_LIMIT_MB = 100  # MiB

CONNECTION_USAGE = defaultdict(lambda: 'nc ' + BIND_ADDR + ' %d')
CONNECTION_USAGE.update({
    'ssh': 'ssh -p %d user@' + BIND_ADDR + ' Password: ' + SECRET,
    'http': 'http://' + BIND_ADDR + ':%d',
})

# Hack to allow parallel executions. There are also such labels in production.
INSTANCE_LABEL = "com.avatao.instance_id"
INSTANCE_ID = uuid4()

def parse_crp_config(repo_name: str, repo_branch: str, crp_config: Dict[str, Dict]) -> List[Tuple[str, Dict]]:
    # This is not how things work anymore but the end result is the same...
    # The order is important because of namespace and volume sharing!
    crp_config = deepcopy(crp_config)
    contaner_configs = sorted_container_configs(crp_config)

    # Set all ports on the first container in the format below...
    # Also set absolute image URLs here
    ports = {}
    for short_name, crp_config_item in contaner_configs:
        crp_config_item['image'] = get_image_url(repo_name, repo_branch, short_name, crp_config_item)

        # Convert ['port/L7_proto'] format to {'port/L4_proto': 'L7_proto'}
        # * We do not differentiate udp at layer 7
        for port in crp_config_item.pop('ports', []):
            parts = port.lower().split('/', 1)
            proto_l7 = parts[1] if len(parts) == 2 else 'tcp'
            port_proto = join(parts[0], 'udp' if proto_l7 == 'udp' else 'tcp')
            ports[port_proto] = proto_l7

    # Set the ports in the first container's config.
    contaner_configs[0][1]['ports'] = ports
    return contaner_configs

def get_container_command(
    crp_config_item: Dict[str, Any], short_name: str, share_with: str = None
) -> Tuple[subprocess.Popen, str, str]:

    container_name = '-'.join((str(INSTANCE_ID), short_name))
    image = crp_config_item['image']

    command = [
        'docker', 'run',
        '-e', 'AVATAO_CHALLENGE_ID=00000000-0000-0000-0000-000000000000',
        '-e', 'AVATAO_USER_ID=00000000-0000-0000-0000-000000000000',
        '-e', 'AVATAO_INSTANCE_ID=%s' % INSTANCE_ID,
        '-e', 'AVATAO_SECRET=%s' % SECRET,
        '-e', 'SECRET=%s' % SECRET,  # for compatibility!
        '--name=%s' % container_name,
        '--label=%s=%s' % (INSTANCE_LABEL, INSTANCE_ID),
        '--memory=%sM' % crp_config_item.get('mem_limit_mb', DEFAULT_MEMORY_LIMIT_MB),
        '--ulimit=nproc=%s' % ULIMIT_NPROC,
        '--ulimit=nofile=%s' % ULIMIT_NOFILE,
    ]

    if ENABLE_CPU_LIMITS:
        cpus = round(int(crp_config_item.get('cpu_limit_ms', DEFAULT_CPU_LIMIT_MS)) / 1000, 2)
        command.append('--cpus=%s' % cpus)

    if FORWARD_PORTS and 'ports' in crp_config_item:
        for port, proto_l7 in crp_config_item['ports'].items():
            port_num = int(port.split('/')[0])
            command += ['-p', '%s:%d:%s' % (BIND_ADDR, port_num, port)]
            logging.info('Connection: %s', CONNECTION_USAGE[proto_l7] % port_num)

    if 'capabilities' in crp_config_item:
        command += ['--cap-drop=ALL']
        command += ['--cap-add=%s' % cap for cap in crp_config_item['capabilities']]

    if crp_config_item.get('read_only', False):
        command += ['--read-only']

    if share_with is None:
        # Disable DNS as there will be no internet access in production
        command += ['--dns=0.0.0.0', '--hostname=avatao']
    else:
        # Share the first container's network namespace and volumes
        command += [
            '--network=container:%s' % share_with,
            '--volumes-from=%s' % share_with,
        ]

    # Absolute URL of the image
    command += [image]
    return command, container_name

def poll_container(proc: subprocess.Popen, container_name: str, *, retries: int, sleeps: float):
    for i in range(0, retries):
        logging.debug('Waiting %ds for %s [%d/%d]', sleeps, container_name, i + 1, retries)
        time.sleep(sleeps)

        # Check whether the process exited
        if proc.poll() is not None:
            raise ValueError('Container exited!')

        try:
            # Check whether the container is running yet
            running: str = subprocess.check_output(
                ['docker', 'inspect', '-f', '{{.State.Running}}', container_name],
                stderr=subprocess.DEVNULL).decode('utf-8').strip()

            if parse_bool(running):
                break
        except subprocess.CalledProcessError:
            pass
    else:
        raise ValueError('Container timed out!')

def run_container(
    crp_config_item: Dict[str, Any], short_name: str, share_with: str = None
) -> Tuple[subprocess.Popen, str]:

    command, container_name = get_container_command(crp_config_item, short_name, share_with)
    image = crp_config_item['image']

    try:
        # Check whether the image exists to avoid horrific edge-cases
        image_output: str = subprocess.check_output(['docker', 'images', '-q', image]).decode('utf-8').rstrip()
        if not image_output:
            fatal_error('Image %s not found! Please, make sure it exists.' % image)

        logging.debug(' '.join(map(str, command)))
        proc = subprocess.Popen(command)

        # (ಥ﹏ಥ)
        poll_container(proc, container_name, retries=15, sleeps=5.0)
        # Ready but PID 1 might not be so wait some more...
        time.sleep(5.0)

        return proc, container_name

    except (subprocess.CalledProcessError, ValueError):
        fatal_error('Failed to run %s!' % image)

def remove_containers():
    subprocess.Popen(
        ['sh', '-c', 'docker rm -fv $(docker ps -aq --filter=label=%s=%s)' % (INSTANCE_LABEL, INSTANCE_ID)],
        stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL).wait()

def start_containers(repo_name: str, repo_branch: str, crp_config: Dict[str, Dict]) -> Dict[str, subprocess.Popen]:
    proc_map, first = OrderedDict(), None
    for short_name, crp_config_item in parse_crp_config(repo_name, repo_branch, crp_config):
        proc, container_name = run_container(crp_config_item, short_name, share_with=first)
        proc_map[container_name] = proc
        if first is None:
            first = container_name

    return proc_map

def run(repo_path: str, repo_name: str, repo_branch: str, config: dict):
    os.chdir(repo_path)
    atexit.register(remove_containers)
    proc_map = start_containers(repo_name, repo_branch, config['crp_config'])

    logging.info('When you gracefully terminate this script [Ctrl+C] the containers will be destroyed.')
    for proc in proc_map.values():
        try:
            proc.wait()
        except KeyboardInterrupt:
            break
<commit_msg>Increase docker start timeout again<commit_after>import atexit
import logging
import os
import subprocess
import time
from collections import OrderedDict, defaultdict
from copy import deepcopy
from posixpath import join
from typing import Any, Dict, List, Tuple
from uuid import uuid4

from toolbox.config.docker import ENABLE_CPU_LIMITS, FORWARD_PORTS
from toolbox.utils import parse_bool, fatal_error

from .utils import get_image_url, sorted_container_configs

BIND_ADDR = '127.0.0.1'
ULIMIT_NPROC = '2048:4096'
ULIMIT_NOFILE = '8192:16384'
SECRET = 'secret'

DEFAULT_CPU_LIMIT_MS = 1000  # 1 vCPU
DEFAULT_MEMORY_LIMIT_MB = 100  # MiB

CONNECTION_USAGE = defaultdict(lambda: 'nc ' + BIND_ADDR + ' %d')
CONNECTION_USAGE.update({
    'ssh': 'ssh -p %d user@' + BIND_ADDR + ' Password: ' + SECRET,
    'http': 'http://' + BIND_ADDR + ':%d',
})

# Hack to allow parallel executions. There are also such labels in production.
INSTANCE_LABEL = "com.avatao.instance_id"
INSTANCE_ID = uuid4()

def parse_crp_config(repo_name: str, repo_branch: str, crp_config: Dict[str, Dict]) -> List[Tuple[str, Dict]]:
    # This is not how things work anymore but the end result is the same...
    # The order is important because of namespace and volume sharing!
    crp_config = deepcopy(crp_config)
    contaner_configs = sorted_container_configs(crp_config)

    # Set all ports on the first container in the format below...
    # Also set absolute image URLs here
    ports = {}
    for short_name, crp_config_item in contaner_configs:
        crp_config_item['image'] = get_image_url(repo_name, repo_branch, short_name, crp_config_item)

        # Convert ['port/L7_proto'] format to {'port/L4_proto': 'L7_proto'}
        # * We do not differentiate udp at layer 7
        for port in crp_config_item.pop('ports', []):
            parts = port.lower().split('/', 1)
            proto_l7 = parts[1] if len(parts) == 2 else 'tcp'
            port_proto = join(parts[0], 'udp' if proto_l7 == 'udp' else 'tcp')
            ports[port_proto] = proto_l7

    # Set the ports in the first container's config.
    contaner_configs[0][1]['ports'] = ports
    return contaner_configs

def get_container_command(
    crp_config_item: Dict[str, Any], short_name: str, share_with: str = None
) -> Tuple[subprocess.Popen, str, str]:

    container_name = '-'.join((str(INSTANCE_ID), short_name))
    image = crp_config_item['image']

    command = [
        'docker', 'run',
        '-e', 'AVATAO_CHALLENGE_ID=00000000-0000-0000-0000-000000000000',
        '-e', 'AVATAO_USER_ID=00000000-0000-0000-0000-000000000000',
        '-e', 'AVATAO_INSTANCE_ID=%s' % INSTANCE_ID,
        '-e', 'AVATAO_SECRET=%s' % SECRET,
        '-e', 'SECRET=%s' % SECRET,  # for compatibility!
        '--name=%s' % container_name,
        '--label=%s=%s' % (INSTANCE_LABEL, INSTANCE_ID),
        '--memory=%sM' % crp_config_item.get('mem_limit_mb', DEFAULT_MEMORY_LIMIT_MB),
        '--ulimit=nproc=%s' % ULIMIT_NPROC,
        '--ulimit=nofile=%s' % ULIMIT_NOFILE,
    ]

    if ENABLE_CPU_LIMITS:
        cpus = round(int(crp_config_item.get('cpu_limit_ms', DEFAULT_CPU_LIMIT_MS)) / 1000, 2)
        command.append('--cpus=%s' % cpus)

    if FORWARD_PORTS and 'ports' in crp_config_item:
        for port, proto_l7 in crp_config_item['ports'].items():
            port_num = int(port.split('/')[0])
            command += ['-p', '%s:%d:%s' % (BIND_ADDR, port_num, port)]
            logging.info('Connection: %s', CONNECTION_USAGE[proto_l7] % port_num)

    if 'capabilities' in crp_config_item:
        command += ['--cap-drop=ALL']
        command += ['--cap-add=%s' % cap for cap in crp_config_item['capabilities']]

    if crp_config_item.get('read_only', False):
        command += ['--read-only']

    if share_with is None:
        # Disable DNS as there will be no internet access in production
        command += ['--dns=0.0.0.0', '--hostname=avatao']
    else:
        # Share the first container's network namespace and volumes
        command += [
            '--network=container:%s' % share_with,
            '--volumes-from=%s' % share_with,
        ]

    # Absolute URL of the image
    command += [image]
    return command, container_name

def poll_container(proc: subprocess.Popen, container_name: str, *, retries: int, sleeps: float):
    for i in range(0, retries):
        logging.debug('Waiting %ds for %s [%d/%d]', sleeps, container_name, i + 1, retries)
        time.sleep(sleeps)

        # Check whether the process exited
        if proc.poll() is not None:
            raise ValueError('Container exited!')

        try:
            # Check whether the container is running yet
            running: str = subprocess.check_output(
                ['docker', 'inspect', '-f', '{{.State.Running}}', container_name],
                stderr=subprocess.DEVNULL).decode('utf-8').strip()

            if parse_bool(running):
                break
        except subprocess.CalledProcessError:
            pass
    else:
        raise ValueError('Container timed out!')

def run_container(
    crp_config_item: Dict[str, Any], short_name: str, share_with: str = None
) -> Tuple[subprocess.Popen, str]:

    command, container_name = get_container_command(crp_config_item, short_name, share_with)
    image = crp_config_item['image']

    try:
        # Check whether the image exists to avoid horrific edge-cases
        image_output: str = subprocess.check_output(['docker', 'images', '-q', image]).decode('utf-8').rstrip()
        if not image_output:
            fatal_error('Image %s not found! Please, make sure it exists.' % image)

        logging.debug(' '.join(map(str, command)))
        proc = subprocess.Popen(command)

        # (ಥ﹏ಥ)
        poll_container(proc, container_name, retries=30, sleeps=5.0)
        # Ready but PID 1 might not be so wait some more...
        time.sleep(5.0)

        return proc, container_name

    except (subprocess.CalledProcessError, ValueError):
        fatal_error('Failed to run %s!' % image)

def remove_containers():
    subprocess.Popen(
        ['sh', '-c', 'docker rm -fv $(docker ps -aq --filter=label=%s=%s)' % (INSTANCE_LABEL, INSTANCE_ID)],
        stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL).wait()

def start_containers(repo_name: str, repo_branch: str, crp_config: Dict[str, Dict]) -> Dict[str, subprocess.Popen]:
    proc_map, first = OrderedDict(), None
    for short_name, crp_config_item in parse_crp_config(repo_name, repo_branch, crp_config):
        proc, container_name = run_container(crp_config_item, short_name, share_with=first)
        proc_map[container_name] = proc
        if first is None:
            first = container_name

    return proc_map

def run(repo_path: str, repo_name: str, repo_branch: str, config: dict):
    os.chdir(repo_path)
    atexit.register(remove_containers)
    proc_map = start_containers(repo_name, repo_branch, config['crp_config'])

    logging.info('When you gracefully terminate this script [Ctrl+C] the containers will be destroyed.')
    for proc in proc_map.values():
        try:
            proc.wait()
        except KeyboardInterrupt:
            break
<|endoftext|>


<commit_before>__version__ = '0.9.0'
<commit_msg>start working on 0.10<commit_after>__version__ = '0.10.0-dev'
<|endoftext|>


<commit_before>from django.core.urlresolvers import reverse
from rdrf.models import RDRFContext
from rdrf.models import RegistryForm, Section
from django.contrib.contenttypes.models import ContentType

import logging
logger = logging.getLogger(__name__)

class NavigationError(Exception):
    pass

class NavigationFormType:
    DEMOGRAPHICS = 1
    CONSENTS = 2
    CLINICAL = 3

class NavigationWizard(object):

    def __init__(self, user, registry_model, patient_model, form_type, context_id, current_form_model=None):
        self.user = user
        self.registry_model = registry_model
        self.patient_model = patient_model
        self.form_type = form_type
        self.context_id = context_id
        self.on_create_form_view = context_id == 'add'
        self.current_form_model = current_form_model
        self.links = []
        self.current_index = None  # set by method below

        self._construct_links()

    def _construct_links(self):
        # aim is to construct a web ring of links:
        # --> demographics --> consents --> fixed group 1 form 1 --> fixed group 1 form 2 --> ... --> --> multiple group 1 assessment 1 form 1 ---> ..
        # ^<---  free form n <---  free form n -1 <--                                                                                <--^
        demographics_link = self._construct_demographics_link()
        self.links.append(demographics_link)
        consents_link = self._construct_consents_link()
        self.links.append(consents_link)

        # there is one context per fixed group (always)
        for fixed_form_group in self._fixed_form_groups():
            for form_model in fixed_form_group.form_models:
                if self.user.can_view(form_model):
                    self.links.append(self._construct_fixed_form_link(fixed_form_group, form_model))

        # for each multiple group, link through each assessment created for that group
        # in form order
        for multiple_form_group in self._multiple_form_groups():
            for context_model in self._get_multiple_contexts(multiple_form_group):
                for form_model in multiple_form_group.form_models:
                    if self.user.can_view(form_model):
                        self.links.append(self._form_link(form_model, context_model))

        # if form models have not been partitioned into form groups, they are "free"
        # most registries just have free forms because they don't define form groups
        for form_model in self._free_forms():
            if self.user.can_view(form_model):
                self.links.append(self._construct_free_form_link(form_model))

        if not self.on_create_form_view:
            self.current_index = self._determine_current_index()

    def _construct_free_form_link(self, form_model):
        # get default context model from patient
        context_model = self.patient_model.default_context(self.registry_model)
        return self._form_link(form_model, context_model)

    def _form_link(self, form_model, context_model):
        link = reverse('registry_form', args=(self.registry_model.code,
                                              form_model.id, self.patient_model.pk, context_model.id))
        return "clinical", form_model.pk, link

    def _fixed_form_groups(self):
        return [cfg for cfg in self.registry_model.fixed_form_groups]

    def _multiple_form_groups(self):
        return [cfg for cfg in self.registry_model.multiple_form_groups]

    def _get_multiple_contexts(self, multiple_form_group):
        def keyfunc(context_model):

            # FollowUp/FHFollowUp/DateOfAssessment
            name_path = multiple_form_group.naming_cde_to_use
            form_name,section_code,cde_code = name_path.split("/")
            section_model = Section.objects.get(code=section_code)
            is_multisection = section_model.allow_multiple

            try:
                return self.patient_model.get_form_value(self.registry_model.code,
                                                         form_name,
                                                         section_code,
                                                         cde_code,
                                                         multisection=is_multisection,
                                                         context_id=context_model.id)
            except:
                 raise Exception("Could not get CDE data (Date of assessment).")

        if multiple_form_group.ordering == "N":
            key_func = keyfunc
        else:
            key_func = lambda c : c.created_at

        contexts = [c for c in self.patient_model.context_models
                    if c.context_form_group is not None and c.context_form_group.pk == multiple_form_group.pk]

        return sorted(contexts, key=key_func, reverse=True)

    def _construct_demographics_link(self):
        return ("demographic", None, reverse("patient_edit", args=[self.registry_model.code, self.patient_model.pk]))

    def _construct_consents_link(self):
        return ("consents", None, reverse("consent_form_view", args=[self.registry_model.code, self.patient_model.pk]))

    def _construct_fixed_form_link(self, fixed_form_group, form_model):
        context_models = list(RDRFContext.objects.filter(context_form_group=fixed_form_group,
                                                         object_id=self.patient_model.pk,
                                                         content_type__model="patient"))

        num_contexts = len(context_models)
        assert num_contexts == 1, "There should only be one context model for this fixed context there are: %s" % num_contexts

        context_model = context_models[0]

        return self._form_link(form_model, context_model)

    def _free_forms(self):
        if self.registry_model.is_normal:
            return [f for f in self.registry_model.forms if not f.is_questionnaire]
        else:
            return []

    def _determine_current_index(self):
        # where are we in the link ring?
        if self.form_type == NavigationFormType.DEMOGRAPHICS:
            return 0  # because demographics is always added first
        elif self.form_type == NavigationFormType.CONSENTS:
            return 1
        else:
            # we're on some form
            for index, (name, form_id, link) in enumerate(self.links):
                if name in ['demographic', 'consents']:
                    continue
                # form link so get the models
                form_model = RegistryForm.objects.get(pk=form_id)
                link_parts = link.split("/")
                context_id = int(link_parts[-1])
                if form_model.pk == self.current_form_model.pk:
                    if context_id == int(self.context_id):
                        return index

        # shouldn't get here ...
        raise Exception("could not determine current index!")

    @property
    def previous_link(self):
        if self.on_create_form_view:
            # unsure what to do here
            return self.links[0]

        num_links = len(self.links)
        next_index = (self.current_index - 1) % num_links
        return self.links[next_index][-1]

    @property
    def next_link(self):
        if self.on_create_form_view:
            # unsure what to do here
            return self.links[0]
        num_links = len(self.links)
        next_index = (self.current_index + 1) % num_links
        return self.links[next_index][-1]
<commit_msg>rdrf #482 wizard should not display message about DateOfAssessment<commit_after>from django.core.urlresolvers import reverse
from rdrf.models import RDRFContext
from rdrf.models import RegistryForm, Section
from django.contrib.contenttypes.models import ContentType

import logging
logger = logging.getLogger(__name__)

class NavigationError(Exception):
    pass

class NavigationFormType:
    DEMOGRAPHICS = 1
    CONSENTS = 2
    CLINICAL = 3

class NavigationWizard(object):

    def __init__(self, user, registry_model, patient_model, form_type, context_id, current_form_model=None):
        self.user = user
        self.registry_model = registry_model
        self.patient_model = patient_model
        self.form_type = form_type
        self.context_id = context_id
        self.on_create_form_view = context_id == 'add'
        self.current_form_model = current_form_model
        self.links = []
        self.current_index = None  # set by method below

        self._construct_links()

    def _construct_links(self):
        # aim is to construct a web ring of links:
        # --> demographics --> consents --> fixed group 1 form 1 --> fixed group 1 form 2 --> ... --> --> multiple group 1 assessment 1 form 1 ---> ..
        # ^<---  free form n <---  free form n -1 <--                                                                                <--^
        demographics_link = self._construct_demographics_link()
        self.links.append(demographics_link)
        consents_link = self._construct_consents_link()
        self.links.append(consents_link)

        # there is one context per fixed group (always)
        for fixed_form_group in self._fixed_form_groups():
            for form_model in fixed_form_group.form_models:
                if self.user.can_view(form_model):
                    self.links.append(self._construct_fixed_form_link(fixed_form_group, form_model))

        # for each multiple group, link through each assessment created for that group
        # in form order
        for multiple_form_group in self._multiple_form_groups():
            for context_model in self._get_multiple_contexts(multiple_form_group):
                for form_model in multiple_form_group.form_models:
                    if self.user.can_view(form_model):
                        self.links.append(self._form_link(form_model, context_model))

        # if form models have not been partitioned into form groups, they are "free"
        # most registries just have free forms because they don't define form groups
        for form_model in self._free_forms():
            if self.user.can_view(form_model):
                self.links.append(self._construct_free_form_link(form_model))

        if not self.on_create_form_view:
            self.current_index = self._determine_current_index()

    def _construct_free_form_link(self, form_model):
        # get default context model from patient
        context_model = self.patient_model.default_context(self.registry_model)
        return self._form_link(form_model, context_model)

    def _form_link(self, form_model, context_model):
        link = reverse('registry_form', args=(self.registry_model.code,
                                              form_model.id, self.patient_model.pk, context_model.id))
        return "clinical", form_model.pk, link

    def _fixed_form_groups(self):
        return [cfg for cfg in self.registry_model.fixed_form_groups]

    def _multiple_form_groups(self):
        return [cfg for cfg in self.registry_model.multiple_form_groups]

    def _get_multiple_contexts(self, multiple_form_group):
        def keyfunc(context_model):
            name_path = multiple_form_group.naming_cde_to_use
            form_name,section_code,cde_code = name_path.split("/")
            section_model = Section.objects.get(code=section_code)
            is_multisection = section_model.allow_multiple

            return self.patient_model.get_form_value(self.registry_model.code,
                                                     form_name,
                                                     section_code,
                                                     cde_code,
                                                     multisection=is_multisection,
                                                     context_id=context_model.id)

        if multiple_form_group.ordering == "N":
            key_func = keyfunc
        else:
            key_func = lambda c : c.created_at

        contexts = [c for c in self.patient_model.context_models
                    if c.context_form_group is not None and c.context_form_group.pk == multiple_form_group.pk]

        return sorted(contexts, key=key_func, reverse=True)

    def _construct_demographics_link(self):
        return ("demographic", None, reverse("patient_edit", args=[self.registry_model.code, self.patient_model.pk]))

    def _construct_consents_link(self):
        return ("consents", None, reverse("consent_form_view", args=[self.registry_model.code, self.patient_model.pk]))

    def _construct_fixed_form_link(self, fixed_form_group, form_model):
        context_models = list(RDRFContext.objects.filter(context_form_group=fixed_form_group,
                                                         object_id=self.patient_model.pk,
                                                         content_type__model="patient"))

        num_contexts = len(context_models)
        assert num_contexts == 1, "There should only be one context model for this fixed context there are: %s" % num_contexts

        context_model = context_models[0]

        return self._form_link(form_model, context_model)

    def _free_forms(self):
        if self.registry_model.is_normal:
            return [f for f in self.registry_model.forms if not f.is_questionnaire]
        else:
            return []

    def _determine_current_index(self):
        # where are we in the link ring?
        if self.form_type == NavigationFormType.DEMOGRAPHICS:
            return 0  # because demographics is always added first
        elif self.form_type == NavigationFormType.CONSENTS:
            return 1
        else:
            # we're on some form
            for index, (name, form_id, link) in enumerate(self.links):
                if name in ['demographic', 'consents']:
                    continue
                # form link so get the models
                form_model = RegistryForm.objects.get(pk=form_id)
                link_parts = link.split("/")
                context_id = int(link_parts[-1])
                if form_model.pk == self.current_form_model.pk:
                    if context_id == int(self.context_id):
                        return index

        # shouldn't get here ...
        raise Exception("could not determine current index!")

    @property
    def previous_link(self):
        if self.on_create_form_view:
            # unsure what to do here
            return self.links[0]

        num_links = len(self.links)
        next_index = (self.current_index - 1) % num_links
        return self.links[next_index][-1]

    @property
    def next_link(self):
        if self.on_create_form_view:
            # unsure what to do here
            return self.links[0]
        num_links = len(self.links)
        next_index = (self.current_index + 1) % num_links
        return self.links[next_index][-1]
<|endoftext|>


<commit_before>r"""
Gathers the reverted status for a set of revisions and
prints a TSV to stdout of the format:

<rev_id>\t<reverted>

Usage:
    label_reverted -h | --help
    label_reverted --host=<url> [--revert-radius=<revs>]
                               [--revert-window=<secs>]
                               [--rev-pages=<path>]
                               [--rev-reverteds=<path>]
                               [--verbose]

Options:
    -h --help               Prints out this documentation
    --host=<url>            The host URL of the MediaWiki install where an API
                            can be found.
    --revert-radius=<revs>  The maximum amount of revisions that a reverting
                            edit can revert [default: 15]
    --revert-window=<secs>  The maximum amount of time to wait for a revision
                            to be reverted [default: 172800]
    --rev-pages=<path>      The location of a file containing rev_ids and
                            page_ids to extract. [default: <stdin>]
    --rev-reverteds=<path>  The location to write output to.
                            [default: <stdout>]
    --verbose               Prints dots and stuff to stderr
"""
import sys
import traceback

import docopt
import mwapi
import mwreverts.api
import mysqltsv

def main(argv=None):
    args = docopt.docopt(__doc__, argv=argv)

    revert_radius = int(args['--revert-radius'])
    revert_window = int(args['--revert-window'])

    if args['--rev-pages'] == "<stdin>":
        rev_pages = read_rev_pages(sys.stdin)
    else:
        rev_pages = read_rev_pages(open(args['--rev-pages']))

    if args['--rev-reverteds'] == "<stdout>":
        rev_reverteds = mysqltsv.Writer(sys.stdout)
    else:
        rev_reverteds = mysqltsv.Writer(open(args['--rev-reverteds'], "w"))

    host = args['--host']
    session = mwapi.Session(host, user_agent="ORES revert labeling utility")

    verbose = args['--verbose']

    run(rev_pages, rev_reverteds, session, revert_radius, revert_window,
        verbose=verbose)

def read_rev_pages(f):
    first_line_parts = f.readline().strip().split("\t")
    if first_line_parts[0] != "rev_id":
        if len(first_line_parts) == 1:
            rev_id = first_line_parts[0]
            yield int(rev_id), None
        elif len(first_line_parts) == 2:
            rev_id, page_id = first_line_parts
            yield int(rev_id), int(page_id)

    for line in f:
        parts = line.strip().split('\t')

        if len(parts) == 1:
            rev_id = parts[0]
            yield int(rev_id), None
        elif len(parts) == 2:
            rev_id, page_id = parts
            yield int(rev_id), int(page_id)

def run(rev_pages, rev_reverteds, session, revert_radius, revert_window,
        verbose=False):
    for rev_id, page_id in rev_pages:
        try:
            # Detect reverted status
            try:
                _, reverted, reverted_to = \
                    mwreverts.api.check(session, rev_id, page_id=page_id,
                                        radius=revert_radius,
                                        window=revert_window,
                                        rvprop=["user"])
            except KeyError:
                # Couldn't find the revision
                sys.stderr.write("?")
                continue

            damaging_revert = False
            if reverted is not None:
                reverted_doc = [r for r in reverted.reverteds
                                if r['revid'] == rev_id][0]

                # Exclude self-reverts and revisions that are reverted back to
                # by others
                self_revert = \
                    reverted_doc['user'] == reverted.reverting['user']
                was_reverted_to_by_someone_else = \
                    reverted_to is not None and \
                    reverted_doc['user'] != reverted_to.reverting['user']

                damaging_revert = not (self_revert or
                                       was_reverted_to_by_someone_else)

            if verbose:
                if damaging_revert:
                    sys.stderr.write("r")
                else:
                    sys.stderr.write(".")
                sys.stderr.flush()

            # Print out row
            rev_reverteds.write([rev_id, damaging_revert])

        except KeyboardInterrupt:
            sys.stderr.write("\n^C Caught.  Exiting...")
            break
        except:
            sys.stderr.write(traceback.format_exc())
            sys.stderr.write("\n")

    sys.stderr.write("\n")

if __name__ == "__main__":
    main()
<commit_msg>Parellelizes label_reverted.<commit_after>r"""
Gathers the reverted status for a set of revisions and
prints a TSV to stdout of the format:

<rev_id>\t<reverted>

Usage:
    label_reverted -h | --help
    label_reverted --host=<url> [--revert-radius=<revs>]
                                [--revert-window=<hrs>]
                                [--revisions=<path>]
                                [--reverteds=<path>]
                                [--verbose]

Options:
    -h --help               Prints out this documentation
    --host=<url>            The host URL of the MediaWiki install where an API
                            can be found.
    --revert-radius=<revs>  The maximum amount of revisions that a reverting
                            edit can revert [default: 15]
    --revert-window=<hrs>   The maximum amount of time (in hours) to wait for a
                            revision to be reverted [default: 48]
    --revisions=<path>      A TSV file containing a list of rev_ids to check.
                            [default: <stdin>]
    --reverteds=<path>      The location to write output to.
                            [default: <stdout>]
    --verbose               Prints dots and stuff to stderr
"""
import sys
import traceback

import docopt
import mwapi
import mwreverts.api
import para

import mysqltsv

def main(argv=None):
    args = docopt.docopt(__doc__, argv=argv)

    revert_radius = int(args['--revert-radius'])
    revert_window = int(args['--revert-window']) * 60 * 60

    if args['--revisions'] == "<stdin>":
        revisions = mysqltsv.Reader(sys.stdin)
    else:
        revisions = mysqltsv.Reader(open(args['--revisions']))

    output_headers = revisions.headers + ['reverted']

    if args['--reverteds'] == "<stdout>":
        reverteds = mysqltsv.Writer(sys.stdout, headers=output_headers)
    else:
        reverteds = mysqltsv.Writer(open(args['--reverteds'], "w"),
                                    headers=output_headers)

    host = args['--host']
    session = mwapi.Session(host, user_agent="ORES revert labeling utility")

    verbose = args['--verbose']

    run(revisions, reverteds, session, revert_radius, revert_window,
        verbose=verbose)

def run(revisions, reverteds, session, revert_radius, revert_window,
        verbose=False):

    def check_was_damaging_revert(revision):
        try:
            # Detect reverted status
            try:
                _, reverted, reverted_to = \
                    mwreverts.api.check(session, revision.rev_id,
                                        radius=revert_radius,
                                        window=revert_window,
                                        rvprop=["user"])
            except KeyError:
                yield revision, None
            else:
                damaging_reverted = False
                if reverted is not None:
                    reverted_doc = [r for r in reverted.reverteds
                                    if r['revid'] == int(revision.rev_id)][0]

                    # Exclude self-reverts and revisions that are reverted
                    # back to by others
                    self_revert = \
                        reverted_doc['user'] == reverted.reverting['user']
                    was_reverted_to_by_someone_else = \
                        reverted_to is not None and \
                        reverted_doc['user'] != reverted_to.reverting['user']

                    damaging_reverted = not (self_revert or
                                             was_reverted_to_by_someone_else)

                # Print out row
                yield revision, damaging_reverted

        except:
            sys.stderr.write(traceback.format_exc())
            sys.stderr.write("\n")

    for revision, reverted in para.map(check_was_damaging_revert, revisions):
        if reverted is None:
            if verbose:
                sys.stderr.write("?")
                sys.stderr.flush()
        else:
            if verbose:
                sys.stderr.write("r" if reverted else ".")
                sys.stderr.flush()

            reverteds.write(list(revision) + [reverted])

    if verbose:
        sys.stderr.write("\n")

if __name__ == "__main__":
    main()
<|endoftext|>


<commit_before>#!/usr/bin/env python

'''
Sets the current screen to a cabin from CabinPorn.com.

Default is set to the most recent picture, which it downloads and puts into a
folder in the current directory.

Optional arguments:
  1. '-r', choose a random image from the current page
  2. '-i', choose a specific image by the page id
  3. '-l', limit files to images larger than 1024x748
  4. 'path=BASE_DIR', choose a directory for the photos to be put into

Based originally on code to set desktop pictures for all screens from:
https://github.com/grahamgilbert/macscripts/tree/master/set_desktops
'''

from bs4 import BeautifulSoup
from AppKit import NSWorkspace, NSScreen
from Foundation import NSURL
from optparse import OptionParser
import requests, glob, random, re, urllib, os, fnmatch, sys
from os import listdir
from os.path import isfile, join

# Set the options
parser = OptionParser()
parser.add_option("-p", "--path", dest="base_dir",
                  help="write cabins to PATH", metavar="PATH")
parser.add_option("-r", "--random", action="store_true",
                  dest="random_cabin", default=False,
                  help="pick a random cabin")
parser.add_option("-i", "--image", dest="image",
                  type="int", default=0,
                  help="pick a specific cabin, by image id")
parser.add_option("-l", "--large-only", dest="large_only",
                  help="only use large images", default=False,
                  action="store_true")
parser.add_option("-o", "--offline", dest="offline",
                  help="use offline", default=False,
                  action="store_true")
(options, args) = parser.parse_args()

# Create a directory for image storage
if options.base_dir:
  base_dir = options.base_dir
  if base_dir[-1] != "/":
    base_dir = base_dir + "/"
# If the base directory is not set, we use ./Pictures/Cabins instead
else:
  base_dir = os.path.dirname(os.path.realpath(__file__)) + "/Cabins/"

if not os.path.exists(base_dir):
    os.makedirs(base_dir)

# Set the root URL
url = "http://cabinporn.com"
if options.image:
  url = url + "/post/" + str(options.image)

# Grab the html
r  = requests.get(url)
if r.status_code == 200:
  data = r.text
  soup = BeautifulSoup(data, "html.parser")

  # Get a list of all of the images of cabins
  cabins = []
  for post in soup.find_all("li", "post"):
    for photo in post.find_all("div", "photo_div") + post.find_all("div", "photoset_div"):
      image = photo.find("img")
      image_src = str(image.get("src").encode('utf-8'))
      if re.search("jpg|png", image_src):
        link_str = image.get("title") or post.find("div", "fb-like").get("data-href") or ''
        if link_str:
            link_str = str(link_str.encode("utf-8"))
        cabins.append({ "src" : image_src, "link": link_str })

  # Choose one of the pictures to download. If random is flagged, pick one from
  # the top page. Else, just choose the most recent.
  if options.random_cabin:
    cabin = random.choice(cabins)
  else:
    cabin = cabins[0]

  # Local filename for the image is the descriptive post link
  post_name = re.search('/post/(.+)$', cabin["link"]).group(1)
  image_ext = os.path.splitext(cabin["src"])[1]

  # eg: 12345-some-cool-place.jpg
  image_file = post_name.replace('/', '-') + image_ext

  # Previously, images were stored using the raw image name, so if an older image
  # exists, just move the old file to the new location
  old_file = cabin["src"].split('/')[-1]
  if os.path.isfile(base_dir + old_file):
    os.rename(base_dir + old_file, base_dir + image_file)

  # If the image has not already been downloaded, get it now
  if not os.path.isfile(base_dir + image_file):
    urllib.urlretrieve(cabin["src"], base_dir + image_file)
elif r.status_code != 200:
  print('You are not connected to the internet. Choosing old cabin')

  # Select all of the cabins in the folder, and pick a random one
  cabins = [ f for f in listdir(base_dir) if isfile(join(base_dir, f)) ]
  image_file = random.choice(cabins)

def setFile():
  # generate a fileURL for the desktop picture
  file_path = NSURL.fileURLWithPath_(base_dir + image_file)

  # get shared workspace
  ws = NSWorkspace.sharedWorkspace()

  # iterate over all screens
  for screen in NSScreen.screens():
      # tell the workspace to set the desktop picture
      (result, error) = ws.setDesktopImageURL_forScreen_options_error_(
                  file_path, screen, ws.desktopImageOptionsForScreen_(screen), None)

# Check the size of the file
if options.large_only:
  from PIL import Image
  im = Image.open(base_dir + image_file).size
  if im[0] >= 1024 and im[1] >= 768:
    print('Image is large:', im)
    setFile()
  else:
    print('Image is too small:', im) # (width,height) tuple
else:
  setFile()
<commit_msg>Fix for utf-8 encoded files<commit_after>#!/usr/bin/env python

'''
Sets the current screen to a cabin from CabinPorn.com.

Default is set to the most recent picture, which it downloads and puts into a
folder in the current directory.

Optional arguments:
  1. '-r', choose a random image from the current page
  2. '-i', choose a specific image by the page id
  3. '-l', limit files to images larger than 1024x748
  4. 'path=BASE_DIR', choose a directory for the photos to be put into

Based originally on code to set desktop pictures for all screens from:
https://github.com/grahamgilbert/macscripts/tree/master/set_desktops
'''

from bs4 import BeautifulSoup
from AppKit import NSWorkspace, NSScreen
from Foundation import NSURL
from optparse import OptionParser
import requests, glob, random, re, urllib, os, fnmatch, sys
from os import listdir
from os.path import isfile, join

# Set the options
parser = OptionParser()
parser.add_option("-p", "--path", dest="base_dir",
                  help="write cabins to PATH", metavar="PATH")
parser.add_option("-r", "--random", action="store_true",
                  dest="random_cabin", default=False,
                  help="pick a random cabin")
parser.add_option("-i", "--image", dest="image",
                  type="int", default=0,
                  help="pick a specific cabin, by image id")
parser.add_option("-l", "--large-only", dest="large_only",
                  help="only use large images", default=False,
                  action="store_true")
parser.add_option("-o", "--offline", dest="offline",
                  help="use offline", default=False,
                  action="store_true")
(options, args) = parser.parse_args()

# Create a directory for image storage
if options.base_dir:
  base_dir = options.base_dir
  if base_dir[-1] != "/":
    base_dir = base_dir + "/"
# If the base directory is not set, we use ./Pictures/Cabins instead
else:
  base_dir = os.path.dirname(os.path.realpath(__file__)) + "/Cabins/"

if not os.path.exists(base_dir):
    os.makedirs(base_dir)

# Set the root URL
url = "http://cabinporn.com"
if options.image:
  url = url + "/post/" + str(options.image)

# Grab the html
r  = requests.get(url)
if r.status_code == 200:
  data = r.text
  soup = BeautifulSoup(data, "html.parser")

  # Get a list of all of the images of cabins
  cabins = []
  for post in soup.find_all("li", "post"):
    for photo in post.find_all("div", "photo_div") + post.find_all("div", "photoset_div"):
      image = photo.find("img")
      image_src = str(image.get("src").encode('utf-8'))
      if re.search("jpg|png", image_src):
        link_str = image.get("title") or post.find("div", "fb-like").get("data-href") or ''
        if link_str:
            link_str = str(link_str.encode("utf-8"))
        cabins.append({ "src" : image_src, "link": link_str })

  # Choose one of the pictures to download. If random is flagged, pick one from
  # the top page. Else, just choose the most recent.
  if options.random_cabin:
    cabin = random.choice(cabins)
  else:
    cabin = cabins[0]

  # Local filename for the image is the descriptive post link
  post_name = re.search('/post/(.+)$', cabin["link"]).group(1)
  image_ext = os.path.splitext(cabin["src"])[1]

  # eg: 12345-some-cool-place.jpg
  image_file = post_name.replace('/', '-') + image_ext

  # Previously, images were stored using the raw image name, so if an older image
  # exists, just move the old file to the new location
  old_file = cabin["src"].split('/')[-1]
  if os.path.isfile(base_dir + old_file):
    os.rename(base_dir + old_file, base_dir + image_file)

  # If the image has not already been downloaded, get it now
  if not os.path.isfile(base_dir + image_file):
    urllib.urlretrieve(cabin["src"], base_dir + image_file)
elif r.status_code != 200:
  print('You are not connected to the internet. Choosing old cabin')

  # Select all of the cabins in the folder, and pick a random one
  cabins = [ f for f in listdir(base_dir) if isfile(join(base_dir, f)) ]
  image_file = random.choice(cabins)

def setFile():
  # generate a fileURL for the desktop picture
  file_path = NSURL.fileURLWithPath_(base_dir + image_file.decode("utf-8"))

  # get shared workspace
  ws = NSWorkspace.sharedWorkspace()

  # iterate over all screens
  for screen in NSScreen.screens():
      # tell the workspace to set the desktop picture
      (result, error) = ws.setDesktopImageURL_forScreen_options_error_(
                  file_path, screen, ws.desktopImageOptionsForScreen_(screen), None)

      if error:
        print error

# Check the size of the file
if options.large_only:
  from PIL import Image
  im = Image.open(base_dir + image_file).size
  if im[0] >= 1024 and im[1] >= 768:
    print('Image is large:', im)
    setFile()
  else:
    print('Image is too small:', im) # (width,height) tuple
else:
  setFile()
<|endoftext|>


<commit_before>from utils import write_csv_rows, read_csv_rows
from classes import truss, force, fixed_node
import numpy as np #for development debug/format only

class parse_var:
    def __init__(self, descript_name, val=None, class_name=None):
        self.descript_name = descript_name

class output_table:
    def __init__(self, filename, content=None):
        self.filename = filename

def blanks_exist(tbl):
    for i in range(2,len(tbl)): #Don't check first (table name) row
        if (len(tbl[i]) != len(tbl[i-1])):
            return True
        for j in range(0,len(tbl[i])):
            if (tbl[i][j] == ''):
                return True
    return False

def define_nodes(tbl_content):
    if blanks_exist(tbl_content):
        print('Table values must not be left blank')
        return 1 #Stop function execution
    ind_x1 = tbl_content[1].index('x1')
    ind_y1 = tbl_content[1].index('y1')
    ind_x2 = tbl_content[1].index('x2')
    ind_y2 = tbl_content[1].index('y2')
    coord_pairs = []
    for i in range(2,len(tbl_content)):
        coord_pairs.append([tbl_content[i][ind_x1],
                            tbl_content[i][ind_y1]])
        coord_pairs.append([tbl_content[i][ind_x2],
                            tbl_content[i][ind_y2]])
    for i in range(0,len(coord_pairs)):
        coord_pairs[i] = '-'.join(coord_pairs[i])
    coord_pairs = set(coord_pairs) #remove non-uniques
    coord_pairs = list(coord_pairs)
    for i in range(0,len(coord_pairs)):
        coord_pairs[i] = coord_pairs[i].split('-')
    for i in range(0,len(coord_pairs)):
        coord_pairs[i][0] = float(coord_pairs[i][0])
        coord_pairs[i][1] = float(coord_pairs[i][1])
    coord_pairs.sort()
    for i in range(0,len(coord_pairs)):
        coord_pairs[i].append(i)
    return coord_pairs

def read_connectivity(tbl_content, node_coords):
    if blanks_exist(tbl_content):
        print('Table values must not be left blank')
        return 1 #Stop function execution
    ind_x1 = tbl_content[1].index('x1')
    ind_y1 = tbl_content[1].index('y1')
    ind_x2 = tbl_content[1].index('x2')
    ind_y2 = tbl_content[1].index('y2')
    ind_E = tbl_content[1].index('E')
    ind_A = tbl_content[1].index('A')
    trusses = []
    for i in range(2,len(tbl_content)): #content rows only
        x1 = float(tbl_content[i][ind_x1])
        y1 = float(tbl_content[i][ind_y1])
        x2 = float(tbl_content[i][ind_x2])
        y2 = float(tbl_content[i][ind_y2])
        node1 = node_coords.index([x1,y1])
        node2 = node_coords.index([x2,y2])
        E = float(tbl_content[i][ind_E])
        A = float(tbl_content[i][ind_A])
        trusses.append(truss(x1,x2,y1,y2,E,A,node1,node2))
    print('Read ' + str(len(trusses)) + ' trusses' +\
          ' from connectivity table')
    return trusses

def read_forces(tbl_content, node_coords):
    if blanks_exist(tbl_content):
        print('Table values must not be left blank')
        return 1 #Stop function execution
    ind_x = tbl_content[1].index('x')
    ind_y = tbl_content[1].index('y')
    ind_fx = tbl_content[1].index('Fx')
    ind_fy = tbl_content[1].index('Fy')
    forces = []
    for i in range(2,len(tbl_content)):
        x = float(tbl_content[i][ind_x])
        y = float(tbl_content[i][ind_y])
        fx = float(tbl_content[i][ind_fx])
        fy = float(tbl_content[i][ind_fy])
        node = node_coords.index([x,y])
        forces.append(force(fx,fy,node))
    print('Read ' + str(len(forces)) + ' forces' +\
          ' from forces table')
    return forces

def read_bcs(tbl_content, node_coords):
    if blanks_exist(tbl_content):
        print('Table values must not be left blank')
        return 1 #Stop function execution
    ind_x = tbl_content[1].index('x')
    ind_y = tbl_content[1].index('y')
    ind_xory = tbl_content[1].index('Constrained Dimension')
    ind_disp = tbl_content[1].index('Displacement')
    bcs = []
    for i in range(2,len(tbl_content)):
        x = float(tbl_content[i][ind_x])
        y = float(tbl_content[i][ind_y])
        x_or_y = tbl_content[i][ind_xory]
        disp = float(tbl_content[i][ind_disp])
        node = node_coords.index([x,y])
        bcs.append(fixed_node(node,x_or_y,disp))
    print('Read ' + str(len(bcs)) + ' boundary conditions' +\
          ' from boundary conditions table')
    return bcs

def read_params(tbl_content, var_list):
    assert (blanks_exist(tbl_content),
            'Table values must not be left blank')
    for i in range(0,len(tbl_content)):
        for j in range(0,len(tbl_content[i])):
            for k in range(0,len(var_list)):
                if (tbl_content[i][j]==var_list[k].descript_name):
                    var_list[k].val=tbl_content[i+1][j]
                    print('Set ' + var_list[k].descript_name +\
                            ' to ' + str(var_list[k].val))
    return var_list

def get_data():

    connect_tbl=output_table('connectivity.csv')
    force_tbl=output_table('forces.csv')
    bc_tbl=output_table('boundary_conditions.csv')
    sim_tbl=output_table('simulation_parameters.csv')

    output_files=[connect_tbl,force_tbl,bc_tbl,sim_tbl]

    # Read in content and convert to nested list
    for i in range(0,len(output_files)):
        output_files[i].content = read_csv_rows(output_files[i].filename)
        for j in range(0,len(output_files[i].content)):
            output_files[i].content[j]=output_files[i].content[j].split(',')
            print('Successfully read ' + output_files[i].filename)

            # for i in range(0,len(output_files)):
            #     print(output_files[i].filename)
            #     print(output_files[i].content)

    num_mult = parse_var(descript_name='Numerical Soln Multiplier')
    dof = parse_var(descript_name='Degrees of Freedom')
    sim_params = [num_mult,dof]

    print('\n')
    sim_params = read_params(sim_tbl.content,sim_params)
    sim_params[0].val = int(sim_params[0].val)
    sim_params[1].val = int(sim_params[1].val)

    # for i in range(0,len(sim_params)):
    #     print(sim_params[i].descript_name)
    #     print(sim_params[i].val)

    nodes = define_nodes(connect_tbl.content)
    node_coords = []
    for i in range(0,len(nodes)):
        node_coords.append(nodes[i][0:2])

    trusses = read_connectivity(connect_tbl.content,node_coords)
        # for i in range(0,len(trusses)):
        #     print(trusses[i].x1,trusses[i].x2,trusses[i].node1,trusses[i].node2)

    forces = read_forces(force_tbl.content,node_coords)
    # for i in range(0,len(forces)):
    #     print(forces[i].fx, forces[i].fy, forces[i].node)

    fixed_nodes = read_bcs(bc_tbl.content,node_coords)
    # for i in range(0,len(fixed_nodes)):
    #     print(fixed_nodes[i].node, fixed_nodes[i].x_or_y,
    #           fixed_nodes[i].disp)

    return trusses, forces, fixed_nodes, sim_params
<commit_msg>Clean up assertions<commit_after>from utils import write_csv_rows, read_csv_rows
from classes import truss, force, fixed_node
import numpy as np #for development debug/format only

class parse_var:
    def __init__(self, descript_name, val=None, class_name=None):
        self.descript_name = descript_name

class output_table:
    def __init__(self, filename, content=None):
        self.filename = filename

def blanks_exist(tbl):
    for i in range(2,len(tbl)): #Don't check first (table name) row
        print(len(tbl[i]),len(tbl[i-1]))
        if (len(tbl[i]) != len(tbl[i-1])):
            return True
        for j in range(0,len(tbl[i])):
            if (tbl[i][j] == ''):
                return True
    return False

def define_nodes(tbl_content):
    assert not blanks_exist(tbl_content),\
        'Table values must not be left blank'
    ind_x1 = tbl_content[1].index('x1')
    ind_y1 = tbl_content[1].index('y1')
    ind_x2 = tbl_content[1].index('x2')
    ind_y2 = tbl_content[1].index('y2')
    coord_pairs = []
    for i in range(2,len(tbl_content)):
        coord_pairs.append([tbl_content[i][ind_x1],
                            tbl_content[i][ind_y1]])
        coord_pairs.append([tbl_content[i][ind_x2],
                            tbl_content[i][ind_y2]])
    for i in range(0,len(coord_pairs)):
        coord_pairs[i] = '-'.join(coord_pairs[i])
    coord_pairs = set(coord_pairs) #remove non-uniques
    coord_pairs = list(coord_pairs)
    for i in range(0,len(coord_pairs)):
        coord_pairs[i] = coord_pairs[i].split('-')
    for i in range(0,len(coord_pairs)):
        coord_pairs[i][0] = float(coord_pairs[i][0])
        coord_pairs[i][1] = float(coord_pairs[i][1])
    coord_pairs.sort()
    for i in range(0,len(coord_pairs)):
        coord_pairs[i].append(i)
    return coord_pairs

def read_connectivity(tbl_content, node_coords):
    assert not blanks_exist(tbl_content),\
        'Table values must not be left blank'
    ind_x1 = tbl_content[1].index('x1')
    ind_y1 = tbl_content[1].index('y1')
    ind_x2 = tbl_content[1].index('x2')
    ind_y2 = tbl_content[1].index('y2')
    ind_E = tbl_content[1].index('E')
    ind_A = tbl_content[1].index('A')
    trusses = []
    for i in range(2,len(tbl_content)): #content rows only
        x1 = float(tbl_content[i][ind_x1])
        y1 = float(tbl_content[i][ind_y1])
        x2 = float(tbl_content[i][ind_x2])
        y2 = float(tbl_content[i][ind_y2])
        node1 = node_coords.index([x1,y1])
        node2 = node_coords.index([x2,y2])
        E = float(tbl_content[i][ind_E])
        A = float(tbl_content[i][ind_A])
        trusses.append(truss(x1,x2,y1,y2,E,A,node1,node2))
    print('Read ' + str(len(trusses)) + ' trusses' +\
          ' from connectivity table')
    return trusses

def read_forces(tbl_content, node_coords):
    assert not blanks_exist(tbl_content),\
        'Table values must not be left blank'
    ind_x = tbl_content[1].index('x')
    ind_y = tbl_content[1].index('y')
    ind_fx = tbl_content[1].index('Fx')
    ind_fy = tbl_content[1].index('Fy')
    forces = []
    for i in range(2,len(tbl_content)):
        x = float(tbl_content[i][ind_x])
        y = float(tbl_content[i][ind_y])
        fx = float(tbl_content[i][ind_fx])
        fy = float(tbl_content[i][ind_fy])
        node = node_coords.index([x,y])
        forces.append(force(fx,fy,node))
    print('Read ' + str(len(forces)) + ' forces' +\
          ' from forces table')
    return forces

def read_bcs(tbl_content, node_coords):
    assert not blanks_exist(tbl_content),\
        'Table values must not be left blank'
    ind_x = tbl_content[1].index('x')
    ind_y = tbl_content[1].index('y')
    ind_xory = tbl_content[1].index('Constrained Dimension')
    ind_disp = tbl_content[1].index('Displacement')
    bcs = []
    for i in range(2,len(tbl_content)):
        x = float(tbl_content[i][ind_x])
        y = float(tbl_content[i][ind_y])
        x_or_y = tbl_content[i][ind_xory]
        disp = float(tbl_content[i][ind_disp])
        node = node_coords.index([x,y])
        bcs.append(fixed_node(node,x_or_y,disp))
    print('Read ' + str(len(bcs)) + ' boundary conditions' +\
          ' from boundary conditions table')
    return bcs

def read_params(tbl_content, var_list):
    assert not blanks_exist(tbl_content),\
        'Table values must not be left blank'
    for i in range(0,len(tbl_content)):
        for j in range(0,len(tbl_content[i])):
            for k in range(0,len(var_list)):
                if (tbl_content[i][j]==var_list[k].descript_name):
                    var_list[k].val=tbl_content[i+1][j]
                    print('Set ' + var_list[k].descript_name +\
                            ' to ' + str(var_list[k].val))
    return var_list

def get_data():

    connect_tbl=output_table('connectivity.csv')
    force_tbl=output_table('forces.csv')
    bc_tbl=output_table('boundary_conditions.csv')
    sim_tbl=output_table('simulation_parameters.csv')

    output_files=[connect_tbl,force_tbl,bc_tbl,sim_tbl]

    # Read in content and convert to nested list
    for i in range(0,len(output_files)):
        output_files[i].content = read_csv_rows(output_files[i].filename)
        for j in range(0,len(output_files[i].content)):
            output_files[i].content[j]=output_files[i].content[j].split(',')
            print('Successfully read ' + output_files[i].filename)

            # for i in range(0,len(output_files)):
            #     print(output_files[i].filename)
            #     print(output_files[i].content)

    num_mult = parse_var(descript_name='Numerical Soln Multiplier')
    dof = parse_var(descript_name='Degrees of Freedom')
    sim_params = [num_mult,dof]

    print('\n')
    sim_params = read_params(sim_tbl.content,sim_params)
    sim_params[0].val = int(sim_params[0].val)
    sim_params[1].val = int(sim_params[1].val)

    # for i in range(0,len(sim_params)):
    #     print(sim_params[i].descript_name)
    #     print(sim_params[i].val)

    nodes = define_nodes(connect_tbl.content)
    node_coords = []
    for i in range(0,len(nodes)):
        node_coords.append(nodes[i][0:2])

    trusses = read_connectivity(connect_tbl.content,node_coords)
        # for i in range(0,len(trusses)):
        #     print(trusses[i].x1,trusses[i].x2,trusses[i].node1,trusses[i].node2)

    forces = read_forces(force_tbl.content,node_coords)
    # for i in range(0,len(forces)):
    #     print(forces[i].fx, forces[i].fy, forces[i].node)

    fixed_nodes = read_bcs(bc_tbl.content,node_coords)
    # for i in range(0,len(fixed_nodes)):
    #     print(fixed_nodes[i].node, fixed_nodes[i].x_or_y,
    #           fixed_nodes[i].disp)

    return trusses, forces, fixed_nodes, sim_params
<|endoftext|>


<commit_before>{
  'includes': [ 'common.gypi' ],
  'target_defaults': {
    'default_configuration': 'Release',
    'cflags': [
      '-std=c99'
    ],
    'xcode_settings': {
      'OTHER_CFLAGS': [
        '-std=c99'
      ],
    },
    'configurations': {
      'Debug': {
        'defines': [ 'DEBUG', '_DEBUG', 'SQLITE_ENABLE_API_ARMOR'],
        'msvs_settings': {
          'VCCLCompilerTool': {
            'RuntimeLibrary': 1, # static debug
          },
        },
      },
      'Release': {
        'defines': [ 'NDEBUG' ],
        'msvs_settings': {
          'VCCLCompilerTool': {
            'RuntimeLibrary': 0, # static release
          },
        },
      }
    },
    'msvs_settings': {
      'VCCLCompilerTool': {
      },
      'VCLibrarianTool': {
      },
      'VCLinkerTool': {
        'GenerateDebugInformation': 'true',
      },
    },
    'conditions': [
      ['OS == "win"', {
        'defines': [
          'WIN32'
        ],
      }]
    ],
  },

  'targets': [
    {
      'target_name': 'action_before_build',
      'type': 'none',
      'hard_dependency': 1,
      'actions': [
        {
          'action_name': 'unpack_sqlite_dep',
          'inputs': [
            './sqlite-autoconf-<@(sqlite_version).tar.gz'
          ],
          'outputs': [
            '<(SHARED_INTERMEDIATE_DIR)/sqlite-autoconf-<@(sqlite_version)/sqlite3.c'
          ],
          'action': ['python','./extract.py','./sqlite-autoconf-<@(sqlite_version).tar.gz','<(SHARED_INTERMEDIATE_DIR)']
        }
      ],
      'direct_dependent_settings': {
        'include_dirs': [
          '<(SHARED_INTERMEDIATE_DIR)/sqlite-autoconf-<@(sqlite_version)/',
        ]
      },
    },
    {
      'target_name': 'sqlite3',
      'type': 'static_library',
      'include_dirs': [ '<(SHARED_INTERMEDIATE_DIR)/sqlite-autoconf-<@(sqlite_version)/' ],
      'dependencies': [
        'action_before_build'
      ],
      'sources': [
        '<(SHARED_INTERMEDIATE_DIR)/sqlite-autoconf-<@(sqlite_version)/sqlite3.c'
      ],
      'direct_dependent_settings': {
        'include_dirs': [ '<(SHARED_INTERMEDIATE_DIR)/sqlite-autoconf-<@(sqlite_version)/' ]
      },
      'cflags_cc': [
        '-Wno-unused-value',
      ],
      'defines': [
        'SQLITE_THREADSAFE=0',
        'SQLITE_DEFAULT_MEMSTATUS=0',
        'SQLITE_OMIT_DECLTYPE',
        'SQLITE_OMIT_DEPRECATED',
        'SQLITE_OMIT_PROGRESS_CALLBACK',
        'SQLITE_ENABLE_FTS5',
        'SQLITE_ENABLE_JSON1',
        'SQLITE_ENABLE_RTREE',
        'SQLITE_USE_URI=1',
        'SQLITE_DEFAULT_CACHE_SIZE=-16000',
        'SQLITE_DEFAULT_FOREIGN_KEYS=1',
        'SQLITE_DEFAULT_WAL_SYNCHRONOUS=1'
      ],
      'export_dependent_settings': [
        'action_before_build',
      ]
    }
  ]
}
<commit_msg>add FTS4 support<commit_after>{
  'includes': [ 'common.gypi' ],
  'target_defaults': {
    'default_configuration': 'Release',
    'cflags': [
      '-std=c99'
    ],
    'xcode_settings': {
      'OTHER_CFLAGS': [
        '-std=c99'
      ],
    },
    'configurations': {
      'Debug': {
        'defines': [ 'DEBUG', '_DEBUG', 'SQLITE_ENABLE_API_ARMOR'],
        'msvs_settings': {
          'VCCLCompilerTool': {
            'RuntimeLibrary': 1, # static debug
          },
        },
      },
      'Release': {
        'defines': [ 'NDEBUG' ],
        'msvs_settings': {
          'VCCLCompilerTool': {
            'RuntimeLibrary': 0, # static release
          },
        },
      }
    },
    'msvs_settings': {
      'VCCLCompilerTool': {
      },
      'VCLibrarianTool': {
      },
      'VCLinkerTool': {
        'GenerateDebugInformation': 'true',
      },
    },
    'conditions': [
      ['OS == "win"', {
        'defines': [
          'WIN32'
        ],
      }]
    ],
  },

  'targets': [
    {
      'target_name': 'action_before_build',
      'type': 'none',
      'hard_dependency': 1,
      'actions': [
        {
          'action_name': 'unpack_sqlite_dep',
          'inputs': [
            './sqlite-autoconf-<@(sqlite_version).tar.gz'
          ],
          'outputs': [
            '<(SHARED_INTERMEDIATE_DIR)/sqlite-autoconf-<@(sqlite_version)/sqlite3.c'
          ],
          'action': ['python','./extract.py','./sqlite-autoconf-<@(sqlite_version).tar.gz','<(SHARED_INTERMEDIATE_DIR)']
        }
      ],
      'direct_dependent_settings': {
        'include_dirs': [
          '<(SHARED_INTERMEDIATE_DIR)/sqlite-autoconf-<@(sqlite_version)/',
        ]
      },
    },
    {
      'target_name': 'sqlite3',
      'type': 'static_library',
      'include_dirs': [ '<(SHARED_INTERMEDIATE_DIR)/sqlite-autoconf-<@(sqlite_version)/' ],
      'dependencies': [
        'action_before_build'
      ],
      'sources': [
        '<(SHARED_INTERMEDIATE_DIR)/sqlite-autoconf-<@(sqlite_version)/sqlite3.c'
      ],
      'direct_dependent_settings': {
        'include_dirs': [ '<(SHARED_INTERMEDIATE_DIR)/sqlite-autoconf-<@(sqlite_version)/' ]
      },
      'cflags_cc': [
        '-Wno-unused-value',
      ],
      'defines': [
        'SQLITE_THREADSAFE=0',
        'SQLITE_DEFAULT_MEMSTATUS=0',
        'SQLITE_OMIT_DECLTYPE',
        'SQLITE_OMIT_DEPRECATED',
        'SQLITE_OMIT_PROGRESS_CALLBACK',
        'SQLITE_ENABLE_FTS4',
        'SQLITE_ENABLE_FTS5',
        'SQLITE_ENABLE_JSON1',
        'SQLITE_ENABLE_RTREE',
        'SQLITE_USE_URI=1',
        'SQLITE_DEFAULT_CACHE_SIZE=-16000',
        'SQLITE_DEFAULT_FOREIGN_KEYS=1',
        'SQLITE_DEFAULT_WAL_SYNCHRONOUS=1'
      ],
      'export_dependent_settings': [
        'action_before_build',
      ]
    }
  ]
}
<|endoftext|>