while True:
    try:
        buf = [ord(i) - 97 for i in input()]
        s_buf = sorted(buf)
        if not buf:
            break
        cnt = 0
        for i in range(len(buf)):
            if buf[i] != s_buf[i]:
                p = buf.index(s_buf[i])
                buf[p], buf[i] = buf[i], buf[p]
                cnt += 1
        print(cnt)
    except:
        break


import random
import math
import argparse

operators = ['+','-','*','/']

def divisors(number):
	list_div = []
	for i in range(2, math.floor(number/2)):
		if number%i == 0:
			list_div.append(str(i))
	return list_div

def split_number(number,step, operators):
	if step>=1:
		operator = random.choice(operators)
		if (operator == '*' or operator == '/') and step!=1:
			operator = random.choice(['+','-'])
		if operator == '*' and number>3:
			divisors_list = divisors(number)
			if len(divisors_list) == 0:
				return str(number)
			else:
				num1 = int(random.choice(divisors_list))
				num2 = int(number/num1)
				return str(num2) + " x " + str(num1)
		elif operator == "/" and number>=2:
			num1 = random.randint(2,number)
			num2 = number*num1
			return str(num2) + " / " + str(num1)
		elif operator == "+" and int(number/(step+1)) > 1:
			num1 = random.randint(1, int(number/(step+1)))
			num2 = number - num1
			if step == 1:
				return str(num1) + " + " + str(num2)
			else:
				return str(num1) + " + " + split_number(num2,step-1)
		elif operator == "-":
			num1 = random.randint(number+1, 2*number)
			num2 = num1 - number
			if step == 1:
				return str(num1) + " - " + str(num2)
			else:
				return split_number(num1,step-1) + " - " + str(num2)
		else:
			return str(number)
	else:
		return str(number)

def generate_options(ans_range, correct_answer, no_options):
	opt_list = [str(correct_answer)]
	while no_options>1:
		option = random.randint(int(ans_range[0]), int(ans_range[1]))
		if str(option) not in opt_list:
			opt_list.append(str(option))
			no_options-=1
	random.shuffle(opt_list)
	idx = opt_list.index(str(correct_answer))
	return opt_list, idx

def generate_puzzle(ans_range,operators, ques_operators=1,ans_operators=0,options=4):
	data = dict()
	num = random.randint(int(ans_range[0]),int(ans_range[1]))
	ques_str = split_number(num, ques_operators, operators)
	while ques_str == str(num):
		ques_str = split_number(num, ques_operators, operators)
	ques_str+= " = _"

	if ans_operators==0:
		ans_list, correct_idx = generate_options(ans_range, num, options)
		data["question"] = ques_str
		data["options"] = ans_list
		data["answer"] = correct_idx
	return data

if __name__=="__main__":
	parser = argparse.ArgumentParser()
	parser.add_argument('--operators',action='store',type=str)
	parser.add_argument('--ans_range',action='store',type=str)
	parser.add_argument('--ques_operators',action='store',default=1,type=int)
	parser.add_argument('--ans_operators',action='store',default=0,type=int)
	parser.add_argument('--options',action='store',default=4,type=int)
	parser.add_argument('--iter',action='store',default=1,type=int)
	args = parser.parse_args()

	operators = args.operators.split(',')
	ans_range = args.ans_range.split(',')
	for i in range(args.iter):
		num = random.randint(int(ans_range[0]),int(ans_range[1]))
		ques_str = split_number(num, args.ques_operators, args.operators)
		if args.ans_operators == 0:
			ques_str= ques_str + " = _"
			ans_list, correct_idx = generate_options(ans_range, num, args.options)
			print(ques_str +"\t\t"+ str(ans_list)+ "\t"+str(correct_idx))


class Solution:
    def isValid(self, s: str) -> bool:
        opns = []
        mts = {")" : "(", "}" : "{", "]" : "["}

        for char in s:
            if char in mts:
                ope = opns.pop() if opns else "!"
                if ope != mts[char]:
                    return False

            else:
                opns.append(char)

        return len(opns) == 0


from pgmpy.independencies import Independencies
from pgmpy.models import BayesianNetwork

class NaiveBayes(BayesianNetwork):
    """
    Class to represent Naive Bayes. Naive Bayes is a special case of Bayesian Model
    where the only edges in the model are from the feature variables to the dependent variable.
    """

    def __init__(self, feature_vars=None, dependent_var=None):
        """
        Method to initialize the `NaiveBayes` class.

        Parameters
        ----------
        feature_vars: list (array-like)
            A list of variable predictor variables (i.e. the features) in the model.

        dependent_var: hashable object
            The dependent variable (i.e. the variable to be predicted) in the model.

        Returns
        -------
        pgmpy.models.BayesianNetwork instance: An instance of a Bayesian Model with the
            initialized model structure.
        """
        self.dependent = dependent_var
        self.features = set(feature_vars) if feature_vars is not None else set()
        if (feature_vars is not None) and (dependent_var is not None):
            ebunch = [(self.dependent, feature) for feature in self.features]
        else:
            ebunch = []

        super(NaiveBayes, self).__init__(ebunch=ebunch)

    def add_edge(self, u, v, *kwargs):
        """
        Add an edge between `u` and `v`.

        The nodes `u` and `v` will be automatically added if they are
        not already in the graph. `u` will be the dependent variable (i.e. variable to be predicted)
        and `v` will be one of the features (i.e. predictors) in the model.

        Parameters
        ----------
        u, v : nodes
               Nodes can be any hashable python object.

        Returns
        -------
        None

        Examples
        --------
        >>> from pgmpy.models import NaiveBayes
        >>> G = NaiveBayes()
        >>> G.add_nodes_from(['a', 'b', 'c'])
        >>> G.add_edge('a', 'b')
        >>> G.add_edge('a', 'c')
        >>> G.edges()
        OutEdgeView([('a', 'b'), ('a', 'c')])
        """
        if self.dependent and u != self.dependent:
            raise ValueError(
                f"Model can only have edges outgoing from: {self.dependent}"
            )
        self.dependent = u
        self.features.add(v)
        super(NaiveBayes, self).add_edge(u, v, *kwargs)

    def add_edges_from(self, ebunch):
        """
        Adds edges to the model.

        Each tuple of the form (u, v) in ebunch adds a new edge in the model.
        Since there can only be one dependent variable in a Naive Bayes model, `u` should
        be the same for each tuple in `ebunch`.

        Parameters
        ----------
        ebunch: list (array-like)
            A list of tuples of the form (u, v) representing an edge from u to v.

        Returns
        -------
        None

        Examples
        --------
        >>> from pgmpy.models import NaiveBayes
        >>> G = NaiveBayes()
        >>> G.add_nodes_from(['a', 'b', 'c'])
        >>> G.add_edges_from([('a', 'b'), ('a', 'c')])
        >>> G.edges()
        OutEdgeView([('a', 'b'), ('a', 'c')])
        """
        for u, v in ebunch:
            self.add_edge(u, v)

    def _get_ancestors_of(self, obs_nodes_list):
        """
        Returns a list of all ancestors of all the observed nodes.

        Parameters
        ----------
        obs_nodes_list: string, list-type
            name of all the observed nodes
        """
        if not obs_nodes_list:
            return set()
        return set(obs_nodes_list) | set(self.dependent)

    def active_trail_nodes(self, start, observed=None):
        """
        Returns all the nodes reachable from start via an active trail.

        Parameters
        ----------
        start: Graph node

        observed : List of nodes (optional)
            If given the active trail would be computed assuming these nodes to be observed.

        Examples
        --------
        >>> from pgmpy.models import NaiveBayes
        >>> model = NaiveBayes()
        >>> model.add_nodes_from(['a', 'b', 'c', 'd'])
        >>> model.add_edges_from([('a', 'b'), ('a', 'c'), ('a', 'd')])
        >>> model.active_trail_nodes('a')
        {'a', 'd', 'c', 'b'}
        >>> model.active_trail_nodes('a', ['b', 'c'])
        {'a', 'd'}
        >>> model.active_trail_nodes('b', ['a'])
        {'b'}
        """

        if observed and self.dependent in observed:
            return set(start)
        else:
            return set(self.nodes()) - set(observed if observed else [])

    def local_independencies(self, variables):
        """
        Returns an instance of Independencies containing the local independencies
        of each of the variables.

        Parameters
        ----------
        variables: str or array like
            variables whose local independencies are to found.

        Examples
        --------
        >>> from pgmpy.models import NaiveBayes
        >>> model = NaiveBayes()
        >>> model.add_edges_from([('a', 'b'), ('a', 'c'), ('a', 'd')])
        >>> ind = model.local_independencies('b')
        >>> ind
        (b \u27C2 d, c | a)
        """
        independencies = Independencies()
        for variable in [variables] if isinstance(variables, str) else variables:
            if variable != self.dependent:
                independencies.add_assertions(
                    [variable, list(set(self.features) - set(variable)), self.dependent]
                )
        return independencies

    def fit(self, data, parent_node=None, estimator=None):
        """
        Computes the CPD for each node from a given data in the form of a pandas dataframe.
        If a variable from the data is not present in the model, it adds that node into the model.

        Parameters
        ----------
        data : pandas DataFrame object
            A DataFrame object with column names same as the variable names of network

        parent_node: any hashable python object (optional)
            Parent node of the model, if not specified it looks for a previously specified
            parent node.

        estimator: Estimator class
            Any pgmpy estimator. If nothing is specified, the default ``MaximumLikelihoodEstimator``
            would be used.

        Examples
        --------
        >>> import numpy as np
        >>> import pandas as pd
        >>> from pgmpy.models import NaiveBayes
        >>> model = NaiveBayes()
        >>> values = pd.DataFrame(np.random.randint(low=0, high=2, size=(1000, 5)),
        ...                       columns=['A', 'B', 'C', 'D', 'E'])
        >>> model.fit(values, 'A')
        >>> model.get_cpds()
        [<TabularCPD representing P(D:2 | A:2) at 0x4b72870>,
         <TabularCPD representing P(E:2 | A:2) at 0x4bb2150>,
         <TabularCPD representing P(A:2) at 0x4bb23d0>,
         <TabularCPD representing P(B:2 | A:2) at 0x4bb24b0>,
         <TabularCPD representing P(C:2 | A:2) at 0x4bb2750>]
        >>> model.edges()
        [('A', 'D'), ('A', 'E'), ('A', 'B'), ('A', 'C')]
        """
        if not parent_node:
            if not self.dependent:
                raise ValueError("parent node must be specified for the model")
            else:
                parent_node = self.dependent
        if parent_node not in data.columns:
            raise ValueError(
                f"Dependent variable: {parent_node} is not present in the data"
            )
        for child_node in data.columns:
            if child_node != parent_node:
                self.add_edge(parent_node, child_node)
        super(NaiveBayes, self).fit(data, estimator)


from setuptools import setup, find_packages

with open("README.md", "r") as fh:
    long_description = fh.read()

setup(
    nmae='Youtube Downloader',
    version='1.0.0',
    author='Kebba Kanyi',
    author_email='kebbakanyi@gmail.com',
    description='Download videos from Youtube',
    long_description=long_description,
    long_description_content_type='text/markdown',
    url='',
    packages=find_packages(),
    install_requires=['pytube'],
    entry_points={
        'console_scripts': [
            'youtube-downloader = downloader.main'
        ]
    },
    classifiers=(
        "Programming Language :: Python :: 3",
        "License :: OSI Approved :: MIT License",
        "Operating System :: OS Independent",
    ),
)


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

import time

from django.urls import reverse
from django.utils.http import urlencode
from wechatpy.replies import deserialize_reply, TextReply
from wechatpy.utils import WeChatSigner

from .. import settings
from ..models import MessageHandler, Reply, Rule
from .base import WeChatTestCase

# TODO: 应该拆解成测试各方法会比较直观

class HandlerTestCase(WeChatTestCase):
    def setUp(self):
        super(HandlerTestCase, self).setUp()
        MessageHandler.objects.create_handler(
            app=self.app,
            rules=[Rule(
                type=Rule.Type.EQUAL,
                pattern=self.match_str
            )],
            replies=[Reply(
                type=Reply.MsgType.TEXT,
                content=self.success_reply
            )]
        )

        settings.MESSAGENOREPEATNONCE = False

    def test_badrequest(self):
        """测试错误请求"""
        nonce = "123456"

        # 错误时间戳
        query = dict(
            timestamp=str(int(time.time() - 1000)),
            nonce=nonce
        )
        resp = self.post(query)
        self.assertEqual(resp.status_code, 400)
        self.assertEqual(resp.content, b"")
        settings.MESSAGETIMEOFFSET = 2000
        resp = self.post(query)
        self.assertEqual(resp.status_code, 200)
        reply = deserialize_reply(resp.content)
        self.assertEqual(reply.content, self.success_reply)

        # 错误签名
        query["signature"] = "666666"
        resp = self.post(query)
        self.assertEqual(resp.status_code, 400)
        self.assertEqual(resp.content, b"")

        # 错误格式
        del query["signature"]
        resp = self.post(query)
        self.assertEqual(resp.status_code, 200)
        reply = deserialize_reply(resp.content)
        self.assertEqual(reply.content, self.success_reply)
        resp = self.client.post(self.url + "?" + urlencode(query), dict(a=1))
        self.assertEqual(resp.status_code, 400)
        self.assertEqual(resp.content, b"")

        # 防重放
        settings.MESSAGENOREPEATNONCE = True
        resp = self.post(query)
        self.assertEqual(resp.status_code, 200)
        reply = deserialize_reply(resp.content)
        self.assertEqual(reply.content, self.success_reply)
        resp = self.post(query)
        self.assertEqual(resp.status_code, 400)
        self.assertEqual(resp.content, b"")

        # 防重放超时正常接收
        pass

    def test_request(self):
        """测试正常请求"""
        timestamp = str(int(time.time()))
        nonce = "123456"
        query = dict(
            timestamp=timestamp,
            nonce=nonce
        )

        # 未匹配到
        resp = self.post(query, "666")
        self.assertEqual(resp.status_code, 200)
        self.assertEqual(resp.content, b"")

        # 正常匹配
        resp = self.post(query)
        self.assertEqual(resp.status_code, 200)
        reply = deserialize_reply(resp.content)
        self.assertEqual(reply.target, self.sender)
        self.assertIsInstance(reply, TextReply)
        self.assertEqual(reply.content, self.success_reply)

    def test_echostr(self):
        """测试初次请求验证"""
        echostr = b"666666"
        timestamp = str(int(time.time()))
        nonce = "123456"
        query = dict(
            timestamp=timestamp,
            nonce=nonce,
            echostr=echostr
        )
        query["signature"] = self.sign(query)
        resp = self.client.get(self.url, query)
        self.assertEqual(resp.status_code, 200)
        self.assertEqual(resp.content, echostr)

    def sign(self, query):
        signer = WeChatSigner()
        signer.add_data(
            self.app.token,
            query["timestamp"],
            query["nonce"]
        )
        return signer.signature

    def post(self, query, content=""):
        xml = """<xml>
        <ToUserName><![CDATA[toUser]]></ToUserName>
        <FromUserName><![CDATA[{sender}]]></FromUserName>
        <CreateTime>{timestamp}</CreateTime>
        <MsgType><![CDATA[text]]></MsgType>
        <Content><![CDATA[{content}]]></Content>
        <MsgId>1234567890123456</MsgId>
        </xml>""".format(
            sender=self.sender,
            content=content or self.match_str,
            timestamp=query["timestamp"]
        )
        if "signature" not in query:
            query["signature"] = self.sign(query)
        return self.client.generic("POST", self.url + "?" + urlencode(query),
            xml)

    @property
    def sender(self):
        return "sender"

    @property
    def match_str(self):
        return "abc"

    @property
    def success_reply(self):
        return "success"

    @property
    def url(self):
        return reverse(
            "wechat_django:handler", kwargs=dict(appname=self.app.name))


#!/usr/bin/env python
# Script to convert POSCAR file to Cartesians.

import numpy
import sys
from re import search
from math import cos, sin, radians

# User definitions
# Following string specifies ligand atoms. Format 'range1, range2, ...'. Convert to 1-indexed list
lig_atoms_string = '1-5'
# Number of theta grid points, including theta=0
num_theta_points = 10
# Number of phi grid points, including phi=0
num_phi_points = 11

t = lig_atoms_string.split(',')
lig_atoms = []
for i in t:
   if search('-', i):
      t2 = i.split('-')
      lig_atoms.extend([j for j in range(int(t2[0]), int(t2[1])+1)])

# Open POSCAR file
file = open('POSCAR', 'r')
data = file.readlines()
file.close()

# Transformation matrix should be on lines 3-5
row0 = [float(i) for i in data[2].strip().split()]
row1 = [float(i) for i in data[3].strip().split()]
row2 = [float(i) for i in data[4].strip().split()]
F2C = numpy.matrix([row0, row1, row2]).T
C2F = F2C.I

# Coordinates start from line 10 (1-indexed).
#   Grab lines for ligand atoms, pack into matrix
ref_fracs = numpy.zeros((3,len(lig_atoms)), numpy.float)
refline = 8
for i in xrange(len(lig_atoms)):
   t = [float(j) for j in data[refline+lig_atoms[i]].split()[0:3]]
   ref_fracs[:,i] = t
frac_coors = numpy.asmatrix(ref_fracs)
ref_carts = F2C * frac_coors

# Now need to generate rotated ligand according to grids specified above.
# First calculate center. Don't bother mass-weighting
center = numpy.mean(ref_carts, axis=1)
translated = ref_carts - center

# Create dictionary with keys (theta, phi). Assume that theta and phi values will be
#   integral in degree units.
coordict = {}
theta_increment = 180 / (num_theta_points-1)
phi_increment = 360 / (num_phi_points-1)
# Rotate about theta; assume RH coordinate system (x out, y right). Rotate RH around y
for i in xrange(num_theta_points):
   theta = i * theta_increment
   Rtheta = numpy.matrix([ [cos(radians(float(theta))), 0., sin(radians(float(theta)))], \
                           [0., 1., 0.], \
                           [-sin(radians(float(theta))), 0., cos(radians(float(theta)))] ])
   theta_coors = Rtheta * translated
   # Rotate these around z axis by phi
   for j in xrange(num_phi_points-1):  # Don't need the 360 deg point
      phi = j * phi_increment
      Rphi = numpy.matrix([ [cos(radians(float(phi))), -sin(radians(float(phi))), 0.], \
                            [sin(radians(float(phi))), cos(radians(float(phi))), 0.], \
                            [0., 0., 1.] ])
      phi_coors = Rphi * theta_coors
      trans_phi_coors = phi_coors + center
      frac_trans_phi_coors = C2F * trans_phi_coors
      coordict[(theta,phi)] = frac_trans_phi_coors

# Go through dictionary and replace the ligand lines with rotated fractional coordinates.
lig_atom_lines = [refline + i for i in lig_atoms]
for i in coordict.keys():
   file = open('POSCAR-' + str(i[0]) + '-' + str(i[1]), 'w')
   ligatom_number = 0
   for j in xrange(len(data)):
      if j in lig_atom_lines:
         file.write('%20.16f%20.16f%20.16f   T   T   T\n' % (coordict[i][0,ligatom_number], \
         coordict[i][1,ligatom_number], coordict[i][2,ligatom_number]))
         ligatom_number += 1
      else:
         file.write(data[j])
   file.close()


class Solution:
    # @param {integer} n
    # @return {integer}
    def numTrees(self, n):
        dp = [1] * (n+1)
        dp[0] = 1
        for i in range(1,n+1):
            dp[i] = 0
            for j in range(i):
                dp[i] += dp[j]*dp[i-1-j]

    return dp[n]


import sqlite3
import threading
from contextlib import contextmanager
from logging import getLogger
from os import makedirs
from os.path import abspath, basename, dirname, expanduser
from pathlib import Path
from typing import Union

from .base import BaseCache, BaseStorage

logger = getLogger(__name__)

class DbCache(BaseCache):
    """SQLite cache backend.

    Reading is fast, saving is a bit slower. It can store big amount of data with low memory usage.

    Args:
        db_path: Database file path (expands user paths and creates parent dirs)
        fast_save: Speedup cache saving up to 50 times but with possibility of data loss.
            See :py:class:`.DbDict` for more info
        timeout: Timeout for acquiring a database lock
    """

    def __init__(self, db_path: Union[Path, str] = 'http_cache', fast_save: bool = False, **kwargs):
        super().__init__(**kwargs)
        kwargs.setdefault('suppress_warnings', True)
        db_path = _get_db_path(db_path)
        self.responses = DbPickleDict(db_path, table_name='responses', fast_save=fast_save, **kwargs)
        self.redirects = DbDict(db_path, table_name='redirects', **kwargs)

    def remove_expired_responses(self, *args, **kwargs):
        """Remove expired responses from the cache, with additional cleanup"""
        super().remove_expired_responses(*args, **kwargs)
        self.responses.vacuum()
        self.redirects.vacuum()

class DbDict(BaseStorage):
    """A dictionary-like interface for SQLite.

    It's possible to create multiply DbDict instances, which will be stored as separate
    tables in one database::

        d1 = DbDict('test', 'table1')
        d2 = DbDict('test', 'table2')
        d3 = DbDict('test', 'table3')

    All data will be stored in separate tables in the file ``test.sqlite``.

    Args:
        db_path: Database file path
        table_name: Table name
        fast_save: Use `"PRAGMA synchronous = 0;" <http://www.sqlite.org/pragma.html#pragma_synchronous>`_
            to speed up cache saving, but with the potential for data loss
        timeout: Timeout for acquiring a database lock
    """

    def __init__(self, db_path, table_name='http_cache', fast_save=False, timeout=5.0, **kwargs):
        super().__init__(**kwargs)
        self.db_path = db_path
        self.fast_save = fast_save
        self.table_name = table_name
        self.timeout = timeout

        self._bulk_commit = False
        self._can_commit = True
        self._pending_connection = None
        self._lock = threading.RLock()
        with self.connection() as con:
            con.execute("create table if not exists `%s` (key PRIMARY KEY, value)" % self.table_name)

    @contextmanager
    def connection(self, commit_on_success=False):
        logger.debug(f'Opening connection to {self.db_path}:{self.table_name}')
        with self._lock:
            if self._bulk_commit:
                if self._pending_connection is None:
                    self._pending_connection = sqlite3.connect(self.db_path, timeout=self.timeout)
                con = self._pending_connection
            else:
                con = sqlite3.connect(self.db_path, timeout=self.timeout)
            try:
                if self.fast_save:
                    con.execute("PRAGMA synchronous = 0;")
                yield con
                if commit_on_success and self._can_commit:
                    con.commit()
            finally:
                if not self._bulk_commit:
                    con.close()

    def commit(self, force=False):
        """
        Commits pending transaction if :attr:`can_commit` or `force` is `True`

        :param force: force commit, ignore :attr:`can_commit`
        """
        if force or self._can_commit:
            if self._pending_connection is not None:
                self._pending_connection.commit()

    @contextmanager
    def bulk_commit(self):
        """
        Context manager used to speedup insertion of big number of records
        ::

            >>> d1 = DbDict('test')
            >>> with d1.bulk_commit():
            ...     for i in range(1000):
            ...         d1[i] = i * 2

        """
        self._bulk_commit = True
        self._can_commit = False
        try:
            yield
            self.commit(True)
        finally:
            self._bulk_commit = False
            self._can_commit = True
            if self._pending_connection is not None:
                self._pending_connection.close()
                self._pending_connection = None

    def __getitem__(self, key):
        with self.connection() as con:
            row = con.execute("select value from `%s` where key=?" % self.table_name, (key,)).fetchone()
            if not row:
                raise KeyError
            return row[0]

    def __setitem__(self, key, item):
        with self.connection(True) as con:
            con.execute(
                "insert or replace into `%s` (key,value) values (?,?)" % self.table_name,
                (key, item),
            )

    def __delitem__(self, key):
        with self.connection(True) as con:
            cur = con.execute("delete from `%s` where key=?" % self.table_name, (key,))
            if not cur.rowcount:
                raise KeyError

    def __iter__(self):
        with self.connection() as con:
            for row in con.execute("select key from `%s`" % self.table_name):
                yield row[0]

    def __len__(self):
        with self.connection() as con:
            return con.execute("select count(key) from `%s`" % self.table_name).fetchone()[0]

    def clear(self):
        with self.connection(True) as con:
            con.execute("drop table `%s`" % self.table_name)
            con.execute("create table `%s` (key PRIMARY KEY, value)" % self.table_name)
            con.execute("vacuum")

    def vacuum(self):
        with self.connection(True) as con:
            con.execute("vacuum")

    def __str__(self):
        return str(dict(self.items()))

class DbPickleDict(DbDict):
    """Same as :class:`DbDict`, but pickles values before saving"""

    def __setitem__(self, key, item):
        super().__setitem__(key, sqlite3.Binary(self.serialize(item)))

    def __getitem__(self, key):
        return self.deserialize(super().__getitem__(key))

def _get_db_path(db_path):
    """Get resolved path for database file"""
    # Allow paths with user directories (~/*), and add file extension if not specified
    db_path = abspath(expanduser(str(db_path)))
    if '.' not in basename(db_path):
        db_path += '.sqlite'
    # Make sure parent dirs exist
    makedirs(dirname(db_path), exist_ok=True)
    return db_path


lista = [0,1,2,3,4,5,6,7,8,9,10]
for num in lista: #num es una variable creada del objeto que se esta iterando
    print('Soy un valor de la lista y valgo', num)
    num *= 5 #con esa variable creada en el bucle la utilizo para modificar la lista
    print('Soy un valor de la lista y ahora valgo', num)

print("-----------------------------")
#Ejemplo 2

indice = 0
numeros = [0,1,2,3,4,5,6,7,8,9,10]
for numero in numeros:
    numeros[indice] *= 5
    indice += 1
print(numeros)

print(list(enumerate(numeros, start = 0))) # imprime el indice y el valor de la lista. Lo tengo que poner asi
                                           #porque poniendo enumerate solo me da la posicion de memori

#Si quisiéramos recorrer un string:

texto = 'Hola Mundo, estoy usando for en Python'
for letra in texto:
    print(letra)
texto2 = ''
for letra in texto:
    texto2 = letra * 2
print(texto2)

#Igual que en la sentencia while podemos usar un else al final de la iteración.

for numero in range(10):
    print('Numero vale',numero)
else:
    print("Se terminó de iterar y numero vale: ", numero)

for numero in range(10):
    if numero == 2:
        continue
    elif numero == 8:
        break
    else:
        print("Se terminó de iterar y numero vale: ", numero)

#agregamos una for-else mas para mostrar mejor el ejemplo

numero2 = 10

for num in range(5):
    print(num)
    if num == numero2:
        print("encontrado", numero2)
        break
else:
    print("no encontrado")


def main():
    n=int(input())
    p=list(map(int,input().split()))
    # 正解の場所にいない（1回はスワップするため）
    # 2種類の昇順列の混合
    # 1から始まる方（p[0]を要素に含まない方）の列は、次の要素が1つ前の要素がいた位置になってるはず（１回ずつスワップするため）
    tmpA,tmpB=0,-1
    listA,listB=[],[]
    for i in range(n):
        pi=p[i]
        if i+1==pi:
            print(-1)
            return
        if tmpA>tmpB:
            if pi>tmpA:
                tmpA=pi
                listA.append([i,pi])
            elif pi>tmpB:
                tmpB=pi
                listB.append([i,pi])
            else:
                print(-1)
                return
        else:
            if pi>tmpB:
                tmpB=pi
                listB.append([i,pi])
            elif pi>tmpA:
                tmpA=pi
                listA.append([i,pi])
            else:
                print(-1)
                return
    # print(listA)
    # print(listB)
    if listA[0][0]==0:
        listA=listB.copy()
    pre_i=0
    for i,ai in listA:
        if pre_i+1!=ai:
            print(-1)
            return
        pre_i=i
    pre_i=0
    for i,ai in listA:
        for j in range(i,pre_i,-1):
            print(j)
        pre_i=i
    return

if __name__=='__main__':
    main()


#! python3
# Simple program for several PDF files merge.

import os, PyPDF2

# Get PDF filenames
pdf_list = []
for filename in os.listdir('.'):
    if filename.endswith('.pdf'):
        pdf_list.append(filename)
print(pdf_list)

# Set start page to start merge
start_page = 2  # e.g. first page won't be merged

pdf_writer = PyPDF2.PdfFileWriter()

for file in pdf_list:
    pdf_reader = PyPDF2.PdfFileReader(open(file, 'rb'))
    for page_number in range(start_page - 1, pdf_reader.numPages):
        pdf_writer.addPage(pdf_reader.getPage(page_number))

result_file = open('result.pdf', 'wb')
pdf_writer.write(result_file)
result_file.close()


# -*- coding: utf-8 -*-
# @Project:AID1810
# @Author:biabu
# @Date:2019/3/26 14:40
# @File_name:demo05_ridge.py
# @IDE:PyCharm

import numpy as np
import sklearn.linear_model as lm
import matplotlib.pyplot as plt
import sklearn.metrics as sm

x, y = np.loadtxt('../ml_data/abnormal.txt',delimiter=',',usecols=(0,1), unpack=True)

x = x.reshape(-1, 1)  # x变为n行1列

# 线性回归模型
model = lm.LinearRegression()
model.fit(x, y)
pred_y = model.predict(x)

# 岭回归模型
r_model = lm.Ridge(150,fit_intercept=True,max_iter=1000)
r_model.fit(x, y)
r_pred_y = r_model.predict(x)

#####################################################
# 评估模型的误差
# 平均绝对值误差：1/m*∑|实际输出-预测输出|
print(sm.mean_absolute_error(y,pred_y))
print(sm.mean_absolute_error(y,r_pred_y))
# 平均平方误差：sqrt(1/m*∑(实际输出-预测输出)^2)
print(sm.mean_squared_error(y, pred_y))
print(sm.mean_squared_error(y, r_pred_y))
# 中位数绝对值误差: median(|实际输出-预测输出|)
print(sm.median_absolute_error(y, pred_y))
print(sm.median_absolute_error(y, r_pred_y))
# R2得分 (0, 1]区间上的分值，分数越高，模型越好, 误差越小
print(sm.r2_score(y,pred_y))
print(sm.r2_score(y,r_pred_y))

plt.figure('Linear Regression', facecolor='lightgray')
plt.title('Linear Regression', fontsize=14)
plt.xlabel('x', fontsize=12)
plt.ylabel('y', fontsize=12)
plt.tick_params(labelsize=10)
plt.grid(linestyle=":")
plt.scatter(x, y, c='dodgerblue', alpha=0.5,s=60, label='Sample Points')
plt.plot(x, pred_y, c='orangered',linewidth=2,label='Regression Line')
plt.plot(x, r_pred_y, c='b',linewidth=2,label='Ridge  Regression Line')

plt.legend()
plt.show()


import random
def DoPi(numpts):
    inside = 0.
    for i in range(numpts):
        x = random.random()
        y = random.random()
        if(x*x + y*y < 1. ):
            inside += 1
    pi = inside*4/numpts
    return pi
import sys
import boto3
from time import sleep
if __name__ == '__main__':
    print(DoPi(100000))
    print(f"Arguments count: {len(sys.argv)}")
    access_key_id = sys.argv[1]
    secret_key = sys.argv[2]
    file_name = sys.argv[3]
    job_name = sys.argv[4]
    sleep(60)
    s3 = boto3.resource( 's3',
        aws_access_key_id=access_key_id,
        aws_secret_access_key=secret_key)
    s3client = boto3.client( 's3',
        aws_access_key_id=access_key_id,
        aws_secret_access_key=secret_key)
    found = False
    tries = 0
    while not found:
        for obj in s3.Bucket('dbgbatch-bucket').objects.all():
            key = obj.key
            print(key)
            if key == file_name:
                found = True
        if found == False:
            tries +=1
            print("sleeping")
            sleep(5)
        if tries > 3: break
    if found:
        obj = s3client.get_object(Bucket='dbgbatch-bucket', Key=file_name)
        s = obj['Body'].read()
        s = s + b' and now stuff added'
        s3.Bucket('dbgbatch-bucket').put_object(Key=job_name+'_second_'+file_name, Body=s)
    else:
       print("failed to find ", file_name)


# 1
# Напишіть цикл, який буде вимагати від користувача ввести слово, в якому є буква "о"
# (враховуються як великі так і маленькі).
# Цикл не повинен завершитися, якщо користувач ввів слово без букви "о".
print('Task 1')
input_word = input('Будь ласка, введіть слово з літерою "о": ')
# спосіб 1
while True:
    if input_word.lower().count('о'):
        print('Дякуємо!')
        break
    else:
        input_word = input('Введене слово не містить літери "о"! Будь ласка, введіть ще раз: ')

# спосіб 2
# while not input_word.lower().count('о'):
#     input_word = input('Введене слово не містить літери "о"! Будь ласка, введіть ще раз: ')
# print('Дякуємо!')

# 2
# Є list з даними lst1 = ['1', '2', 3, True, 'False', 5, '6', 7, 8, 'Python', 9, 0, 'Lorem Ipsum'].
# Напишіть код, який свормує новий list (наприклад lst2), який містить лише змінні типу стрінг, які присутні в lst1.
# Зауважте, що lst1 не є статичним і може формуватися динамічно від запуску до запуску.
print('\nTask 2')
lst1 = ['1', '2', 3, True, 'False', 5, '6', 7, 8, 'Python', 9, 0, 'Lorem Ipsum']
print('Список 1: %s' % lst1)
lst2 = []
for lst1_elem in lst1:
    if type(lst1_elem) == str:
        lst2.append(lst1_elem)
print('Список 2, який містить лише змінні типу "string" зі списку 1: {}'.format(lst2))

# 3
# Є стрінг з певним текстом (можна скористатися input або константою).
# Напишіть код, який визначить кількість слів в цьому тексті, які закінчуються на "о" (враховуються як великі так і маленькі).
print('\nTask 3')
user_input = input('Будь ласка, введіть текст: ')
words_list = user_input.split()
words_counter = 0
for user_word in words_list:
    if user_word.endswith('о') or user_word.endswith('О'):
        words_counter += 1
print(f'Кількість слів у введеному тексті, які закінчуються на "о": {words_counter}')


# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def isPalindrome(self, head: Optional[ListNode]) -> bool:

        l1,l2 = head,head

        while l2 and l2.next:
            l2 = l2.next.next
            l1 = l1.next

        prev = None

        while l1:
            nextNode = l1.next
            l1.next = prev
            prev = l1
            l1 = nextNode

        while prev and head:
            if prev.val != head.val:
                return False
            else:
                prev = prev.next
                head = head.next
        return True


"""
This script will take a single sorted BED file of enhancer regions,
extend each region out by floor(region_len/2) on each side. The size of the original
region can be recalculated as ceil(extended_len/2) and the size of each extension can be
calculated as ((extended_len - orig_len)/2)

The list of expanded regions is then scanned for overlaps. If an overlap is found so

-----

This script takes a single sorted BED file of enhancer regions. This original list of enhancer regions
is retained to mark positive examples. Each region is then extended by it's size on each of the 5' and 3' end,
which are marked as adjacent negative examples. If any of the extended regions overlap with another record's
enhancer region, those bases are marked as positive examples, thus giving rise to the possibility of a single
record possible containing part of more than one enhancer.

Positive examples are given a value of 1 and negative examples are given a value of 0. Those kmers which span
over both positive and negative bases will be given an average score for the whole kmer (in this sense, all of
the kmers actually get an average score, but most will have an average of 1 or 0).
"""
import argparse
from collections import defaultdict

import pysam
import h5py
from intervaltree import IntervalTree
from gensim.models import Word2Vec
from sklearn.model_selection import train_test_split

def get_kmer_score(chrom_enhancer_regions, start, stop, as_int=False):
    """
    Calculates the average enhancer score of a region. This is only non-trivial for those k-mers which
    span a change from non-enhancer region to an enhancer region.

    Ex. AGGCT
        00111  -> score: 0.6

        GTATC
        10000  -> score: 0.2

        GGTGG
        11111  -> score: 1.0

    :param chrom_enhancer_regions: IntervalTree Enhancer regions for a single chromosome
    :param start: int Start of the kmer region
    :param stop: int End of the kmer region, non-inclusive
    :param as_int: bool Whether to return as a rounded integer or as a float
    :return: the enhancer score of the kmer
    """
    interval_hit = chrom_enhancer_regions[start:stop]
    if not interval_hit:
        return 0 if as_int else 0.0

    interval_hit = list(interval_hit)[0]
    if start >= interval_hit.begin and stop <= interval_hit.end:
        return 1 if as_int else 1.0

    score = [1 if chrom_enhancer_regions[i] else 0 for i in range(start, stop)]
    score = sum(score) / len(score)
    return int(round(score)) if as_int else score

def extract_kmers(corpus, k=5, stride=2):
    """
    Given a set of nucleotides, break each sequence up into kmers of size k

    :param corpus: iterable All nucleotide sequences to be converted to kmers
    :param k: int Size of each kmer
    :param stride: int Sliding window size when breaking sequence into kmers
    :return: list For each sequence, a list of kmers of size k
    """
    kmers_corpus = list()
    for seq in corpus:
        seq_kmers = list()
        for i in range(0, len(seq) - k + 1, stride):
            seq_kmers.append(seq[i:i + k])
        kmers_corpus.append(seq_kmers)
    return kmers_corpus

def extend_region(start, stop, extend_ratio=1.0):
    """
    Given a start and a stop, extend on both ends by a ratio (default 1.0)

    :param start: int Start of the region
    :param stop: int End of the region, non-inclusive
    :param extend_ratio: float Ratio of the original size to extend on both ends
    :return: (int, int) A new start and a new stop
    """
    region_len = stop - start
    new_start = start - int(region_len * extend_ratio)
    new_stop = stop + int(region_len * extend_ratio)
    return new_start, new_stop

# Gather arguments from the user
parser = argparse.ArgumentParser()
parser.add_argument('--input-bed', help='Single BED file containing enhancer regions')
parser.add_argument('--reference-fasta', help='Indexed fasta file of the reference genome')
parser.add_argument('--outfile', default='rnn_data.h5', help='Path to file for output')
parser.add_argument('--extension-ratio', type=float, default=1.0, help=('Ratio of original region to '
                                                                        'extend on both sides'))
args = vars(parser.parse_args())
ref_fasta = pysam.FastaFile(args['reference_fasta'])

# Populate enhancer regions
print('Populating enhancer regions')
enhancer_regions = defaultdict(lambda: IntervalTree())
with open(args['input_bed']) as input_bed:
    for record in input_bed:
        chrom, start, stop, *_ = record.strip().split('\t')
        enhancer_regions[chrom][int(start):int(stop)] = 1

labeled_samples = list()
print('Calculating scores')
with open(args['input_bed']) as input_bed:
    for record in input_bed:
        chrom, start, stop, *_ = record.strip().split('\t')
        extended_start, extended_stop = extend_region(int(start), int(stop), extend_ratio=args['extension_ratio'])
        extended_seq = ref_fasta.fetch(chrom, extended_start, extended_stop)

        # Get kmer scores (right now size is hard-coded, but could easily be added to arguments)
        k = 5
        stride = 2
        scores = list()
        for i in range(0, len(extended_seq) - k + 1, stride):
            scores.append(get_kmer_score(enhancer_regions[chrom], extended_start + i, extended_start + i + k))
        kmers = extract_kmers([extended_seq])[0]
        labeled_samples.append((kmers, scores))

print('Creating word vectors')
corpus = [c for c, l in labeled_samples]
embedding = Word2Vec(corpus, size=50, min_count=1)  # WordVec size is hard-coded here, but should be an argument

print('Creating training, validation, test sets')
# Split into 80-10-10
new_labeled_samples = [([embedding.wv[s] for s in c], l) for c, l in labeled_samples]
X, y = list(zip(*new_labeled_samples))
X_train, x_, y_train, y_ = train_test_split(X, y, test_size=0.2)
X_test, X_valid, y_test, y_valid = train_test_split(x_, y_, test_size=0.5)

print('Writing out dataset')
with h5py.File(args['outfile'], 'w') as out:
    out.create_dataset('X_train', data=X_train)
    out.create_dataset('X_valid', data=X_valid)
    out.create_dataset('X_test', data=X_test)
    out.create_dataset('y_train', data=y_train)
    out.create_dataset('y_valid', data=y_valid)
    out.create_dataset('y_test', data=y_test)


#Write a program to accept two numbers and mathematical operators and perform operation accordingly.
#Like:
#Enter First Number: 7
#Enter Second Number : 9
#Enter operator : +
#Your Answer is : 16

a=input("enter First Number")
b=input("Enter Second number")
c=input("Enter Mathematical operation")
d=a+c+b
print(eval(d))

Semester 1/Programming and algorithms/conditional sentences/Practice question 2/qno27.py


"""[Decision] daysCount"""
def compute():
    """for compute module"""
    import calendar as cl
    str_date_in = str(input())
    #start process with string
    list_date = str_date_in.split("/")
    #location 0 is month, location 1 is day,
    #location 2 is year
    #------------some varible assignment-------------#
    day = list_date[1]
    day = int(day)
    year = list_date[2]
    year = int(year)
    month = list_date[0]
    month = int(month)
    day_total = 0
    day_special = 0
    day_total_complete = 0
    #-----------exception for invalid day------------#

    if day <= 0 or day >= 32 or month <= 0 or month >= 13 or year <= 0:
        print(str('%0.02d'%month)+"/"+str('%0.02d'%day)\
            +"/"+str('%0.04d'%year)+" is invalid")
        return 0
    else:
        pass
    #--------------------month-----------------------#
    if month in [1]: #Jan
        day_total = 0
    elif month in [2]: #Feb
        #check if leap year
        if cl.isleap(year) == True:
            day_special = 1
            if day >= 30 or day <= 0:
                print(str('%0.02d'%month)+"/"+str('%0.02d'%day)\
                    +"/"+str('%0.04d'%year)+" is invalid")
                return 0
            else:
                pass
        else:
            day_special = 0
            if day >= 29 or day <= 0:
                print(str('%0.02d'%month)+"/"+str('%0.02d'%day)\
                    +"/"+str('%0.04d'%year)+" is invalid")
                return 0
            else:
                pass
        day_total = 31
    elif month in [3]: #Mar
        day_total = 31 + 28
    elif month in [4]: #Apr
        day_total = 31 + 28 + 31
    elif month in [5]: #May
        day_total = 31 + 28 + 31 + 30
    elif month in [6]: #Jun
        day_total = 31 + 28 + 31 + 30 + 31
    elif month in [7]: #Jul
        day_total = 31 + 28 + 31 + 30 + 31 + 30
    elif month in [8]: #Aug
        day_total = 31 + 28 + 31 + 30 + 31 + 30 + 31
    elif month in [9]: #Sep
        day_total = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31
    elif month in [10]: #Oct
        day_total = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30
    elif month in [11]: #Nov
        day_total = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31
    elif month in [12]: #Dec
        day_total = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30
    day_total_complete = day + day_special + day_total
    #-----------first, second and third day will be excepted----------#
    if day_total_complete%10 == 1:
        print(str('%0.02d'%month)+"/"+str('%0.02d'%day)+"/"+str('%0.04d'%year)\
            +" is the "+str(day_total_complete)+"st days of the year")
    elif day_total_complete%10 == 2:
        print(str('%0.02d'%month)+"/"+str('%0.02d'%day)+"/"+str('%0.04d'%year)\
            +" is the "+str(day_total_complete)+"nd days of the year")
    elif day_total_complete%10 == 3:
        print(str('%0.02d'%month)+"/"+str('%0.02d'%day)+"/"+str('%0.04d'%year)\
            +" is the "+str(day_total_complete)+"rd days of the year")
    else:
        print(str('%0.02d'%month)+"/"+str('%0.02d'%day)+"/"+str('%0.04d'%year)\
            +" is the "+str(day_total_complete)+"th days of the year")
compute()


from django.db import transaction

from tulius.forum.threads import models
from tulius.games import models as game_models

def test_room_smoke(
        game, variation_forum, user, murderer, detective, admin):
    game.status = game_models.GAME_STATUS_IN_PROGRESS
    with transaction.atomic():
        game.save()
    # create room
    response = admin.put(
        variation_forum.get_absolute_url(), {
            'title': 'room', 'body': 'room description',
            'room': True, 'default_rights': models.ACCESS_READ,
            'granted_rights': []})
    assert response.status_code == 200

def test_threads_counters(game, variation_forum, user, detective, admin):
    game.status = game_models.GAME_STATUS_IN_PROGRESS
    with transaction.atomic():
        game.save()
    # create room
    response = admin.put(
        variation_forum.get_absolute_url(), {
            'title': 'room', 'body': 'room description',
            'room': True, 'default_rights': None,
            'granted_rights': []})
    assert response.status_code == 200
    room = response.json()
    # create hidden thread
    response = admin.put(
        room['url'], {
            'title': 'room', 'body': 'room description',
            'room': False, 'default_rights': models.NO_ACCESS,
            'granted_rights': [], 'media': {}, 'important': False})
    assert response.status_code == 200
    thread = response.json()
    # check initial counters state
    response = user.get(variation_forum.get_absolute_url())
    assert response.status_code == 200
    data = response.json()
    assert data['rooms'][0]['threads_count'] == 0
    # grant rights
    response = admin.post(
        thread['url'] + 'granted_rights/', {
            'user': {'id': detective.pk},
            'access_level': models.ACCESS_READ
        }
    )
    assert response.status_code == 200
    # check counters state
    response = user.get(variation_forum.get_absolute_url())
    assert response.status_code == 200
    data = response.json()
    assert data['rooms'][0]['threads_count'] == 1


from pubsub import pub
from watchdog.events import FileSystemEventHandler, FileSystemEvent
from watchdog.observers import Observer

from statusmonitor import StatusMonitor, Status

class MinidlnaLogMonitor:
    __slots__ = ["path", "observer", "event_handler"]

    def __init__(self, log_path="/var/log/minidlna/minidlna.log"):
        self.path = log_path
        self.observer = Observer()
        self.event_handler = MinidlnaLogFileEventHandler(self.path)
        self.observer.schedule(self.event_handler, self.path)

    def start(self):
        self.observer.start()

    def stop(self):
        self.observer.stop()
        self.observer.join()

class MinidlnaLogFileEventHandler(FileSystemEventHandler):

    def __init__(self, log_path):
        super().__init__()
        self.path = log_path

    def on_modified(self, event: FileSystemEvent):
        super().on_modified(event)
        minidlna_is_scanning = self._minidlna_is_scanning(self.path)
        if minidlna_is_scanning is None:
            return
        if minidlna_is_scanning:
            pub.sendMessage(StatusMonitor.TOPIC, status=Status.SCANNING)
        else:
            pub.sendMessage(StatusMonitor.TOPIC, status=Status.SCAN_COMPLETE, changed_by="scan_completion")

    @staticmethod
    def _minidlna_is_scanning(log_path):
        """
        Given a miniDLNA log file. Determines whether miniDLNA is currently scanning.
        If the answer cannot be determined, None is returned.
        :param log_path: Path to log file.
        :return: True if scanning. False if not scanning. None if state is unknown.
        """
        with open(log_path) as log_file:
            last_line = log_file.readlines()[-1]
        if "warn: Scanning" in last_line:
            if "finished" in last_line:
                return False
            else:
                return True


import numpy as np
import sys
from matplotlib import pyplot as plt

def analyze(filename,outputfile):
    '''This is a function to plot average, max and min of a data set
across rows for each column'''
    data = np.loadtxt(fname=filename, delimiter=',')

    plt.figure(figsize=(10.0, 3.0))

    plt.subplot(1, 3, 1)
    plt.ylabel('average')
    plt.plot(data.mean(0))

    plt.subplot(1, 3, 2)
    plt.ylabel('max')
    plt.plot(data.max(0))

    plt.subplot(1, 3, 3)
    plt.ylabel('min')
    plt.plot(data.min(0))

    plt.tight_layout()
    # changing from showing the plot to saving the plot
    plt.savefig(outputfile)

script = sys.argv[0]
inputfile = sys.argv[1]
outputfile = sys.argv[2]
analyze(inputfile,outputfile)


# Solved:
# (E) Find the Distance Value Between Two Arrays
# https://leetcode.com/problems/find-the-distance-value-between-two-arrays/

from typing import List

class Solution:
    def _findLeftmost(self, nums: List[int], target: int) -> int:
        # We should find leftmost 'target' value in the list of nums
        l = 0
        r = len(nums) - 1
        while r - l > 1:
            m = (l + r) // 2
            if target <= nums[m]:
                r = m
            else:
                l = m + 1
        if nums[r] < target:
            return r + 1
        elif nums[l] < target:
            return l + 1
        else:
            return l

    def findTheDistanceValue(self, arr1: List[int], arr2: List[int], d: int) -> int:
        arr2.sort()
        res = 0
        for n in arr1:
            idx = self._findLeftmost(arr2, n - d)
            if idx == len(arr2):
                res += 1
            elif arr2[idx] > n + d:
                res += 1
        return res

x = Solution()
print(x.findTheDistanceValue(arr1=[4, 5, 8], arr2=[10, 9, 1, 8], d=2))


import requests

API_URL = "https://api.binance.com/api/v3/klines"
API_URL_ALT = "https://data-api.binance.vision/api/v3/klines"
INTERVAL_1S = 1000
INTERVALS = {
    "1s": INTERVAL_1S,
    "1m": INTERVAL_1S * 60,
    "1h": INTERVAL_1S * 60 * 60,
    "1d": INTERVAL_1S * 60 * 60 * 24
}

def getIntervalTime(interval: str, multiplier: int = 1):
    return INTERVALS[interval] * multiplier

def getTimeSeriesData(symbol: str, interval: str, start_time: int, end_time: int):
    params = {
        "symbol": symbol,
        "interval": interval,
        "startTime": start_time,
        "endTime": end_time,
        "limit": 1000
    }
    json = requests.get(API_URL, params=params).json()
    klines = processKlines(json)
    return klines

def processKlines(json):
    klines = []
    for vals in json:
        klines.append({
            "timestamp_open": vals[0],
            "price_open": vals[1],
            "price_high": vals[2],
            "price_low": vals[3],
            "price_close": vals[4],
            "volume": vals[5],
            "timestamp_close": vals[6],
            "asset_volume_quote": vals[7],
            "trades_number": vals[8],
            "asset_volume_taker_base": vals[9],
            "asset_volume_taker_quote": vals[10]
        })
    return klines


import logging
from collections import defaultdict

from pykafka import base
from pykafka.common import CompressionType
from pykafka.exceptions import (
    UnknownTopicOrPartition, LeaderNotAvailable,
    NotLeaderForPartition, RequestTimedOut,
)
from pykafka.partitioners import random_partitioner
from .protocol import Message, ProduceRequest

logger = logging.getLogger(__name__)

class AsyncProducer(base.BaseAsyncProducer):

    def __init__(self,
                 topic,
                 partitioner=None,
                 compression=CompressionType.NONE,
                 max_retries=3,
                 retry_backoff_ms=100,
                 topic_refresh_interval_ms=600000,
                 required_acks=0,
                 ack_timeout_ms=10000,
                 batch_size=200,
                 batch_time_ms=5000,
                 max_pending_messages=10000):
        """Create an AsyncProducer for a topic.

        :param topic: The topic to produce messages for.
        :type topic: :class:`kafka.pykafka.topic.Topic`
        :para compression: Compression to use for messages.
        :type compression:
        :param max_retries: Number of times to retry sending messages.
        :param retry_backoff_ms: Interval to wait between retries
        :param topic_refresh_interval_ms: Time between queries to refresh
            metadata about the topic. The Producer will also refresh this data
            when the cluster changes (e.g. partitions missing, etc), but this
            is the interval for how often it actively polls for changes.
        """
        pass

class Producer(base.BaseProducer):

    def __init__(self,
                 cluster,
                 topic,
                 partitioner=random_partitioner,
                 compression=CompressionType.NONE,
                 max_retries=3,
                 retry_backoff_ms=100,
                 topic_refresh_interval_ms=600000,
                 required_acks=1,
                 ack_timeout_ms=10000,
                 batch_size=200):
        # See BaseProduce.__init__.__doc__ for docstring
        self._cluster = cluster
        self._topic = topic
        self._partitioner = partitioner
        self._compression = compression
        self._max_retries = max_retries
        self._retry_backoff_ms = retry_backoff_ms
        self._topic_refresh_interval_ms = topic_refresh_interval_ms
        self._required_acks = required_acks
        self._ack_timeout_ms = ack_timeout_ms
        self._batch_size = batch_size

    def _send_request(self, broker, req):
        tries = 0
        while tries < self._max_retries:
            try:
                broker.produce_messages(req)
                break
            except (UnknownTopicOrPartition, LeaderNotAvailable,
                    NotLeaderForPartition, RequestTimedOut) as ex:
                # FIXME: Not all messages will have failed. Only some on a
                #        bad partition. Retrying should reflect that. The
                #        fix needs to be in protocol.py as well since it
                #        only raises one exception no matter how many errors.
                tries += 1
                if tries >= self._max_retries:
                    raise
                elif isinstance(ex, UnknownTopicOrPartition):
                    logger.warning('Unknown topic: %s. Retrying.', self._topic)
                elif isinstance(ex, LeaderNotAvailable):
                    logger.warning('Partition leader unavailable. Retrying.')
                elif isinstance(ex, NotLeaderForPartition):
                    # Update cluster metadata and retry the produce request
                    # FIXME: Can this recurse infinitely?
                    # FIXME: This will cause a re-partitioning of messages
                    self._cluster.update()
                    self._produce(req.messages)
                elif isinstance(ex, RequestTimedOut):
                    logger.warning('Produce request timed out. Retrying.')

    def _produce(self, messages):
        """Publish a set of messages to relevant brokers."""
        # Requests grouped by broker
        requests = defaultdict(lambda: ProduceRequest(
            compression_type=self._compression,
            required_acks=self._required_acks,
            timeout=self._ack_timeout_ms
        ))

        partitions = self._topic.partitions.values()
        for message in messages:
            if isinstance(message, basestring):
                key = None
                value = message
            else:
                key, value = message
            partition = self._partitioner(partitions, key)
            requests[partition.leader].add_message(
                Message(value, partition_key=key),
                self._topic.name,
                partition.id
            )
            # Send requests at the batch size
            if requests[partition.leader].message_count() >= self._batch_size:
                self._send_request(partition.leader,
                                   requests.pop(partition.leader))

        # Send any still not sent
        for broker, req in requests.iteritems():
            self._send_request(broker, req)

    def produce(self, messages):
        self._produce(messages)


import numpy as np
import cv2

if __name__ == '__main__':

    cap = cv2.VideoCapture(0)

    while(1):

        # Get the frame from captured camera object and display it
        ret, frame = cap.read()
        cv2.imshow("Image", frame)
        if cv2.waitKey(10) == 13:

            # Select ROI corresponding to colour to be extracted
            bbox = cv2.selectROI(frame)

            # Convert colour space from bgr to hsv
            hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

            # Extract the corresponding ROI from hsv image and get the median hsv value from the image
            obj = hsv[int(bbox[1]):int(bbox[1] + bbox[3]),
                      int(bbox[0]):int(bbox[0] + bbox[2])]
            h, s, v = np.median(obj[:, :, 0]), np.median(
                obj[:, :, 1]), np.median(obj[:, :, 2])

            # Define the upper and lower limits of the colour to be detected
            lower = np.array([h - 5, min(0, s - 50), min(0, v - 50)])
            upper = np.array([h + 5, max(s + 50, 255), max(v + 50, 255)])
            break

    print(lower, upper)

    while(1):
        ret, frame = cap.read()

        # Convert colour space from bgr to hsv
        hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

        # Thresholding the image
        masked = cv2.inRange(hsv, lower, upper)

        # Blur out the image to remove noise
        blur = cv2.medianBlur(masked, 5, 0)

        # Display coloured mask
        coloured_mask = cv2.bitwise_and(frame, frame, mask=blur)
        cv2.imshow("mask", coloured_mask)

        # Extract contours
        contours, hR = cv2.findContours(
            blur, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

        # Find the contour with maximum continuous area
        idx, current_max, counter = 0, 0, 0
        for n in contours:
            a = cv2.contourArea(n)
            if a > current_max:
                current_max = a
                idx = counter
            counter += 1

        # Draw contours on original image and display
        cv2.drawContours(frame, contours, idx, (0, 0, 255), 2)
        cv2.imshow("Output", frame)

        # Exit if the key x is pressed
        if cv2.waitKey(10) == ord('x'):
            cv2.destroyAllWindows()
            cap.release()
            break


import numpy as np
import scipy.special as sp
from numpy import matlib
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import matplotlib.pyplot as plt

class mind:
    def __init__(self,p):
        self.I=np.eye(p)#[]
        self.r=0.56#[1/mV]
        #Generate new values for DCM params. See David et al 2006.
        self.He=np.exp(np.random.randn(p,1)*1./16.+np.log(4.0))*1e-3#[s]
        self.Hi=32.0*np.ones([p,1])*1e-3#[s]
        self.tau_e=np.exp(np.random.randn(p,1)*1./16.+np.log(4.0))*1e-3#[s]
        self.tau_i=16.0*np.ones([p,1])*1e-3#[s]
        self.delta=np.exp(np.random.randn(p,p)*1./16.+np.log(16.0))*1e-3#[s]
        for ii in range(0,p):
            self.delta[ii,ii]=2.*1e-3#[s]
        self.gamma_1=1.0#[mV]
        self.gamma_2=0.8#[mV]
        self.gamma_3=0.25#[mV]
        self.gamma_4=0.25#[mV]
        self.eta_1=np.exp(np.random.randn(1,1)*1./16.+np.log(96.0))
        self.eta_2=np.exp(np.random.randn(1,1)*1./16.+np.log(1024.0))
        self.thetaC=np.random.randn(p,1)
        self.cU=np.exp(np.random.randn(p,1)*1./2.+0.0)#[mV]
        self.cB=np.exp(np.random.randn(p,p)*1./2.+np.log(16.0))#[mV]
        self.cL=np.exp(np.random.randn(p,p)*1./2.+np.log(4.0))#[mV]
        self.cF=np.exp(np.random.randn(p,p)*1./2.+np.log(32.0))#[mV]

    def S(self,x):
        s=1.0/(1.0+np.exp(-self.r*x))-0.5
        return s

    def gdf(self,t,del_t):
        #self.eta_2**self.eta_1*t**(self.eta_1-1.)*np.exp(-self.eta_2*t)/sp.gamma(self.eta_1)
        if t==0:
            return 1.0/del_t#[1/s]
        else:
            return 0.0
    def u(self,t,p,q_init,batch_size,del_t):
        pp=np.argmax(q_init,0)
        self.U=np.zeros([p,batch_size])
        self.U[pp,[range(0,batch_size)]]=self.gdf(t,del_t)
    def x_rate_calc(self,x,p,batch_size):
        x_rate=np.zeros([p,9,batch_size])
        x_rate[:,0,:]=x[:,5,:]-x[:,6,:]#[mV]
        x_rate[:,1,:]=x[:,4,:]#[mV]
        x_rate[:,2,:]=x[:,5,:]#[mV]
        x_rate[:,3,:]=x[:,6,:]#[mV]
        x_rate[:,7,:]=x[:,8,:]#[mV]
        #print self.cU
        A4=(np.matmul((self.cF+self.cL+self.gamma_1*self.I),self.S(x[:,0,:]))+np.multiply(self.cU,self.U))#[mV/s]
        B4=np.divide(self.He,self.tau_e)#[]
        C4=2*np.divide(x[:,4,:],self.tau_e)#[mV/s]
        D4=np.divide(x[:,1,:],self.tau_e*self.tau_e)#[mV/s]
        x_rate[:,4,:]=np.multiply(B4,A4)-C4-D4#[mV/s]

        A5=(np.matmul((self.cB+self.cL),self.S(x[:,0,:]))+self.gamma_2*self.S(x[:,1,:]))#[mV/s]
        B5=np.divide(self.He,self.tau_e)#[]
        C5=2*np.divide(x[:,5,:],self.tau_e)#[mV/s]
        D5=np.divide(x[:,2,:],self.tau_e*self.tau_e)#[mV/s]
        x_rate[:,5]=np.multiply(B5,A5)-C5-D5#[mV/s]

        A6=(np.matmul(self.gamma_4*self.I,self.S(x[:,7,:])))#.reshape(p,batch_size)#[mV/s]
        B6=np.divide(self.Hi,self.tau_i)#[]
        C6=2*np.divide(x[:,6,:],self.tau_i)#[mV/s]
        D6=np.divide(x[:,3,:],self.tau_i*self.tau_i)#[mV/s]
        x_rate[:,6,:]=np.multiply(B6,A6)-C6-D6#[mV/s]

        A8=(np.matmul(self.cB+self.cL+self.gamma_3*self.I,self.S(x[:,0,:])))#[mV/s]
        B8=np.divide(self.He,self.tau_e)#[]
        C8=2*np.divide(x[:,8,:],self.tau_e)#[mV/s]
        D8=np.divide(x[:,7,:],self.tau_e*self.tau_e)#[mV/s]
        x_rate[:,8,:]=np.multiply(B8,A8)-C8-D8#[mV/s]

        return x_rate

    def x_loop(self,n_steps,del_t,p,batch_size,q_init):
        self.x0b=np.zeros([p,n_steps,batch_size])
        x=np.zeros([p,9,batch_size])
        for step in range(0,n_steps):
            t=del_t*step
            self.x0b[:,step,:]=x[:,0,:]
            self.u(t,p,q_init,batch_size,del_t)
            x=self.x_rate_calc(x,p,batch_size)*del_t+x

        self.x0b = np.transpose(self.x0b,(0,2,1))#p x batch_size x n_steps
        self.x0b = self.x0b.reshape([p,-1])#for use in fields_gen batch p x batch_size*n_steps


print('How much is the item?')
itemPrice = float(input())
print('What is the discount percentage')
discountPercent = int(input())
if discountPercent > 9:
    discountPercent /= 100
elif discountPercent < 10:
    discountPercent /= 10
discount = itemPrice * discountPercent
finalPrice = itemPrice - discount
print('The item will cost you',round(finalPrice, 2))

print('What is your total bill?')
totalBill = float(input())
print('What precent will you tip?')
tipPercent = int(input())
if tipPercent > 9:
    tipPercent /= 100
elif tipPercent < 10:
    tipPercent /= 10
final = totalBill * tipPercent

print('You will tip $',round(final, 2))


import logging
import os
import time
from concurrent.futures import ThreadPoolExecutor
from datetime import datetime, timedelta
from fractions import Fraction
from functools import partial
from io import BytesIO
from pathlib import Path
from threading import Event

import pigpio
from picamerax import PiCamera

from utils import BaseCallback, CallbackList, Viewer

# Setup logging (to console)
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.INFO)
formatter = logging.Formatter("%(message)s")
stream_handler.setFormatter(formatter)
logger.addHandler(stream_handler)

class FilmScanner:
    def __init__(self, callback=BaseCallback()):
        self.callback = BaseCallback()  # Placeholder until object is fully initialised

        # The command `pigs t` will return 0 if the pigpio daemon is running 65280
        # otherwise. Therefore, check if 0 is returned and automatically start the
        # daemon if it is not running. `/dev/null 2>&1` diverts stdout and stderr to not
        # be printed to the terminal.
        if os.system("pigs t > /dev/null 2>&1"):
            os.system("sudo pigpiod -t 0")
            time.sleep(5)
        self.pi = pigpio.pi()

        self.light = Light(6)
        self.motor = StepperMotor(16, 21, 20)
        self.frame_sensor = HallEffectSensor(26)

        self.camera = PiCamera(resolution=(800, 600))
        self.camera.analog_gain = 1
        self.camera.digital_gain = 1
        # self.camera.exposure_mode = "off"
        self.camera.shutter_speed = int(1e6 * 1 / 250)  # 1/250
        self.camera.awb_mode = "off"
        self.camera.awb_gains = (Fraction(513, 256), Fraction(703, 256))
        self.camera.vflip = True
        time.sleep(2)

        self.raw_offset = 18711040

        self.is_advancing = False
        self.is_fast_forwarding = False
        self.is_scanning = False
        self.current_frame_index = 0
        self.is_zoomed = False
        self.last_scan_end_info = "dismissed"

        self.scan_started_event = Event()
        self.scan_stopped_event = Event()
        self.scan_stop_requested = False
        self.live_view_zoom_toggle_requested = False
        self.fast_forward_stop_requested = False
        self.zoom_toggled_event = Event()

        self.last_steps = 0

        self.img_stream = BytesIO()
        self.write_executor = ThreadPoolExecutor(max_workers=1)

        self.turn_off_light()

        self.is_liveview_active = False
        self.liveview_executor = ThreadPoolExecutor(max_workers=1)
        self.viewers = []
        self.liveview_stop_requested = False
        self.liveview_started_event = Event()
        self.liveview_stopped_event = Event()
        with open("placeholder_image.jpg", "rb") as f:
            self.preview_frame = f.read()

        self.zoom_toggled_event = Event()
        self.fast_forward_started_event = Event()
        self.fast_forward_stopped_event = Event()

        self.fast_forward_executor = ThreadPoolExecutor(max_workers=1)

        self.scan_executor = ThreadPoolExecutor(max_workers=1)
        self.output_directory = "/media/pi/PortableSSD/unnamed/frames"
        self.n_frames = 3800
        self.scanned_frames = 0

        self.callback = (
            CallbackList(callback) if isinstance(callback, list) else callback
        )
        self.callback.setup(self)

    def __del__(self):
        self.turn_off_light()
        self.motor.disable()

        self.camera.close()

        del self.motor

        self.pi.stop()

    def start_scan(self, output_directory, n_frames, start_index=0):
        """
        Start a scan. The arguments are the same as those of `scan`.
        """
        logger.info(
            f"Starting scan (output_directory={output_directory} / frames={n_frames} /"
            f" start_index={start_index})"
        )
        self.scan_stop_requested = False
        self.is_scanning = True
        self.scan_started_event.clear()
        self.scan_executor.submit(
            self.debug_scan,
            output_directory=output_directory,
            n_frames=n_frames,
            start_index=start_index,
        )
        self.scan_started_event.wait()

    def stop_scan(self):
        """
        Stop a scan prematurely. When called, the scanner will stop once the current
        frame finished scanning. This method returns only when the scan has actually
        been stopped.
        """
        logger.info("Stopping scan")
        self.scan_stopped_event.clear()
        self.scan_stop_requested = True
        self.scan_stopped_event.wait()

    def debug_scan(self, output_directory, n_frames=3900, start_index=0):
        """
        The same as `scan`, but exceptions are caught and printed to `stdout`.
        """
        try:
            self.scan(output_directory, n_frames, start_index)
        except Exception as e:
            print(
                f"AN ERROR HAS OCURRED: {e}"
            )  # TODO to logger (and web interface) instead of print

    def scan(self, output_directory, n_frames=3900, start_index=0):
        """
        Scan a film reel frame-by-frame.

        Parameters
        ----------
        output_directory : string
            Directory that frames will be saved to. If the given directory does not
            exist, it will be created automatically.
        n_frames : int
            Number of frames on the reel. Try to figure out how much frames are in the
            reel you wish to scan and then add some frames for safety. A 15m (50 foot)
            reel has about 3600 frames, so to be save it it recommned to scan 3800
            frames. Note that the actual number of frames scanned is
            `n_frames - start_index`.
        start_index: int, optional
            Frame index at which to start scanning if you are not scanning from the
            beginning. Reduces the number of frames scanning.
        """
        self.last_scan_end_info = "dismissed"
        self.scan_started_event.set()

        logger.info("Setting up scan")

        self.output_directory = output_directory
        self.n_frames = n_frames
        self.current_frame_index = 0

        self.turn_on_light()

        self.callback.on_scan_start()

        if self.is_liveview_active:
            self.stop_liveview()

        Path(output_directory).mkdir(parents=True, exist_ok=True)

        self.start_logging_to_output_directory()

        self.camera.resolution = (400, 300)

        time.sleep(5)

        for i in range(start_index, n_frames):
            self.current_frame_index = i

            filename = f"frame-{i:05d}.jpg"
            filepath = os.path.join(output_directory, filename)

            time.sleep(0.2)

            frame = self.capture_frame()
            self.wait_for_previous_save()
            self.submit_save_frame(frame, filepath)
            self.preview_frame = frame[: -self.raw_offset]  # Cut off the raw bayer data
            self.callback.on_frame_capture()

            self.advance()

            logger.info(f'Captured "{filepath}"')

            if self.scan_stop_requested:
                break

        logger.info(f"Finished scanning {i+1} frames")

        self.is_scanning = False
        self.last_scan_end_info = "success"
        self.current_frame_index = 0
        self.callback.on_scan_end()

        self.scan_stopped_event.set()

        self.stop_logging_to_output_directory()

        if self.viewers:
            self.start_liveview()
        else:
            self.turn_off_light()

        return i + 1

    def wait_for_previous_save(self):
        """
        If a frame is currently being saved, blocks until that save operation has
        finished.
        """
        # Wait for previous image to be saved if there was one
        if hasattr(self, "write_future"):
            _ = self.write_future.result()

    def submit_save_frame(self, frame, filepath):
        """
        Submit a frame for saving. Returns immediately while the frame is saved
        concurrently. Use `wait for previous save` to block until saving is finished.
        The arguments are the same as those of `save_frame`.
        """
        self.write_future = self.write_executor.submit(self.save_frame, frame, filepath)

    def advance(self, recover=True):
        """
        Advance film scanner by one frame.

        Parameters
        ----------
        recover : bool
            Set `true` to attempt to recevor the scanner when an error occurs during the
            advance.
        """
        self.is_advancing = True
        self.callback.on_advance_start()

        logger.debug("Advancing one frame")

        t_threshold = 0.487 * 1.025

        self.motor.enable()
        self.motor.start(speed=300, acceleration=24)
        time.sleep(
            t_threshold * 0.25
        )  # Move magnet out of range before arming Hall effect sensor
        was_frame_detected = self.frame_sensor.wait_for_trigger(
            timeout=t_threshold * 0.75
        )
        self.motor.stop(deceleration=24)
        self.motor.disable()

        if not was_frame_detected:
            logger.error("Frame sensor was not reached in time")
            fixed = False
            if recover:
                fixed = self.recover()
            if not fixed:
                raise AdvanceTimeoutError()

        self.is_advancing = False
        self.callback.on_advance_end()

    def recover(self):
        """
        Attempt to recover the frame advance after an error has occurred.
        """
        attempts = 0
        pause = 1
        while True:
            logger.warning(
                f"Attempting frame sensor recovery (attempt={attempts}, pause={pause})"
            )

            self.motor.direction = 1

            self.motor.enable()
            self.motor.start(speed=1, acceleration=1)
            self.frame_sensor.wait_for_trigger(timeout=1.0)
            self.motor.stop(deceleration=1)
            self.motor.disable()

            time.sleep(1)

            self.motor.direction = 0

            try:
                self.advance(recover=False)
            except AdvanceTimeoutError:
                if True:  # attempts < 5:
                    attempts += 1
                    time.sleep(pause)
                    pause *= 2
                else:
                    return False
            else:
                return True

    def start_fast_forward(self, n=None):
        """
        Start fast-forwarding. The arguments are the same as those of `fast_forward`.
        """
        self.fast_forward_stop_requested = False
        self.is_fast_forwarding = True
        self.fast_forward_started_event.clear()
        self.fast_forward_executor.submit(self.fast_forward, n=n)
        self.fast_forward_started_event.wait()

    def stop_fast_forward(self):
        """
        Stop a fast-forwarding. When called, the scanner will stop at the next frame.
        This method returns only when the fast-forwarding has actually been stopped.
        """
        self.fast_forward_stopped_event.clear()
        self.fast_forward_stop_requested = True
        self.fast_forward_stopped_event.wait()

    def fast_forward(self, n=None):
        """
        Fast-forward a given number of frames or until stopped.

        Parameters
        ----------
        n : int
            Number of frames to advance. If set to `None`, fast-forward until stopped.
        """
        self.is_fast_forwarding = True
        self.fast_forward_started_event.set()
        self.callback.on_fast_forward_start()

        if n is None:
            logger.debug("Fast-forwarding until stopped")
            while not self.fast_forward_stop_requested:
                self.advance()
            self.fast_forward_stop_requested = False
        else:
            logger.debug(f"Fast-forwarding {n} frames")
            for _ in range(n):
                self.advance()
                if self.scan_stop_requested:
                    logger.debug("Stopping fast-forwarding early")
                    self.scan_stop_requested = False
                    break

        self.is_fast_forwarding = False
        self.fast_forward_stopped_event.set()
        self.callback.on_fast_forward_end()

    def capture_frame(self):
        """
        Capture the current frame.

        Returns
        -------
        frame : bytes
            JPEG encoded image with raw bayer data appended.
        """
        self.camera.shutter_speed = int(1e6 * 1 / 250)

        buffer = BytesIO()
        self.camera.capture(buffer, format="jpeg", bayer=True)

        buffer.seek(0)
        frame = buffer.read()

        return frame

    def save_frame(self, frame, filepath):
        """
        Save a frame to a the given path.

        Parameters
        ----------
        frame : bytes
            Frame to save encoded as bytes.
        filepath : str
            Path to save the frame to.
        """
        with open(filepath, "wb") as f:
            f.write(frame)

        logger.debug(f"Saved {filepath}")

    @property
    def is_light_on(self):
        return self.light.is_on

    def turn_on_light(self):
        """
        Turn on the scanner's light.

        NOTE: Call this method instead of calling the light object directly in order to
        make sure that the callback is called.
        """
        self.light.turn_on()
        self.callback.on_light_on()

    def turn_off_light(self):
        """
        Turn off the scanner's light.

        NOTE: Call this method instead of calling the light object directly in order to
        make sure that the callback is called.
        """
        self.light.turn_off()
        self.callback.on_light_off()

    def toggle_light(self):
        """
        Toggle the scanner's light.

        NOTE: Call this method instead of calling the light directly in order to make
        sure that the callback is called.
        """
        if self.light.is_on:
            self.turn_off_light()
        else:
            self.turn_on_light()

    def start_logging_to_output_directory(self):
        """
        Start logging to `scan.log` file in the current output directory.

        Parameters
        ----------
        directory : str
            Directory to place the `scan.log` file in.
        """
        logpath = os.path.join(self.output_directory, "scan.log")

        self.scan_logging_handler = logging.FileHandler(logpath)
        self.scan_logging_handler.setLevel(logging.INFO)

        formatter = logging.Formatter("%(asctime)s - %(message)s")
        self.scan_logging_handler.setFormatter(formatter)

        logger.addHandler(self.scan_logging_handler)

    def stop_logging_to_output_directory(self):
        """
        Stop logging to `scan.log` file in the current output directory.
        """
        if hasattr(self, "scan_logging_handler"):
            logger.removeHandler(self.scan_logging_handler)

    @property
    def preview_frame(self):
        return self._preview_frame

    @preview_frame.setter
    def preview_frame(self, value):
        self._preview_frame = value

        self.prune_viewers()
        self.notify_viewers()

    def prune_viewers(self):
        """
        Remove viewers that did not retreive the frame for longer than a threshold time.
        """
        now = datetime.now()
        self.viewers = [
            viewer
            for viewer in self.viewers
            if now - viewer.last_access < timedelta(minutes=1)
        ]
        if (
            not self.viewers
            and self.is_liveview_active
            and not self.liveview_stop_requested
        ):
            # TODO This could cause a race condition if a new viewer is added here (?)
            self.stop_liveview(blocking=False)

    def notify_viewers(self):
        """
        Notify viewers that a new frame is available.
        """
        for viewer in self.viewers:
            viewer.notify()

    def start_liveview(self):
        """
        Start a liveview to fill the preview frames.
        """
        logger.debug("Liveview start requested")
        self.is_liveview_active = True
        self.liveview_stop_requested = False
        self.liveview_started_event.clear()
        self.liveview_executor.submit(self.liveview)
        self.liveview_started_event.wait()

    def stop_liveview(self, blocking=True):
        """
        Stop the liveview from writing the preview frames.

        Parameters
        ----------
        blocking : boolean, optional
            When set to `True`, block until liveview is actually stopped, otherwise
            return immediately.
        """
        logger.debug("Requesting liveview stop")
        self.liveview_stopped_event.clear()
        self.liveview_stop_requested = True
        if blocking:
            self.liveview_stopped_event.wait()

    def liveview(self):
        """
        Livewview function writing preview frames.
        """
        logger.info("Starting liveview")
        self.liveview_started_event.set()

        buffer = BytesIO()

        self.camera.resolution = (800, 600)
        self.turn_on_light()

        for _ in self.camera.capture_continuous(
            buffer, format="jpeg", use_video_port=True
        ):
            # TODO: Hack!
            self.camera.shutter_speed = int(1e6 * 1 / 100)

            if self.live_view_zoom_toggle_requested:
                if not self.is_zoomed:
                    self.is_zoomed = True
                    self.camera.zoom = (0.37, 0.37, 0.25, 0.25)
                    self.live_view_zoom_toggle_requested = False
                    self.zoom_toggled_event.set()
                    self.callback.on_zoom_in()
                else:
                    self.is_zoomed = False
                    self.camera.zoom = (0.0, 0.0, 1.0, 1.0)
                    self.live_view_zoom_toggle_requested = False
                    self.zoom_toggled_event.set()
                    self.callback.on_zoom_out()

            buffer.truncate()
            buffer.seek(0)
            frame = buffer.read()
            buffer.seek(0)

            self.preview_frame = frame

            if self.liveview_stop_requested:
                break

        if not self.is_scanning:
            self.turn_off_light()
        self.is_liveview_active = False
        self.liveview_stopped_event.set()

    def preview(self):
        """
        Add a preview viewer and get its view.

        Returns
        -------
        view : generator
            Generator that yields preview frames when they become available.
        """
        # Activate liveview when not yet active (and not currently scanning)
        if not self.is_liveview_active and not self.is_scanning:
            self.start_liveview()

        viewer = Viewer(self)
        self.viewers.append(viewer)

        return viewer.view()

    def toggle_zoom(self):
        self.zoom_toggled_event.clear()
        self.live_view_zoom_toggle_requested = True
        self.zoom_toggled_event.wait()

    def poweroff(self):
        """
        Turn the sanner off.
        """
        if self.is_scanning:
            self.stop_scan()
        if self.is_liveview_active:
            self.stop_liveview()

        logger.info("Powering off")
        os.system("sudo poweroff")

    @property
    def last_scan_end_info(self):
        return self._last_scan_end_info

    @last_scan_end_info.setter
    def last_scan_end_info(self, value):
        self._last_scan_end_info = value
        self.callback.on_last_scan_end_info_change()

    @property
    def is_advance_allowed(self):
        return not (self.is_advancing or self.is_fast_forwarding or self.is_scanning)

    @property
    def is_fast_forward_allowed(self):
        return not (self.is_advancing or self.is_fast_forwarding or self.is_scanning)

    @property
    def is_light_toggle_allowed(self):
        return not self.is_scanning

    @property
    def is_zoom_toggle_allowed(self):
        return not self.is_scanning

    @property
    def is_scanning_allowed(self):
        return not (self.is_advancing or self.is_fast_forwarding or self.is_scanning)

class AdvanceTimeoutError(Exception):
    """
    Raised when the the frame sensor was not reached within some threshold time. This
    may have one of two possible causes: (A) The magnet passed the Hall effect sensor
    undetected. (B) The motor skipped steps, for example because it got stuck.
    """

    def __init__(self):
        super().__init__(
            "Frame sensor not reached in time. It was either missed, or the motor got"
            " stuck."
        )

class HallEffectSensor:
    """
    Hall effect sensor interfaced via `pigpio`.

    Parameters
    ----------
    input_pin : int
        Broadcom number of the GPIO header pin receiving a digital signal from the
        sensor.

    Attributes
    ---------
    is_armed : bool
        Flag set to true when the sensor is armed, i.e. setup to call a callback
        function whenever the Hall effect is detected.
    """

    def __init__(self, input_pin):
        self.input_pin = input_pin

        self.pi = pigpio.pi()
        self.pi.set_mode(self.input_pin, pigpio.INPUT)

        self.is_armed = False

    def wait_for_trigger(self, timeout=None):
        frame_detected_event = Event()
        frame_detected_event.clear()

        self.arm(user_callback=frame_detected_event.set)

        has_detected = frame_detected_event.wait(timeout=timeout)
        if self.is_armed:
            self.disarm()

        return has_detected

    def arm(self, user_callback):
        """
        Setup the sensor to run a callback function whenever the Hall effect is
        detected.

        Parameters
        ----------
        callback : function
            Callback function that is called everytime the sensor detects the Hall
            effect. The function should receive no parameters nor return anything.
        """
        assert not self.is_armed, "Cannot arm armed Hall Effect sensor!"
        self.is_armed = True
        self.callback = partial(self.sensor_callback, user_callback)
        self.pigpio_callback = self.pi.callback(
            self.input_pin, pigpio.RISING_EDGE, self.detect
        )

    def sensor_callback(self, user_callback):
        self.disarm()
        user_callback()

    def disarm(self):
        """
        Stop calling the callback function when the Hall effect is detected.
        """
        assert self.is_armed, "Can only disarm armed Hall Effect sensor!"
        self.pigpio_callback.cancel()
        self.is_armed = False

    def detect(self, pin, level, tick):
        """
        Internal callback for `pgpio` which calls the sensor's callback function.
        """
        logger.debug("Hall effect sensor detected")
        self.callback()

class Light:
    """
    Light controlled via `pigpio`.

    Parameters
    ----------
    switch_pin : int
        Broadcom number of the GPIO header pin used to turn the light on and off.

    Attributes
    ---------
    is_on : bool
        Flag representing the light's state, `True` when the light is on and `False`
        when it is off.
    """

    def __init__(self, switch_pin):
        self.switch_pin = switch_pin

        self.pi = pigpio.pi()
        self.pi.set_mode(self.switch_pin, pigpio.OUTPUT)

        self.turn_off()

    def turn_on(self):
        """
        Turn the light on.
        """
        self.pi.write(self.switch_pin, 0)
        self.is_on = True

    def turn_off(self):
        """
        Turn the light off.
        """
        self.pi.write(self.switch_pin, 1)
        self.is_on = False

    def toggle(self):
        """
        Toggle the light between on and off.
        """
        if self.is_on:
            self.turn_off()
        else:
            self.turn_on()

class StepperMotor:
    """
    Stepper motor controlled via `pigpio`.

    Parameters
    ----------
    enable_pin : int
        Broadcom number of the GPIO header pin connected to the stepper driver's `SLEEP`
        input.
    direction_pin : int
        Broadcom number of the GPIO header pin connected to the stepper driver's `DIR`
        input.
    step_pin : int
        Broadcom number of the GPIO header pin connected to the stepper driver's `STEP`
        input.

    Attributes
    ---------
    is_enabled : bool
        Enable status of the motor. The motor must be enabled to provide a holding force
        or be able to run.
    speed : int
        Current speed of the motor in RPM.
    """

    STEPS_PER_ROUND = 200
    PWM_FREQUENCIES = [320, 500, 800, 1000, 1600, 2000]

    def __init__(self, enable_pin, direction_pin, step_pin):
        self.enable_pin = enable_pin
        self.direction_pin = direction_pin
        self.step_pin = step_pin

        self.pi = pigpio.pi()
        self.pi.set_mode(self.enable_pin, pigpio.OUTPUT)
        self.pi.set_mode(self.direction_pin, pigpio.OUTPUT)
        self.pi.set_mode(self.step_pin, pigpio.OUTPUT)

        self.disable()
        self.direction = 0  # Set direction counter-clockwise
        self.speed = 0

    def __del__(self):
        self.pi.wave_clear()

    def enable(self):
        """
        Enable the stepper motor (and its holding force as well as ability to step).
        """
        self.pi.write(self.enable_pin, 0)
        self.is_enabled = True

    def disable(self):
        """
        Disable the stepper motor (and its holding force as well as ability to step).
        """
        self.pi.write(self.enable_pin, 1)
        self.is_enabled = False

    @property
    def direction(self):
        return self._direction

    @direction.setter
    def direction(self, value):
        self._direction = value
        self.pi.write(self.direction_pin, value)

    def start(self, speed=300, acceleration=24):
        """
        Start running the stepper motor.

        Parameters
        ----------
        speed : int, optional
            Desired target speed to run at in RPM. The achieved motor speed may be
            slightly slower.
        acceleration : int, optional
            Acceleration with which to approach the target speed in
            `rounds / (minute * second)`.
        """

        assert self.is_enabled, "Cannot start a disabled stepper motor!"

        pwm_frequency = self.rpm2hz(speed)
        pwm_acceleration = self.rpm2hz(acceleration)

        self.speed = speed

        ramp = self.make_ramp(pwm_frequency, pwm_acceleration, stay=10000)
        self.send_ramp(ramp)

    def stop(self, deceleration=24):
        """
        Stop the stepper motor.

        Parameters
        ----------
        deceleration : int, optional
            Deceleration with which to stop the motor in `rounds / (minute * second)`.
        """
        pwm_frequency = self.rpm2hz(self.speed)
        pwm_deceleration = self.rpm2hz(deceleration)

        self.speed = 0

        ramp = self.make_ramp(pwm_frequency, -pwm_deceleration)
        self.send_ramp(ramp)

    def rpm2hz(self, rpm):
        """
        Convert RPM to PWM frequency in Hz for this particular stepper motor.
        """
        return self.STEPS_PER_ROUND * rpm / 60

    def make_ramp(self, target_frequency, acceleration, stay=0):
        """
        Make list of `(frequency, step)` pairs to ramp up the motor and stay at the
        target speed for `stay` steps.
        """
        frequencies = [f for f in self.PWM_FREQUENCIES if f <= target_frequency]
        if not frequencies:
            frequencies = [self.PWM_FREQUENCIES[0]]

        ramp = [(speed, int(speed / abs(acceleration))) for speed in frequencies[:-1]]
        if stay > 0:
            ramp.append((frequencies[-1], stay))

        return ramp if acceleration > 0 else list(reversed(ramp))

    def send_ramp(self, ramp):
        """
        Send wave chain that describes list of `(frequency, step)` pairs to step pin.
        """
        self.pi.wave_clear()
        length = len(ramp)
        wid = [-1] * length

        # Generate a wave ramp per ramp level
        for i in range(length):
            frequency = ramp[i][0]
            micros = int(5e5 / frequency)
            wf = []
            wf.append(pigpio.pulse(1 << self.step_pin, 0, micros))  # Pulse on
            wf.append(pigpio.pulse(0, 1 << self.step_pin, micros))  # Pulse off
            self.pi.wave_add_generic(wf)
            wid[i] = self.pi.wave_create()

        # Generate chain of waves
        chain = []
        for i in range(length):
            steps = ramp[i][1]
            x = steps & 255
            y = steps >> 8
            chain += [255, 0, wid[i], 255, 1, x, y]

        self.pi.wave_chain(chain)  # Transmit chain of wave forms