#!/usr/bin/env python3

# Convert a DICOM file into plain text in a suitable format
# for passing into the anonymisation/annotations parts of SemEHR.
# Can alternatively read from the MongoDB dicom database instead of files.
# Usage: -y default.yaml -i input -o output
#  -y = path to the default.yaml file to get FileSystemRoot and Mongo
#  -i = input DICOM file, full path or relative to FileSystemRoot,
#       or if not found then looked up in the MongoDB.
#  -o = output filename or directory for the plain text file
#  -m = output filename or directory for metadata json file
#  --semehr-unique = only extract records from Mongo dicom database
#    if they are not already in the SemEHR database.
# Needs both dataLoad and dataExtract yaml files because Mongo is
# defined in the former and the rest in the latter.
# The Mongo definitions expected in yaml are:
#   MongoDatabases | DicomStoreOptions for reading records from
#     the dicom database instead of from DICOM files.
#   MongoDatabases | SemEHRStoreOptions for testing if the record
#     read from the dicom database already exists in the SemEHR db.

import argparse
import logging, logging.handlers
import os
import sys
import json
import yaml
import pydicom
import re
from deepmerge import Merger    # for deep merging yaml dictionaries
from SmiServices import Mongo
from SmiServices import Dicom
from SmiServices import DicomText
from SmiServices import StructuredReport as SR
from SmiServices import IdentifierMapper

# List of DICOM SR tags which we want exported in metadata json files
metadata_fields = [
  "SOPClassUID",
  "SOPInstanceUID",
  "StudyInstanceUID",
  "SeriesInstanceUID",
  "ContentDate",
  "ModalitiesInStudy",
  "PatientID", # this one will be mapped from CHI to EUPI
]

# ---------------------------------------------------------------------
# PatientID mapping from CHI to EUPI

def patientid_map(PatientID):
    """ Map patientid from CHI to EUPI using the database
    defined in the IdentifierMapper configuration yaml file.
    Returns "UNKNOWN" if there is no mapping or the database
    is not available.
    XXX Note that there's no error raised for database failure.
    """
    try:
        eupi = IdentifierMapper.CHItoEUPI().lookup(PatientID)
    except Exception as e:
        #print(e)
        eupi = None
    if not eupi:
        return 'UNKNOWN'
    return eupi

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

def extract_mongojson(mongojson, output, metadata_output=None, DicomTextArgs = None):
    """ Called by extract_mongojson_file
    to parse the JSON from Mongo and write to output.
    mongojson - the DICOM in JSON format.
    output - can be a directory or a filename.
    metadata_output - likewise.
    DicomTextArgs - can be a dict with options passed to StructuredReport
    ('replace_HTML_char' and 'replace_newline_char' in particular).
    """

    if not DicomTextArgs:
        DicomTextArgs = {}

    if os.path.isdir(output):
        filename = Dicom.tag_val(mongojson,'SOPInstanceUID', atomic=True) + '.txt'
        output = os.path.join(output, filename)
    if metadata_output and os.path.isdir(metadata_output):
        mfilename = Dicom.tag_val(mongojson,'SOPInstanceUID', atomic=True) + '.json'
        metadata_output = os.path.join(metadata_output, mfilename)
    logging.info('Parse %s' % mongojson.get('header',{}).get('DicomFilePath','<NoFilePath?>'))
    if 'PatientID' in mongojson:
        mongojson['PatientID'] = patientid_map(mongojson['PatientID'])
    with open(output, 'w') as fd:
        sr = SR.StructuredReport(**DicomTextArgs)
        sr.SR_parse(mongojson, filename, fd)
    if metadata_output:
        with open(metadata_output, 'w') as fd:
            print(json.dumps({k:mongojson[k] for k in metadata_fields if k in mongojson}), file=fd)
        logging.info(f'Wrote {metadata_output}')
    logging.info(f'Wrote {output}')

def extract_mongojson_file(input, output, metadata_output=None, DicomTextArgs = None):
    """ Read MongoDB data in JSON format from input file
    convert to output, which can be a filename or directory.
    input - filename containing DICOM data in JSON format
    output - can be a directory or a filename.
    metadata_output - likewise.
    DicomTextArgs - can be a dict with options passed to StructuredReport
    ('replace_HTML_char' and 'replace_newline_char' in particular).
    """
    with open(input, 'r') as fd:
        mongojson = json.load(fd)
    extract_mongojson(mongojson, output, metadata_output=metadata_output, DicomTextArgs = DicomTextArgs)

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

def extract_dicom_file(input, output, metadata_output=None, DicomTextArgs = None):
    """ Extract text from a DICOM file.
    input - filename of DICOM file.
    output - can be a directory or a filename.
    For a directory the file is named by its SOPInstanceUID.
    metadata_output - likewise.
    DicomTextArgs - can be a dict with options passed to DicomText
    ('replace_HTML_char' and 'replace_newline_char' in particular).
    """

    if not DicomTextArgs:
        DicomTextArgs = {}

    # Extract text using DicomText class
    dicomtext = DicomText.DicomText(input, **DicomTextArgs)
    dicomtext.parse()

    if os.path.isdir(output):
        filename = dicomtext.SOPInstanceUID() + '.txt'
        output = os.path.join(output, filename)
    if metadata_output and os.path.isdir(metadata_output):
        filename = dicomtext.SOPInstanceUID() + '.json'
        metadata_output = os.path.join(metadata_output, filename)
    with open(output, 'w') as fd:
        fd.write(dicomtext.text())
    if metadata_output:
        with open(metadata_output, 'w') as fd:
            metadata_json = {k:dicomtext.tag(k) for k in metadata_fields if dicomtext.tag(k)}
            metadata_json['PatientID'] = patientid_map(metadata_json.get('PatientID',''))
            print(json.dumps(metadata_json), file=fd)
        logging.info(f'Wrote {metadata_output}')
    logging.info(f'Wrote {output}')

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

def extract_file(input, output, metadata_output=None, DicomTextArgs=None):
    """ Extract text from a DICOM file or a JSON file (from MongoDB).
    input - filename of DICOM/JSON file.
    output - can be a directory or a filename.
    For a directory the file is named by its SOPInstanceUID.
    metadata_output - likewise.
    DicomTextArgs - can be a dict with options passed to DicomText
    ('replace_HTML_char' and 'replace_newline_char' in particular).
    Calls extract_dicom_file or extract_mongojson_file as appropriate.
    """
    try:
        pydicom.dcmread(input)
        is_dcm = True
    except:
        is_dcm = False

    if is_dcm:
        extract_dicom_file(input, output, metadata_output, DicomTextArgs = DicomTextArgs)
    else:
        extract_mongojson_file(input, output, metadata_output, DicomTextArgs = DicomTextArgs)

# ---------------------------------------------------------------------
if __name__ == '__main__':

    # Parse command line arguments
    parser = argparse.ArgumentParser(description='SR-to-Anon')
    parser.add_argument('-y', dest='yamlfile', action="append", help='path to yaml config file (can be used more than once)')
    parser.add_argument('-i', dest='input', action="store", help='SOPInstanceUID or path to raw DICOM file from which text will be redacted')
    parser.add_argument('-o', dest='output_dir', action="store", help='path to directory where extracted text will be written')
    parser.add_argument('-m', dest='metadata_dir', action="store", help='path to directory where extracted metadata will be written')
    parser.add_argument('--semehr-unique', dest='semehr_unique', action="store_true", help='only extract from MongoDB/dicom if not already in MongoDB/semehr')
    parser.add_argument('--replace-html', action="store", help='replace HTML with a character, default is dot (.), or "squash" to eliminate')
    parser.add_argument('--replace-newlines', action="store", help='replace carriage returns and newlines with a character (e.g. a space) or "squash" to eliminate')
    args = parser.parse_args()
    if not args.input:
        parser.print_help()
        exit(1)
    if not args.output_dir:
        args.output_dir = '.'

    cfg_dict = {}
    if not args.yamlfile:
        args.yamlfile = [os.path.join(os.environ['SMI_ROOT'], 'configs', 'smi_dataExtract.yaml')]
    for cfg_file in args.yamlfile:
        with open(cfg_file, 'r') as fd:
            # Merge all the yaml dicts into one
            cfg_dict = Merger([(list, ["append"]),(dict, ["merge"])],["override"],["override"]).merge(cfg_dict, yaml.safe_load(fd))

    # For reading SRs
    mongo_dicom_host = cfg_dict.get('MongoDatabases', {}).get('DicomStoreOptions',{}).get('HostName',{})
    mongo_dicom_user = cfg_dict.get('MongoDatabases', {}).get('DicomStoreOptions',{}).get('UserName',{})
    mongo_dicom_pass = cfg_dict.get('MongoDatabases', {}).get('DicomStoreOptions',{}).get('Password',{})
    mongo_dicom_db   = cfg_dict.get('MongoDatabases', {}).get('DicomStoreOptions',{}).get('DatabaseName',{})

    # For writing annotations
    mongo_semehr_host = cfg_dict.get('MongoDatabases', {}).get('SemEHRStoreOptions',{}).get('HostName',{})
    mongo_semehr_user = cfg_dict.get('MongoDatabases', {}).get('SemEHRStoreOptions',{}).get('UserName',{})
    mongo_semehr_pass = cfg_dict.get('MongoDatabases', {}).get('SemEHRStoreOptions',{}).get('Password',{})
    mongo_semehr_db   = cfg_dict.get('MongoDatabases', {}).get('SemEHRStoreOptions',{}).get('DatabaseName',{})

    log_dir = cfg_dict['LoggingOptions']['LogsRoot']
    root_dir = cfg_dict['FileSystemOptions']['FileSystemRoot']

    # ---------------------------------------------------------------------
    # Now we know the LogsRoot we can set up logging
    log_file_handler = logging.handlers.RotatingFileHandler(filename = os.path.join(log_dir,'SRAnonymiser.log'), maxBytes=64*1024*1024, backupCount=9)
    log_stdout_handler = logging.StreamHandler(sys.stdout)
    logging.basicConfig(level=logging.INFO, handlers=[log_file_handler, log_stdout_handler],
        format='[%(asctime)s] {%(filename)s:%(lineno)d} %(levelname)s - %(message)s')

    # ---------------------------------------------------------------------
    # Initialise the PatientID mapping by opening a DB connection
    if cfg_dict:
        try:
            IdentifierMapper.CHItoEUPI(cfg_dict)
        except:
            logging.warning('Cannot initialise CHI to EUPI mapping (check IdentifierMapperOptions and check database server)')

    # ---------------------------------------------------------------------
    # If the file is a DICOM then DicomText has options to change the output format.
    # These are passed to the DicomText and StructuredReport constructors.
    DicomTextArgs = {
        #'include_header' : True,
        #'replace_HTML_entities' : True,
        'replace_HTML_char' : '.',
        'replace_newline_char' : '\n'
    }
    if args.replace_html:
        DicomTextArgs['replace_HTML_char'] = args.replace_html
        if args.replace_html == "squash":
            DicomTextArgs['replace_HTML_char'] = ''
    if args.replace_newlines:
        DicomTextArgs['replace_newline_char'] = args.replace_newlines
        if args.replace_newlines == "squash":
            DicomTextArgs['replace_newline_char'] = ''

    # ---------------------------------------------------------------------
    if os.path.isfile(args.input):
        # actual path to DICOM
        extract_file(args.input, args.output_dir, args.metadata_dir, DicomTextArgs)
    elif os.path.isfile(os.path.join(root_dir, args.input)):
        # relative to FileSystemRoot
        extract_file(os.path.join(root_dir, args.input), args.output_dir, args.metadata_dir, DicomTextArgs)
    elif os.path.isdir(args.input):
        # Recurse directory
        for root, dirs, files in os.walk(args.input, topdown=False):
            for name in files:
                extract_file(os.path.join(root, name), args.output_dir, args.metadata_dir, DicomTextArgs)
    elif mongo_dicom_db != {}:
        # Only DicomFilePath and StudyDate are indexed in MongoDB.
        # Passing a SOPInstanceUID would be handy but no point if not indexed.
        mongodb_in = Mongo.SmiPyMongoCollection(mongo_dicom_host, mongo_dicom_user, mongo_dicom_pass)
        mongodb_in.setImageCollection('SR')
        mongodb_out = Mongo.SmiPyMongoCollection(mongo_semehr_host, mongo_semehr_user, mongo_semehr_pass)
        mongodb_out.setSemEHRCollection('semehr_results')
        # If it looks like a date YYYY/MM/DD or YYYYMMDD extract all on that day:
        if re.match('^\\s*\\d+/\\d+/\\d+\\s*$|^\\s*\\d{8}\\s*$', args.input):
            for mongojson in mongodb_in.StudyDateToJSONList(args.input):
                # If it's already in the annotation database then don't bother extracting.
                if not args.semehr_unique or not mongodb_out.findSOPInstanceUID(mongojson['SOPInstanceUID']):
                    extract_mongojson(mongojson, args.output_dir, args.metadata_dir, DicomTextArgs)
        # Otherwise assume a DICOM file path which can be retrieved from MongoDB
        else:
            mongojson = mongodb_in.DicomFilePathToJSON(args.input)
            extract_mongojson(mongojson, args.output_dir, args.metadata_dir, DicomTextArgs)
    else:
        logging.error(f'Cannot find {args.input} as file and MongoDB not configured')
        exit(1)


import pandas as pd
import numpy as np
from .helpers import wavelength_to_rgb
pd.options.mode.chained_assignment = None

def background_polynomial(data, data_to_fit, poly_order):
    # Fit background:
    polyCoefficients = np.polyfit(data_to_fit['time/s'], data_to_fit['I/mA'], poly_order)
    # add background current
    data['I_bckg/mA'] = np.array([np.sum(np.array([polyCoefficients[len(polyCoefficients) - i - 1] * (j ** i) for i in range(len(polyCoefficients))])) for j in data['time/s']])
    # add resultant current (after background correction)
    data['I_corr/mA'] = data['I/mA'] - data['I_bckg/mA']
    return data

def background_interpolated(data, data_to_fit, interp_points):
    # 1st interpolation
    data_bckg = pd.DataFrame()
    data_bckg['time/s'] = np.linspace(data['time/s'].min(), data['time/s'].max(), num=interp_points)
    data_bckg['I/mA'] = np.interp(data_bckg['time/s'], data_to_fit['time/s'], data_to_fit['I/mA'])
    # 2nd interpolation
    data['I_bckg/mA'] = np.interp(data['time/s'], data_bckg['time/s'], data_bckg['I/mA'])
    data['I_corr/mA'] = data['I/mA'] - data['I_bckg/mA']
    return data

def background_poly_roll(data, list_wavelengths, voltage, poly_order, n_pts_fit, n_pts_retention):
    # mapie variable for a I(lambda) for a given voltage
    mapie = pd.DataFrame({'voltage/V': pd.Series(dtype='float'),
                          'wavelength/nm': pd.Series(dtype='float'),
                          'photocurrent/mA': pd.Series(dtype='float64'),
                          'mean_background/mA': pd.Series(dtype='float64'),
                          'mean_current/mA': pd.Series(dtype='float64')})
    data_to_fit = pd.DataFrame()

    data['I_bckg/mA'] = np.NaN
    data['I_corr/mA'] = np.NaN
    # Fit backgrounds:
    for wavelength in list_wavelengths:
        #print(f'For {wavelength} the color is {wavelength_to_rgb(wavelength)}')
        # Index where peak starts and ends, Indexes for fit ranges
        index_min = data.loc[data['wavelength/nm'] == wavelength].idxmin()[0]
        index_max = data.loc[data['wavelength/nm'] == wavelength].idxmax()[0]
        i1 = index_min - n_pts_retention - n_pts_fit
        i2 = index_min - n_pts_retention
        i3 = index_max + n_pts_retention + 1
        i4 = index_max + n_pts_retention + n_pts_fit + 1
        # Select two ranges of bckg data (before and after peak), including number of points and retention
        data_to_fit_wavelength = data.loc[np.r_[i1 : i2, i3 : i4], :]
        poly_coeffs = np.polyfit(data_to_fit_wavelength['time/s'], data_to_fit_wavelength['I/mA'], poly_order)

        data['I_bckg/mA'].loc[i1:i4] = np.array([np.sum(np.array([poly_coeffs[len(poly_coeffs) - i - 1] * (j ** i) for i in range(len(poly_coeffs))])) for j in data['time/s'].loc[i1:i4]])
        # add resultant current (after background correction)
        data['I_corr/mA'].loc[i1:i4] = data['I/mA'] - data['I_bckg/mA']
        data_to_fit = pd.concat([data_to_fit, data_to_fit_wavelength])

        #photocurrent = data['I_corr/mA'].loc[i2:i3].median()
        photocurrent = data['I_corr/mA'].loc[i2:i3].mean()
        mean_background = data_to_fit_wavelength['I/mA'].loc[i1:i4].mean()
        mean_current = data['I/mA'].loc[i2:i3].mean()

        mapie = mapie.append({'voltage/V': voltage,
                              'wavelength/nm': wavelength,
                              'photocurrent/mA': photocurrent,
                              'mean_background/mA': mean_background,
                              'mean_current/mA': mean_current}, ignore_index=True)

    # add background current

    return [data, data_to_fit, mapie]


import tensorflow as tf
import tensorflow_addons as tfa

from nets.models.base import BaseTFKerasModel

@tf.keras.utils.register_keras_serializable("nets")
class GatedMixture(BaseTFKerasModel):
    """
    Gated mixture of experts.

    Takes raw inputs, passes them through each expert and gate
    layer pair, elementwise multiplies the pairs, and sums,
    returning a tensor of shape (batch_size, embedding_dim).

    Inheritors should define the expert models in the init method and
     assign a list of the experts to a `self._experts` attribute.
    """

    def __init__(self, n_experts, expert_dim, spectral_norm=False,
                 name="GatedMixture", **kwargs):

        super().__init__(name=name, **kwargs)

        self._n_experts = n_experts
        self._expert_dim = expert_dim
        self._spectral_norm = spectral_norm

        self._gate_layers = []

        for i in range(self._n_experts):
            dense_layer = tf.keras.layers.Dense(
                    units=expert_dim, activation="sigmoid"
            )
            if self._spectral_norm:
                dense_layer = tfa.layers.SpectralNormalization(
                            dense_layer
                )
            self._gate_layers.append(dense_layer)

    def call(self, inputs, training=True):

        outputs = None

        # Iterate over experts and gate layers, take the elementwise product
        # and add to the outputs sum vector.
        # AutoGraph convertible -- no side effects
        for expert, gate_layer in zip(self._experts, self._gate_layers):
            expert_output = expert.__call__(inputs)
            gates = gate_layer.__call__(inputs)
            gated_expert = tf.math.multiply(gates, expert_output)
            if outputs is None:
                outputs = gated_expert
            else:
                outputs = tf.math.add(outputs, gated_expert)

        return outputs

    def get_config(self):
        config = super().get_config()
        config.update({
            "n_experts": self._n_experts,
            "expert_dim": self._expert_dim,
            "spectral_norm": self._spectral_norm
        })
        return config

    @property
    def experts(self):
        return self._experts


from transformers import (
    RobertaForMaskedLM,
    RobertaForTokenClassification,
    AutoTokenizer
)
from collections import Counter

def load_roberta(model_path, mode="prompt"):
    tokenizer = AutoTokenizer.from_pretrained(model_path, use_fast=True, add_prefix_space=True, do_lower_case=False)
    if mode == "prompt-tuning":
        model = RobertaForMaskedLM.from_pretrained(model_path)
        tokenizer.model_max_length = model.config.max_position_embeddings - 2
        return tokenizer, model
    elif mode == "fine-tuning":
        model = RobertaForTokenClassification.from_pretrained(model_path)
        tokenizer.model_max_length = model.config.max_position_embeddings - 2
        return tokenizer, model
    else:
        raise NotImplementedError("Choose from prompt-tuning or fine-tuning")

def add_label_token_roberta(model, tokenizer, label_map, wo_label_words=False):
    sorted_add_tokens = sorted(list(label_map.keys()), key=lambda x: len(x), reverse=True)
    # tokenizer.add_tokens(sorted_add_tokens)
    num_tokens, _ = model.roberta.embeddings.word_embeddings.weight.shape
    model.resize_token_embeddings(len(sorted_add_tokens) + num_tokens)
    if wo_label_words:
        return model
    for token in sorted_add_tokens:
        if token.startswith('i-'):
            index = tokenizer.convert_tokens_to_ids(tokenizer.tokenize(token))
            if len(index) > 1:
                raise RuntimeError(f"{token} wrong split: {index}")
            else:
                index = index[0]
            # assert index >= num_tokens, (index, num_tokens, token)
            # n_label_word = len(list(set(label_map[token])))
            ws = label_map[token]
            print(tokenizer.convert_ids_to_tokens(ws))
            e_token = model.roberta.embeddings.word_embeddings.weight.data[ws[0]]
            for i in ws[1:]:
                e_token += model.roberta.embeddings.word_embeddings.weight.data[i]
            e_token /= len(ws)
            model.roberta.embeddings.word_embeddings.weight.data[index] = e_token

    return model


from flask import Flask, jsonify, request
from flask_cors import CORS
import main

app = Flask(__name__)
CORS(app)

@app.route('/summoner', methods=['GET'])
def get_summoner():
    summoner_name = request.args.get('summoner_name')
    region = request.args.get('region')
    api_key = request.args.get('api_key')
    summoner_info = main.get_summoner_info(summoner_name, region, api_key)
    return jsonify(summoner_info)

if __name__ == '__main__':
    app.run(debug=True)


# -*- coding: utf-8 -*-
from odoo.tests import common
from unittest.mock import patch

@common.tagged('post_install', '-at_install')
class TestWebSearchRead(common.TransactionCase):

    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        cls.ResCurrency = cls.env['res.currency'].with_context(active_test=False)
        cls.max = cls.ResCurrency.search_count([])

    def assert_web_search_read(self, expected_length, expected_records_length, expected_search_count_called=True,
                               **kwargs):
        original_search_count = self.ResCurrency.search_count
        search_count_called = [False]

        def search_count(obj, *method_args, **method_kwargs):
            search_count_called[0] = True
            return original_search_count(*method_args, **method_kwargs)

        with patch('odoo.addons.base.models.res_currency.Currency.search_count', new=search_count):
            results = self.ResCurrency.web_search_read(domain=[], specification={'id':{}}, **kwargs)

        self.assertEqual(results['length'], expected_length)
        self.assertEqual(len(results['records']), expected_records_length)
        self.assertEqual(search_count_called[0], expected_search_count_called)

    def test_unity_web_search_read(self):
        self.assert_web_search_read(self.max, self.max, expected_search_count_called=False)
        self.assert_web_search_read(self.max, 2, limit=2)
        self.assert_web_search_read(self.max, 2, limit=2, offset=10)
        self.assert_web_search_read(2, 2, limit=2, count_limit=2, expected_search_count_called=False)
        self.assert_web_search_read(20, 2, limit=2, offset=10, count_limit=20)
        self.assert_web_search_read(12, 2, limit=2, offset=10, count_limit=12, expected_search_count_called=False)


from fastapi import FastAPI, Request, HTTPException, status
from fastapi.responses import HTMLResponse, FileResponse, JSONResponse
import uvicorn
from sklearn.datasets import load_iris
from sklearn.naive_bayes import GaussianNB
from pydantic import BaseModel
from fastapi.staticfiles import StaticFiles
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import RedirectResponse
from fastapi.templating import Jinja2Templates

# Creating FastAPI instance
app = FastAPI(title="Movie API", openapi_url="/openapi.json")

app.mount("/static", StaticFiles(directory="static"), name="static")

templates = Jinja2Templates(directory="templates")

origins = ["*"]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Creating class to define the request body
# and the type hints of each attribute
class request_body(BaseModel):
    sepal_length : float
    sepal_width : float
    petal_length : float
    petal_width : float

@app.get("/")
async def login(request: Request)->HTMLResponse:
    context = {
        "request": request,
    }
    return templates.TemplateResponse("index.html", context=context)

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.metrics.pairwise import linear_kernel
from sklearn.metrics.pairwise import cosine_similarity
from ast import literal_eval
import json
from typing import Optional
import imdb
import requests

def search_movie_poster(movie_title):
    # Create an instance of the IMDb class
    ia = imdb.IMDb()

    # Search for the movie by title
    movies = ia.search_movie(movie_title)

    if movies:
        # Retrieve the first movie from the search results
        movie = movies[0]

        # Get the IMDb ID of the movie
        movie_id = movie.movieID

        # Fetch additional details for the movie
        ia.update(movie)

        # Retrieve the IMDb poster URL for the movie
        poster_url = movie.get('full-size cover url')

        if poster_url:
            return poster_url
        else:
            return None
    else:
        return None

@app.get("/get_movie_data")
async def get_movies()->JSONResponse:
    # credits_df = pd.read_csv("DATA/credits.csv")
    # movies_df = pd.read_csv("DATA/movies.csv")

    with open("DATA/json_files/movies.json") as file:
        data = json.load(file)

    # Create a DataFrame from the JSON data
    movies_df = pd.DataFrame(data)

    # Define the maximum number of entries to fetch
    max_entries = 200

    movie_data = []

    # Iterate over the limited number of rows in the DataFrame
    for _, row in movies_df.head(max_entries).iterrows():

        tmdb_id = row["tmdb_id"]
        imdb_id = row["imdb_id"]
        title = row["title"]
        original_title = row["original_title"]
        tagline = row["tagline"]
        overview = row["overview"]
        # "genre": [
        #     "Action",
        #     "Adventure",
        #     "Fantasy",
        #     "Science Fiction"
        # ],
        # "director": [],
        # "actors": [],
        release_year = str(row["release_year"])
        runtime = str(row["runtime"])
        language = row["language"]
        country = row["country"]
        poster_url = row["poster_url"]
        trailer_url = row["trailer_url"]
        revenue = str(row["revenue"])
        rating = str(row["rating"])
        popularity = str(row["popularity"])
        vote_average = str(row["vote_average"])
        vote_count = str(row["vote_count"])

        movie = {
            "tmdb_id": tmdb_id,
            "imdb_id": imdb_id,
            "title": title,
            "original_title": original_title,
            "tagline": tagline,
            "overview": overview,
            "release_year": release_year,
            "runtime": runtime,
            "language": language,
            "country": country,
            "poster_url": poster_url,
            "trailer_url": trailer_url,
            "revenue": revenue,
            "rating": rating,
            "popularity": popularity,
            "vote_average": vote_average,
            "vote_count": vote_count
        }

        movie_data.append(movie)

    return JSONResponse(content=movie_data)

from pydantic import BaseModel

class SwipeAction(BaseModel):
    id: int
    username: str
    swipeDirection: str

# use this for a users swipe to rank a movie by id
@app.post("/counter/")
def handle_swipe_action(swipe_action: SwipeAction):
    swipe_action_dict = swipe_action.dict()
    with open("DATA/ratings_test.json", "a") as outfile:
        json.dump(swipe_action_dict, outfile, indent=2)
        outfile.write(",\n")

    # print("Received swipe action:", swipe_action)
    return {"message": "Swipe action received"}
    # if item_id not in counters:
    #     counters[item_id] = {}

    # # Check if the username exists for the item ID
    # if username not in counters[item_id]:
    #     counters[item_id][username] = 0

    # # Increment or decrement the counter based on the 'increment' parameter
    # if increment:
    #     counters[item_id][username] += 1
    # else:
    #     counters[item_id][username] -= 1

    # return {"item_id": item_id, "username": username, "counter": counters[item_id][username]}


import math
import time
import collections

from sqlalchemy import func, or_, and_, desc
from sqlalchemy.orm import joinedload
from clld.db.meta import DBSession
from clld.db.models import common
from matplotlib.cm import viridis
from matplotlib.colors import to_hex

from gramfinder import models
from gramfinder.maps import SearchMap
from gramfinder import config

def vir(n):
    return to_hex(viridis(float(n)))

def search(ctx, req):
    doctypes = DBSession.query(models.Doctype).order_by(desc(models.Doctype.rank)).all()
    inlgs = {r.id: r for r in DBSession.query(models.Inlg)}
    ndocs = DBSession.query(models.Document).count()
    cutoff = 400 if ndocs > 1000 else 10
    selected_doctypes = {t.partition('-')[2] for t in req.params if t.startswith('dt-')} \
                        or ["grammar", "grammar_sketch"]
    tmpl = {
        'hits': [],
        'q': {},
        'inlgs': sorted([(r.id, r.description, r.ndocs) for r in inlgs.values() if r.ndocs > cutoff], key=lambda i: -i[2]) + [('any', 'All', ndocs)],
        'inlg_map': inlgs,
        'doctypes': [(dt, dt.id in selected_doctypes) for dt in doctypes],
    }

    s = time.time()
    print('searching ...')
    q = {t.partition('-')[2]: s for t, s in req.params.items() if t.startswith('query-') and s.strip()}
    if not q:
        return tmpl

    by_lg = collections.defaultdict(list)

    def qinlgtyp(q, inlg):
        if inlg == 'any':
            return config.tsearch(models.Page.terms, q, 'simple')
        return and_(models.Document.inlg_pk == inlgs[inlg].pk, config.tsearch(models.Page.terms, q, inlg))

    dt_id2pk = {dt.id: dt.pk for dt in doctypes}
    selected_doctypes = set(dt_id2pk[dt] for dt in selected_doctypes)
    res =  DBSession\
        .query(models.Document, func.count(models.Page.pk))\
        .join(models.Page) \
        .join(models.DocumentDoctype)\
        .filter(models.DocumentDoctype.doctype_pk.in_(selected_doctypes))\
        .filter(or_(*[qinlgtyp(term, inlg) for inlg, term in q.items()]))\
        .group_by(models.Document.pk, common.Source.pk)\
        .all()
    for doc, c in res:
        for lid in doc.langs.split():
            by_lg[lid].append((doc, c))

    occs = [sum(c for _, c in l) for l in by_lg.values()]
    if not occs:
        return tmpl

    min_occs, max_occs = min(occs), max(occs)
    occs = {c: math.log(c) for c in occs}
    min_log_occs = min(occs.values())
    max_log_occs = max(occs.values())
    colors = {
        o: vir(float(lo - min_log_occs) / (max_log_occs - min_log_occs) if max_log_occs > min_log_occs else 0)
        for o, lo in occs.items()}

    langs = {l.id: l for l in DBSession.query(common.Language)\
        .options(joinedload(models.GramfinderLanguage.family))\
        .filter(common.Language.id.in_(list(by_lg)))}
    #print(len(res))

    tmpl.update({
        'map': SearchMap(
            (
                [langs[lid] for lid in by_lg],
                {lid: colors[sum(c for _, c in hits)] for lid, hits in by_lg.items()},
                [(min_occs, vir(0)), (None, vir(0.25)), (None, vir(0.5)), (None, vir(0.75)), (max_occs, vir(1))],
            ),
            req),
        'hits': res,
        'q': q,
        'by_lg': by_lg,
        'langs': langs,
    })
    print('... done: {}'.format(time.time() - s))
    return tmpl


# Good morning! Here's your coding interview problem for today.

# This problem was asked by Stripe.

# Given an array of integers, find the first missing positive integer in linear time and constant space.

# In other words, find the lowest positive integer that does not exist in the array. The array can contain duplicates and negative numbers as well.

# For example, the input [3, 4, -1, 1] should give 2. The input [1, 2, 0] should give 3.

# You can modify the input array in-place

def findMissingPositiveNum(arr):
    containsOne = False
    arrLength = len(arr)

    # Update all the values that are
    # greater than N or less than 0
    # to be 1
    for i in range(arrLength):
        if arr[i] is 1:
            containsOne = True
        elif arr[i] < 1 or arr[i] > arrLength:
            arr[i] = 1

    # We know 1 is the smallest number possible and if it is not seen
    # that means we have to return 1
    if not containsOne:
        return 1

    # Mark all elements in the array that are within our range of 1->N
    # to be a negative number
    for i in range(arrLength):
        indexToUpdate = abs(arr[i]) - 1
        if arr[indexToUpdate] >= 0:
            arr[indexToUpdate] = -1

    # The first index that is not negative means, we have not seen it yet
    # is our smallest positive number
    for i in range(arrLength):
        if arr[i] > 0:
            return i+1

    # If we have seen all the numbers then that means we are missing the max number
    return arrLength + 1

print("result: " + str(findMissingPositiveNum([2, 3, -1])))


"""first.

Revision ID: de23d4edb0e2
Revises:
Create Date: 2021-12-20 11:41:48.292514
"""
import sqlalchemy as sa
from alembic import op

# revision identifiers, used by Alembic.
revision = "de23d4edb0e2"
down_revision = None
branch_labels = None
depends_on = None

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table(
        "tournaments",
        sa.Column("id", sa.Integer(), nullable=False),
        sa.Column("name", sa.String(length=255), nullable=False),
        sa.PrimaryKeyConstraint("id"),
    )
    op.create_table(
        "users",
        sa.Column("id", sa.Integer(), nullable=False),
        sa.Column("username", sa.String(length=255), nullable=False),
        sa.Column("password", sa.String(length=255), nullable=True),
        sa.Column("email", sa.String(length=255), nullable=True),
        sa.Column("verified", sa.Boolean(), nullable=True),
        sa.Column("firebase_id", sa.String(length=255), nullable=False),
        sa.PrimaryKeyConstraint("id"),
    )
    op.create_table(
        "user_tournaments",
        sa.Column("id", sa.Integer(), nullable=False),
        sa.Column("user_id", sa.Integer(), nullable=True),
        sa.Column("tournament_id", sa.Integer(), nullable=True),
        sa.ForeignKeyConstraint(
            ["tournament_id"],
            ["tournaments.id"],
        ),
        sa.ForeignKeyConstraint(
            ["user_id"],
            ["users.id"],
        ),
        sa.PrimaryKeyConstraint("id"),
    )
    # ### end Alembic commands ###

def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_table("user_tournaments")
    op.drop_table("users")
    op.drop_table("tournaments")
    # ### end Alembic commands ###


class Solution:
    def wordPattern(self, pattern: str, s: str) -> bool:
        d1, d2 = {}, {}
        words = s.split()

        if len(words) != len(pattern):
            return False

        for i in range(len(pattern)):
            char, word = pattern[i], words[i]
            if ((char in d1 and d1[char] != word) or (word in d2 and d2[word] != char)):
                return False
            else:
                d1[char], d2[word] = word, char
        return True


from django.shortcuts import render,get_object_or_404
from post.models import post
from subscribe.models import sub
from django.core.paginator import Paginator,EmptyPage,PageNotAnInteger
from django.db.models import Count,Q

def search(request):
	queryset=post.objects.all()
	searched=request.GET.get('q')
	if searched:
		find=queryset.filter(
			Q(title__icontains=searched) |
			Q(overview__icontains=searched)
			).distinct()
	context={'result':find}

	return render(request, 'search.html',context)

def get_cat_count():
	count=post.objects.values('cat__title').annotate(Count('cat'))

def index(request):
	ft=post.objects.filter(featured=True)
	latest=post.objects.order_by('-time')[0:3]
	if request.method == 'POST':
		email=request.POST['Email']
		reg=sub()
		reg.email=email
		reg.save()
	context={
		'post_data':ft,
		'latest':latest
	}
	return render(request,'index.html',context)

def blog(request):
	cat_count=get_cat_count()
	article = post.objects.all()
	pagination=Paginator(article,4)
	pg='page'
	page=request.GET.get(pg)
	latest=post.objects.order_by('-time')[0:4]
	try:
		set=pagination.page(page)
	except EmptyPage:
		set=pagination.page(Paginator.num_pages)
	except PageNotAnInteger:
		set = pagination.page(1)

	context={
		'post':set,
		'pg':pg,
		'latest':latest,
		'count':cat_count
	}
	return render(request,'blog.html',context)

def Post(request,id):
	data=get_object_or_404(post,id=id)
	latest=post.objects.order_by('-time')[0:4]
	context={
		"data":data,'latest':latest
	}
	return render(request,'post.html',context)


from ctypes import *
import cv2
from PyQt5 import QtWidgets, QtGui, QtCore
import numpy as np

# Carrega a biblioteca compartilhada contendo a função de filtro de mediana em C
mediana_lib = CDLL("./filtro_mediana.so")

# Define os tipos de argumentos e retorno para a função de filtro de mediana em C
mediana_lib.filtro_mediana.argtypes = [c_int, c_int, POINTER(c_ubyte), POINTER(c_ubyte)]
mediana_lib.filtro_mediana.restype = None

# Função de filtro de mediana em Python que chama a função de filtro de mediana em C
def filtro_mediana_c(image):
    width, height = image.shape[:2]
    data_in = image.ctypes.data_as(POINTER(c_ubyte))
    data_out = (c_ubyte * (width * height * 3))()
    mediana_lib.filtro_mediana(width, height, data_in, data_out)
    return np.ctypeslib.as_array(data_out, shape=(height, width, 3))

# Função de filtro de mediana em Python que aplica o filtro usando o OpenCV
def filtro_mediana_python(image):
    return cv2.medianBlur(image, 5)

#bibliotcas
#cv2 (OpenCV) é uma biblioteca de visão computacional muito utilizada em processamento de imagens e vídeos;
#PyQt5 é uma biblioteca que fornece uma interface gráfica para aplicações em Python;
#numpy é uma biblioteca de computação numérica utilizada em diversas aplicações, incluindo processamento de imagens.

#O método __init__ é chamado quando uma instância da classe é criada. Ele define o título da janela (self.setWindowTitle), o tamanho do vídeo (self.video_size)
# e chama o método setup_ui para configurar a interface gráfica.
#
#
class Interface(QtWidgets.QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setWindowTitle("Filtro da Mediana")
        self.video_size = QtCore.QSize(640, 480)
        self.setup_ui()

    def setup_ui(self):
        self.image_label = QtWidgets.QLabel()
        self.image_label.setFixedSize(self.video_size)

        self.quit_button = QtWidgets.QPushButton("Quit")
        self.quit_button.clicked.connect(self.close)

        self.filter_dropdown = QtWidgets.QComboBox()
        self.filter_dropdown.addItems(["Imagem_normal", "Imagem_sal_e_pimenta", "Filtro_mediana"])
        self.filter_dropdown.currentIndexChanged.connect(self.aplicando_filtro)

        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.image_label)
        layout.addWidget(self.filter_dropdown)
        layout.addWidget(self.quit_button)

        #pode ser uma função que recebe uma imagem como entrada e um filtro (kernel) para aplicar na imagem. Essa função usa a técnica de convolução para aplicar o filtro na imagem.

    def aplicando_filtro(self):
        filter_name = self.filter_dropdown.currentText()
        if filter_name == "Imagem_sal_e_pimenta":
            self.filtro_imagem(sal_e_pimenta)
        elif filter_name == "Filtro_mediana":
            self.filtro_imagem(filtro_mediana)
        else:
            self.filtro_imagem(lambda x: x)

    def filtro_imagem(self, filter_function):
        pixmap = self.image_label.pixmap()
        if pixmap is None:
            return

        image = pixmap.toImage()
        width, height = image.width(), image.height()
        image = image.convertToFormat(QtGui.QImage.Format_RGB888)
        ptr = image.constBits()
        ptr.setsize(image.byteCount())

        np_array = np.array(ptr).reshape(height, width, 3)

        np_array = filter_function(np_array)

        qt_image = QtGui.QImage(np_array.data, width, height, np_array.strides[0], QtGui.QImage.Format_RGB888)

        pixmap = QtGui.QPixmap.fromImage(qt_image)
        self.image_label.setPixmap(pixmap)

#sta função aplica um efeito de sal e pimenta aleatório à imagem. Isso é feito selecionando aleatoriamente alguns pixels e definindo seus valores de pixel para preto ou branco.
def sal_e_pimenta(image):
    probability = 0.08
    rand = np.random.rand(*image.shape[:2])
    mask = rand < probability / 2.
    image[mask, :] = 0
    out = np.copy(image)
    mask = rand > 1 - probability / 2.
    out[mask, :] = 255
    return out

def filtro_mediana(image):
    return cv2.medianBlur(image, 5)
#ste método é chamado quando uma instância da classe MainWindow é criada
class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.camera_widget = Interface()
        self.setCentralWidget(self.camera_widget)
        self._capture = None
        self.start_webcam()

    def start_webcam(self):
        self._capture = cv2.VideoCapture(0)
        self._capture.set(cv2.CAP_PROP_FRAME_WIDTH, self.camera_widget.video_size.width())
        self._capture.set(cv2.CAP_PROP_FRAME_HEIGHT, self.camera_widget.video_size.height())

        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self.update_frames)
        self.timer.start(5)

    def update_frames(self):
        ret, frame = self._capture.read()
        if ret:
            filter_name = self.camera_widget.filter_dropdown.currentText()
            if filter_name == "Imagem_sal_e_pimenta":
                frame = sal_e_pimenta(frame)
            self.camera_widget.image_label.setPixmap(QtGui.QPixmap.fromImage(
                QtGui.QImage(frame.data, frame.shape[1], frame.shape[0], QtGui.QImage.Format_RGB888)
            ))

    def closeEvent(self, event):
        self._capture.release()
        event.accept()

if __name__ == "__main__":
    app = QtWidgets.QApplication([])
    win = MainWindow()
    win.show()
    app.exec_()


"""
This file holds the trainer for the segmentation network.
"""

import argparse
import numpy as np
import os
import platform

# pytorch includes
import torch
import torch.nn as nn
import torchvision as tv
from torch.autograd import Variable
from torch.utils.data import DataLoader

# ml_utils includes
from general.utils import create_session_dir, retain_session_dir

# local includes
from datasets import RGBPatches
from cropunet import CropUNet
from utils import transform_cdl

pe = os.path.exists
pj = os.path.join
HOME = os.path.expanduser("~")
if platform.node() == "matt-XPS-8900":
    DATA = HOME
else:
    DATA = "/media/data"

def main(args):
    session_dir = os.path.dirname(args.data_dir_or_file)
    supdir = pj(session_dir, "segmentations")
    output_dir = create_session_dir(supdir, dir_stub="segment_%02d")

    dataset = RGBPatches(args.data_dir_or_file, args.labels_dir_or_file,
            mode="test")
    num_classes = dataset.get_num_cats()
#    loader = DataLoader(dataset,
#            batch_size=args.batch_size,
#            num_workers=8,
#            shuffle=True)
    model = CropUNet(num_classes=num_classes)
    model.load_state_dict( torch.load(args.model_path) )
    if args.use_cuda:
        model = model.cuda()
    model.eval()
    for i in range(len(dataset)):
        patch,label = dataset[i]
        patch.unsqueeze_(0)
        label,_ = transform_cdl(label.cpu().data.numpy())
        label = np.transpose(label, (2,0,1))
        label = torch.FloatTensor(label)
        if args.use_cuda:
            patch = Variable(patch).cuda()
            label = Variable(label).cuda()
        else:
            patch = Variable(patch)
            label = Variable(label)
        yhat = model(patch)
        preds = torch.argmax(yhat, dim=1).squeeze_()
        preds,_ = transform_cdl(preds.cpu().data.numpy())
        preds = np.transpose(preds, (2,0,1))
        preds = torch.FloatTensor(preds)
        if args.use_cuda:
            preds = Variable(preds).cuda()
        else:
            preds = Variable(preds)
        patch = patch.squeeze()
        tv.utils.save_image([patch, preds, label], pj(output_dir,
            "segments_%03d.png" % (i)))

    retain_session_dir(output_dir)

def _test_main(args):
    print("This function does not currently have any tests.")

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--test", action="store_true",
            help="If set, just run the test code")
    parser.add_argument("--mp", "--model-path", dest="model_path", type=str,
            default=pj(HOME, "Training/cropnet/models/seg_model.pkl"))
    parser.add_argument("-d", "--data-dir-or-file", type=str,
            default=pj(HOME, "Training/cropnet/sessions/session_07/feats.npy"))
    parser.add_argument("-l", "--labels-dir-or-file", type=str,
            default=pj(DATA, "Datasets/HLS/test_imgs/cdl/" \
                    "cdl_2016_neAR_0_0_500_500.npy"))
    parser.add_argument("--no-cuda", dest="use_cuda", action="store_false")
    args = parser.parse_args()
    if args.test:
        _test_main(args)
    else:
        main(args)


from _pytest.logging import LogCaptureFixture
import pytest

from pytest_mock import MockerFixture

from mock import AsyncMock

from pythclient.solana import SolanaAccount, SolanaPublicKey, SolanaClient

@pytest.fixture
def solana_pubkey() -> SolanaPublicKey:
    return SolanaPublicKey("AHtgzX45WTKfkPG53L6WYhGEXwQkN1BVknET3sVsLL8J")

@pytest.fixture
def solana_account(solana_pubkey: SolanaPublicKey, solana_client: SolanaClient) -> SolanaAccount:
    return SolanaAccount(
        key=solana_pubkey,
        solana=solana_client,
    )

@pytest.fixture()
def mock_get_account_info(mocker: MockerFixture) -> AsyncMock:
    async_mock = AsyncMock()
    mocker.patch('pythclient.solana.SolanaClient.get_account_info', side_effect=async_mock)
    return async_mock

def test_solana_account_update_with_rpc_response(solana_account: SolanaAccount) -> None:
    assert solana_account.slot is None
    assert solana_account.lamports is None

    slot = 106498726
    value = {
        "lamports": 1000000000
    }

    solana_account.update_with_rpc_response(slot=slot, value=value)

    assert solana_account.slot == slot
    assert solana_account.lamports == value["lamports"]

@pytest.mark.asyncio
async def test_solana_account_update_success(solana_account: SolanaAccount,
                                             mock_get_account_info: AsyncMock) -> None:

    mock_get_account_info.return_value = {'context': {'slot': 93752509}, 'value': {'lamports': 1000000001}}

    await solana_account.update()
    assert solana_account.slot == mock_get_account_info.return_value['context']['slot']
    assert solana_account.lamports == mock_get_account_info.return_value['value']['lamports']

@pytest.mark.asyncio
async def test_solana_account_update_fail(solana_account: SolanaAccount,
                                          mock_get_account_info: AsyncMock,
                                          caplog: LogCaptureFixture,
                                          solana_pubkey: SolanaPublicKey) -> None:
    mock_get_account_info.return_value = {'value': {'lamports': 1000000001}}
    exc_message = f'error while updating account {solana_pubkey}'
    await solana_account.update()
    assert exc_message in caplog.text

@pytest.mark.asyncio
async def test_solana_account_update_null(solana_account: SolanaAccount,
                                          mock_get_account_info: AsyncMock,
                                          caplog: LogCaptureFixture,
                                          solana_pubkey: SolanaPublicKey,) -> None:
    mock_get_account_info.return_value = {'context': {'slot': 93752509}}
    exc_message = f'got null value from Solana getAccountInfo for {solana_pubkey}; ' \
        + f'non-existent account? {mock_get_account_info.return_value}'
    await solana_account.update()
    assert exc_message in caplog.text

def test_solana_account_str(solana_account: SolanaAccount) -> None:
    actual = str(solana_account)
    expected = f"SolanaAccount ({solana_account.key})"
    assert actual == expected


import unittest
import numpy as np  # type: ignore
from tffm2 import TFFMClassifier, TFFMRegressor
import tensorflow as tf  # type: ignore

class TestFM(unittest.TestCase):

	def setUp(self):
		# Reproducibility.
		np.random.seed(0)

		n_samples = 20
		n_features = 10

		self.X = np.random.randn(n_samples, n_features)
		self.y = np.random.binomial(1, 0.5, size=n_samples)
		self.w = np.ones_like(self.y).astype(np.float32)
		self.dataset = tf.data.Dataset.from_tensor_slices({"X": self.X.astype(np.float32), "y": self.y.astype(np.float32), "w": self.w}).batch(1000)

	def classifier(self, use_diag):
		model = TFFMClassifier(
			order=4,
			rank=10,
			optimizer=tf.keras.optimizers.Adam(learning_rate=0.1),
			n_epochs=1,
			init_std=1.0,
			seed=0,
			use_diag=use_diag
		)
		return model

	def regressor(self, use_diag):
		model = TFFMRegressor(
			order=4,
			rank=10,
			optimizer=tf.keras.optimizers.Adam(learning_rate=0.1),
			n_epochs=0,
			init_std=1.0,
			seed=0,
			use_diag=use_diag
		)
		return model

	def decision_function_order_4(self, model, X, y):
		model.fit(X_train=X, y_train=y)
		b = model.intercept
		w = model.weights

		desired = self.bruteforce_inference(self.X, w, b, use_diag=model.core.use_diag)

		actual = model.decision_function(X)

		actual_np = np.reshape([l["pred_raw"] for l in actual], [-1])

		np.testing.assert_almost_equal(actual_np, desired, decimal=4)

	def test_FM_classifier(self):
		X = self.X.astype(np.float32)
		self.decision_function_order_4(self.classifier(use_diag=False), X, self.y)

	def test_PN_classifier(self):
		X = self.X.astype(np.float32)
		self.decision_function_order_4(self.classifier(use_diag=True), X, self.y)

	def test_FM_regressor(self):
		X = self.X.astype(np.float32)
		self.decision_function_order_4(self.regressor(use_diag=False), X, self.y)

	def test_PN_regressor(self):
		X = self.X.astype(np.float32)
		self.decision_function_order_4(self.regressor(use_diag=True), X, self.y)

	def test_FM_classifier_dataset(self):
		self.decision_function_order_4(self.classifier(use_diag=False), self.dataset, None)

	def test_FM_regressor_dataset(self):
		self.decision_function_order_4(self.regressor(use_diag=False), self.dataset, None)

	def test_saving_model(self):
		model = self.regressor(use_diag=False)
		model.fit(X_train=self.dataset, y_train=self.y)
		model.save("./saved_model/")

	def test_loading_model(self):
		imported = tf.saved_model.load("./saved_model/")
		pred = imported(self.X).numpy()
		assert pred.shape == (20, 1)

	def bruteforce_inference_one_interaction(self, X, w, order, use_diag):
		n_obj, n_feat = X.shape
		ans = np.zeros(n_obj)
		if order == 2:
			for i in range(n_feat):
				for j in range(0 if use_diag else i + 1, n_feat):
					x_prod = X[:, i] * X[:, j]
					w_prod = np.sum(w[1][i, :] * w[1][j, :])
					denominator = 2.0 ** (order - 1) if use_diag else 1.0
					ans += x_prod * w_prod / denominator
		elif order == 3:
			for i in range(n_feat):
				for j in range(0 if use_diag else i + 1, n_feat):
					for k in range(0 if use_diag else j + 1, n_feat):
						x_prod = X[:, i] * X[:, j] * X[:, k]
						w_prod = np.sum(w[2][i, :] * w[2][j, :] * w[2][k, :])
						denominator = 2.0 ** (order - 1) if use_diag else 1.0
						ans += x_prod * w_prod / denominator
		elif order == 4:
			for i in range(n_feat):
				for j in range(0 if use_diag else i + 1, n_feat):
					for k in range(0 if use_diag else j + 1, n_feat):
						for ell in range(0 if use_diag else k + 1, n_feat):
							x_prod = X[:, i] * X[:, j] * X[:, k] * X[:, ell]
							w_prod = np.sum(w[3][i, :] * w[3][j, :] * w[3][k, :] * w[3][ell, :])
							denominator = 2.0 ** (order - 1) if use_diag else 1.0
							ans += x_prod * w_prod / denominator
		else:
			assert False
		return ans

	def bruteforce_inference(self, X, w, b, use_diag):
		assert len(w) <= 4
		ans = X.dot(w[0]).flatten() + b
		if len(w) > 1:
			ans += self.bruteforce_inference_one_interaction(X, w, 2, use_diag)
		if len(w) > 2:
			ans += self.bruteforce_inference_one_interaction(X, w, 3, use_diag)
		if len(w) > 3:
			ans += self.bruteforce_inference_one_interaction(X, w, 4, use_diag)
		return ans

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


# encoding = utf-8
# author : renlei
# Reference: 统计学习方法
'''
Test accuary = 0.8975
cost time = 1.2083406448364258
'''
import numpy as np
import time
# mnist 数据集的特征 在区间[0,1]之间
# 这里为了便于实现贝叶斯估计，对特征进行二值化
# 设置阈值为 0.5 ，大于0.5是1，小于0.5是0
# 其中每个样本 (x, y) 中特征都是784列
def load_mnist(txt_data):
    f = open(txt_data, 'r')
    fr = f.readlines()
    dataArr = []
    for line in fr:
        feats = line.strip().split(',')
        tmpList = []
        for feat in feats[:-1]:
            if float(feat) >= 0.5:
                tmpList.append(1)
            else:
                tmpList.append(0)
        tmpList.append(int(feats[-1]))
        dataArr.append(tmpList)
    f.close()
    return np.array(dataArr)

def train_test_split(data, train_rate):
    Idx = np.arange(len(data))
    np.random.shuffle(Idx) # shuffle in-place
    trainIdx, testIdx = Idx[:round(train_rate*len(data))], Idx[round(train_rate*len(data)):]
    train, test = data[trainIdx], data[testIdx]
    return train, test

class Bayes(object):
    def __init__(self):
        return

    def getProbaility(self, x_train, y_train):
        sampleNum, self.featNum= x_train.shape
        label, uniqueFeat = np.unique(y_train), np.unique(x_train)
        self.labelNum, self.featNum = len(label), len(uniqueFeat)
        # 根据式 4.11计算p_y
        self.p_y = [0]*self.labelNum
        for y in y_train:
            self.p_y[y] += 1
        for ck in range(self.labelNum):
            self.p_y[ck] = (self.p_y[ck]+1)/(sampleNum+self.labelNum)

        #计算条件概率 Px_y=P（X=x|Y = y）
        #计算条件概率分成了两个步骤，下方第一个大for循环用于累加，
        #参考书中“4.2.3 贝叶斯估计 式4.10”，下方第一个大for循环内部是
        #用于计算式4.10的分子，至于分子的+1以及分母的计算在下方第二个大For内
        #初始化为全0矩阵，用于存放所有情况下的条件概率
        self.p_xy = np.zeros((self.labelNum, self.featNum, self.featNum))
        for i in range(sampleNum):
            curX = x_train[i]
            curY = y_train[i]
            for j in range(self.featNum):
                self.p_xy[curY, j, curX[j]] += 1

        #第二个大for，计算式4.10的分母，以及分子和分母之间的除法
        #循环每一个标记（共10个）
        for ck in range(self.labelNum):
            #循环每一个标记对应的每一个特征
            for j in range(self.featNum):
                #获取y=ck，第j个特诊为0的个数
                Px_y0 = self.p_xy[ck][j][0]
                #获取y=ck，第j个特诊为1的个数
                Px_y1 = self.p_xy[ck][j][1]
                #对式4.10的分子和分母进行相除，再除之前依据贝叶斯估计，
                #分母需要加上uniqueself.featNum（2）
                #分别计算对于y= ck，x第j个特征为0和1的条件概率分布
                self.p_xy[ck][j][0] = np.log((Px_y0 + 1) / (Px_y0 + Px_y1 + 2))
                self.p_xy[ck][j][1] = np.log((Px_y1 + 1) / (Px_y0 + Px_y1 + 2))

        return np.log(self.p_y), self.p_xy
    #转换为log对数形式
    #最后求后验概率估计的时候，形式是各项的相乘（“4.1 朴素贝叶斯法的学习” 式4.7），
    # 这里存在两个问题：
    # 1.某一项为0时，结果为0.这个问题通过分子和分母加上一个相应的数可以排除，前面已经做好了处理。
    # 2.如果特诊特别多（例如在这里，需要连乘的项目有784个特征
    #加一个先验概率分布一共795项相乘，所有数都是0-1之间，结果一定是一个很小的接近0的数。）
    # 理论上可以通过结果的大小值判断， 但在程序运行中很可能会向下溢出无法比较，因为值太小了。
    # 所以人为把值进行log处理。log在定义域内是一个递增函数，也就是说log（x）中，
    #x越大，log也就越大，单调性和原数据保持一致。
    # 所以加上log对结果没有影响。此外连乘项通过log以后，可以变成各项累加，简化了计算。

    def train(self, x_train, y_train):
        self.p_y, self.p_xy = self.getProbaility(x_train, y_train)
        return
    def getMaxPro(self, x_test):
        p = [0]*self.labelNum
        for ck in range(self.labelNum):
            p[ck] += self.p_y[ck]
            for j in range(self.featNum):
                p[ck] += self.p_xy[ck][j][x_test[j]]
        # 找到该概率最大值对应的索引
        return np.argmax(p)
    def test(self, x_test, y_test):
        errCnt = 0
        for ix, x_te in enumerate(x_test):
            if y_test[ix] == self.getMaxPro(x_te): errCnt += 1
        acc = 1-errCnt/len(x_test)
        print("Test accuary = {}".format(acc))
        return

if __name__ == "__main__":
    start = time.time()
    data = load_mnist('./_Data/mnist.txt')
    Train, Test= train_test_split(data, 0.8)
    bay = Bayes()
    bay.train(Train[:,:-1], Train[:,-1])
    bay.test(Test[:,:-1],Test[:,-1])
    end = time.time()
    print("cost time = {}".format(end-start))


# Create a method that decrypts reversed-order.txt

def decrypt(file_name, result_file_name):
  try:
    with open(file_name, 'r') as source_file:
      with open(result_file_name, 'a') as result_file:
        line_list = source_file.readlines()
        result_file.write(''.join(reverse_order(line_list)))
  except Exception as e:
    print(f'Error occurs when do decrypt {file_name}: {e}')

def reverse_order(line_list):
  return line_list[::-1]

decrypt('reversed_order.txt', 'reversed_order_result.txt')


import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, Dataset
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import json
from collections import Counter

# Load the features from the JSON file
with open('./features.json', 'r') as f:
    data = json.load(f)

# Extract features and labels from the data
features = [item['features'] for item in data]
labels = [item['label'] for item in data]

# Convert features and labels to PyTorch tensors
X_train_tensor = torch.tensor(features, dtype=torch.float32)
# Convert labels to unique indices
label_to_index = {label: i for i, label in enumerate(set(labels))}
y_train_tensor = torch.tensor([label_to_index[label] for label in labels], dtype=torch.long)

# Split the data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(features, labels, test_size=0.2, random_state=42)

# Define a simple classifier
class SimpleClassifier(nn.Module):
    def __init__(self, input_size, output_size):
        super(SimpleClassifier, self).__init__()
        self.fc = nn.Linear(input_size, output_size)

    def forward(self, x):
        return self.fc(x)

# Initialize the classifier
input_size = len(features[0])  # Assuming each feature vector has the same length
output_size = len(set(labels))  # Number of unique celebrity labels
classifier = SimpleClassifier(input_size, output_size)

# Calculate class weights
class_counts = Counter(labels)
class_weights = torch.tensor([1.0 / class_counts[label] for label in label_to_index], dtype=torch.float32)

# Normalize class weights
sum_weights = sum(class_weights)
class_weights_normalized = class_weights / sum_weights if sum_weights > 0 else class_weights

# Modify the loss function
criterion = nn.CrossEntropyLoss(weight=class_weights_normalized)
optimizer = optim.Adam(classifier.parameters(), lr=0.001)

# Train the model
epochs = 50
for epoch in range(epochs):
    optimizer.zero_grad()
    outputs = classifier(X_train_tensor)
    loss = criterion(outputs, y_train_tensor)
    loss.backward()
    optimizer.step()

# Evaluate the model
X_test_tensor = torch.tensor(X_test, dtype=torch.float32)
y_test_tensor = torch.tensor([label_to_index[label] for label in y_test], dtype=torch.long)

with torch.no_grad():
    test_outputs = classifier(X_test_tensor)
    _, predicted = torch.max(test_outputs, 1)
    accuracy = accuracy_score(y_test_tensor.numpy(), predicted.numpy())

# Save the model
torch.save(classifier.state_dict(), './resnet18New.pth')

print(f'Test Accuracy: {accuracy * 100:.2f}%')


class Board:
    def __init__(self):
        self.ROW = 20
        self.COL = 10
        self.score = 0
        self.grid = [[(128, 128, 128) for i in range(self.COL)] for j in range(self.ROW)]
        self.locked_pos = {}

    def reset_grid(self):
        self.grid = self.grid = [[(128, 128, 128) for i in range(self.COL)] for j in range(self.ROW)]

    def add_score(self, increment):
        self.score += increment

    def add_locked_position(self, pos_key, color):
        self.locked_pos[pos_key] = color

    def update_locked_pos(self, current_row_idx):
        keys_to_remove = []
        keys_to_modify_position = []
        for (row, col) in self.locked_pos:
            if row == current_row_idx:
                keys_to_remove.append((row, col))
            elif row < current_row_idx:
                keys_to_modify_position.append((row, col))

        for (r, c) in keys_to_remove:
            self.locked_pos.pop((r, c))
        for (r, c) in keys_to_modify_position:
            self.locked_pos[r + 1, c] = self.locked_pos.pop((r, c))

    # for grid operations
    def reset_grid_for_current_piece(self, piece):
        for (row, cow) in piece.occupy_positions:
            if self.ROW > row >= 0 and self.COL > cow >= 0:
                self.grid[row][cow] = (128, 128, 128)

    def update_grid_from(self, positions_map):
        for (row, col) in positions_map:
            self.grid[row][col] = positions_map[(row, col)]

    def is_removable_row(self, row_idx):
        occupied_cell_count = 0
        for i in range(len(self.grid[row_idx])):
            if self.grid[row_idx][i] != (128, 128, 128):
                occupied_cell_count += 1
        return occupied_cell_count == 10

    def remove_curr_row(self, row):
        empty_row = [(128, 128, 128) for i in range(self.COL)]
        self.grid.pop(row)
        self.grid.insert(0, empty_row)

    def clear_rows_and_get_scores(self, rows_to_check):
        curr_round_score = 0
        for r in rows_to_check:
            if self.is_removable_row(r) is True:
                self.remove_curr_row(r)
                self.update_locked_pos(r)
                curr_round_score += 10
        self.score += curr_round_score


import tensorflow as tf
import tensorflow.keras as tfk
from ..utils.metrics import AOP

class ProtectedClassifier(tfk.Model):
    def __init__(self, classifier, discriminator):
        super(ProtectedClassifier, self).__init__()
        self.classifier = classifier
        self.softmax = tfk.Sequential(classifier.layers[-1:])
        self.softmax.build(classifier.layers[-2].output_shape)
        self.discriminator = discriminator
        self.beta = tf.Variable(1., trainable=False, name="beta", validate_shape=False)

        self.loss_tracker = tfk.metrics.Mean(name='loss')
        self.classification_loss_tracker = tfk.metrics.Mean(name='cce')
        self.discriminator_loss_tracker = tfk.metrics.Mean(name='disc_bce')
        self.accuracy_tracker = tfk.metrics.CategoricalAccuracy(name="accuracy")

        self.val_loss_tracker = tfk.metrics.Mean(name='val_loss')
        self.val_classification_loss_tracker = tfk.metrics.Mean(name='val_cce')
        self.val_discriminator_loss_tracker = tfk.metrics.Mean(name='val_disc_bce')
        self.val_accuracy_tracker = tfk.metrics.CategoricalAccuracy(name="val_accuracy")
        self.val_auc_mia_tracker = tfk.metrics.AUC(name="val_auc_mia")
        self.aop_tracker = AOP(name="val_aop")

    @property
    def metrics(self):
        return[
            self.loss_tracker,
            self.classification_loss_tracker,
            self.discriminator_loss_tracker,
            self.accuracy_tracker,

            self.val_loss_tracker,
            self.val_classification_loss_tracker,
            self.val_discriminator_loss_tracker,
            self.val_accuracy_tracker,
            self.val_auc_mia_tracker,
            self.aop_tracker
        ]

    def compile(self, optimizer):
        super(ProtectedClassifier, self).compile()
        self.optimizer = optimizer

    @tf.function
    def train_step(self,data):

        train, test = data
        images, labels = train
        test_images, test_labels = test

        # step to optimize the classifier
        with tf.GradientTape() as tape:
            predictions = self.classifier(images)

            cce_extended_loss = tfk.losses.categorical_crossentropy(labels,predictions)
            cce_loss = tf.reduce_mean(cce_extended_loss)
            step_loss = cce_loss

        grads = tape.gradient(step_loss, self.classifier.trainable_weights)
        self.optimizer.apply_gradients(zip(grads, self.classifier.trainable_weights))
        del tape

        # step to protect the classifier
        with tf.GradientTape() as tape:
            predictions = self.classifier(images)

            cce_extended_loss = tfk.losses.categorical_crossentropy(labels,predictions)
            cfce_extended_loss = tfk.losses.categorical_focal_crossentropy(labels,predictions)
            ch_extended_loss = tfk.losses.categorical_hinge(labels,predictions)

            mi_data = tf.concat([
                predictions,
                tf.expand_dims(cce_extended_loss,axis=-1),
                tf.expand_dims(cfce_extended_loss,axis=-1),
                tf.expand_dims(ch_extended_loss,axis=-1),
                tf.expand_dims(tf.cast(tf.argmax(labels,axis=1),tf.float32),axis=1)],axis=-1)
            # Inverted label
            mi_data = tf.where(tf.math.is_nan(mi_data), 0., mi_data)
            mi_labels = tf.ones((tf.shape(mi_data)[0],1))

            test_predictions = self.classifier(test_images)

            test_cce_extended_loss = tfk.losses.categorical_crossentropy(test_labels,test_predictions)
            test_cfce_extended_loss = tfk.losses.categorical_focal_crossentropy(test_labels,test_predictions)
            test_ch_extended_loss = tfk.losses.categorical_hinge(test_labels,test_predictions)

            test_mi_data = tf.concat([
                test_predictions,
                tf.expand_dims(test_cce_extended_loss,axis=-1),
                tf.expand_dims(test_cfce_extended_loss,axis=-1),
                tf.expand_dims(test_ch_extended_loss,axis=-1),
                tf.expand_dims(tf.cast(tf.argmax(test_labels,axis=1),tf.float32),axis=1)],axis=-1)
            # Inverted label
            test_mi_data = tf.where(tf.math.is_nan(test_mi_data), 0., test_mi_data)
            test_mi_labels = tf.zeros((tf.shape(test_mi_data)[0],1))

            mi_data = tf.concat((mi_data,test_mi_data),axis=0)
            mi_labels = tf.concat((mi_labels,test_mi_labels),axis=0)

            disc_predictions = self.discriminator(mi_data)
            disc_bce = tf.reduce_mean(tfk.losses.binary_crossentropy(mi_labels,disc_predictions))
            disc_bce = tf.where(tf.math.is_nan(disc_bce), 0., disc_bce)
            step_loss = disc_bce * self.beta

        grads = tape.gradient(step_loss, self.softmax.trainable_weights)
        self.optimizer.apply_gradients(zip(grads, self.softmax.trainable_weights))

        loss = cce_loss + step_loss

        self.loss_tracker.update_state(loss)
        self.classification_loss_tracker.update_state(cce_loss)
        self.discriminator_loss_tracker.update_state(disc_bce)
        self.accuracy_tracker.update_state(labels,predictions)

        return{
            "loss": self.loss_tracker.result(),
            "cce": self.classification_loss_tracker.result(),
            "disc_bce": self.discriminator_loss_tracker.result(),
            "accuracy": self.accuracy_tracker.result(),
            "beta": self.beta
        }

    @tf.function
    def test_step(self,data):
        images, labels = data

        val, train = data
        val_images, val_labels = val
        train_images, train_labels = train

        val_predictions = self.classifier(val_images)

        val_cce_extended_loss = tfk.losses.categorical_crossentropy(val_labels,val_predictions)
        val_cfce_extended_loss = tfk.losses.categorical_focal_crossentropy(val_labels,val_predictions)
        val_ch_extended_loss = tfk.losses.categorical_hinge(val_labels,val_predictions)
        val_cce_loss = tf.reduce_mean(val_cce_extended_loss)

        val_mi_data = tf.concat([
            val_predictions,
            tf.expand_dims(val_cce_extended_loss,axis=-1),
            tf.expand_dims(val_cfce_extended_loss,axis=-1),
            tf.expand_dims(val_ch_extended_loss,axis=-1),
            tf.expand_dims(tf.cast(tf.argmax(val_labels,axis=1),tf.float32),axis=1)],axis=-1)
        # Correct label
        val_mi_data = tf.where(tf.math.is_nan(val_mi_data), 0., val_mi_data)
        val_mi_labels = tf.ones((tf.shape(val_mi_data)[0],1))

        train_predictions = self.classifier(train_images)

        train_cce_extended_loss = tfk.losses.categorical_crossentropy(train_labels,train_predictions)
        train_cfce_extended_loss = tfk.losses.categorical_focal_crossentropy(train_labels,train_predictions)
        train_ch_extended_loss = tfk.losses.categorical_hinge(train_labels,train_predictions)
        train_mi_data = tf.concat([
            train_predictions,
            tf.expand_dims(train_cce_extended_loss,axis=-1),
            tf.expand_dims(train_cfce_extended_loss,axis=-1),
            tf.expand_dims(train_ch_extended_loss,axis=-1),
            tf.expand_dims(tf.cast(tf.argmax(train_labels,axis=1),tf.float32),axis=1)],axis=-1)
        # Correct label
        train_mi_data = tf.where(tf.math.is_nan(train_mi_data), 0., train_mi_data)
        train_mi_labels = tf.zeros((tf.shape(train_mi_data)[0],1))

        val_mi_data = tf.concat((val_mi_data,train_mi_data),axis=0)
        val_mi_labels = tf.concat((val_mi_labels,train_mi_labels),axis=0)

        val_disc_predictions = self.discriminator(val_mi_data)
        val_disc_bce = tf.reduce_mean(tfk.losses.binary_crossentropy(val_mi_labels,val_disc_predictions))
        val_disc_bce = tf.where(tf.math.is_nan(val_disc_bce), 0., val_disc_bce)

        val_loss = val_cce_loss + val_disc_bce * self.beta

        self.val_loss_tracker.update_state(val_loss)
        self.val_classification_loss_tracker.update_state(val_cce_loss)
        self.val_discriminator_loss_tracker.update_state(val_disc_bce)
        self.val_accuracy_tracker.update_state(val_labels,val_predictions)
        self.val_auc_mia_tracker.update_state(val_mi_labels,val_disc_predictions)
        self.aop_tracker.update_state(self.val_accuracy_tracker.result(),self.val_auc_mia_tracker.result(),10)

        return{
            "loss": self.val_loss_tracker.result(),
            "cce": self.val_classification_loss_tracker.result(),
            "disc_bce": self.val_discriminator_loss_tracker.result(),
            "accuracy": self.val_accuracy_tracker.result(),
            "auc_mia": self.val_auc_mia_tracker.result(),
            "aop": self.aop_tracker.result()
        }

    def call(self, data):
        return self.classifier(data)


#!/usr/bin/env python

# data analysis example program
# Including some examples of how to use DataFrames from pandas
#
# Usage :
# python analysis.py -i test.dat

import pickle
import numpy as np
import matplotlib.pyplot as plt
import argparse

from event import Event, Pulse

parser = argparse.ArgumentParser(description='Analyse CSV file')
parser.add_argument("-i", "--in_file", help="input file")
parser.add_argument("-o", "--out_file", help='output file')
parser.add_argument("-n", "--n_max", help='max number of lines to process')

args = parser.parse_args()

print("Starting analysis")

# open the file
ifile = open(args.in_file, 'rb')
events= pickle.load(ifile)
n_events= len(events)

print("Read {} events from file".format(n_events))

# example event loop
count = [0, 0, 0, 0]  # counts per channel

for event in events:
    for pulse in event.pulses:
        # only count rising edges
        if pulse.edge == 0:
            count[pulse.chan] += 1

print("Counts by channel")
print("Channel 0 : {} ".format(count[0]))
print("Channel 1 : {} ".format(count[1]))
print("Channel 2 : {} ".format(count[2]))
print("Channel 3 : {} ".format(count[3]))

# now find concidences betwen two channels (0 and 1)
n_coinc = 0
for event in events:
    found0 = False
    found1 = False
    for pulse in event.pulses:
        # only count rising edges
        if pulse.edge==0 and pulse.chan == 0:
            found0 = True
        if pulse.edge==0 and pulse.chan == 1:
            found1 = True
    if found0 and found1:
        n_coinc += 1

print("N (0,1) coincidences : {}".format(n_coinc))

# get some pulse time information
dts = []
for event in events:
    found0 = False
    found1 = False
    time0 = 0.
    time1 = 0.
    for pulse in event.pulses:
        # only count rising edges
        if pulse.edge==0 and pulse.chan == 0:
            found0 = True
            time0 = pulse.time
        if pulse.edge==0 and pulse.chan == 1:
            found1 = True
            time1 = pulse.time
    if found0 and found1:
        dts.append(abs(time1-time0))

# print some summary info
print("Mean delta-t : {}".format(np.mean(dts)))
print("Std dev delta-t : {}".format(np.std(dts)))

bins = np.linspace(0.,2000., 100)
plt.hist(dts, bins)
plt.yscale('log')
plt.ylabel("N")
plt.xlabel(r'$\Delta t$')
plt.show()


# You are given a string s representing an attendance record for a student where each character signifies whether the student was absent, late, or present on that day. The record only contains the following three characters:
# 'A': Absent.
# 'L': Late.
# 'P': Present.
# The student is eligible for an attendance award if they meet both of the following criteria:
# The student was absent ('A') for strictly fewer than 2 days total.
# The student was never late ('L') for 3 or more consecutivedays.
# Return true if the student is eligible for an attendance award, or false otherwise.
# Example 1:
# Input: s = "PPALLP"
# Output: true
# Explanation: The student has fewer than 2 absences and was never late 3 or more consecutive days.
# Example 2:
# Input: s = "PPALLL"
# Output: false
# Explanation: The student was late 3 consecutive days in the last 3 days, so is not eligible for the award.

#Pseudo:
    #Count "a's"
        #if not more than 2,
        #return false
    #Check consecutive L's:
        #use sliding window
        #brute force = slices

#brute force version

# def attendance(record):
#     c_A = record.count('A')

#     if c_A > 1:
#         return False

#     c_L = 0
#     for i in range(len(record)):
#         if record[i] == 'L':
#             c_L += 1
#         if c_L == 3:
#             return False
#         if record[i] != 'L':
#             c_L = 0

#     return True

# print(attendance("PPALLL"))

#sliding window  (optimal of three because only one loop, but all three O(n)):

def attendance(record):
    c_A = 0
    c_L = 0

    for i in range(len(record)):
        if record[i] == 'A':
            c_A += 1
        if c_A > 1:
            return False
        if record[i] == 'L':
            c_L += 1
        if c_L == 3:
            return False
        if record[i] != 'L':
            c_L = 0

    return True

print(attendance('PPALLP'))

# more compact double loop
# def attendance(record):

#     return False if 'LLL' in record or record.count('A') > 1 else True

# print(attendance('PPALLP'))


from flask import Flask, render_template, request, redirect, flash
from flask_debugtoolbar import DebugToolbarExtension
from utility import append_data,load_data

app = Flask(__name__)

app.config["SECRET_KEY"] = 'whateverpassword'
app.config["SEND_FILE_MAX_AGE_DEFAULT"] = 0
tales = load_data()

@app.route('/')
def main_page():
    return render_template('main.html')

@app.route('/create_story')
def create_story():
    return render_template('create_story.html')

@app.route('/create_story', methods=['POST'])
def post_story():
    title = request.form["title"]
    story = request.form["story"]
    append_data(title,story)
    flash("Story was created...","success")
    return redirect('/')

@app.route('/choose_story')
def madlibs_select():
    global tales
    tales = load_data()
    titles = tales
    return render_template('choose_story.html', titles=titles)

@app.route('/form')
def madlibs_form():
    val = request.args.get('story')
    words = tales[int(val)].prompts
    return render_template('form.html',words=words, val=val)

@app.route('/your_story/<int:val>')
def your_story(val):
    text = tales[val].generate(request.args)
    return render_template('story.html',story=text)


from setuptools import setup, find_packages

requirements = [
    'numpy >=1.14.6',
    'scipy >=1.1.0',
]

setup_requires = [
    'numpy',
    'scipy'
]

setup(
    name = 'clayton',
    version = '0.0.3',
    description = 'Sampling from copulae',
    long_description=open('README.md', 'r').read(),
    author = 'Alexis Boulin',
    author_email = 'aboulin@unice.fr',
    url = 'https://github.com/Aleboul/clayton',
    download_url = 'https://github.com/Aleboul/clayton/',
    classifiers = [],
    include_package_data=True,
    packages=find_packages()
)


import ivy_local as ivy

def mrca(t, tids):
    db = t._db
    q = "select min(next), max(back) from {} where id in ({})".format(
        t._tablename, ','.join([ str(x) for x in tids ]))
    min_next, max_back = db.executesql(q)[0]
    q = (t.next<min_next)&(t.back>max_back)
    return db(q).select(orderby=t.back,limitby=(0,1)).first()

def subtree(t, tids):
    """
    return an ivy tree (root node) representing the taxonomy subtree having
    tids (list of taxon uids) at its tips
    """
    db = t._db
    Node = ivy.tree.Node
    q = "select next, back from {} where id in ({}) order by next asc".format(
        t._tablename, ','.join([ str(x) for x in tids ]))
    v = db.executesql(q)
    q = "select id, parent, name from ott_node where ({}) order by next asc"
    v = [ "(next <= {} and back >= {})".format(nxt, bck) for nxt, bck in v ]
    q = q.format(" or ".join(v))
    rows = db.executesql(q)
    nodes = [ Node(id=i, pid=p, name=n, label=n) for i, p, n in rows ]
    nodes[0].isroot = True
    id2node = dict([ (n.id, n) for n in nodes ])
    for n in nodes[1:]: id2node[n.pid].add_child(n)
    for n in nodes:
        if not n.children: n.isleaf = True


import os
from celery import Celery
from celery.schedules import crontab

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')

app = Celery('backend')

# Using a string here means the worker don't have to serialize
# the configuration object to child processes.
# - namespace='CELERY' means all celery-related configuration keys
#   should have a `CELERY_` prefix.
app.config_from_object('django.conf:settings', namespace='CELERY')

# Load task modules from all registered Django app configs.
app.autodiscover_tasks()

app.conf.beat_schedule = {
    # 'add-every-10-seconds': {
    #     'task': 'base.tasks.add',
    #     'schedule': 10.0,
    #     'args': (7,8)
    # },
    'check-expiry': {
        'task': 'base.tasks.check_expiry',
        'schedule': crontab(minute=0, hour=0), #every day at 12am
        'args': ()
    },

    'log-menuItemSold': {
        'task': 'base.tasks.log_menuItemSold',
        'schedule': crontab(minute=59, hour=11), #every day at 11:59am
        'args': ()
    },

    'calibrate-ingredient': {
        'task': 'base.tasks.calibrate_ingredient',
        'schedule': crontab(minute=0, hour=0), #every day at 12am
        'args': ()
    },
}


from tensorflow.python.keras.models import Sequential
from tensorflow.python.keras.layers import Dense, Conv2D,Flatten

model = Sequential()
model.add(Conv2D(7, (2,2),
                 padding='same',
                 input_shape=(8,8,1)))  #출력 : (N, 7, 7, 7) /
                                        #(batch_size, rows, columns, channels)
model.add(Conv2D(filters=4,             #아웃풋이 4개
                 kernel_size=(3,3),     #자르는 사이즈
                 activation = 'relu'))  #출력 : (N, 5 , 5 , 4)
model.add(Conv2D(10, (2,2)))            #출력 : (N, 4, 4 ,10)
model.add(Flatten())                    #출력 : (N, 4*4*10) -> (N, 160)
model.add(Dense(32, activation='relu'))
model.add(Dense(10, activation='relu'))
model.add(Dense(3, activation='softmax'))
model.summary()

# 30_1을 복붙
#padding=same 추가하니 (7,7,7) 패딩을 입어서 (8,8,7)로 바뀜
#padding=valid 추가하니 그대로임 디폴트값이 valid
#kernel_size가 늘어나면 패딩을 한겹씩 더 껴입음


import sys
import hashlib
import random
import statistics
import math
import time

def getParameters():
    try:
        u = sys.argv[1]
        k = sys.argv[2]
        c = sys.argv[3]
        widthOfConfidenceInterval = sys.argv[4]
        if (u is False or k is False or c is False or widthOfConfidenceInterval is False):
            print("Invalid parameters")
            print("Usage:", '"MicroMintSimulator u k c w"')
            print("For example:", '"python3 MicroMintSimulator.py 16 2 10000 22"')
            exit()
        else:
            return {"u":u, "k":k, "c":c, "woci": widthOfConfidenceInterval}
    except:
        print("Invalid parameters")
        print("Usage:", '"MicroMintSimulator u k c w"')
        print("For example:", '"python3 MicroMintSimulator.py 16 2 10000 22"')
        exit()

def throwBalls(k, u, c):
    bins = {} # Dictonary, compare to Map.
    mintedCoins = 0
    tossedBalls = 0

    while(mintedCoins < c):
        tossedBalls += 1
        binIndex = random.getrandbits(u)
        if(binIndex in bins):
            bins[binIndex] += 1 # If it exist we increment.
        else:
            bins[binIndex] = 1 # Otherwise add it.

        if(bins[binIndex] == k): # Bingo! we have a match and it is not used before
            mintedCoins +=1

    return tossedBalls

if __name__ == "__main__":
    parameters = getParameters()
    u = int(parameters["u"])
    k = int(parameters["k"])
    c = int(parameters["c"])
    widthOfConfidenceInterval = int(parameters["woci"])
    data = []
    simulationCounter = 0
    lambdaValue = 3.66
    calculatedWidth = widthOfConfidenceInterval + 1 # This way we will allways enter the while loop.
    print("Simulation starts!")
    start = time.time()
    while(calculatedWidth > widthOfConfidenceInterval):
        simulationCounter += 1
        data.append(throwBalls(k, u, c))
        if(len(data) < 2): # Without alleast 2 values we can't calculate deviation.
            continue
        if(simulationCounter % 20 is 0):
            mean = statistics.mean(data)
            deviation = statistics.stdev(data)
            minValue = mean - (lambdaValue * (deviation/math.sqrt(simulationCounter)))
            maxValue = mean + (lambdaValue * (deviation/math.sqrt(simulationCounter)))
            calculatedWidth = maxValue - minValue
            print("Width:", calculatedWidth)
    end = time.time()
    print("----------------------")
    print("The mean value is:", statistics.mean(data))
    print("Time elapsed:", (end - start) / 60, "minutes")


from django.urls import path

from . import views

urlpatterns = [
   path('create_report/', views.create_report),
   path('reports/', views.ReportListView.as_view(), name='reports'),
   path('report/<int:pk>', views.ReportDetailView.as_view(), name='report'),
   path('report/<int:pk>/edit', views.update_report_metrics, name='update_metric'),
   path('report/upload/', views.ExcelUploadView.as_view(), name='file_download'),
   path('report/search/', views.ReportSearchView.as_view(), name='search'),
   path('report/me', views.my_reports, name='my_reports')
]


"""survey URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/2.2/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
from django.views.generic import TemplateView
from rest_framework.schemas import get_schema_view
from rest_framework.schemas.openapi import SchemaGenerator

class TOSSchemaGenerator(SchemaGenerator):
    def get_schema(self, *args, **kwargs):
        schema = super().get_schema(*args, **kwargs)
        schema.update({
            "security": [
                {'ApiKeyAuth': []}
            ],
        })
        schema["components"].update({
                "securitySchemes": {
                    "ApiKeyAuth": {
                        "type": "apiKey",
                        "in": "header",
                        "name": "Authorization"
                    }
                }
        })
        return schema

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/v1/', include('main.urls')),
    path('swagger-ui/', TemplateView.as_view(
        template_name='main/swagger-ui.html',
        extra_context={'schema_url': 'openapi-schema'}
    ), name='swagger-ui'),
    path('openapi', get_schema_view(
        title="Survey",
        description="Survey API DOC",
        version="1.0.0",
        generator_class=TOSSchemaGenerator,
        public=True
    ), name='openapi-schema'),
    path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]


import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.autograd import Variable

device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')

class SiameseNetwork(nn.Module):
    def __init__(self, args):
        super(SiameseNetwork, self).__init__()

        C = args.output_num
        Ci = 1
        Co = args.kernel_num
        Ks = args.kernel_sizes
        D = args.embeding_dim
        self.embed = args.embed
        self.embed.weight.requires_grad = not args.static

        self.convs1 = nn.ModuleList([nn.Conv2d(Ci, Co, (K, D)) for K in Ks])

#         self.fc1 = nn.Sequential(
#             nn.Linear(len(Ks) * Co * 3, len(Ks) * Co * 3),
#             nn.ReLU(inplace=True),

#             nn.Linear(len(Ks) * Co * 3, len(Ks) * Co * 2),
#             nn.ReLU(inplace=True),

#             nn.Linear(len(Ks) * Co * 2, len(Ks) * Co),
#             nn.ReLU(inplace=True),

#             nn.Linear(len(Ks) * Co, len(Ks) * Co),
#             nn.ReLU(inplace=True),

#             nn.Linear(len(Ks) * Co, C),
#             nn.ReLU(inplace=True),
#             nn.Dropout(args.dropout),
#         )
        self.fc1 = nn.Sequential(
            nn.Linear(len(Ks) * Co * 3, len(Ks) * Co * 3),
            nn.ReLU(inplace=True),

            nn.Linear(len(Ks) * Co * 3, len(Ks) * Co),
            nn.ReLU(inplace=True),

            nn.Linear(len(Ks) * Co, len(Ks) * Co),
            nn.ReLU(inplace=True),
            nn.Dropout(args.dropout),

            nn.Linear(len(Ks) * Co, C)
        )

    def piece_pooling(self, x, e1_size, e2_size):
        e1_idx = e1_size
        e2_idx = x.size(2) - e2_size

        t1_tensor = x[:, :, :e1_idx]
        t2_tensor = x[:, :, e1_idx:e2_idx]
        t3_tensor = x[:, :, e2_idx:]

        pool_1 = F.max_pool1d(t1_tensor, t1_tensor.size(2)).squeeze(2)
        pool_2 = F.max_pool1d(t2_tensor, t2_tensor.size(2)).squeeze(2)
        pool_3 = F.max_pool1d(t3_tensor, t3_tensor.size(2)).squeeze(2)

        return torch.cat([pool_1, pool_2, pool_3], 1)

    def forward_once(self, x_list):
        e1_size = x_list[0].size(1)
        e2_size = x_list[2].size(1)

        x = torch.cat(x_list, 1)
        x = self.embed(x)  # (N, W, D)

        if self.embed.weight.requires_grad:
            x = Variable(x)

        x = x.unsqueeze(1)  # (N, Ci, W, D)
        x = [F.relu(conv(x)).squeeze(3) for conv in self.convs1]  # [(N, Co, W), ...] * len(Ks)
        x = [self.piece_pooling(i, e1_size, e2_size) for i in x]
        x = torch.cat(x, 1)
        output = self.fc1(x)

        return output

    def forward(self, input1, input2):
        output1 = self.forward_once(input1)
        output2 = self.forward_once(input2)
        return output1, output2

class ContrastiveLoss(nn.Module):
    """
    Contrastive loss function.
    Based on: http://yann.lecun.com/exdb/publis/pdf/hadsell-chopra-lecun-06.pdf
    """
    def __init__(self, margin=2.0):
        super(ContrastiveLoss, self).__init__()
        self.margin = margin

    def forward(self, output1, output2, label):
        euclidean_distance = F.pairwise_distance(output1, output2)
        loss_contrastive = torch.mean((1-label) * torch.pow(euclidean_distance, 2) +
                                      (label) * torch.pow(torch.clamp(self.margin - euclidean_distance, min=0.0), 2))
        return loss_contrastive


def get_arduino(port=None):
    """
    This is a PyFirmata 'helper' that tries to connect to an Arduino
    compatible board.

    If no port is informed, using pyserial's serial.tools.list_ports.comports(),
    if one port is found, tries that one. If more than one port is found,
    shows for the user to choose one. Returns None if no port is found or if the
    user cancels the dialog.

    If it successfully connects, it will return a pyfirmata Arduino object,
    but before that, it starts a pyfirmata.util.Iterator, and adds to the object
    both analog_read() and digital_read() functions that mimic Processing's
    Firmata library interface:
    Readings are never None, and analog pins return a value between 0 and 1023.
    """
    from pyfirmata import Arduino, util
    from serial.tools import list_ports

    comports = [comport.device for comport in list_ports.comports()]
    if not comports:
        print('No ports found.')
        return None
    elif isinstance(port, str) and port not in comports:
        print(f'Port "{port}" not found.')
        return None
    elif isinstance(port, int):
        if port >= len(comports):
            print(f'Port [{port}] not found.')
            return None
        else:
            port = comports[port]
    elif len(comports) == 1:
        port = comports[0]
    elif port is None:
        port = option_pane(
            'Where is your board?',
            'Please select the USB port where your '
            'Arduino compatible board is connected:',
            comports,
            -1)  # index for default option
        if port is None:
            print('No port selected.')
            return None
    try:
        print(f'Connecting to port {port}...')
        arduino = Arduino(port)
        util.Iterator(arduino).start()
    except Exception as e:
        print(repr(e))
        return None
    # Prepare analog_read() for A0 A1 A2 A3 A4 A5
    for a in range(6):
        arduino.analog[a].enable_reporting()
    arduino.analog_read = (lambda a: round(arduino.analog[a].read() * 1023)
                           if arduino.analog[a].read() is not None
                           else 0)
    # Prepare digital_read() for D2 to D13
    digital_pin_dict = {d: arduino.get_pin(f'd:{d}:i')
                        for d in range(2, 14)}
    for d in digital_pin_dict.keys():
        digital_pin_dict[d].enable_reporting()
    arduino.digital_read = (lambda d: digital_pin_dict[d].read()
                            if digital_pin_dict[d].read() is not None
                            else False)
    return arduino

def option_pane(title, message, options, default=None, index_only=False):
    """
    A helper for Java swing JOptionPane input dialog with drop down options.

    title     : str   - Dialog window's title (make it shorter than message).
    message   : str   - Text shown before the drop down.
    options   : list  - List of strings to show in the drop down.
    default   : int   - None or index to the pre-selected option in the list.
    index_only: False - Function returns an option string from the options list
                        provided, or None, if the dialog was cancelled;
                True  - Function returns the position index to the options list.
    """
    from javax.swing import JOptionPane

    if default is None:
        default = options[0]
    elif index_only:
        default = options[default]

    selection = JOptionPane.showInputDialog(
        None,     # frame
        message,
        title,
        JOptionPane.INFORMATION_MESSAGE,
        None,     # for Java null
        options,
        default)  # must be in options, otherwise first is shown
    if selection:
        if index_only:
            return options.index(selection)
        else:
            # Trouble: selection can be java.lang.String
            return str(selection) if selection else None


from turtle import *

def pentagon(turt):
    for i in range(5):
        turt.fd(200)
        turt.lt(72)

def rosetta(turt, n, angle):
    if n >= 21:
        return None
    else:
        pentagon(turt)
        turt.left(angle)
        rosetta(turt, n + 1, angle)

t = Turtle()
t.speed(0)
rosetta(t, 1, 360 / 20)

done()


import pandas as pd
pd.set_option('display.max_colwidth', -1)

df = pd.read_csv('jeopardy.csv')
print(df.head())

def count_rows(words, col):
  ct = 0
  for row in col:
    for word in words:
      if word in row:
        ct += 1
  return ct

ls = ["King", "England"]
count = count_rows(ls, df[' Question'])
print(count)

def clean(string):
  string = string.replace('$', '')
  string = string.replace(',', '')
  return string

def ave_val(col):
  ct = 0
  tot = 0
  for row in col:
    if row == "None":
      continue
    num = float(clean(row))
    tot += num
    ct += 1
  ave = tot / ct
  return ave

mean = ave_val(df[' Value'])
print(mean)

def unique_ans(words, col):
  ct = 0
  dt = {'num unique': 0}
  for row in col:
    for word in words:
      if word in row:
        dt['num unique'] += 1
        if row not in dt:
          dt[row] = 1
        else:
          dt[row] += 1
  return dt

ls = ["King"]
print(unique_ans(ls, df[' Answer']))


class Maksukortti:

    def __init__(self, saldo: float):
        self.saldo = saldo

    def lataa_rahaa(self, lisays: float):
        self.saldo += lisays

    def ota_rahaa(self, maara: float):
        if self.saldo >= maara:
            self.saldo -= maara
            return True
        else:
            return False

class Kassapaate:

    maukkaan_hinta = 4.3
    edullisen_hinta = 2.5

    def __init__(self):
        self.rahaa = 1000
        self.edulliset = 0
        self.maukkaat = 0

    def syo_edullisesti(self, maksu: float):
        if maksu >= self.edullisen_hinta:
            self.edulliset += 1
            self.rahaa += self.edullisen_hinta
            return maksu - self.edullisen_hinta
        else:
            return float(maksu)

    def syo_maukkaasti(self, maksu: float):
        if maksu >= 4.3:
            self.maukkaat += 1
            self.rahaa += self.maukkaan_hinta
            return maksu - self.maukkaan_hinta
        else:
            return float(maksu)

    def syo_edullisesti_kortilla(self, kortti:Maksukortti):
        if kortti.saldo >= self.edullisen_hinta:
            kortti.saldo -= self.edullisen_hinta
            self.edulliset += 1
            return True
        else:
            return False

    def syo_maukkaasti_kortilla(self, kortti:Maksukortti):
        if kortti.saldo >= self.maukkaan_hinta:
            kortti.saldo -= self.maukkaan_hinta
            self.maukkaat += 1
            return True
        else:
            return False

    def lataa_rahaa_kortille(self, kortti: Maksukortti, summa:float ):
        self.rahaa += summa
        kortti.lataa_rahaa(summa)

    def __repr__(self):
        return f"kassassa rahaa {self.rahaa} edullisia lounaita myyty {self.edulliset} maukkaita lounaita myyty {self.maukkaat}"

if __name__ == "__main__":

    unicafe_exactum = Kassapaate()
    print(unicafe_exactum)

    antin_kortti = Maksukortti(2)

    print(f"kortilla rahaa {antin_kortti.saldo} euroa")

    onnistuiko = unicafe_exactum.syo_maukkaasti_kortilla(antin_kortti)
    print("riittikö raha:", onnistuiko)

    unicafe_exactum.lataa_rahaa_kortille(antin_kortti, 100)

    onnistuiko = unicafe_exactum.syo_maukkaasti_kortilla(antin_kortti)
    print("riittikö raha:", onnistuiko)

    print(f"kortilla rahaa {antin_kortti.saldo} euroa")

    print(unicafe_exactum)


"""Utilities for reading and plotting ArcGIS binary files.

This module contains some simple functions to make it easier
to read and plot the data contained in the binary grid files
produced by ArcGIS.

"""
import sys
import numpy as np
from numpy import ma

def read_bin(fname):
    """Read data from a ArcGIS binary file into an array.

    Read the data from a binary file created by ArcGIS into
    a Numpy array. The file is expected to be in binary format
    with floating point precision. e.g. ".flt" extension.

    """

    f = open(fname, "rb")
    raw = f.read()
    f.close()
    data = np.fromstring(raw, 'f')
    if sys.byteorder == 'big':
        data = data.byteswap()

    return data

def read(bingrid_name):
    """Read the data field and headers from an ArcGIS binary grid

    This function reads the header and data from the ArcGIS binary
    data files produced by the "Raster to Float" tool in ArcGIS 9.1

    """

    if bingrid_name[-4:] == '.flt':
        hdr_name = bingrid_name[:-4]
        bin_name = bingrid_name
    else:
        hdr_name = bingrid_name
        bin_name = bingrid_name + '.flt'

    li_headers=read_headers(hdr_name)

    rows = li_headers[1]
    cols = li_headers[0]

    a = read_bin(bin_name)

    a = a.reshape(rows, cols)

    return a, li_headers

def read_headers(bingrid_name):
    """Read the ascii headers of the ArcGIS binary grid file

    The headers have the following format:

    ncols         62
    nrows         121
    xllcorner     -288595.47161281
    yllcorner     -3158065.5722693
    cellsize      1000
    NODATA_value  -9999
    byteorder     LSBFIRST
    """

    hdr_name = bingrid_name + '.hdr'
    f=open(hdr_name,'r')
    tab_read=f.readlines()
    f.close()

    li_headers=[]
    i=-1
    for line in tab_read:
        i=i+1
        donnees=line.split()
        if i<6:
            li_headers.append(float(donnees[1]))
        else:
            li_headers.append(donnees[1])

    return li_headers

def plot(bin_name, fig_name, title='Raster Plot'):
    """Create a plot of the data in an ArcGIS binary file."""
    import matplotlib.pyplot as plt

    a, headers = read(bin_name)

    a_mask = ma.masked_where(a < 0, a)
    plt.imshow(a_mask, interpolation='nearest')
    plt.colorbar()
    plt.title(title)
    plt.savefig(fig_name)
    plt.close()