import functools
import itertools

from absl.testing import parameterized
import numpy as np

from tensorflow.compiler.tests import xla_test
from tensorflow.python.framework import dtypes
from tensorflow.python.framework import errors_impl
from tensorflow.python.framework import test_util
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import math_ops
from tensorflow.python.platform import googletest

@parameterized.named_parameters(('32_bit_index', dtypes.int32),
                                ('64_bit_index', dtypes.int64))
class ReduceOpsTest(xla_test.XLATestCase, parameterized.TestCase):
  def _testReduction(self,
                     tf_reduce_fn,
                     np_reduce_fn,
                     dtype,
                     test_inputs,
                     index_dtype,
                     rtol=1e-4,
                     atol=1e-4):
    """Tests that the output of 'tf_reduce_fn' matches numpy's output."""

    for test_input in test_inputs:
      with self.session() as sess:
        with self.test_scope():
          a = array_ops.placeholder(dtype)
          index = array_ops.placeholder(index_dtype)
          out = tf_reduce_fn(a, index)
        result = sess.run(out, {a: test_input, index: [0]})
        self.assertAllClose(
            result, np_reduce_fn(test_input, axis=0), rtol=rtol, atol=atol)

        result = sess.run(out, {a: test_input, index: [1]})
        self.assertAllClose(
            result, np_reduce_fn(test_input, axis=1), rtol=rtol, atol=atol)

        result = sess.run(out, {a: test_input, index: [-1]})
        self.assertAllClose(
            result, np_reduce_fn(test_input, axis=1), rtol=rtol, atol=atol)

        # MLIR bridge doesn't return the same error so it can't be matched
        # directly.
        if not test_util.is_mlir_bridge_enabled():
          with self.assertRaisesWithPredicateMatch(
              errors_impl.InvalidArgumentError, 'Invalid reduction dim'):
            sess.run(out, {a: test_input, index: [-33]})

          with self.assertRaisesWithPredicateMatch(
              errors_impl.InvalidArgumentError, 'Invalid reduction dim'):
            sess.run(out, {a: test_input, index: [2]})

  REAL_DATA = [
      np.zeros(shape=(2, 0)),
      np.zeros(shape=(0, 30)),
      np.arange(1, 7).reshape(2, 3),
      np.arange(-10, -4).reshape(2, 3),
      np.arange(-4, 2).reshape(2, 3),
  ]
  COMPLEX_DATA = [
      np.zeros(shape=(2, 0)).astype(np.complex64),
      np.zeros(shape=(0, 30)).astype(np.complex64),
      np.arange(1, 13, dtype=np.float32).view(np.complex64).reshape(2, 3),
      np.arange(-14, -2, dtype=np.float32).view(np.complex64).reshape(2, 3),
      np.arange(-4, 8, dtype=np.float32).view(np.complex64).reshape(2, 3),
  ]
  NONEMPTY_REAL_DATA = [x for x in REAL_DATA if np.size(x) > 0]
  NONEMPTY_COMPLEX_DATA = [x for x in COMPLEX_DATA if np.size(x) > 0]
  BOOL_DATA = [
      np.array([], dtype=np.bool_).reshape(2, 0),
      np.array([], dtype=np.bool_).reshape(0, 3),
      np.array([[False, True, False], [True, True, False]]),
  ]
  ONES = [np.ones([34000, 2])]

  def testReduceSumF32(self, index_dtype):
    self._testReduction(math_ops.reduce_sum, np.sum, np.float32, self.REAL_DATA,
                        index_dtype)

  def testReduceSumC64(self, index_dtype):
    self._testReduction(math_ops.reduce_sum, np.sum, np.complex64,
                        self.COMPLEX_DATA, index_dtype)

  def testReduceProdF32(self, index_dtype):
    self._testReduction(math_ops.reduce_prod, np.prod, np.float32,
                        self.REAL_DATA, index_dtype)

  def testReduceProdC64(self, index_dtype):
    self._testReduction(math_ops.reduce_prod, np.prod, np.complex64,
                        self.COMPLEX_DATA, index_dtype)

  def testReduceMin(self, index_dtype):

    def reference_min(dtype, inp, axis):
      """Wrapper around np.amin that returns +infinity for an empty input."""
      if inp.shape[axis] == 0:
        if np.issubdtype(dtype, np.floating):
          return np.full(inp.shape[0:axis] + inp.shape[axis + 1:], float('inf'))
        return np.full(inp.shape[0:axis] + inp.shape[axis + 1:],
                       np.iinfo(dtype).max)
      return np.amin(inp, axis)

    for dtype in set(self.all_types).intersection(
        [np.float32, np.int32, np.int64]):
      self._testReduction(math_ops.reduce_min,
                          functools.partial(reference_min, dtype), dtype,
                          self.REAL_DATA, index_dtype)

  def testReduceMax(self, index_dtype):

    def reference_max(dtype, inp, axis):
      """Wrapper around np.amax that returns -infinity for an empty input."""
      if inp.shape[axis] == 0:
        if np.issubdtype(dtype, np.floating):
          return np.full(inp.shape[0:axis] + inp.shape[axis + 1:],
                         float('-inf'))
        return np.full(inp.shape[0:axis] + inp.shape[axis + 1:],
                       np.iinfo(dtype).min)
      return np.amax(inp, axis)

    for dtype in set(self.all_types).intersection(
        [np.float32, np.int32, np.int64]):
      self._testReduction(math_ops.reduce_max,
                          functools.partial(reference_max, dtype), dtype,
                          self.REAL_DATA, index_dtype)

  def testReduceMeanF32(self, index_dtype):
    # TODO(phawkins): mean on XLA currently returns 0 instead of NaN when
    # reducing across zero inputs.
    self._testReduction(math_ops.reduce_mean, np.mean, np.float32,
                        self.NONEMPTY_REAL_DATA, index_dtype)

  def testReduceMeanF16(self, index_dtype):
    if np.float16 in self.all_types:
      self._testReduction(math_ops.reduce_mean, np.mean, np.float16, self.ONES,
                          index_dtype)

  def testReduceMeanC64(self, index_dtype):
    self._testReduction(math_ops.reduce_mean, np.mean, np.complex64,
                        self.NONEMPTY_COMPLEX_DATA, index_dtype)

  def testReduceAll(self, index_dtype):
    self._testReduction(math_ops.reduce_all, np.all, np.bool_, self.BOOL_DATA,
                        index_dtype)

  def testReduceAny(self, index_dtype):
    self._testReduction(math_ops.reduce_any, np.any, np.bool_, self.BOOL_DATA,
                        index_dtype)

  @test_util.disable_mlir_bridge('Error messages differ')
  def testReduceSumWithDuplicateAxes(self, index_dtype):
    with self.session() as sess:
      with self.test_scope():
        a = array_ops.placeholder(np.float32)
        index = array_ops.placeholder(np.int32)
        out = math_ops.reduce_sum(a, index)
      with self.assertRaisesWithPredicateMatch(
          errors_impl.InvalidArgumentError,
          'Axes contains duplicate dimension'):
        sess.run(out, {a: [10, 20, 30], index: [0, 0]})

class ReduceOpPrecisionTest(xla_test.XLATestCase):

  def _testReduceSum(self,
                     expected_result,
                     dtype,
                     test_inputs,
                     rtol=1e-3,
                     atol=1e-4):
    """Tests reduce sum on a list of input arrays.

    For each array in test_inputs, check that performing reduce sum on the array
    produces a value that is close to the expected result.

    Args:
      expected_result: the expected result.
      dtype: the data type of the reduce sum operation.
      test_inputs: a list of input arrays for the reduce sum operation.
      rtol: the relative error.
      atol: the absolute error.
    """

    for test_input in test_inputs:
      with self.session() as sess:
        with self.test_scope():
          a = array_ops.placeholder(dtype)
          index = array_ops.placeholder(dtypes.int32)
          out = math_ops.reduce_sum(a, index)
        result = sess.run(out, {
            a: np.array(test_input, dtype=dtype),
            index: [0]
        })
        # Compare the results using float32 type.
        self.assertAllClose(
            np.float32(result),
            np.float32(expected_result),
            rtol=rtol,
            atol=atol)

  def testReduceSumF16(self):
    """Tests the reduce sum of float16 doesn't lose too much precision."""

    if np.float16 not in self.all_types:
      return

    f16_max = np.finfo(np.float16).max
    self._testReduceSum(
        f16_max, np.float16,
        itertools.permutations([f16_max, f16_max, f16_max * (-1.0)], 3))

  def testReduceSumBF16(self):
    """Tests the reduce sum of bfloat16 doesn't lose too much precision."""

    if dtypes.bfloat16.as_numpy_dtype not in self.all_types:
      return

    bf16_max = np.float32(dtypes.bfloat16.max)
    f32_max = dtypes.float32.max
    value = min(bf16_max, f32_max - bf16_max) / 2
    self._testReduceSum(
        dtypes.bfloat16.as_numpy_dtype(value), dtypes.bfloat16.as_numpy_dtype,
        itertools.permutations([bf16_max, value, bf16_max * (-1.0)], 3))

if __name__ == '__main__':
  googletest.main()


class Group:
    def __init__(self, group_id, files, parser, metadata=None):

        self.group_id = group_id

        assert(type(files) is list)
        self.files = files

        # NOTE that parser can be None as it will be indexed as such later on.
        assert type(parser) is str or parser is None, f"Parser is of improper type: {type(parser)}"
        self.parser = parser

        assert type(metadata) is dict or metadata is None, "Group metadata is not of type 'dict' or None"
        if metadata is None:
            self.metadata = {}
        else:
            self.metadata = metadata

    def update_metadata(self, metadata):
        self.metadata = metadata


import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
from torch.autograd import Variable
import matplotlib.pyplot as plt
import torch.nn.functional as F
import re
def build_corpus(raw_corpus):
    corpus = []
    for sentence in raw_corpus:
        pattern = re.compile(r'[A-Za-z]+[\w^\']*|[\w^\']*[A-Za-z]+[\w^\']*')
        corpus.append(pattern.findall(sentence.lower()))
    return corpus

raw_corpus = ['i dance',
          'she cook for me',
          'he sing with my mon at home']

corpus = build_corpus(raw_corpus)

vocab = []
for sentence in corpus:
    for word in sentence:
        if word not in vocab and word:
            vocab.append(word.lower())
vocab.sort()

# print(vocab)
# print(word2idx)

END_SENT = "E"
START_SENT = "S"
PARSING = "P"

max_len = 0
for sentence in corpus:
    if len(sentence) > max_len:
        max_len = len(sentence)
# print(max_len)

def passing_word(corpus, max_len, START_SENT='S', END_SENT='E', PARSING='P'):
    for i in range(len(corpus)):
        len_sent = len(corpus[i])
        num_parsing = max_len - len_sent
        corpus[i].insert(0, START_SENT)
        for j in range(num_parsing):
            corpus[i].extend(PARSING)
        corpus[i].insert(len(corpus[i]), END_SENT)
    return corpus

corpus = passing_word(corpus, max_len)
# print(corpus)
max_len = max_len + 2
vocab.insert(0, END_SENT)
vocab.insert(0, START_SENT)
vocab.insert(0, PARSING)
word2idx = {word: i for i, word in enumerate(vocab)}
# print(vocab)
# print(word2idx)

def convert_to_idx(sentence, word2idx):
    sentence_idx = []
    for word in sentence:
        sentence_idx.append(word2idx[word])
    return sentence_idx
corpus_idx = []
for sentence in corpus:
    corpus_idx.append(convert_to_idx(sentence, word2idx))
# print(corpus)
# print(corpus_idx)
def outputs_shifted_right(sentence_idx):
    len_sentence = len(sentence_idx)
    outputs = np.zeros((len_sentence, max_len))
    for i in range(len_sentence):
        for j in range(len_sentence):
            if j <= i:
                outputs[i][j] = sentence_idx[j]
    outputs.tolist()
    return torch.LongTensor(outputs)

# print(outputs_shifted_right(corpus_idx[1]))

# build model
vocab_size = len(vocab)
src_len = 5
tgt_len = 5

d_model = 512  # Embedding Size
d_ff = 2048  # FeedForward dimension
d_k = d_v = 64  # dimension of K(=Q), V
n_layers = 6  # number of Encoder of Decoder Layer
n_heads = 8  # number of heads in Multi-Head Attention

def poition_encoder(n_position, d_model):
    def compute_angle(pos, i):
        return pos / np.power(10000, 2*i/d_model)
    sinusoid_table = np.zeros((n_position, d_model))
    for pos in range(n_position):
        for i in range(d_model):
            if i % 2 == 0:
                sinusoid_table[pos][i] = np.sin(compute_angle(pos, i))
            else:
                sinusoid_table[pos][i] = np.cos(compute_angle(pos, i))
    return torch.FloatTensor(sinusoid_table)

class ScaledDotProductAttention(nn.Module):
    def __init__(self):
        super(ScaledDotProductAttention, self).__init__()
    def forward(self, Q, K, V):
        scores = torch.matmul(Q, K.t()) / np.sqrt(d_k)
        attn = nn.Softmax(dim=-1)(scores)
        context = torch.matmul(attn, V)
        return context

class MultilHeadAttention(nn.Module):
    def __init__(self):
        super(MultilHeadAttention, self).__init__()
        self.W_Q = nn.Linear(d_model, d_k*n_heads)
        self.W_K = nn.Linear(d_model, d_k*n_heads)
        self.W_V = nn.Linear(d_model, d_v*n_heads)
    def forward(self, Q, K, V):
        residual, batch_size = Q, Q.size(0)
        Q_scores = self.W_Q(Q)
        K_scores = self.W_K(K)
        V_scores = self.W_V(V)
        Qs = Q_scores.view(batch_size, n_heads, d_k)
        Ks = K_scores.view(batch_size, n_heads, d_k)
        Vs = V_scores.view(batch_size, n_heads, d_v)
        contexts = []
        for i in range(n_heads):
            context= ScaledDotProductAttention()(Qs[:, i, :], Ks[:, i, :], Vs[:, i, :])
            contexts.append(context)
        context = torch.cat(contexts, dim=1)
        output = nn.Linear(n_heads*d_v, d_model)(context)
        return nn.LayerNorm(d_model)(output + residual)    # add & norm

class FeedForwardNet(nn.Module):
    def __init__(self, d_model, d_ff, dropout=0.1):
        super(FeedForwardNet, self).__init__()
        self.w_1 = nn.Linear(d_model, d_ff)
        self.w_2 = nn.Linear(d_ff, d_model)
        self.dropout = nn.Dropout(dropout)

    def forward(self, inputs):
        residual = inputs
        output = nn.ReLU()(self.w_1(inputs))
        output = self.w_2(output)
        return nn.LayerNorm(d_model)(output + residual)

class EncoderLayer(nn.Module):
    def __init__(self):
        super(EncoderLayer, self).__init__()
        self.enc_self_attn = MultilHeadAttention()
        self.enc_ff = FeedForwardNet(d_model, d_ff)
    def forward(self, enc_inputs):
        enc_outputs = self.enc_self_attn(enc_inputs, enc_inputs, enc_inputs)
        enc_outputs = self.enc_ff(enc_outputs)
        return enc_outputs

class DecoderLayer(nn.Module):
    def __init__(self):
        super(DecoderLayer, self).__init__()
        self.dec_self_attn = MultilHeadAttention()
        self.dec_enc_attn = MultilHeadAttention()
        self.dec_ff = FeedForwardNet(d_model, d_ff)
    def forward(self, dec_inputs, enc_outputs):
        dec_outputs = self.dec_self_attn(dec_inputs, dec_inputs, dec_inputs)
        dec_outputs = self.dec_enc_attn(enc_outputs, enc_outputs, dec_outputs)
        dec_outputs = self.dec_ff(dec_outputs)
        return dec_outputs

class Encoder(nn.Module):
    def __init__(self):
        super(Encoder, self).__init__()
        self.emb = nn.Embedding(vocab_size, d_model)
        self.pos_emb = nn.Embedding.from_pretrained(poition_encoder(max_len, d_model), freeze=True)
        self.layers = nn.ModuleList([EncoderLayer() for _ in range(n_layers)])
    def forward(self, enc_inputs):
        enc_outputs = self.emb(enc_inputs)
        for layer in self.layers:
            enc_outputs = layer(enc_outputs)
        return enc_outputs

class Decoder(nn.Module):
    def __init__(self):
        super(Decoder, self).__init__()
        self.emb = nn.Embedding(vocab_size, d_model)
        self.pos_emb = nn.Embedding.from_pretrained(poition_encoder(max_len, d_model), freeze=True)
        self.layers = nn.ModuleList([DecoderLayer() for _ in range(n_layers)])

    def forward(self, dec_inputs, enc_outputs):
        dec_outputs = self.emb(dec_inputs)
        for layer in self.layers:
            dec_outputs = layer(dec_outputs, enc_outputs)
        return dec_outputs

class Transformer(nn.Module):
    def __init__(self):
        super(Transformer, self).__init__()
        self.encoder = Encoder()
        self.decoder = Decoder()
        self.projection = nn.Linear(d_model, vocab_size, bias=False)

    def forward(self, enc_inputs, dec_inputs):
        enc_outputs = self.encoder(enc_inputs)
        dec_outputs = self.decoder(dec_inputs, enc_outputs)
        dec_logits = self.projection(dec_outputs)
        return F.log_softmax(dec_logits.view(-1, dec_logits.size(-1)), dim=-1)

model = Transformer()
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

def showgraph(attn):
    attn = attn[-1].squeeze(0)[0]
    attn = attn.squeeze(0).data.numpy()
    fig = plt.figure(figsize=(n_heads, n_heads)) # [n_heads, n_heads]
    ax = fig.add_subplot(1, 1, 1)
    ax.matshow(attn, cmap='viridis')
    ax.set_xticklabels(['']+raw_corpus[0].split(), fontdict={'fontsize': 14}, rotation=90)
    ax.set_yticklabels(['']+raw_corpus[2].split(), fontdict={'fontsize': 14})
    plt.show()

n_epochs = 100

for epoch in range(n_epochs):
    optimizer.zero_grad()
    total_loss = 0
    for sentence in corpus_idx:
        enc_inputs = Variable(torch.LongTensor(sentence))
        outputs_sr = outputs_shifted_right(sentence)
        for i in range(len(sentence)-1):
            dec_inputs, target = outputs_sr[i], outputs_sr[i+1]
            dec_inputs = Variable(dec_inputs)
            outputs = model(enc_inputs, dec_inputs)
            loss = criterion(outputs, target.contiguous().view(-1))

            total_loss += loss
            loss.backward()
            optimizer.step()
    # print('Epoch:', '%04d' % (epoch + 1), 'cost =', '{:.6f}'.format(total_loss))

torch.save(model.state_dict(), 'models/transformer_v1.pkl')


import click
import mlflow
import mlflow.sklearn
import pandas as pd

@click.command("evaluate")
@click.option("--data-path", required=True)
@click.option("--target-path", required=True)
@click.option("--run-id", required=True)
def evaluate(data_path: str, target_path: str, run_id: str):
    data = pd.read_csv(data_path, index_col=0)
    target = pd.read_csv(target_path, index_col=0, squeeze=True)

    pipeline = mlflow.sklearn.load_model(f"runs:/{run_id}/pipeline")
    classifier = mlflow.sklearn.load_model(f"runs:/{run_id}/classifier")

    prepared_data = pipeline.transform(data)

    with mlflow.start_run(run_id=run_id):
        mlflow.sklearn.eval_and_log_metrics(classifier, prepared_data, target, prefix="val_")

if __name__ == '__main__':
    evaluate()


from datetime import date
from typing import List

from implementation.market_app.models.api_models import ApartmentOfferAveragePrice, CompanyStatisticResult, \
    SaleOfferStatusUpdate
from implementation.market_app.models.postgres_models import Offer
from implementation.market_app.repositories.repository_dependencies import get_postgres_db

class PostgresOfferRepository:

    def __init__(self):
        self.connection = get_postgres_db()

    def create_table(self):
        cursor = self.connection.cursor()
        create_table_query = """
                CREATE TABLE IF NOT EXISTS offer (
                    id SERIAL PRIMARY KEY,
                    price DECIMAL(8,2) NOT NULL,
                    status VARCHAR(8) NOT NULL,
                    negotiable BOOLEAN NOT NULL,
                    description VARCHAR(300),
                    agency_fee DECIMAL(8,2),
                    creation_date DATE NOT NULL,
                    modification_date DATE,
                    apartment_id INTEGER REFERENCES apartment(id) ON DELETE CASCADE
                );
            """
        cursor.execute(create_table_query)
        self.connection.commit()

    def insert(self, sale_offer: Offer) -> Offer:
        with self.connection.cursor() as cur:
            cur.execute(
                "INSERT INTO offer (price, status, negotiable, description, agency_fee, creation_date,modification_date,apartment_id) VALUES (%s, %s, %s, "
                "%s, %s,%s,%s,%s) RETURNING id",
                (sale_offer.price, sale_offer.status, sale_offer.negotiable, sale_offer.description,sale_offer.agency_fee, sale_offer.creation_date,sale_offer.modification_date,sale_offer.apartment_id),
            )
            new_id = cur.fetchone()[0]
        self.connection.commit()
        return new_id

    def get_offers_by_city_and_address(self, city: str, street: str) -> List[Offer]:
        with self.connection.cursor() as cursor:
            cursor.execute(
                """
                SELECT * from offer where apartment_id in (SELECT apartment_id from apartment where address_id in
                (SELECT address_id from address where city = %s and street_name = %s));
                """, (city, street))
            offers = cursor.fetchall()
        return [
            Offer(offer[0], offer[1], offer[2], offer[3], offer[4],
                  offer[5], offer[6], offer[7], offer[8]) for offer
            in offers]

    def get_offers_by_city_and_price_range(self, city: str, min_price: float, max_price: float) -> List[Offer]:
        with self.connection.cursor() as cursor:
            cursor.execute(
                """
                SELECT * FROM offer as so
                JOIN apartment as ap on so.apartment_id = ap.id
                JOIN address as ad on ap.address_id = ad.id
                WHERE ad.city = %s and so.price BETWEEN %s and %s
                """, (city, min_price, max_price))
            offers = cursor.fetchall()
        return [
            Offer(offer[0], offer[1], offer[2], offer[3], offer[4],
                  offer[5], offer[6], offer[7], offer[9]) for offer
            in offers]

    def get_offers_by_company_name(self, company_name: str) -> List[Offer]:
        with self.connection.cursor() as cursor:
            cursor.execute(
                """
                SELECT * FROM offer as so
                JOIN apartment as ap on so.apartment_id = ap.id
                JOIN owner as ow on ap.owner_id = ow.id
                WHERE ow.company_name = %s
                """, (company_name,))
            offers = cursor.fetchall()
        return [
            Offer(offer[0], offer[1], offer[2], offer[3], offer[4],
                  offer[5], offer[6], offer[7], offer[8]) for offer
            in offers]

    ## chyba nie ma sensu?
    # def get_offers_by_city_and_price_and_id(self, city: str, price: float, id: int) -> List[
    #     SaleOffer]:
    #     with self.connection.cursor() as cursor:
    #         cursor.execute(
    #             """
    #             SELECT * FROM sale_offer as so
    #             JOIN apartment as ap on so.apartment_id = ap.id
    #             JOIN address as ad on ap.address_id = ad.id
    #             WHERE ad.city = %s and so.price = %s and so.id = %s
    #             """, (city, price, id))
    #         offers = cursor.fetchall()
    #         offers_list = []
    #     for offer in offers:
    #         sale_offer = SaleOffer(offer_id=offer['offer_id'],
    #                                price=offer['price'],
    #                                status=offer['status'],
    #                                negotiable=offer['negotiable'],
    #                                description=offer['description'],
    #                                agency_fee=offer['agency_fee'],
    #                                creation_date=offer['creation_date'],
    #                                modification_date=offer['modification_date'],
    #                                apartment_id=offer['apartment_id']
    #                                )
    #         offers_list.append(sale_offer)
    #         return offers_list

    def update_sale_offer_status(self, offer_id: int, update_info: SaleOfferStatusUpdate) -> Offer:
        with self.connection.cursor() as cursor:
            cursor.execute("""
                UPDATE offer
                SET status = %s
                WHERE id = %s
                RETURNING *
            """, (update_info.status, offer_id))
            self.connection.commit()
            updated_offer = cursor.fetchone()
        return Offer(*updated_offer)

    def get_average_price_by_city(self, city: str) -> List[ApartmentOfferAveragePrice]:
        with self.connection.cursor() as cursor:
            cursor.execute("""
                SELECT ad.city, AVG(so.price) as avg_price, AVG(so.price/ap.area) as avg_price_per_m2
                FROM offer as so
                JOIN apartment as ap on so.apartment_id = ap.id
                JOIN address as ad on ap.address_id = ad.id
                WHERE ad.city = %s
                GROUP BY ad.city
            """, (city,))
            result = cursor.fetchall()
        return [ApartmentOfferAveragePrice(city=row[0], avg_price=row[1], avg_price_per_m2=row[2]) for row in result]

    def get_companies_sales_statistics(self, company_name: str) -> List[CompanyStatisticResult]:
        with self.connection.cursor() as cursor:
            cursor.execute("""
                SELECT
                    ow.company_name as company_name,
                    COUNT(so.id) as total_sales,
                    SUM(so.price) as total_sales_price,
                    AVG(so.price) as average_sales_price
                FROM offer as so
                JOIN apartment as ap on so.apartment_id = ap.id
                JOIN owner as ow on ap.owner_id = ow.id
                WHERE ow.company_name = %s
                GROUP BY ow.company_name
            """, (company_name,))
            result = cursor.fetchall()
        return [CompanyStatisticResult(company_name=row[0], total_sales=row[1], total_sales_price=row[2],
                                       average_sales_price=row[3]) for row in result]

    def get_statistic_by_company(self, company_filter: str) -> List[CompanyStatisticResult]:
        with self.connection.cursor() as cursor:
            cursor.execute(
                """
                SELECT company_name,
                       AVG(price) as avg_price,
                       AVG(price/area) as avg_price_per_m2,
                       COUNT(*) as sales_offer_count
                FROM market_app.offers_by_company_name
                WHERE company_name = %s
                GROUP BY company_name
                """, (company_filter,))
            results = cursor.fetchall()
        return [CompanyStatisticResult(company_name=row[0],
                                       avg_price=row[1],
                                       avg_price_per_m2=row[2],
                                       sales_offer_count=row[3])
                for row in results]

    def delete(self, id: int) -> None:
        with self.connection.cursor() as cursor:
            cursor.execute("DELETE FROM offer WHERE id = %s", (id,))
            self.connection.commit()

    def update(self, id: int, price: float, status: str, negotiable: bool, description: str, agency_fee: float,
               creation_date: date, modification_date: date, apartment_id: int) -> Offer:
        with self.connection.cursor() as cursor:
            cursor.execute("""
                UPDATE offer
                SET price = %s, status = %s, negotiable = %s, description = %s, agency_fee = %s,
                creation_date = %s, modification_date = %s,
                apartment_id = %s
                WHERE id = %s
                """, (
                price, status, negotiable, description, agency_fee, creation_date, modification_date, apartment_id, id))
            self.connection.commit()

        updated_offer = self.get_by_id(id)
        return updated_offer

    def get_by_id(self, sale_offer_id: int) -> Offer | None:
        with self.connection.cursor() as cursor:
            cursor.execute("SELECT * FROM offer WHERE id = %s", (sale_offer_id,))
            result = cursor.fetchone()
        if result:
            return Offer(*result)
        else:
            return None

    def get_all(self) -> List[Offer]:
        with self.connection.cursor() as cursor:
            cursor.execute("SELECT * FROM offer")
            results = cursor.fetchall()
        return [Offer(*result) for result in results]


import art
import game_data
import random

def higher_lower():
    print(art.logo)
    score = 0
    gameover = False
    while not gameover:
        option_a = random.choice(game_data.data)
        option_b = random.choice(game_data.data)
        while option_a == option_b:
            option_b = random.choice(game_data.data)
        print(f'Compare A: {option_a["name"]}, a {option_a["description"]}, from {option_a["country"]}.')
        #print(f'{option_a["follower_count"]}')
        print(art.vs)
        print(f'Against B: {option_b["name"]}, a {option_b["description"]}, from {option_b["country"]}.')
        #print(f'{option_b["follower_count"]}')
        answer = input('Who has more followers? Type \'A\' or \'B\': ').lower()
        if (option_a['follower_count'] > option_b['follower_count'] and answer == 'a') or (option_b['follower_count'] > option_a['follower_count'] and answer == 'b'):
            score += 1
            print(f'You\'re right! Current score: {score}.')
        else:
            print(f'Sorry, that\'s wrong. Final score: {score}.')
            gameover = True

def main():
    still_play = True
    while still_play:
        higher_lower()
        new_game_answer = input('Do you want to play again? \'y\' or \'n\': ')
        if new_game_answer != 'y':
            still_play = False

main()


# SPDX-License-Identifier: MIT
# See LICENSE.md and CONTRIBUTORS.md at https://github.com/SSAGESLabs/PySAGES

from abc import ABCMeta, abstractmethod
from functools import reduce
from inspect import getfullargspec
from operator import or_
from sys import modules as sys_modules

from jax import jit
from plum import parametric

from pysages.backends import SamplingContext
from pysages.colvars.core import build
from pysages.grids import Grid, build_grid, get_info
from pysages.methods.restraints import canonicalize
from pysages.methods.utils import ReplicasConfiguration
from pysages.typing import Callable, Optional, Union
from pysages.utils import ToCPU, copy, dispatch, dispatch_table, has_method, identity

#  Base Classes
#  ============

@parametric
class Result:
    """
    Bundles the essential information needed to estimate the free energy of a
    system, as well as the necessary data for restarting the simulation.

    Parameters
    ----------
    method: ``SamplingMethod``
        The sampling method used.
    states: ``List[SamplingMethodState]``
        The last state of the sampling method for each system replica run.
    callbacks: ``Optional[List[Callback]]``
        Optional set of callbacks for all simulation replicas.
    snapshots: ``List[Snapshot]``
        Last snapshot of each replica of the simulation.
    """

    @classmethod
    def __infer_type_parameter__(cls, method, *_):
        return type(method)

    def __init__(self, method, states, callbacks, snapshots):
        self.method = method
        self.states = states
        self.callbacks = callbacks
        self.snapshots = snapshots

class ReplicaResult(Result):
    pass

class SamplingMethodMeta(ABCMeta):
    """
    Metaclass for enhanced sampling methods.

    It helps making parametric Result types serializable.
    """

    def __new__(cls, name, bases, namespace):
        S = super().__new__(cls, name, bases, namespace)
        T = Result[S]
        T.__qualname__ = T.__name__ = f"Result[{S.__name__}]"
        setattr(sys_modules[T.__module__], T.__name__, T)
        return S

class SamplingMethod(metaclass=SamplingMethodMeta):
    """
    Abstract base class for all sampling methods.

    This class defines a constructor that expects the list of collective
    variables and provides the necessary methods for initializing and executing
    the biasing during a simulation. Inheriting classes are expected to enhance
    or overwrite its methods as needed.
    """

    __special_args__ = set()
    snapshot_flags = set()

    def __init__(self, cvs, **kwargs):
        self.cvs = cvs
        self.cv = build(*cvs, differentiate=kwargs.get("cv_grad", True))
        self.requires_box_unwrapping = reduce(
            or_, (cv.requires_box_unwrapping for cv in cvs), False
        )
        self.kwargs = kwargs

    def __getstate__(self):
        return default_getstate(self)

    def __setstate__(self, state):
        default_setstate(self, state)

    @abstractmethod
    def build(self, snapshot, helpers, *args, **kwargs):
        """
        Returns the snapshot, and two functions, ``initialize`` and ``update``.

        The ``initialize`` function is intended to allocate any run-time
        information required by the ``update`` function. The ``update``
        function is called after each integration step, that is, after each
        call to the wrapped context's ``run`` method.
        """

class GriddedSamplingMethod(SamplingMethod):
    """Base class for sampling methods that use grids."""

    __special_args__ = {"grid"}

    def __init__(self, cvs, grid, **kwargs):
        check_dims(cvs, grid)
        super().__init__(cvs, **kwargs)
        self.grid = grid
        self.restraints = canonicalize(kwargs.get("restraints", None), cvs)

    def __getstate__(self):
        return (get_info(self.grid), *default_getstate(self))

    def __setstate__(self, state):
        grid_args, args, kwargs = state
        args["grid"] = build_grid(*grid_args)
        default_setstate(self, (args, kwargs))

    @abstractmethod
    def build(self, snapshot, helpers, *args, **kwargs):
        pass

class NNSamplingMethod(GriddedSamplingMethod):
    """Base class for sampling methods that use neural networks."""

    def __init__(self, cvs, grid, topology, **kwargs):
        super().__init__(cvs, grid, **kwargs)
        self.topology = topology

    @abstractmethod
    def build(self, snapshot, helpers, *args, **kwargs):
        pass

#  Main functions
#  ==============

@dispatch.abstract
def run(method_or_result, context_generator, timesteps, **kwargs):
    """
    Runs a single or multiple replicas of a simulation with the specified sampling method.

    **Note**: Many specializations for this method are provided.
    """

@dispatch
def run(  # noqa: F811 # pylint: disable=C0116,E0102
    method: SamplingMethod,
    context_generator: Callable,
    timesteps: Union[int, float],
    callback: Optional[Callable] = None,
    context_args: dict = {},
    post_run_action: Optional[Callable] = None,
    config: ReplicasConfiguration = ReplicasConfiguration(),
    **kwargs,
):
    # """
    # Parameters
    # ----------

    # method_or_result: Union[SamplingMethod, Result]

    # context_generator: Callable
    #     User defined function that sets up a simulation context with the backend.
    #     Must return an instance of hoomd.context.SimulationContext for HOOMD-blue
    #     and openmm.Simulation for OpenMM. The function gets context_args
    #     unpacked for additional user arguments.

    # timesteps: int
    #     Number of time steps the simulation is running.

    # callback: Optional[Callable] = None
    #     Allows for user defined actions into the simulation workflow of the method.
    #     kwargs gets passed to the backend run function.

    # context_args: dict = {}
    #     Arguments to pass down to context_generator to setup the simulation context.

    # post_run_action: Optional[Callable] = None
    #     Callable function that enables actions after the run execution of PySAGES.
    #     Actions are executed inside the generated context. Example uses for this
    #     include writing a final configuration file. This function gets context_args
    #     unpacked just like context_generator.

    # config: ReplicasConfiguration = ReplicasConfiguration()
    #     Specifies the number of replicas of the simulation to generate.
    #     It also contains an executor which will manage different process
    #     or threads in case the multiple simulation are to be run in parallel.
    #     Defaults to ReplicasConfiguration(1, SerialExecutor()),
    #     which means only one simulation is run.
    # """
    timesteps = int(timesteps)

    def submit_work(executor, method, callback):
        return executor.submit(
            _run_replica,
            method,
            context_generator,
            timesteps,
            context_args,
            callback,
            post_run_action,
            **kwargs,
        )

    with config.executor as ex:
        futures = [submit_work(ex, method, callback) for _ in range(config.copies)]
    results = [future.result() for future in futures]
    states = [r.states for r in results]
    snapshots = [r.snapshots for r in results]
    callbacks = None if callback is None else [r.callbacks for r in results]

    return Result(method, states, callbacks, snapshots)

@dispatch
def run(  # noqa: F811 # pylint: disable=C0116,E0102
    sampling_context: SamplingContext,
    timesteps: Union[int, float],
    **kwargs,
):
    # """
    # Alternative interface for running a simulation from a SamplingContext.

    # Parameters
    # ----------
    # sampling_context: SamplingContext
    #     Instance of the simulation context of one of the supported backends
    #     wrapped as a SamplingContext.
    # timesteps: int
    #     Number of time steps the simulation is running.
    # kwargs: dict
    #     These gets passed to the backend run function.

    # Notes
    # -----
    # This interface supports only single replica runs.
    # """
    method = sampling_context.method
    method_type = type(method)
    if has_custom_run(method_type):
        raise RuntimeError(
            f"Method {method_type} is not compatible with the SamplingContext interface "
            "use pysages.run(method, context_generator, timesteps) instead."
        )

    timesteps = int(timesteps)
    sampler = sampling_context.sampler
    callback = None if sampler.callback is None else [sampler.callback]

    with sampling_context:
        sampling_context.run(timesteps, **kwargs)

    return Result(method, [sampler.state], callback, [sampler.take_snapshot()])

@dispatch
def run(  # noqa: F811 # pylint: disable=C0116,E0102
    result: Result,
    context_generator: Callable,
    timesteps: Union[int, float],
    context_args: dict = {},
    post_run_action: Optional[Callable] = None,
    config: ReplicasConfiguration = ReplicasConfiguration(),
    **kwargs,
):
    # """
    # Restart a simulation from a previously stored result.
    # """
    method = result.method
    timesteps = int(timesteps)
    callbacks_ = result.callbacks
    callbacks = [None] * len(result.states) if callbacks_ is None else callbacks_

    def submit_work(executor, result):
        return executor.submit(
            _run_replica,
            result,
            context_generator,
            timesteps,
            context_args,
            post_run_action,
            **kwargs,
        )

    with config.executor as ex:
        result_args = zip(result.states, callbacks, result.snapshots)
        futures = [submit_work(ex, ReplicaResult(method, *args)) for args in result_args]

    results = [future.result() for future in futures]
    states = [r.states for r in results]
    snapshots = [r.snapshots for r in results]
    callbacks = None if callbacks_ is None else [r.callbacks for r in results]

    return Result(method, states, callbacks, snapshots)

def _run_replica(method, *args, **kwargs):
    # Trampoline method to enable multiple replicas to be run with mpi4py.
    run = dispatch_table(dispatch)["_run"]
    return run(method, *args, **kwargs)

@dispatch
def _run(  # noqa: F811 # pylint: disable=C0116,E0102
    method: SamplingMethod,
    context_generator: Callable,
    timesteps: Union[int, float],
    context_args: dict = {},
    callback: Optional[Callable] = None,
    post_run_action: Optional[Callable] = None,
    **kwargs,
):
    """
    Base implementation for running a single simulation with the specified `SamplingMethod`.

    Parameters
    ----------

    method: SamplingMethod

    context_generator: Callable
        User defined function that sets up a simulation context with the backend.
        Must return an instance of `hoomd.context.SimulationContext` for HOOMD-blue
        and `openmm.Simulation` for OpenMM. The function gets `context_args`
        unpacked for additional user arguments.

    timesteps: int
        Number of time steps the simulation is running.

    context_args: dict = {}
        Arguments to pass down to `context_generator` to setup the simulation context.

    callback: Optional[Callable] = None
        Allows for user defined actions into the simulation workflow of the method.
        `kwargs` gets passed to the backend `run` function. Default value is `None`.

    post_run_action: Optional[Callable] = None
        Callable function that enables actions after the run execution of PySAGES.
        Actions are executed inside the generated context. Example uses for this
        include writing a final configuration file. This function gets `context_args`
        unpacked just like `context_generator`.

    **Note**: All arguments must be pickable.
    """
    timesteps = int(timesteps)

    sampling_context = SamplingContext(method, context_generator, callback, context_args)
    context_args["context"] = sampling_context.context
    sampler = sampling_context.sampler

    with sampling_context:
        sampling_context.run(timesteps, **kwargs)
        if post_run_action:
            post_run_action(**context_args)

    return ReplicaResult(method, sampler.state, callback, sampler.take_snapshot())

@dispatch
def _run(  # noqa: F811 # pylint: disable=C0116,E0102
    result: ReplicaResult,
    context_generator: Callable,
    timesteps: Union[int, float],
    context_args: dict = {},
    post_run_action: Optional[Callable] = None,
    **kwargs,
):
    """
    Base implementation for running a single simulation from a previously stored `Result`.
    """
    timesteps = int(timesteps)
    method = result.method
    callback = result.callbacks

    sampling_context = SamplingContext(method, context_generator, callback, context_args)
    context_args["context"] = sampling_context.context
    sampler = sampling_context.sampler
    prev_snapshot = result.snapshots
    if sampler.state.xi.device().platform == "cpu":
        prev_snapshot = copy(prev_snapshot, ToCPU())
    sampler.restore(prev_snapshot)
    sampler.state = result.states

    with sampling_context:
        sampling_context.run(timesteps, **kwargs)
        if post_run_action:
            post_run_action(**context_args)

    return ReplicaResult(method, sampler.state, callback, sampler.take_snapshot())

@dispatch.abstract
def analyze(result: Result):
    pass

#  Utils
#  =====

def default_getstate(method: SamplingMethod):
    init_args = set(getfullargspec(method.__init__).args[1:]) - method.__special_args__
    return {key: method.__dict__[key] for key in init_args}, method.kwargs

def default_setstate(method, state):
    args, kwargs = state
    method.__init__(**args, **kwargs)

@dispatch
def check_dims(cvs, grid: Grid):
    if len(cvs) != grid.shape.size:
        raise ValueError("Grid and Collective Variable dimensions must match.")

@dispatch
def check_dims(cvs, grid: type(None)):  # noqa: F811 # pylint: disable=C0116,E0102
    pass

@dispatch
def get_method(method: SamplingMethod):
    return method

@dispatch
def get_method(result: Result):  # noqa: F811 # pylint: disable=C0116,E0102
    return result.method

def has_custom_run(method: type):
    """
    Determine if ``method`` has a specialized ``run`` implementation.
    """
    return has_method(dispatch_table(dispatch)["run"], method, 0)

def generalize(concrete_update, helpers, jit_compile=True):
    if jit_compile:
        _jit = jit
    else:
        _jit = identity

    _update = _jit(concrete_update)

    def update(snapshot, state):
        return _update(state, helpers.query(snapshot))

    return _jit(update)


# ----------------------------------
import streamlit as st
import plotly.express as px
import altair as alt
import pandas as pd

# ----------------------------------

def main():
    st.title('내 앱 대시보드')
    df1 = pd.read_csv('data/lang_data.csv')
    st.dataframe(df1)
    st.write( df1.shape )

    ### 멀티셀렉트를 이용해 언어를 선택하게 하고 그거와 관련된 차트 그려보기

    # 컬럼에 뭐 있는지 확인
    # print( df1.columns )
    # 슬라이싱 이용해서 week 빼기
    print( df1.columns[ 1: ] )

    # 변수에 저장
    lang_list = df1.columns[ 1: ]

    # 유저에게 언어 선택 받기
    choice_list = st.multiselect('언어를 선택하세요', lang_list)

    # 프린트해서 확인
    print(choice_list)

    #@@
    # 유저가 아무것도 선택 안했을때 처리하기
    if len(choice_list) > 0 :  # 데이터가 있다면

        # 유저가 선택한 리스트만 가져와 변수에 넣고 표 보여주기
        choice_df = df1[ choice_list ]
        st.dataframe(choice_df)

        ## 스트림릿이 제공하는 라인차트
        # 각 행의 데이터를 y, 행 정보를 x축
        st.line_chart(choice_df)

        ## 스트림릿이 제공하는 영역차트
        #
        st.area_chart(choice_df)

    ### 아무것도 선택 안했을때 차트영역등이 빈공간으로 나오지 않게 하기
    # 조건문이 필요
    # 위치가 중요
    #@@ 위치에 집어넣으면 됨.

    ### 아이리스 데이터 ---------------------------------------
    df2 = pd.read_csv('data/iris.csv')

    ## 스트림릿이 제공하는 바 차트
    df3 = df2[ ['sepal_length', 'sepal_width'] ]
    st.bar_chart(df3)

    ## Altair 이용
    chart = alt.Chart(df2).mark_circle().encode(
        x = 'petal_length', y = 'petal_width', color = 'species')

    st.altair_chart(chart)

    ### 로케이션 데이터 ----------------------------------------

    ## 스트림릿의 map차트
    df4 = pd.read_csv('data/location.csv', index_col = 0)
    print(df4)

    # zoom = 5 : 숫자가 작을수록 멀리서 보는것. 숫자만 적어도 됨.
    st.map(df4, zoom = 5)

    ### 프로그램 언어 데이터
    df5 = pd.read_csv('data/prog_languages_data.csv', index_col = 0)
    st.dataframe(df5)

    # plotly 의 pie 차트 ( 파이차트 - 비율을 보고 싶을때)
    fig1 = px.pie(df5, 'lang', 'Sum', title=' 각언어별 비율') # 차트 영역 만들기
    # df5 : 가져올 데이터, 'lang': 어떤거에대해 그릴꺼냐, 'Sum': 수치 뭘로할까
    st.plotly_chart(fig1)

    # plotly 의 bar 차트
    # fig2 = px.bar()
    df6 = df5.sort_values('Sum', ascending = False)
    fig2 = px.bar(df6, x = 'lang', y = 'Sum')
    st.plotly_chart(fig2)

if __name__ == '__main__':
    main()


# ---------------------------------------------#
# This is the SVS image processing code from the example of openslide
# Some of the codes were referred to Nicolas's script.
#
# ---------------------------------------------#
import openslide
from openslide import open_slide, ImageSlide
from openslide.deepzoom import DeepZoomGenerator
from multiprocessing import Process, JoinableQueue
import numpy as np
import os
import sys
import simplejson as json

VIEWER_SLIDE_NAME = 'slide'

class TileWorker(Process):
    """A child process that generates and writes tiles."""

    def __init__(self, queue, slidepath, tile_size, overlap, limit_bounds, quality):
        Process.__init__(self, name='TileWorker')
        self.daemon = True
        self._queue = queue
        self._slidepath = slidepath
        self._tile_size = tile_size
        self._overlap = overlap
        self._limit_bounds = limit_bounds
        self._quality = quality
        self._slide = None

    def bk_detect(self, _img):
        """
        Writing the new function for the background detection;
        Remove the image patches which the background is more than 50% of the whole patches.
        """
        try:
            _gray = _img.convert('L')
            bw = _gray.point(lambda x: 0 if x < 220 else 1, 'F')
            arr = np.array(np.asarray(bw))
            avg_bkg = np.average(bw)
            if arr.shape[0] + arr.shape[1] - 2*self._tile_size == 4:
                return avg_bkg
            else:
                return 1

        except Exception as e:
            print(e)
            # print(level, address)
            return 1

    def run(self):
        self._slide = open_slide(self._slidepath)
        last_associated = None
        dz = self._get_dz()
        while True:
            data = self._queue.get()
            if data is None:
                self._queue.task_done()
                break
            associated, level, address, outfile = data
            if last_associated != associated:
                dz = self._get_dz(associated)
                last_associated = associated
            tile = dz.get_tile(level, address)
            bkg_val = self.bk_detect(tile)
            if bkg_val <= 0.5:
                tile.save(outfile, quality=self._quality)
            self._queue.task_done()

    def _get_dz(self, associated=None):
        if associated is not None:
            image = ImageSlide(self._slide.associated_images[associated])
        else:
            image = self._slide
        return DeepZoomGenerator(image, self._tile_size, self._overlap,
                                 limit_bounds=self._limit_bounds)

class DeepZoomImageTiler(object):
    """Handles generation of tiles and metadata for a single image."""

    def __init__(self, dz, basename, format, associated, queue, t_mag, slide):
        self._dz = dz
        self._basename = basename
        self._format = format
        self._associated = associated
        self._queue = queue
        self._processed = 0
        self._t_mag = int(t_mag)
        self._slide = slide

    def run(self):
        self._write_tiles_new()
        #self._write_dzi()

    def _write_tiles_new(self):
        _magnification = 20
        _tol = 2
        _factors = self._slide.level_downsamples
        _objective = None
        try:
            _objective = float(self._slide.properties[openslide.PROPERTY_NAME_OBJECTIVE_POWER])
        except Exception as e:
            print(e)
            print(self._basename + " - No Objective information found")
            return
        _available = tuple(_objective / x for x in _factors)
        for level in range(self._dz.level_count-1, -1, -1):
            _thisMag = int(_available[0] / pow(2, self._dz.level_count - (level + 1)))
            if self._t_mag != _thisMag:
                continue
            tile_dir = os.path.join("%s_files" % self._basename, str(_thisMag))
            if not os.path.exists(tile_dir):
                os.makedirs(tile_dir)
            cols, rows = self._dz.level_tiles[level]
            for row in range(rows):
                for col in range(cols):
                    tile_name = os.path.join(tile_dir, '%d_%d.%s' % (col, row, self._format))
                    if not os.path.exists(tile_name):
                        self._queue.put((self._associated, level, (col, row), tile_name))
                    self._tile_done()

    def _tile_done(self):
        self._processed += 1
        count, total = self._processed, self._dz.tile_count
        if count % 100 == 0 or count == total:
            print("Tiling %s: wrote %d/%d tiles" % (self._associated or 'slide',
                                                    count, total), end='\r', file=sys.stderr)
            if count == total:
                print(file=sys.stderr)

    def _write_dzi(self):
        with open('%s.dzi' % self._basename, 'w') as fh:
            fh.write(self.get_dzi())

    def get_dzi(self):
        return self._dz.get_dzi(self._format)

class DeepZoomStaticTiler(object):
    """Handles generation of tiles and metadata for all images in a slide."""

    def __init__(self, slidepath, basename, format, tile_size, overlap,
                 limit_bounds, quality, workers, with_viewer, tile_level):
        if with_viewer:
            # Check extra dependency before doing a bunch of work
            import jinja2
        self._slide = open_slide(slidepath)
        self._basename = basename
        self._format = format
        self._tile_size = tile_size
        self._overlap = overlap
        self._limit_bounds = limit_bounds
        self._queue = JoinableQueue(2 * workers)
        self._workers = workers
        self._with_viewer = with_viewer
        self._dzi_data = {}
        self._tile_level = tile_level
        for _i in range(workers):
            TileWorker(self._queue, slidepath, tile_size, overlap, limit_bounds, quality).start()

    def run(self):
        self._run_image()
        if self._with_viewer:
            for name in self._slide.associated_images:
                self._run_image(name)
            self._write_html()
            self._write_static()
        self._shutdown()

    def _run_image(self, associated=None):
        """Run a single image from self._slide."""
        if associated is None:
            image = self._slide
            if self._with_viewer:
                basename = os.path.join(self._basename, VIEWER_SLIDE_NAME)
            else:
                basename = self._basename
        else:
            image = ImageSlide(self._slide.associated_images[associated])
            basename = os.path.join(self._basename, self._slugify(associated))
        dz = DeepZoomGenerator(image, self._tile_size, self._overlap,
                               limit_bounds=self._limit_bounds)
        tiler = DeepZoomImageTiler(dz, basename, self._format, associated,
                                   self._queue, self._tile_level, image)
        tiler.run()
        self._dzi_data[self._url_for(associated)] = tiler.get_dzi()

    def _url_for(self, associated):
        if associated is None:
            base = VIEWER_SLIDE_NAME
        else:
            base = self._slugify(associated)
        return '%s.dzi' % base

    def _write_html(self):
        import jinja2
        env = jinja2.Environment(loader=jinja2.PackageLoader(__name__),
                                 autoescape=True)
        template = env.get_template('slide-multipane.html')
        associated_urls = dict((n, self._url_for(n)) for n in self._slide.associated_images)
        try:
            mpp_x = self._slide.properties[openslide.PROPERTY_NAME_MPP_X]
            mpp_y = self._slide.properties[openslide.PROPERTY_NAME_MPP_Y]
            mpp = (float(mpp_x) + float(mpp_y)) / 2
        except (KeyError, ValueError):
            mpp = 0
        # Embed the dzi metadata in the HTML to work around Chrome's
        # refusal to allow XmlHttpRequest from file:///, even when
        # the originating page is also a file:///
        data = template.render(slide_url=self._url_for(None), slide_mpp=mpp,
                               associated=associated_urls, properties=self._slide.properties,
                               dzi_data=json.dumps(self._dzi_data))
        with open(os.path.join(self._basename, 'index.html'), 'w') as fh:
            fh.write(data)

    def _write_static(self):
        basesrc = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'static')
        basedst = os.path.join(self._basename, 'static')
        self._copydir(basesrc, basedst)
        self._copydir(os.path.join(basesrc, 'images'), os.path.join(basedst, 'images'))

    def _copydir(self, src, dest):
        if not os.path.exists(dest):
            os.makedirs(dest)
        for name in os.listdir(src):
            srcpath = os.path.join(src, name)
            if os.path.isfile(srcpath):
                shutil.copy(srcpath, os.path.join(dest, name))

    @classmethod
    def _slugify(cls, text):
        text = normalize('NFKD', text.lower()).encode('ascii', 'ignore').decode()
        return re.sub('[^a-z0-9]+', '_', text)

    def _shutdown(self):
        for _i in range(self._workers):
            self._queue.put(None)
        self._queue.join()


'''
Create a list by concatenating a given list which range goes from 1 to n
'''

l1 = ['r', 't', 'g', 's', 'u']
n = 4

def concat_lis(lst, num):
    new_list = ['{}{}'.format(x, y) for y in range(1, num + 1) for x in lst]
    return new_list

print(concat_lis(l1, n))


""" @auteur : johanna
date : 10/09/2020
description : atelier3 exercice 2
version 1
"""

import math
from math import *

def position_1(L,e):
    taille = len(L)
    compteur = -1
    for i in range (0,taille):
        if L[i]==e:
            compteur=i
    return(compteur)

def position_2(L,e):
    i=0
    taille = len(L)
    compteur=-1
    while i<taille:
        if L[i]==e:
            compteur=i
        i+=1
    return(compteur)

def test_position():
    L=[7,12,3,0,4]
    L2=[8,16,2,1]
    L3=[5615,6848,3]
    print(position_1(L,3))
    print(position_2(L,7))
    print(position_1(L2, 7))
    print(position_2(L2, 7))
    print(position_1(L3, 6848))
    print(position_2(L3, 6848))

def nb_occurences(L,e):
    taille = len(L)
    compteur = 0
    for i in range(0, taille):
        if L[i] == e:
            compteur +=1
    return (compteur)

def test_occurence():
    L=[1,1]
    L2=[2,8,5,9,1,9]
    L3=[1,2,9,4]

    print(nb_occurences(L,1))
    print(nb_occurences(L,0))

    print(nb_occurences(L2, 9))
    print(nb_occurences(L2, 0))

    print(nb_occurences(L3, 1))
    print(nb_occurences(L3, 0))

def est_triee(L):
    taille = len(L)
    est_croissant = True
    for i in range(0,taille-1):
        if(L[i]>L[i+1]):
            est_croissant=False
    return(est_croissant)

def test_est_triee():
    L=[0,1,2,3,4]
    print(est_triee(L))
    L=[2,8,65,0,1]
    print(est_triee(L))

def est_triee_2(L):
    est_croissant=True
    taille = len(L)
    i=0
    fin = False
    while fin != True :
        print(i)
        if(L[i+1]<L[i]):
            est_croissant=False
            fin = True
        if i==taille-2:
            fin = True
        else:
            i+=1
    return(est_croissant)

def test_est_triee_2():
    L=[0,1,2,3,4]
    print(est_triee_2(L))
    L=[2,8,65,0,1]
    print(est_triee_2(L))

def a_repetitions(L):
    T=[]
    repetition = False
    while (repetition == False) or (len(T)!=len(L)):
        for element in L:
            if not(element in T):
                T.append(element)
            else:
                repetition = True
    return(repetition)

def position_tri(L,e):
    taille = len(L)
    res = 0
    taille2 = floor(taille/2)

    if e< L[taille2] :
        Liste2 =[]
        for i in range(0,taille2):
            Liste2.append(L[i])
        res = position_tri(Liste2,e)
    elif e > L[taille2]:
        Liste2 =[]
        for i in range(taille2,taille):
            Liste2.append(L[i])
        res = position_tri(Liste2, e) + taille2

    elif e == L[taille2]:
        res = taille2

    else:
        res = -1

    return(res)

def test_position_tri():
    L2 = [2, 8,  9, 19]
    print(position_tri(L2,2))
    L2 = [2, 8, 9, 19]
    print(position_tri(L2, 19))
    L2 = [2, 8, 9, 19]
    print(position_tri(L2, 9))
    L2 = [8, 9, 19]
    print(position_tri(L2, 8))

test_position_tri()

def test_a_repetitions():
    L = [1, 1]
    L2 = [2, 8, 5, 9, 1]
    L3 = [1, 2, 9, 4]
    print(a_repetitions(L))
    print(a_repetitions(L2))
    print(a_repetitions(L3))

    print("L/2")
    print(L/2)
    print(L2/2)

test_a_repetitions()


from enum import Enum, auto

class ActionPrototype:
    class Type(Enum):
        MOMENTARY = auto()
        CONTINUOUS = auto()

class FunctionAction(ActionPrototype):
    def __init__(self, callback, _type: ActionPrototype.Type = ActionPrototype.Type.MOMENTARY):
        super().__init__()
        self.callback = callback
        self.type = _type

    def call(self, args, kwargs):
        self.callback(*args, **kwargs)


import random
import time
import numpy as np
import torch
import os
import math
import torch.nn as nn
from iou_cc import calc_iou

import cv2 #changedByAlex
#Importing library to do image related operations
from PIL import Image, ImageOps

#Importing the important functionalities of Pytorch such as the dataloader, Variable, transform's
#and optimizer related functions.

from torch.optim import SGD, Adam, lr_scheduler
from torch.autograd import Variable
from torch.utils.data import DataLoader
from torchvision.transforms import Resize
from torchvision.transforms import ToTensor, ToPILImage
from erfnet import Net

# Importing the dataset class for VOC12 and cityscapes
from dataset import cityscapes
from dataset import idd_lite

import sys

#Importing the Relabel, ToLabel and Colorize class from transform.py file
from transform import Relabel, ToLabel, Colorize
import matplotlib
from matplotlib import pyplot as plt

import importlib
from iouEval import iouEval, getColorEntry #importing iouEval class from the iouEval.py file
from shutil import copyfile

# ### A few global parameters ###

NUM_CHANNELS = 3 #RGB Images
NUM_CLASSES = 2 #IDD Lite has 8 labels or Level1 hierarchy of labels
USE_CUDA = torch.cuda.is_available()
IMAGE_HEIGHT = 256
OUTPUT_DIR = r'D:\Users Data\inbal.tlgip\Project\output_images'
DATA_ROOT = r'D:\Users Data\inbal.tlgip\Desktop\ChangeDetectionDataset'
BATCH_SIZE = 2
NUM_WORKERS = 0
NUM_EPOCHS = 150
ENCODER_ONLY = False
device = torch.device("cuda")
# device = torch.device("cpu")
device = 'cuda'
color_transform = Colorize(NUM_CLASSES)
image_transform = ToPILImage()

IOUTRAIN = False
IOUVAL = True

#Augmentations - different function implemented to perform random augments on both image and target
class MyCoTransform(object):
    def __init__(self, enc, augment=True, height=160):
        self.enc=enc
        self.augment = augment
        self.height = height
        pass
    def __call__(self, input, input1, target):
        # Resizing data to required size
        input =  Resize((self.height,320), Image.BILINEAR)(input) #askalex
        input1 =  Resize((self.height,320), Image.BILINEAR)(input1) #ChangedByUs
        target = Resize((self.height,320), Image.NEAREST)(target)

        if(self.augment):
            # Random horizontal flip
            hflip = random.random()
            if (hflip < 0.5):
                input = input.transpose(Image.FLIP_LEFT_RIGHT)
                input1 = input1.transpose(Image.FLIP_LEFT_RIGHT) #ChangedByUs
                target = target.transpose(Image.FLIP_LEFT_RIGHT)

            #Random translation 0-2 pixels (fill rest with padding)
            transX = random.randint(0, 2)
            transY = random.randint(0, 2)

            input = ImageOps.expand(input, border=(transX,transY,0,0), fill=0)
            input1 = ImageOps.expand(input1, border=(transX,transY,0,0), fill=0) #ChangedByUs
            target = ImageOps.expand(target, border=(transX,transY,0,0), fill=255) #pad label filling with 7  #askalex- change 255
            input = input.crop((0, 0, input.size[0]-transX, input.size[1]-transY))
            input1 = input1.crop((0, 0, input1.size[0]-transX, input1.size[1]-transY)) #ChangedByUs
            target = target.crop((0, 0, target.size[0]-transX, target.size[1]-transY))

        input = ToTensor()(input)
        input1 = ToTensor()(input1) #ChangedByUs

        target = ToLabel()(target)

        #target = Relabel(255, 7)(target)
        return input, input1, target #ChangedByUs

# ### Loading Data
#
# We'll follow pytorch recommended semantics, and use a dataloader to load the data.

def main():
    best_acc = 0

    co_transform = MyCoTransform(ENCODER_ONLY, augment=True, height=IMAGE_HEIGHT)
    co_transform_val = MyCoTransform(ENCODER_ONLY, augment=False, height=IMAGE_HEIGHT)

    #train data
    dataset_train = idd_lite(DATA_ROOT, co_transform, 'train')
    print("length of training set: ",len(dataset_train))
    #test data
    dataset_val = idd_lite(DATA_ROOT, co_transform_val, 'val')
    print("length of validation set: ",len(dataset_val))

    # NOTE: PLEASE DON'T CHANGE batch_size and num_workers here. We have limited resources.
    loader_train = DataLoader(dataset_train, num_workers=NUM_WORKERS, batch_size=BATCH_SIZE, shuffle=True)
    loader_val = DataLoader(dataset_val, num_workers=NUM_WORKERS, batch_size=BATCH_SIZE, shuffle=True)
    dataiter = iter(loader_val)
    seven_val_images = []
    for i in range(7):
        (val_image_A, val_image_B, val_image_labels) = dataiter.next()
        seven_val_images.append((val_image_A.to(device), val_image_B.to(device)))
        cv2.imwrite(os.path.join(OUTPUT_DIR, str(i), 'A.tiff'),
                    np.rollaxis((val_image_A[0, :, :, :].squeeze().cpu().numpy() * 255).astype('uint8'), 0, 3))
        cv2.imwrite(os.path.join(OUTPUT_DIR, str(i), 'B.tiff'),
                    np.rollaxis((val_image_B[0, :, :, :].squeeze().cpu().numpy() * 255).astype('uint8'), 0, 3))
        cv2.imwrite(os.path.join(OUTPUT_DIR, str(i), 'label.tiff'),
                    (val_image_labels[0, :, :, :].squeeze().cpu().numpy()).astype('uint8'))

    # ## Cross Entropy  Loss ##
    # Negative Log Loss   |Plot of -log(x) vs x
    # - | -
    # ![alt](img/nll.png) | ![alt](img/nll-log.png)
    #
    # The negative log-likelihood becomes unhappy at smaller values, where it can reach infinite unhappiness (that’s too sad), and becomes less unhappy at larger values. Because we are summing the loss function to all the correct classes, what’s actually happening is that whenever the network assigns high confidence at the correct class, the unhappiness is low, but when the network assigns low confidence at the correct class, the unhappiness is high.

    # In[12]:

    criterion = torch.nn.CrossEntropyLoss()

    #get some random training images
    print("length of training couples: ",len(loader_train))
    print(len(loader_val))
    dataiter = iter(loader_train)
    (images, images1, labels, filename) = dataiter.next() #ChangedByUs
    # for step, (images, labels) in enumerate(loader_train):
    # plt.figure()
    # plt.imshow(ToPILImage()(images[0].cpu()))
    # plt.figure()
    # plt.imshow(ToPILImage()(Colorize()(labels[0].cpu())))
    # break

    # ## Model ##

    model_file = importlib.import_module('erfnet')
    model = model_file.Net(NUM_CLASSES).to(device)

    # ### Optimizer ###

    # We use adam optimizer. It can be replaced with SGD and other optimizers
    optimizer = Adam(model.parameters(), 5e-4, (0.9, 0.999),  eps=1e-08, weight_decay=1e-4)
    start_epoch = 1

    print("device used: ",device)

    # ### Training Procedure ###
    softmax = torch.nn.Softmax(dim=1)

    steps_loss = 50
    my_start_time = time.time()
    for epoch in range(start_epoch, NUM_EPOCHS+1):
        print("----- TRAINING - EPOCH", epoch, "-----")

        epoch_loss = []
        time_train = []

        doIouTrain = IOUTRAIN
        doIouVal =  IOUVAL

        if (doIouTrain):
            iouEvalTrain = iouEval(NUM_CLASSES)

        model.train()
        for step, (images, images1, labels, filename) in enumerate(loader_train): #ChangedByUs
            start_time = time.time()
            # inputs = [images.to(device), images1.to(device)] #ChangedByUs
            inputs = images.to(device)
            inputs1 = images1.to(device) #ChangedByUs
            targets = labels.to(device)
            targets_orig = targets.clone()
            targets[targets_orig >= 128] = 1  # ChangedByUs
            targets[targets_orig < 128] = 0  # ChangedByUs
            #for x_u in targets.unique():
            #    print(int(x_u), ' appears ', int(torch.stack([(targets==x_u).sum()])), ' times.\n')
            outputs = model([inputs, inputs1], only_encode=ENCODER_ONLY)
            # zero the parameter gradients
            optimizer.zero_grad()
            # forward + backward + optimize
            loss = criterion(outputs, targets[:, 0])
            loss.backward()
            optimizer.step()

            epoch_loss.append(loss.item())
            time_train.append(time.time() - start_time)

            if (doIouTrain):
                #start_time_iou = time.time()
                iouEvalTrain.addBatch(outputs.max(1)[1].unsqueeze(1).data, targets.data)
                #print ("Time to add confusion matrix: ", time.time() - start_time_iou)

            # print statistics
            if steps_loss > 0 and step % steps_loss == 0:
                average = sum(epoch_loss) / len(epoch_loss)
                print('loss: {average:',average,'} (epoch: {',epoch,'}, step: {', step, '})', "// Avg time/img: %.4f s" % (sum(time_train) / len(time_train) / BATCH_SIZE))

        average_epoch_loss_train = sum(epoch_loss) / len(epoch_loss)

        iouTrain = 0
        if (doIouTrain):
            iouTrain, iou_classes = iouEvalTrain.getIoU()
            iouStr = getColorEntry(iouTrain)+'{:0.2f}'.format(iouTrain*100) + '\033[0m'
            print ("EPOCH IoU on TRAIN set: ", iouStr, "%")

        #save one image per epoch
        # if USE_CUDA:
        #     first_val_image_A = first_val_image_A.to(device)
        #     first_val_image_B = first_val_image_B.to(device)  # ChangedByUs
        #     first_val_image_labels = first_val_image_labels.to(device)
        #
        # inputs = first_val_image_A.to(device)
        # inputs1 = first_val_image_B.to(device)  # ChangedByUs
        for i in range(len(seven_val_images)):
            outputs_val = model([seven_val_images[i][0].cuda(), seven_val_images[i][1].cuda()], only_encode=ENCODER_ONLY)
            outputs_val = softmax(outputs_val)
            cv2.imwrite(os.path.join(OUTPUT_DIR, str(i), 'epoch' + str(epoch) + '_output.tiff'),
                        (((outputs_val[0, 1, :, :] > 0.5) * 255).squeeze().cpu().numpy()).astype('uint8'))

    my_end_time = time.time()
    print(my_end_time - my_start_time)

    print('loss: {average:',average,'} (epoch: {',epoch,'}, step: {',step,'})', "// Avg time/img: %.4f s" % (sum(time_train) / len(time_train) / BATCH_SIZE))

    # # ### Validation ###
    # #Validate on val images after each epoch of training
    # print("----- VALIDATING - EPOCH", epoch, "-----")
    # model.eval()
    # epoch_loss_val = []
    # time_val = []
    #
    # if (doIouVal):
    #     iouEvalVal = iouEval(NUM_CLASSES)
    #
    # for step, (images, labels) in enumerate(loader_val):
    #     start_time = time.time()
    #
    #     inputs = images.to(device)
    #     targets = labels.to(device)
    #
    #     with torch.no_grad():
    #         outputs = model(inputs, only_encode=ENCODER_ONLY)
    #         #outputs = model(inputs)
    #     loss = criterion(outputs, targets[:, 0])
    #     epoch_loss_val.append(loss.item())
    #     time_val.append(time.time() - start_time)
    #
    #
    #     #Add batch to calculate TP, FP and FN for iou estimation
    #     if (doIouVal):
    #         #start_time_iou = time.time()
    #         iouEvalVal.addBatch(outputs.max(1)[1].unsqueeze(1).data, targets.data)
    #         #print ("Time to add confusion matrix: ", time.time() - start_time_iou)
    #
    #     if steps_loss > 0 and step % steps_loss == 0:
    #         average = sum(epoch_loss_val) / len(epoch_loss_val)
    #         print('VAL loss: {average:',average,'} (epoch: {',epoch,'}, step: {',step,'})',
    #                 "// Avg time/img: %.4f s" % (sum(time_val) / len(time_val) / BATCH_SIZE))
    #
    #
    # average_epoch_loss_val = sum(epoch_loss_val) / len(epoch_loss_val)
    #
    # iouVal = 0
    # if (doIouVal):
    #
    #     iouVal, iou_classes = iouEvalVal.getIoU()
    #     print(iou_classes)
    #     iouStr = getColorEntry(iouVal)+'{:0.2f}'.format(iouVal*100) + '\033[0m'
    #     print ("EPOCH IoU on VAL set: ", iouStr, "%")

    #
    #  ### Visualizing the Output###
    torch.save(model.state_dict(),r'C:\Users\inbal.tlgip\modelsave.pt')
    # Qualitative Analysis

    ##################### calc iou on test data #####################
    dataset_test = idd_lite(DATA_ROOT, co_transform_val, 'test')
    loader_test = DataLoader(dataset_test, num_workers=NUM_WORKERS, batch_size=BATCH_SIZE, shuffle=True)
    # dataiter = iter(loader_test)
    # (val_image_A, val_image_B, val_image_labels) = dataiter.next()
    for step, (images, images1, labels, filename) in enumerate(loader_test):

        outputs_val = model([images.cuda(), images1.cuda()], only_encode=ENCODER_ONLY)
        outputs_val = softmax(outputs_val)
        cv2.imwrite(r'D:\Users Data\inbal.tlgip\Project\output_images\test_output/'+str(step)+'.tiff',
                    (((outputs_val[0, 1, :, :] > 0.5) * 255).squeeze().cpu().numpy()).astype('uint8'))

if __name__ == '__main__':
    #main()

    #to delete later: (WE DID THIS TO NOT RUN WHOLE MAIN AGAIN...)
    softmax = torch.nn.Softmax(dim=1)
    model_file = importlib.import_module('erfnet')
    model = model_file.Net(NUM_CLASSES).to(device)
    model.load_state_dict(torch.load(r'D:\Users Data\inbal.tlGIP\Desktop\modelsave.pt'))
    model.cuda()
    model.eval()
    co_transform_val = MyCoTransform(ENCODER_ONLY, augment=False, height=IMAGE_HEIGHT) #askAlex why we dont augment in val?

    dataset_test = idd_lite(DATA_ROOT, co_transform_val, 'test')
    loader_test = DataLoader(dataset_test, num_workers=NUM_WORKERS, batch_size=1, shuffle=True)
    # dataiter = iter(loader_test)
    # (val_image_A, val_image_B, val_image_labels) = dataiter.next()
    iou_sum = 0
    count = 0
    recall_sum = 0
    precision_sum = 0
    for step, (images, images1, labels, filename) in enumerate(loader_test):

        inputs = images.to(device)
        inputs1 = images1.to(device)  # ChangedByUs
        targets = labels.to(device)
        # targets_orig = targets.clone()
        # targets[targets_orig >= 128] = 1  # ChangedByUs
        # targets[targets_orig < 128] = 0  # ChangedByUs
        #outputs_val = model([images.cuda(), images1.cuda()], only_encode=ENCODER_ONLY)
        outputs_val = model([inputs.cuda(), inputs1.cuda()], only_encode=ENCODER_ONLY)
        outputs_val = softmax(outputs_val)
        cv2.imwrite(r'D:\Users Data\inbal.tlgip\Project\output_images\test_output/'+str(filename[0])+'.tiff',
                    (((outputs_val[0, 1, :, :] > 0.5) * 255).squeeze().cpu().numpy()).astype('uint8'))
        # cv2.imwrite(r'D:\Users Data\inbal.tlgip\Project\output_images\test_label/'+str(filename[0])+'.tiff',
        #             (targets[0, :, :, :].squeeze().cpu().numpy()).astype('uint8'))
        iou_avg_local, recall, precision = calc_iou((((outputs_val[0, 1, :, :] > 0.5) * 255).squeeze().cpu().numpy()).astype('uint8'),
                        (targets[0, :, :, :].squeeze().cpu().numpy()).astype('uint8'), 0.5)

        if not np.isnan(iou_avg_local): # if there are no blobs: calc=nan
            iou_sum += iou_avg_local
            recall_sum += recall
            precision_sum += precision
            count += 1

    iou_avg = iou_sum/count
    recall_avg = recall_sum/count
    precision_avg = precision_sum/count
    print("iou = ", iou_avg)
    print("recall = ", recall_avg)
    print("precision = ", precision_avg)


import tkinter as tk
from tkinter import filedialog as fd
from PIL import Image, ImageTk

window = tk.Tk()
window.title("Image Viewer")
window.resizable(width=False, height=False)

images = []
cursor = 0

def open_image():
    global cursor
    filename = fd.askopenfilename(
        title="Select an image",
        initialdir="/",
        )

    file = Image.open(filename)

    if file.width > 1000:
        file = file.resize((1000, file.height * 1000 // file.width))
    elif file.height > 1000:
        file = file.resize((file.width * 1000 // file.height, 1000))

    img = ImageTk.PhotoImage(file)
    images.append(img)
    cursor = len(images) - 1
    display_image(img)

def display_image(img):
    global lbl_image

    if len(images) > 1:
        lbl_image.grid_forget()

    lbl_image = tk.Label(image=img)
    lbl_image.grid(row=1, column=0)
    lbl_index = tk.Label(text=f"{cursor + 1} / {len(images)}")
    lbl_index.grid(row=0, column=0)

def forward():
    global cursor
    if cursor < len(images) - 1:
        cursor += 1
        display_image(images[cursor])

def back():
    global cursor
    if cursor > 0:
        cursor -= 1
        display_image(images[cursor])

lbl_index = tk.Label()
lbl_image = tk.Label(text="Display an image here!", width=15, height=15)
frm_buttons = tk.Frame(master=window)

btn_back = tk.Button(
    master=frm_buttons,
    text="<<",
    command=back,
    )

btn_addImage = tk.Button(
    master=frm_buttons,
    text="Add Image",
    command=open_image,
    )

btn_forward = tk.Button(
    master=frm_buttons,
    text=">>",
    command=forward,
    )

lbl_index.grid(row=0, column=0)
lbl_image.grid(row=1, column=0)
frm_buttons.grid(row=2, column=0)
btn_back.grid(row=0, column=0)
btn_addImage.grid(row=0, column=1)
btn_forward.grid(row=0, column=2)

window.mainloop()


sieve = [1, 1]

fout = open("sieve.out", "wt")

def next_int(fname):
    for line in open(fname):
        for val in line.split():
            yield int(val)

def simple_sieve(nr):
	i = 4
	while (i < nr + 1):
		sieve[i] = 1
		i += 2
	i = 3
	while(i * i < nr + 1):
		if sieve[i] == 0:
			j = i * i
			while(j < nr + 1):
				sieve[j] = 1
				j += 2 * i
		i += 2

def special_sieve(nr):
	i = 4
	while (i < nr + 1):
		sieve[i] = 2
		i += 2
	i = 3
	while(i * i < nr + 1):
		if sieve[i] == 0:
			j = i * i
			while(j < nr + 1):
				sieve[j] = i
				j += 2 * i
		i += 2

def prime_factorisation(nr):

	if nr == 1:
		fout.write("\n")
		return

	if sieve[nr] == 0:
		fout.write("%d^1\n" % (nr))
		return

	div = sieve[nr]
	exp = 0
	no = nr
	while (nr % div == 0):
		nr /= div
		exp += 1

	fout.write("%d^%d " % (div, exp))
	prime_factorisation(nr)

for n in next_int("sieve.in"):
	''' Initialize the sieve vector'''
	for i in range(2, n + 1):
		sieve.append(0)

	special_sieve(n)
	for i in range(2, n + 1):
		fout.write("%d: " % (i))
		prime_factorisation(i)

fout.close()


# -*- coding: utf-8 -*-
# @Author: cyang
# @Date:   2020-09-13 10:44:28
# @Last Modified by:   cyang
# @Last Modified time: 2020-09-19 15:47:58

import os
import send2trash

SUFFIX = ('.torrent', '.txt', '.url', 'rar', '.jpg', '.mht', '.gif', '.png', '.mhtml', '.xltd', '.chm', '.bpm', '.apk', 'pdf')
# SUFFIX = ('.torrent', '.txt', '.url', 'rar', '.mht','.mhtml', '.xltd', '.chm', '.ass')
PATH = 'D:\迅雷下载'

def deleteFile(path):
	for folderName, subFolders, fileNames in os.walk(path):
		print('\n-----------------------------------')
		print('The current folder is ' + folderName)
		# print(subFolders, fileNames)
		if not os.listdir(folderName):
			print(folderName + ' is an empty folder, remove it')
			filePath = os.path.join(folderName)
			print('#send2trash#: ' + filePath)
			send2trash.send2trash(filePath)

		for subFolder in subFolders:
			print('SUBFOLDER of ' + folderName + ': ' + subFolder)
		for fileName in fileNames:
			print('FILE INSIDE ' + folderName + ': ' + fileName)

			#remove file to trash if its suffix is one of SUFFIX
			if fileName.endswith(SUFFIX):
				filePath = os.path.join(folderName, fileName)
				print('#send2trash#: ' + filePath)
				send2trash.send2trash(filePath)
			elif fileName.endswith('.mp4'):
				filePath = os.path.join(folderName, fileName)
				fileSize = os.path.getsize(filePath)
				fileSize = round(fileSize/float(1024*1024), 2)
				print('%s, %d MB' % (filePath, fileSize))

				if fileSize < 100:
					print('#send2trash#: ' + filePath)
					send2trash.send2trash(filePath)

if __name__ == '__main__':
	deleteFile(PATH)


import os

import pandas as pd
from py._path.local import LocalPath

from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import MinMaxScaler

from src.run_pipeline import train, run_pipeline
from src.entities import (
    SplittingParams,
    TrainParams,
    PredictParams,
    ModelParams,
    TransformParams,
    ConfigParams,
)

def test_run_pipeline(
    tmpdir: LocalPath,
    dataset_path: str,
    target_col: str,
):

    params = ConfigParams(
        do_train=True,
        do_predict=True,
        bin_model_path=tmpdir.join("bin_model.json"),
        train_params=TrainParams(
            train_data_path=dataset_path,
            target_col=target_col,
            train_metric_path=tmpdir.join("metrics.json"),
            splitting_params=SplittingParams(val_size=0.2, random_state=239),
        ),
        transformer=TransformParams(
            builder="",
        ),
        model=ModelParams(
            params={},
            module="sklearn.tree.DecisionTreeClassifier",
        ),
        test_params=PredictParams(
            target_col=target_col,
            predict_metric_path=None,
            predict_data_path=dataset_path,
            out_predict_path=tmpdir.join("predicts.csv"),
        ),
    )

    run_pipeline(params)

def test_train(
    tmpdir: LocalPath,
    dataset_path: str,
    target_col: str,
):
    expected_metric_path = tmpdir.join("metrics.json")
    params = TrainParams(
        train_data_path=dataset_path,
        target_col=target_col,
        train_metric_path=expected_metric_path,
        splitting_params=SplittingParams(val_size=0.2, random_state=239),
    )
    pipeline = Pipeline(
        [("transformer", MinMaxScaler()), ("model", LogisticRegression())]
    )
    pipeline = train(pipeline, params)

    data = pd.read_csv(dataset_path)
    X = data.drop(columns=target_col)
    y = data[target_col]

    assert pipeline.score(X, y) > 0.8
    assert os.path.exists(params.train_metric_path)


maxx = 0

for i in range(10000):
    s = i
    n = 200
    while s // n >= 2:
        s = s + 5
        n = n + 5
    if 100 <= s <= 999:
        if i > maxx:
            maxx = i
print(maxx)


from django.urls import path
from . import views
app_name = 'carts'
urlpatterns = [
    # 购物车管理
    path('carts/', views.CartsView.as_view(), name='info'),
    # 选择购物车商品
    path('carts/selection/', views.CartsSelectAllView.as_view()),
    # 简单购物车
    path('carts/simple/', views.CartsSimpleView.as_view()),
]


#############################################################################
# compiler_wrapper.py
#
# Authors: Anurag
#
# Provides a wrapper interface for the compiler process
# This includes programming language detection
#############################################################################

# ocr_wrapper
# Author: Anurag
# Return value: string of data
# Parameters:
#	1. compiler_input - text input
#	2. language - programming language
# This function is a wrapper for the entire Compiler Process

import subprocess
import os
import re
import docker

def compiler_wrapper(compiler_input, language):
	# Jenkins testing
	#return None
	# End Jenkins testing
	container = None
	line_numbers = []
	if language == "C":
		dockerCommand = ["/bin/sh", "-c", ("printf '" + compiler_input + "' > compile.c && gcc compile.c && ./a.out")]
		client = docker.from_env()
		error_r = False
		try:
			container = client.containers.run("frolvlad/alpine-gcc", command=dockerCommand, privileged=True, mem_limit="50m", cpuset_cpus="0")
		except docker.errors.ContainerError as e:
			error_r = True
			out_text = str(e.stderr.decode())
		if not error_r:
			out_text = str(container.decode())
		out_text = out_text.replace("./compile_c.sh: 2: ./a.out: not found\n", "")
		matches = re.findall("compile\.c:[0-9]+:[0-9]+:", out_text)
		for match in matches:
			temp_m = match.replace("compile.c:", "")
			temp_m = temp_m.split(':')
			if int(temp_m[0]) not in line_numbers:
				line_numbers += [int(temp_m[0])]
		return out_text, line_numbers
	elif language == "C++":
		dockerCommand = ["/bin/sh", "-c", ("printf '" + compiler_input + "' > compile.cpp && g++ compile.cpp && ./a.out")]
		client = docker.from_env()
		error_r = False
		out_text = ""
		try:
			container = client.containers.run("frolvlad/alpine-gxx", command=dockerCommand, privileged=True, mem_limit="50m", cpuset_cpus="0")
		except docker.errors.ContainerError as e:
			error_r = True
			out_text = str(e.stderr.decode())
		if not error_r:
			out_text = str(container.decode())
		out_text = out_text.replace("./compile_c.sh: 2: ./a.out: not found\n", "")
		matches = re.findall("compile\.cpp:[0-9]+:[0-9]+:", out_text)
		for match in matches:
			temp_m = match.replace("compile.cpp:", "")
			temp_m = temp_m.split(':')
			if int(temp_m[0]) not in line_numbers:
				line_numbers += [int(temp_m[0])]
		return out_text, line_numbers
	elif language == "C#":
		dockerCommand = ["/bin/sh", "-c", ("printf '" + compiler_input + "' > compile.cs && mcs compile.cs && mono compile.exe")]
		client = docker.from_env()
		error_r = False
		out_text = ""
		try:
			#container = client.containers.run("frolvlad/alpine-mono", command=dockerCommand, privileged=True)
			container = client.containers.run("mono", command=dockerCommand, privileged=True, mem_limit="50m", cpuset_cpus="0")
		except docker.errors.ContainerError as e:
			error_r = True
			out_text = str(e.stderr.decode())
		if not error_r:
			out_text = str(container.decode())
			out_text = out_text.replace("Microsoft (R) Visual C# Compiler version 3.6.0-4.20224.5 (ec77c100)\nCopyright (C) Microsoft Corporation. All rights reserved.\n\n", "")
		matches = re.findall("compile\.cs\([0-9]+,[0-9]+\):", out_text)
		for match in matches:
			temp_m = match.replace("compile.cs(", "")
			temp_m = temp_m.split(',')
			if int(temp_m[0]) not in line_numbers:
				line_numbers += [int(temp_m[0])]
		return out_text, line_numbers
	elif language.upper() == "JAVA":
		temp = compiler_input
		classn = ""
		if len(re.findall("class .* {", temp)) > 1:
			# Multiple classes
			pass
		else:
			# Only 1 class
			classn = re.findall("class .*? {", temp)
			if classn == []:
				return ("Unable to locate class in program. Please review your code.", [1])
			else:
				classn = classn[0]
			classn = classn.split(" ")[1]
		dockerCommand = ["/bin/sh", "-c", ("printf '" + compiler_input + "' > compile.java && javac compile.java && java " + classn)]
		client = docker.from_env()
		error_r = False
		out_text = ""
		try:
			container = client.containers.run("openjdk:11", command=dockerCommand, privileged=True, mem_limit="50m", cpuset_cpus="0")
		except docker.errors.ContainerError as e:
			error_r = True
			out_text = str(e.stderr.decode())
		if not error_r:
			out_text = str(container.decode())
		matches = re.findall("compile\.java:[0-9]+:", out_text)
		for match in matches:
			temp_m = match.replace("compile.java:", "")
			temp_m = temp_m.split(':')
			if int(temp_m[0]) not in line_numbers:
				line_numbers += [int(temp_m[0])]
		return out_text, line_numbers
	else:
		"Language Not Supported"
	return None, None

def main():
	# Testing function for pipeline
	print(compiler_wrapper('#include<stdio.h>\n\nint main(int argc, char *argv[]) {\nprintf ("Hello World") ;\nreturn 0;\n\n}', "C"))
	#print(compiler_wrapper('#include<stdio.h>\n#include<stdlib.h>\nint main(int argc, char *argv[]) {\nchar * a = malloc(sizeof(char) * 52000000);\na[51999999]="\0";\nprintf("%s\n", a);\nreturn 0;\n\n}', "C"))
	#print(compiler_wrapper("#include <iostream>\nint main() {\nstd::cout << \"Hello World\";\nreturn 0;\n}", "C++"))
	#print(compiler_wrapper("namespace HelloWorld {\nclass Hello {\n static void Main(string[] args) {\nSystem.Console.WriteLine(\"Hello World\");\n}\n}\n}", "C#"))
	print(compiler_wrapper("class BC { public void e() { } } class HelloWorld {\npwublic static void main(String[] args) {\nSystem.out.println(\"Hello World\");\n}\n}", "Java"))

if __name__ == "__main__":
	main()