import pygame as pg
from pygame import *
from OpenGL.GL import *
from OpenGL.GLU import *
import numpy as np
import random
from rectangle import RectangleMesh
from handle_json import write, clear_json

class App:

    def __init__(self):

        # initialize pygame for GUI
        pg.init()
        self.display = (512,512)
        self.screen = pg.display.set_mode(self.display, pg.OPENGL|pg.DOUBLEBUF) # tell pygame we run OPENGL & DOUBLEBUFFERING, one frame vis & one drawing
        pg.display.set_caption("Wireframe generator")

        # activation variables
        self.axes = 0
        self.screenshot = 1
        clear_json()

        # initialize OpenGL
        glClearColor(0,0,0,1)

        glMatrixMode(GL_PROJECTION) # activate projection matrix
        gluPerspective(45, self.display[0]/self.display[1], 0.1, 50)
        self.projectionmatrix = glGetDoublev(GL_PROJECTION_MATRIX)
        # draw wired rectangle
        self.rectangle = RectangleMesh(random.uniform(0.1,5), random.uniform(0.1,5), random.uniform(0.1,5), [0,0,0], [0,0,-15])
        self.rectangle.draw_wired_rect()

        self.mainLoop()

    def mainLoop(self):
        rect_name = 1
        img_number = 1 # counts the rectangle that is been shown
        img_shot = 1 # counts how many screenshots were taken

        running = True
        while(running):
            # Check for events
            for event in pg.event.get():

                if (event.type == pg.QUIT):
                    running = False

                if (event.type == KEYDOWN) and (event.key == K_s):
                    # enable screenshots
                    self.screenshot = not self.screenshot

                if (event.type == KEYDOWN) and (event.key == K_a):
                    # draw axes
                    self.axes = not self.axes

                if (event.type == KEYDOWN) and (event.key == K_RIGHT):

                    # random position of rectangle
                    self.rectangle.set_rotation(random.uniform(0,360), random.uniform(0,360), random.uniform(0,360))
                    self.rectangle.set_translation(random.uniform(-5,5), random.uniform(-5,5), random.uniform(-10,-20))
                    self.rectangle.draw_wired_rect()
                    pg.time.wait(60)

                    print(f"random rotation: {self.rectangle.eulers}")
                    print(f"random translation: {self.rectangle.position}")

                    # take screenshot && write rectangle data to CSV file
                    if (self.screenshot):

                        # calculate annotation
                        wc, pc, center = self.get_annotations(self.rectangle.modelview, self.projectionmatrix, glGetIntegerv(GL_VIEWPORT))
                        # check if rectangle valid
                        valid = self.object_on_screen(pc)
                        # write to json
                        write(rect_name, img_shot, self.rectangle.get_norm_dim(),  wc, pc, center, valid)

                        if (rect_name == img_number):
                            self.save_image(rect_name, img_shot)
                            img_shot += 1
                        else:
                            img_number += 1
                            rect_name = img_number
                            img_shot = 1
                            self.save_image(rect_name, img_shot)
                            img_shot += 1

                if (event.type == KEYDOWN) and (event.key == K_RETURN):
                    print("delete rectangle...")
                    del self.rectangle
                    # new size of rectangle
                    self.rectangle = RectangleMesh(random.uniform(0.1,5), random.uniform(0.1,5), random.uniform(0.1,5), [0,0,0], [0,0,-15])
                    print("created rectangle: ", self.rectangle.width, self.rectangle.height, self.rectangle.depth)
                    # rectangle name count
                    rect_name += 1

                # --- Drawing the scene --- #
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

                self.rectangle.draw_wired_rect()

                if (self.axes):
                    self.draw_axes()

                pg.display.flip()
                pg.time.wait(60)

        self.quit()

    def quit(self):
        pg.quit()

    def save_image(self, rect_name, img_shot):
        print("taking screenshot...")
        pixels = glReadPixels(0, 0, self.display[0], self.display[1], GL_RGB, GL_UNSIGNED_BYTE)
        image = pg.image.frombuffer(pixels, (self.display[0], self.display[1]), 'RGB') # read pixels from the OpenGL buffer
        #image = pg.transform.flip(image, False, True) # flip
        name = "wireframes\\img" + str(rect_name) + "_" + str(img_shot) + ".png"
        pg.image.save(image, name) # It then converts those pixels into a Pygame surface and saves it using pygame.image.save()

    def draw_axes(self):
        glPushMatrix()
        glTranslatef(0,0,-15)
        # X axis (red)
        glBegin(GL_LINES)
        glColor3f(1, 0, 0)
        glVertex3f(0, 0, 0)
        glVertex3f(5, 0, 0)
        glEnd()

        # Y axis (green)
        glBegin(GL_LINES)
        glColor3f(0, 1, 0)
        glVertex3f(0, 0, 0)
        glVertex3f(0, 5, 0)
        glEnd()

        # Z axis (blue)
        glBegin(GL_LINES)
        glColor3f(0, 0, 1)
        glVertex3f(0, 0, 0)
        glVertex3f(0, 0, 5)
        glEnd()
        glPopMatrix()

    def get_annotations(self, model_view, projection, viewport):
        # Calculate world and pixel cords of vertices rectangle
        world_coordinates = []
        pixel_coordinates = []
        center = []
        for vertex in self.rectangle.vertices:
            x_screen, y_screen, z =  gluProject(vertex[0], vertex[1], vertex[2], model_view, projection, viewport)
            pixel_coordinates.append((int(x_screen),int(y_screen)))
            x_world, y_world, z_world = gluUnProject( x_screen, y_screen, 0, model_view, projection, viewport)
            world_coordinates.append((x_world, y_world, z_world))

        print("pixel coordinates: ",pixel_coordinates)
        print("world coordinates: ",world_coordinates)

        # Calculate center
        x_screen, y_screen, z = gluProject(0, 0, 0, model_view, projection, viewport)
        x_world, y_world, z_world = gluUnProject( x_screen, y_screen, 0, model_view, projection, viewport)
        center.append((x_world, y_world, z_world))
        center.append((int(x_screen), int(y_screen)))

        return world_coordinates, pixel_coordinates, center

    def object_on_screen(self, projection_coordinates):
        for i in projection_coordinates:
            if (i[0] not in range(0,self.display[0]+1) or i[1] not in range(0,self.display[1]+1)):
                return "false"
            else:
                continue
        return "true"

if __name__ == "__main__":
    myApp = App()


from functools import reduce

from odoo import _, api, fields, models

class CrmPhonecall(models.Model):
    """Model for CRM phonecalls."""

    _name = "crm.phonecall"
    _description = "Phonecall"
    _order = "id desc"
    _inherit = ["mail.thread", "utm.mixin"]

    date_action_last = fields.Datetime(string="Last Action", readonly=True)
    date_action_next = fields.Datetime(string="Next Action", readonly=True)
    create_date = fields.Datetime(string="Creation Date", readonly=True)
    team_id = fields.Many2one(
        comodel_name="crm.team",
        string="Sales Team",
        index=True,
        help="Sales team to which Case belongs to.",
    )
    user_id = fields.Many2one(
        comodel_name="res.users",
        string="Responsible",
        default=lambda self: self.env.user,
    )
    partner_id = fields.Many2one(comodel_name="res.partner", string="Contact")
    company_id = fields.Many2one(comodel_name="res.company", string="Company")
    description = fields.Text()
    state = fields.Selection(
        [
            ("open", "Confirmed"),
            ("cancel", "Cancelled"),
            ("pending", "Pending"),
            ("done", "Held"),
        ],
        string="Status",
        tracking=3,
        default="open",
        help="The status is set to Confirmed, when a case is created.\n"
        "When the call is over, the status is set to Held.\n"
        "If the callis not applicable anymore, the status can be set "
        "to Cancelled.",
    )
    email_from = fields.Char(string="Email", help="These people will receive email.")
    date_open = fields.Datetime(string="Opened", readonly=True)
    name = fields.Char(string="Call Summary", required=True)
    active = fields.Boolean(required=False, default=True)
    duration = fields.Float(help="Duration in minutes and seconds.")
    tag_ids = fields.Many2many(
        comodel_name="crm.tag",
        relation="crm_phonecall_tag_rel",
        string="Tags",
        column1="phone_id",
        column2="tag_id",
    )
    partner_phone = fields.Char(string="Phone")
    partner_mobile = fields.Char("Mobile")
    priority = fields.Selection(
        selection=[("0", "Low"), ("1", "Normal"), ("2", "High")],
        default="1",
    )
    date_closed = fields.Datetime(string="Closed", readonly=True)
    date = fields.Datetime(default=lambda self: fields.Datetime.now())
    opportunity_id = fields.Many2one(comodel_name="crm.lead", string="Lead/Opportunity")
    direction = fields.Selection(
        [("in", "In"), ("out", "Out")], default="out", required=True
    )

    @api.onchange("partner_id")
    def _onchange_partner_id(self):
        """Contact number details should be change based on partner."""
        if self.partner_id:
            self.partner_phone = self.partner_id.phone
            self.partner_mobile = self.partner_id.mobile

    @api.onchange("opportunity_id")
    def _onchange_opportunity_id(self):
        """Based on opportunity, change contact, tags, partner, team."""
        if self.opportunity_id:
            self.team_id = self.opportunity_id.team_id.id
            self.partner_phone = self.opportunity_id.phone
            self.partner_mobile = self.opportunity_id.mobile
            self.partner_id = self.opportunity_id.partner_id.id
            self.tag_ids = self.opportunity_id.tag_ids.ids

    def write(self, values):
        """Override to add case management: open/close dates."""
        if values.get("state"):
            if values.get("state") == "done":
                values["date_closed"] = fields.Datetime.now()
                self.compute_duration()
            elif values.get("state") == "open":
                values["date_open"] = fields.Datetime.now()
                values["duration"] = 0.0
        return super().write(values)

    def compute_duration(self):
        """Calculate duration based on phonecall date."""
        phonecall_dates = self.filtered("date")
        phonecall_no_dates = self - phonecall_dates
        for phonecall in phonecall_dates:
            if phonecall.duration <= 0 and phonecall.date:
                duration = fields.Datetime.now() - phonecall.date
                values = {"duration": duration.seconds / 60.0}
                phonecall.write(values)
            else:
                phonecall.duration = 0.0
        phonecall_no_dates.write({"duration": 0.0})
        return True

    def get_values_schedule_another_phonecall(self, vals):
        res = {
            "name": vals.get("name"),
            "user_id": vals.get("user_id") or self.user_id.id,
            "description": self.description,
            "date": vals.get("schedule_time") or self.date,
            "team_id": vals.get("team_id") or self.team_id.id,
            "partner_id": self.partner_id.id,
            "partner_phone": self.partner_phone,
            "partner_mobile": self.partner_mobile,
            "priority": self.priority,
            "opportunity_id": self.opportunity_id.id,
            "campaign_id": self.campaign_id.id,
            "source_id": self.source_id.id,
            "medium_id": self.medium_id.id,
        }
        if vals.get("tag_ids"):
            res.update({"tag_ids": [(6, 0, vals.get("tag_ids"))]})
        return res

    def schedule_another_phonecall(self, vals, return_recordset=False):
        """Action :('schedule','Schedule a call'), ('log','Log a call')."""
        phonecall_dict = {}
        for call in self:
            values = call.get_values_schedule_another_phonecall(vals)
            new_id = self.create(values)
            if vals.get("action") == "log":
                call.write({"state": "done"})
            phonecall_dict[call.id] = new_id
        if return_recordset:
            return reduce(lambda x, y: x + y, phonecall_dict.values())
        else:
            return phonecall_dict

    def redirect_phonecall_view(self):
        """Redirect on the phonecall related view."""
        # Select the view
        tree_view_id = self.env.ref("crm_phonecall.crm_case_phone_tree_view").id
        form_view_id = self.env.ref("crm_phonecall.crm_case_phone_form_view").id
        search_view_id = self.env.ref(
            "crm_phonecall.view_crm_case_phonecalls_filter"
        ).id
        value = {}
        for call in self:
            value = {
                "name": _("Phone Call"),
                "view_type": "form",
                "view_mode": "tree,form",
                "res_model": "crm.phonecall",
                "res_id": call.id,
                "views": [
                    (form_view_id or False, "form"),
                    (tree_view_id or False, "tree"),
                    (False, "calendar"),
                ],
                "type": "ir.actions.act_window",
                "search_view_id": search_view_id or False,
            }
        return value

    def action_make_meeting(self):
        """Open meeting's calendar view to schedule a meeting on phonecall."""
        partner_ids = [self.env["res.users"].browse(self.env.uid).partner_id.id]
        res = {}
        for phonecall in self:
            if phonecall.partner_id and phonecall.partner_id.email:
                partner_ids.append(phonecall.partner_id.id)
            res = self.env["ir.actions.act_window"]._for_xml_id(
                "calendar.action_calendar_event"
            )
            res["context"] = {
                "default_phonecall_id": phonecall.id,
                "default_partner_ids": partner_ids,
                "default_user_id": self.env.uid,
                "default_email_from": phonecall.email_from,
                "default_name": phonecall.name,
            }
        return res

    def _prepare_opportunity_vals(self):
        return {
            "name": self.name,
            "partner_id": self.partner_id.id,
            "phone": self.partner_phone or self.partner_id.phone,
            "mobile": self.partner_mobile or self.partner_id.mobile,
            "email_from": self.partner_id.email,
            "team_id": self.team_id.id,
            "description": self.description,
            "priority": self.priority,
            "type": "opportunity",
            "campaign_id": self.campaign_id.id,
            "source_id": self.source_id.id,
            "medium_id": self.medium_id.id,
            "tag_ids": [(6, 0, self.tag_ids.ids)],
        }

    def action_button_convert2opportunity(self):
        """Convert a phonecall into an opp and redirect to the opp view."""
        self.ensure_one()
        opportunity = self.env["crm.lead"]
        opportunity_id = opportunity.create(self._prepare_opportunity_vals())
        self.write({"opportunity_id": opportunity_id.id, "state": "done"})
        return opportunity_id.redirect_lead_opportunity_view()


import argparse
import torch
import numpy as np
import pandas as pd
import os
import random

def normalize(array, axis=0):
    _min = array.min(axis=axis, keepdims=True)
    _max = array.max(axis=axis, keepdims=True)
    factor = _max - _min
    return (array - _min) / np.where(factor != 0, factor, 1)

def parse_click_history(history_list):
    clicks = list(map(lambda user_click: list(map(lambda item: item.split(':')[0],
                                                  user_click.split(','))),
                      history_list))
    _max_len = max(len(items) for items in clicks)
    clicks = [items + [0] * (_max_len - len(items)) for items in clicks]
    clicks = torch.tensor(np.array(clicks, dtype=np.long)) - 1
    return clicks

def parse_user_protrait(protrait_list):
    return torch.tensor(normalize(np.array(list(map(lambda x: x.split(','),
                                                    protrait_list)),
                                           dtype=np.float32)))

def process_item(filename, outdir):
    item_info = pd.read_csv(filename, ' ')
    item2id = np.array(item_info['item_id']) - 1
    item2loc = torch.tensor(np.array(item_info['location'], dtype=np.float32)[item2id])
    item2price = torch.tensor(normalize(np.array(item_info['price'], dtype=np.float32)[item2id]) * 10, dtype=torch.float32)
    item2feature = torch.tensor(normalize(np.array(list(map(lambda x: x.split(','),
                                               item_info['item_vec'])),
                                      dtype=np.float32)[item2id]))
    item2info = torch.cat([item2feature, item2price[:, None], item2loc[:, None]], dim=-1)
    torch.save([item2info, item2price, item2loc], os.path.join(outdir, 'items_info.pt'))

def process_data(filename, outdir, savename):
    dataset = pd.read_csv(filename, ' ')
    click_items = parse_click_history(dataset['user_click_history'])
    user_protrait = parse_user_protrait(dataset['user_protrait'])
    exposed_items = None
    if 'exposed_items' in dataset.columns:
        exposed_items = torch.tensor(np.array(list(map(lambda x: x.split(','),
                                                       dataset['exposed_items'])),
                                              dtype=np.long) - 1)
    torch.save([user_protrait, click_items, exposed_items],
               os.path.join(outdir, savename))

def main(args):
    print('processing items info ...')
    process_item(args.itemset, args.outdir)
    print('processing trainset ...')
    process_data(args.trainset, args.outdir, 'train.pt')
    print('processing devset ...')
    process_data(args.devset, args.outdir, 'dev.pt')
    print('processing testset ...')
    process_data(args.testset, args.outdir, 'test.pt')

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--trainset', required=True, type=str)
    parser.add_argument('--devset', required=True, type=str)
    parser.add_argument('--testset', required=True, type=str)
    parser.add_argument('--itemset', required=True, type=str)
    parser.add_argument('--outdir', required=True, type=str)
    args = parser.parse_args()

    if not os.path.exists(args.outdir):
        os.makedir(args.outdir, exists_ok=True)

    main(args)


"""Unit tests for Wikipedia Sourcelist Generator."""
from absl import flags
from absl.testing import absltest
from absl.testing import flagsaver
import wikipedia_sourcelist_generator as scraper

FLAGS = flags.FLAGS

class WikipediaSourcelistGeneratorTests(absltest.TestCase):
  def testChunkPageIds(self):
    results = scraper._chunk_page_ids([1, 2, 3, 4, 5, 6, 7], chunk_size=3)
    self.assertSameElements(results,
                              [[1, 2, 3], [4, 5, 6], [7]])

  def testChunkPageIdsEmptyList(self):
    results = scraper._chunk_page_ids([], chunk_size=3)
    self.assertEqual(results, [])

if __name__ == '__main__':
  # Pass flags to pass initial required flags check.
  FLAGS.num_images = 10
  FLAGS.outputdir = 'somedir'
  absltest.main()


#!/usr/bin/env python
# coding: utf-8

# In[7]:

# !pip install -q pandas
# !pip install -q streamlit
# !pip install -q matplotlib
# !pip install -q seaborn
# !pip install -q plotly
# !pip install -q geopandas

import streamlit as st
import pandas as pd
import matplotlib.pyplot as plt
import plotly.express as px
import seaborn as sns
import locale
import geopandas as gpd
import numpy as np
import altair as alt
import plotly.graph_objects as go

df = pd.read_csv('global-data-on-sustainable-energy (1).csv')
df.rename(columns={"Value_co2_emissions_kt_by_country":"CO2 Emissions"}, inplace=True)
df2 = df.dropna(subset=['Land Area(Km2)'])

# In[9]:

# Streamlit WebApp

# Set the theme settings
st.set_page_config(
    page_title="Sustainable Energy",
    page_icon="🌍♻",
    layout="wide",  # You can set the layout as per your preference
)

# Define your theme
st.markdown(
    f"""

    """,
    unsafe_allow_html=True
)

# # Set page config to wide layout
# st.set_page_config(layout="wide")

# Set the title of your Streamlit app
st.markdown("
Sustainable Energy
", unsafe_allow_html=True)

st.markdown(" ")
st.markdown(" ")
st.markdown(" ")
st.markdown(" ")
st.markdown(" ")
st.markdown(" ")
st.markdown(" ")

# Add a title to the sidebar
st.sidebar.markdown("
2022 Stats
", unsafe_allow_html=True)
st.sidebar.markdown(" ")
st.sidebar.markdown(" ")
st.sidebar.markdown(" ")
st.sidebar.markdown(" ")

# CO₂ Emissions Metric
st.sidebar.metric(label="Gloabl CO₂ Emissions", value="36.8 gigatons", delta="+0.9%")

st.sidebar.markdown(" ")
st.sidebar.markdown(" ")
st.sidebar.markdown(" ")

# Largest CO₂ Emissions Metric
st.sidebar.metric(label="Top Contributar to CO₂ Emissions", value="China")

st.sidebar.markdown(" ")
st.sidebar.markdown(" ")
st.sidebar.markdown(" ")

# Renewable Energy Electricity Generation Metric
st.sidebar.metric(label="Renewable Energy Electricity Generation", value="90%")

st.sidebar.markdown(" ")
st.sidebar.markdown(" ")
st.sidebar.markdown(" ")

# Visualization 1: Scatter Plot
st.markdown("
Renewable Energy Share in Consumption vs GDP
", unsafe_allow_html=True)

# Define the scatter plot
fig1 = px.scatter(
    df2,
    x='gdp_per_capita',
    y='Renewable energy share in the total final energy consumption (%)',
    size='Land Area(Km2)',
    size_max=50,
    hover_name='Entity',
    color='Continent',
    animation_frame='Year',
    animation_group='Entity',
    log_x=True,
    range_y=[0, 100],
    range_x=[100, 120000]
)

# Customize the layout
fig1.update_layout(
    width=1700,
    height=750,
)

# Display the scatter plot
st.plotly_chart(fig1)

st.markdown(" ")
st.markdown(" ")
st.markdown(" ")
st.markdown(" ")

# Visualization: Choropleth Map
st.markdown("
CO₂ Emissions per Capita
", unsafe_allow_html=True)

# Define custom colorscale
custom_colorscale = [
    [0.0, 'blue'],
    [0.0005, 'lightblue'],
    [0.001, 'lightcyan'],
    [0.08, 'lightgray'],
    [0.15, 'lightpink'],
    [0.3, 'lightcoral'],
    [0.5, 'salmon'],
    [0.75, 'orangered'],
    [0.9, 'red'],
    [1.0, 'darkred']
]

# Create the choropleth map
fig = px.choropleth(
    df,
    locations="Entity",
    locationmode="country names",
    color="CO2 Emissions",
    hover_name="Entity",
    animation_frame='Year',
    color_continuous_scale=custom_colorscale,
    projection='natural earth',
)

# Customize the color axis
fig.update_coloraxes(colorbar_title="CO₂ Emissions", cmin=0, cmax=10_000_000)

# Customize the layout
fig.update_layout(
    width=1700,
    height=750,
)

# Display the choropleth map
st.plotly_chart(fig)

st.markdown(" ")
st.markdown(" ")
st.markdown(" ")
st.markdown(" ")

# Visualization: Electricity Generation Over Time
st.markdown("
Global Electricity Generation Mix Over Time
", unsafe_allow_html=True)

# Group the data by year and aggregate the columns
grouped_df = df.groupby('Year').agg({
    'Electricity from fossil fuels (TWh)': 'sum',
    'Electricity from nuclear (TWh)': 'sum',
    'Electricity from renewables (TWh)': 'sum'
}).reset_index()

# Create a Figure
fig = go.Figure()

# Define distinct colors for each energy source
colors = {
    'Fossil Fuels': 'green',
    'Nuclear': 'red',
    'Renewables': 'blue'
}

# Add traces for each energy source
fig.add_trace(go.Scatter(x=grouped_df['Year'], y=grouped_df['Electricity from fossil fuels (TWh)'], fill='tozeroy', mode='none', name='Fossil Fuels', fillcolor=colors['Fossil Fuels']))
fig.add_trace(go.Scatter(x=grouped_df['Year'], y=grouped_df['Electricity from nuclear (TWh)'], fill='tonexty', mode='none', name='Nuclear', fillcolor=colors['Nuclear']))
fig.add_trace(go.Scatter(x=grouped_df['Year'], y=grouped_df['Electricity from renewables (TWh)'], fill='tonexty', mode='none', name='Renewables', fillcolor=colors['Renewables']))

# Customize the layout of the chart
fig.update_layout(xaxis_title="Year",
                  yaxis_title="Electricity Generation (TWh)",
                  showlegend=True)

fig.update_layout(
    width=1700,  # Set the width of the figure in pixels
    height=750,  # Set the height of the figure in pixels
)

# Display the chart in the Streamlit app
st.plotly_chart(fig)

st.markdown(" ")
st.markdown(" ")
st.markdown(" ")
st.markdown(" ")

st.markdown("
Access to Electricity Over Time (% of population)
", unsafe_allow_html=True)

# Create a filter for the continent
selected_continent = st.selectbox('Select Continent:', df['Continent'].unique())

# Filter the data based on the selected Continent
continent_filtered_df = df[df['Continent'] == selected_continent]

# Create a selectbox for filtering by Entity within the selected Continent
selected_entity = st.selectbox(f'Select Entity in {selected_continent}:', continent_filtered_df['Entity'].unique())

# Filter the data based on the selected Entity
filtered_df = continent_filtered_df[continent_filtered_df['Entity'] == selected_entity]

# Create the line chart
fig = px.line(filtered_df, x="Year", y="Access to electricity (% of population)", title=f"{selected_entity} ({selected_continent})")
fig.update_layout(xaxis_title="Year", yaxis_title="Access to Electricity (%)", width=1700, height=750)

# Display the line chart
st.plotly_chart(fig)


from Bio import SeqIO
import gzip
import numpy as np
import pandas as pd
import re
from tqdm import tqdm
import time
import random
import tools.funclib as funclib

#region 从gizp读取数据
def read_file_from_gzip(file_in_path, file_out_path, extract_type):
    """从原始Zip file 中解析数据

    Args:
        file_in_path ([string]): [输入文件路径]
        file_out_path ([string]): [输出文件路径]]
        extract_type ([string]): [抽取数据的类型：with_ec, without_ec, full]]
    """
    table_head = [  'id',
                    'name',
                    'isenzyme',
                    'isMultiFunctional',
                    'functionCounts',
                    'ec_number',
                    'ec_specific_level',
                    'date_integraged',
                    'date_sequence_update',
                    'date_annotation_update',
                    'seq',
                    'seqlength'
                ]
    counter = 0
    saver = 0
    reslist = []
    file_write_obj = open(file_out_path,'w')
    #reslist.append(['id', 'description', 'seq'])
    with gzip.open(file_in_path, "rt") as handle:
        file_write_obj.writelines('\t'.join(table_head))
        file_write_obj.writelines('\n')
        for record in tqdm( SeqIO.parse(handle, 'swiss')):
            res = process_record(record, extract_type= extract_type)
            counter+=1
            if counter %10==0:
                file_write_obj.flush()
            if saver%100000==0:
                print(saver)
            if len(res) >0:
                saver +=1
                file_write_obj.writelines('\t'.join(map(str,res)))
                file_write_obj.writelines('\n')
            else:
                continue

    file_write_obj.close()
    # result = pd.DataFrame(reslist, columns= table_head)
    # result.date_integraged = pd.to_datetime(result['date_integraged'])
    # result.date_sequence_update = pd.to_datetime(result['date_sequence_update'])
    # result.date_annotation_update = pd.to_datetime(result['date_annotation_update'])
    # result.sort_values(by='date_integraged', inplace=True)
    # result.to_csv(file_out_path, sep="\t", index=0, header=0 )

 #endregion

#region 提取单条含有EC号的数据
def process_record(record, extract_type='with_ec'):
    """
    提取单条含有EC号的数据
    Args:
        record ([type]): uniprot 中的记录节点
        extract_type (string, optional): 提取的类型，可选值：with_ec, without_ec, full。默认为有EC号（with_ec).
    Returns:
        [type]: [description]
    """

    description = record.description
    isEnzyme = 'EC=' in description     #有EC号的被认为是酶，否则认为是酶
    isMultiFunctional = False
    functionCounts = 0
    ec_specific_level =0

    if isEnzyme:
        ec = str(re.findall(r"EC=[0-9,.\-;]*",description)
                 ).replace('EC=','').replace('\'','').replace(']','').replace('[','').replace(';','').strip()

        #统计酶的功能数
        isMultiFunctional = ',' in ec
        functionCounts = ec.count(',') + 1

        # - 单功能酶
        if not isMultiFunctional:
            levelCount = ec.count('-')
            ec_specific_level = 4-levelCount

        else: # -多功能酶
            ecarray = ec.split(',')
            for subec in ecarray:
                current_ec_level = 4- subec.count('-')
                if ec_specific_level < current_ec_level:
                    ec_specific_level = current_ec_level
    else:
        ec = '-'

    id = record.id.strip()
    name = record.name.strip()
    seq = record.seq.strip()
    date_integrated = record.annotations.get('date').strip()
    date_sequence_update = record.annotations.get('date_last_sequence_update').strip()
    date_annotation_update = record.annotations.get('date_last_annotation_update').strip()
    seqlength = len(seq)
    res = [id, name, isEnzyme, isMultiFunctional, functionCounts, ec,ec_specific_level, date_integrated, date_sequence_update, date_annotation_update,  seq, seqlength]

    if extract_type == 'full':
        return res

    if extract_type == 'with_ec':
        if isEnzyme:
            return res
        else:
            return []

    if extract_type == 'without_ec':
        if isEnzyme:
            return []
        else:
            return res
#endregion

# 将给定的数据随机划分为2份
def split_random(data):
    index_ref = random.sample(range(0,len(data)), int(len(data)/2))  #创建随机index
    ref = data.iloc[index_ref]     #筛选ref
    query = data.iloc[~data.index.isin(index_ref)] # 剩下的是Query
    funclib.table_2_fasta(ref, './data/sprot_with_ec_ref.fasta')   #写入文件ref fasta
    funclib.table_2_fasta(query, './data/sprot_with_ec_query.fasta') #写入文件query fasta
    return query, ref

# 按时序前一半后一般划分
def split_time_half(data):
    index_ref = range(int(len(data)/2))
    ref = data.iloc[index_ref]     #筛选ref
    query = data.iloc[~data.index.isin(index_ref)] # 剩下的是Query
    funclib.table_2_fasta(ref, './data/sprot_with_ec_ref.fasta')   #写入文件ref fasta
    funclib.table_2_fasta(query, './data/sprot_with_ec_query.fasta') #写入文件query fasta

if __name__ =="__main__":
    start =  time.process_time()
    # in_filepath = r'/home/shizhenkun/codebase/BioUniprot/data/201802/uniprot_sprot.dat.gz'
    # out_filepath = r'/home/shizhenkun/codebase/BioUniprot/data/201802/sprot_full.tsv'

    in_filepath = r'/public/data/uniprot/uniprot_trembl.dat.gz'
    out_filepath = r'/home/shizhenkun/codebase/BioUniprot/data/trembl/uniprot_trembl.tsv'
    extract_type ='full'
    read_file_from_gzip(file_in_path=in_filepath, file_out_path=out_filepath, extract_type=extract_type)
    end =  time.process_time()
    print('finished use time %6.3f s' % (end - start))


from copy import copy
from openpyxl import Workbook, load_workbook
from openpyxl.styles import Font, DEFAULT_FONT

# модуль для переноса значений и некоторых свойств ячеек из одного файла в другой.
# шрифт по умолчанию для всего документа задается отдельно в строчках 17-18

file_in = 'Расписание весна 21-22 v2.xlsx'
file_out = 'result.xlsx'

wb_from = load_workbook(file_in)
ws_from = wb_from.active

wb_to = Workbook()
ws_to = wb_to.active
_font = Font(name="Times New Roman", sz=14, b=False)
{k: setattr(DEFAULT_FONT, k, v) for k, v in _font.__dict__.items()}

for row in ws_from.rows:
    for cell in row:
        ws_to.cell(cell.row, cell.column).value = copy(cell.value)
        ws_to.cell(cell.row, cell.column).font = ws_to.cell(cell.row, cell.column).font + Font(bold=cell.font.b)
        ws_to.cell(cell.row, cell.column).fill = copy(cell.fill)

wb_to.save(file_out)

Excel/перенос форматирования/borrow_cells.py


#!/usr/bin/env python3

import sys
import math
import argparse

def print_usage(name):
    print("python3 {} <input file>".format(name))

def compute_module_fuel(mass):
    fuel = math.floor(mass/3) - 2;
    if fuel < 0:
        fuel = 0

    return fuel

def compute_module_and_fuel(mass):
    fuel = compute_module_fuel(mass)

    additional_fuel = compute_module_fuel(fuel)

    while additional_fuel > 0:
        #print(f'additional_fuel is {additional_fuel}')
        fuel += additional_fuel
        additional_fuel = compute_module_fuel(additional_fuel)

    return fuel

def compute_total_fuel(input_file,name, modules_and_fuel):
    total_fuel = 0
    for module in input_file:
        if modules_and_fuel is True:
            total_fuel += compute_module_and_fuel(int(module))
        else:
            total_fuel += compute_module_fuel(int(module))

    return total_fuel

def main():
    parser = argparse.ArgumentParser(description='Compute required fuel for modules, or modules+fuel')
    parser.add_argument('file', type=argparse.FileType('r'))
    parser.add_argument('--modules-and-fuel', action='store_true', default=False, help='Compute fuel for modules plus the loaded fuel.')

    args = parser.parse_args()

    if (len(sys.argv) > 1):
        with args.file as input_file:
            total_fuel = compute_total_fuel(input_file,sys.argv[1], args.modules_and_fuel)
            print(f'Total fuel required = {total_fuel}')
    else:
        print_usage(sys.argv[0])

if __name__ == "__main__":
    main()


#!/usr/bin/env python
# coding=utf-8

import sys
import os
import shutil

sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'common'))
import common

_creator_list = []

class UnityRuntimeCreator(object):
    def __init__(self, opts):
        self.TAG = "UnityRuntimeCreator"
        common.LOGI(self.TAG, "opts: " + str(opts))
        self.build_sdk = opts["build_sdk"]
        self.workspace = opts["workspace"]
        self.script_path = opts["script_path"]
        self.target = opts["target"]
        if not self.target:
            self.target = "online"

        self.build_replacer_list = []

        self.proj_unityruntime_dir = os.path.join(self.script_path, "../../framework/UnityRuntime")
        self.proj_gplayenginebridge_dir = os.path.join(self.script_path, "../../framework/GplayEngineBridge")

        self.proj_unityruntime_dir_src_dir = os.path.join(self.proj_unityruntime_dir, "src", "main", "java")
        self.proj_gplayenginebridge_src_dir = os.path.join(self.proj_gplayenginebridge_dir, "src", "main", "java")

        self.proj_unityruntime_build_dir = os.path.join(self.proj_unityruntime_dir, "build")
        self.proj_gplayenginebridge_build_dir = os.path.join(self.proj_gplayenginebridge_dir, "build")

        self.version = self._get_version()
        self.versionName = self._get_version_name().replace('"', "")
        common.LOGI(self.TAG, "Runtime SDK versionCode: " + self.version)

        if not opts["out"]:
            self.out_dir = os.path.join(self.workspace, 'out-unityruntime-sdk')
            self.out_dir = os.path.join(self.out_dir, self._get_version_name().replace('"', ""))
            common.recreate_folder(self.out_dir)
            self.debug_directory = os.path.join(self.workspace, 'debug')
        else:
            self.out_dir = os.path.join(opts["out"], self._get_version_name().replace('"', ""))
            self.debug_directory = os.path.join(self.out_dir, 'debug')
        self.out_dir_temp = os.path.join(self.workspace, "out-unityruntime-sdk-temp")
        common.recreate_folder(self.out_dir_temp)

        self.sdk_file_for_runtimesdk_no_dex = os.path.join(self.out_dir, "libunityruntime-not-dex-" + self.versionName + ".jar")
        self.sdk_file_for_runtimesdk = os.path.join(self.out_dir, "libunityruntime-" + self.versionName + ".jar")

        self.sdk_jar_no_dex_obfuscated_path = os.path.join(self.out_dir_temp, "libunityruntime-sdk-no-dex-obfuscated.jar")
        self.sdk_jar_dex_path = os.path.join(self.out_dir_temp, "libunityruntime-sdk-dex.jar")
        self.output_class_path = os.path.join(self.out_dir_temp, "classes")
        self.proguard = not opts["dont_proguard"]

    def _get_version(self):
        # Get the version of current SDK
        return common.find_string_from_file(
            os.path.join(self.proj_unityruntime_dir_src_dir, "com", "skydragon", "gplay", "runtime", "bridge", "CocosRuntimeBridge.java"),
            r"private\s+static\s+final\s+int\s+VERSION_CODE\s*=\s*(.*)\s*;"
        )

    def _get_version_name(self):
        versionName =  common.find_string_from_file(
            os.path.join(self.proj_unityruntime_dir_src_dir, "com", "skydragon", "gplay", "runtime", "bridge", "CocosRuntimeBridge.java"),
            r"private\s+static\s+final\s+String\s+VERSION\s*=\s*(.*);"
        )
        return versionName

    def _clean(self):
        common.LOGI(self.TAG, "Cleaning ...")

        file_to_remove_list = [
            self.out_dir_temp,
            self.proj_unityruntime_build_dir,
            self.proj_gplayenginebridge_build_dir
        ]

        common.safe_remove_files(file_to_remove_list)

    def _generate_cut_jar(self, jar_path, config, out_dir):
        '''Invoke JarCutter tool to customize jar file'''
        # Ensure the our dir is empty
        common.recreate_folder(out_dir)

        # Run the JarCutter
        common.run_command(
            "python " + os.path.join(self.script_path, "../jar-cutter/JarCutter.py") +
            " -c " + config +
            " -s " + jar_path +
            " -o " + out_dir,
            error_message="cutting jar file (%s) failed!" % jar_path
        )

    def _generate_unityruntime_jar_file(self, force_dont_proguard=False):
        common.LOGI(self.TAG, "Generating runtime sdk jar file ..., force_dont_proguard:" + str(force_dont_proguard))

        common.ensure_folder_exists(self.debug_directory)

        proguard_file_path = "None"
        mapping_file_path = "None"
        if not force_dont_proguard and self.proguard:
            proguard_file_path = os.path.join(self.script_path, "proguard-unityruntime.txt")
            mapping_file_path = os.path.join(self.debug_directory, "mapping-libunityruntime-" + self.version + ".txt")

        common.run_command(
            "python " + os.path.join(self.script_path, "../jar-maker/JarMaker.py") +
            " -s " + self.proj_unityruntime_dir_src_dir +
            " -s " + self.proj_gplayenginebridge_src_dir +
            " -o " + self.out_dir_temp +
            " -f " + os.path.split(self.sdk_jar_no_dex_obfuscated_path)[-1] +
            " --ref-lib " + os.path.join(self.script_path, "..", "common", "lib", "android.jar") +
            " -p " + proguard_file_path +
            " -m " + mapping_file_path
        )

    def _generate_cut_jar_for_unityruntime_sdk_dex(self):
        common.LOGI(self.TAG, "Generating jar file for unityruntime sdk ...")
        out_jar_file_name = common.get_file_name(self.sdk_jar_no_dex_obfuscated_path)
        jar_cutter_out_dir = os.path.join(self.out_dir_temp, "jar-cutter-out-for-unityruntime-dex")
        jar_cutter_config_path = os.path.join(self.script_path, "jar-cutter-for-unityruntime-dex.json")
        self._generate_cut_jar(self.sdk_jar_no_dex_obfuscated_path, jar_cutter_config_path, jar_cutter_out_dir)
        cut_jar_file_path = os.path.join(jar_cutter_out_dir, out_jar_file_name)
        common.generate_dex_jar(cut_jar_file_path, self.sdk_jar_dex_path)
        # Copy dex sdk file to the output directory
        shutil.copy(self.sdk_jar_dex_path, self.sdk_file_for_runtimesdk)
        shutil.copy(self.sdk_jar_no_dex_obfuscated_path, self.sdk_file_for_runtimesdk_no_dex)
        # Remove the dex file since it may be generated with the same name
        # in next step (I means generating cut jar for tencent)
        common.safe_remove_file(self.sdk_jar_dex_path)

    def revert(self):
        for replacer in self.build_replacer_list:
            replacer.revert()
        return

    def run(self):
        common.LOGI(self.TAG, "RUNNING ...")
        # Clean temp files before generate classes files
        self._clean()

        if self.build_sdk == "all" or self.build_sdk == "runtime":
            # Generate runtime for normal channel
            self._generate_unityruntime_jar_file()
            self._generate_cut_jar_for_unityruntime_sdk_dex()
            self.revert()

        # clean after build
        self._clean()

        common.LOGI(self.TAG, "DONE!")

def main():
    common.LOGI("SDKCreator.py:main", "main entry ...")

    from optparse import OptionParser

    parser = OptionParser()

    build_sdk = ("all", "gplay", "runtime", "cocosv2", "cocosv3")

    build_target = ("online", "sandbox", "develop")

    parser.add_option("-t", "--target",
                      action="store", type="choice", choices=build_target, dest="target", default="online",
                      help="SDK run in target to be built, could be " + "'" + "', '".join(build_target) + "'")

    parser.add_option("-o", "--out",
                      action="store", type="string", dest="out", default=None,
                      help="The output folder")

    parser.add_option("-b", "--build-sdk",
                      action="store", type="choice", choices=build_sdk,
                      dest="build_sdk", default="all",
                      help="SDK kind to be built, could be " + "'" + "', '".join(build_sdk) + "'")

    parser.add_option("", "--dont-proguard",
                      action="store_true", dest="dont_proguard", default=False,
                      help="Whether to obfuscate java codes")

    (opts, args) = parser.parse_args()

    common.assert_if_failed(len(args) == 0, "Don't add parameters without `-t`,`-b` and `--dont-proguard`")

    opts = vars(opts)
    opts['workspace'] = os.path.abspath(os.getcwd())
    opts['script_path'] = os.path.dirname(os.path.realpath(__file__))

    if opts["build_sdk"] == "all" or opts["build_sdk"] == "unityv5":
        opts["engineVersion"] = "V5"
        unity_creator = UnityRuntimeCreator(opts)
        _creator_list.append(unity_creator)
        unity_creator.run()

if __name__ == '__main__':
    try:
        main()
    except Exception as e:
        # raceback.print_exc()
        #for creator in _creator_list:
        #    creator.revert()

        if e.__class__.__name__ == "ErrorMessage":
            common.LOGE("SDKCreator.py", e.message)
            sys.exit(1)
        else:
            raise


import streamlit as st
from PIL import Image

import cv2
import numpy as np

import tempfile

#適応的2値化処理
def threshold(src, ksize=3, c=2):

    # 局所領域の幅
    d = int((ksize-1)/2)

    # 画像の高さと幅
    h, w = src.shape[0], src.shape[1]

    # 出力画像用の配列（要素は全て255）
    dst = np.empty((h,w))
    dst.fill(255)

    # 局所領域の画素数
    N = ksize**2

    for y in range(0, h):
        for x in range(0, w):
            # 局所領域内の画素値の平均を計算し、閾値に設定
            t = np.sum(src[y-d:y+d+1, x-d:x+d+1]) / N

            # 求めた閾値で二値化処理
            if(src[y][x] < t - c): dst[y][x] = 0
            else: dst[y][x] = 255

    return dst

st.title('スマホで撮影した書類写真をくっきりと白黒化するWebアプリ！')
'''
## 影がかかっている写真であってもクッキリとした白黒画像に変換できる

スマホで書類の写真を撮影する際に、影がかかってしまうことがある。
通常の白黒化処理では特定の画素が「この閾値より黒っぽかったら黒！」と決め打ちするため、影のかかった部分は黒として判定されてしまい、下の添付画像のように汚くなってしまうことが頻繁にある。
そのような写真であっても、適応的二値化処理を用いることで、影を取り除いたクッキリとした白黒画像が生成される。

適応的二値化処理（AdaptiveThreshold）とは白か黒かの閾値を固定せず、画素ごとに自分の周囲の画素を参考にして白か黒かを判断する二値化処理のことで、陰影を取り除くのに適している。
'''
st.image("siroku.jpg",caption ="一般的な白黒化",use_column_width=True)
st.image("sirokuro.jpg",caption ="適応的2値化処理を用いた白黒化",use_column_width=True)

uploaded_file = st.file_uploader("jpg画像を選択してください",type = "jpg")
if uploaded_file is not None:
    #img = Image.open(uploaded_file)#imgはPillow型
    #uploaded_fileをcv2.imreadで読み取れるようにする処理
    tfile = tempfile.NamedTemporaryFile(delete=False)
    tfile.write(uploaded_file.read())
    #検索の受け売りなので、どうしてtempfileを使うとuploaded_fileをcv2.imreadしたときにエラーがでなくなるのかわからない
    img = cv2.imread(tfile.name)
    #一度cv2.imwriteを使わないと、st.imageしたときにエラーが出る
    cv2.imwrite('temp.jpg',img)
    st.image('temp.jpg',caption ="アップロードされた画像",use_column_width=True)
    #これも検索の受け売り。なぜcv2.imwriteしてから指定した'temp.jpg'をst.imageするとうまくいくのかわからない
    st.title("↓に白黒化画像が表示されます")
    # グレースケール変換
    gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)#grayはopenCV型
    # 方法1
    dst = threshold(gray, ksize=11, c=13)
    cv2.imwrite('temporary.jpg', dst)
    st.image('temporary.jpg',caption ="適応的2値化処理で白黒化された画像",use_column_width=True)


# -*- coding: utf-8 -*-
# Name: sql.py
# Author: Shao Shidong
# Date: 2020/5/24
# Version: Python 3.6 64-bit

import re
import shlex
from itertools import zip_longest

SQL_OPS = ['=','>','<','>=','<=','!=','NOT LIKE','LIKE','BETWEEN']
SQL_AGG = ['max','min','count','sum','avg','']
SQL_COND_OPS = ['AND','OR','']
SQL_ORDERBY_OPS = ['DESC LIMIT','ASC LIMIT','DESC','ASC','LIMIT','']
SQL_DISTINCT_OP = ['distinct','']
SQL_KEYWORDS = ['where','group by','order by']

SQL_AGG_dict = {'max':'maximum', 'min':'minimum', 'count':'count','sum':'sum', 'avg':'average'}
SQL_ORDERBY_OPS_dict = {'DESC LIMIT':'descending limit', 'ASC LIMIT':'ascending limit', 'DESC':'descending', 'ASC':'ascending', 'LIMIT':'limit', 'NONE': 'none'}
SQL_OPS_dict = {'=':'=','>':'>','<':'<','>=':'> =','<=':'< =','!=':'! =','NOT LIKE':'not like','LIKE':'like','BETWEEN':'between'}

class SQLStatement():
    def __init__(self, query = None, database=None):
        self.COLS = []
        self.WHERE = []
        self.GROUPBY = []
        self.ORDERBY = []
        self.ORDERBY_OP = []
        self.TABLE = ""
        self.HAVING = []
        self.LIMIT_VALUE = ""
        self.database = database
        if isinstance(query, str):
            self.from_query(query)

    def __eq__(self, other):
        if not isinstance(other, SQLStatement):
            return NotImplemented
        if not self.TABLE :
            self.TABLE = self.COLS[0].column.table_name
        if not other.TABLE :
            other.TABLE = other.COLS[0].column.table_name
        return (set(self.COLS)==set(other.COLS) and set(self.WHERE)==set(other.WHERE) and set(self.GROUPBY)==set(other.GROUPBY)and set(self.ORDERBY)==set(other.ORDERBY)and set(self.ORDERBY_OP)==set(other.ORDERBY_OP)
                and self.TABLE == other.TABLE and set(self.HAVING)==set(other.HAVING) and str(self.LIMIT_VALUE)==str(other.LIMIT_VALUE))

    def component_match(self, other):
        return (
            set(self.COLS)==set(other.COLS),
            set(self.WHERE)==set(other.WHERE) if self.WHERE else None,
            set(self.GROUPBY)==set(other.GROUPBY) if self.GROUPBY else None,
            set(self.ORDERBY)==set(other.ORDERBY) and set(self.ORDERBY_OP)==set(other.ORDERBY_OP) if self.ORDERBY else None,
            set(self.HAVING)==set(other.HAVING) if self.HAVING else None,
            str(self.LIMIT_VALUE)==str(other.LIMIT_VALUE) if self.LIMIT_VALUE else None,
            self.keywords == other.keywords)

    @property
    def keywords(self):
        keywords = []
        if self.WHERE:
            keywords += ['where']
        if self.GROUPBY:
            keywords += ['group by']
        if self.ORDERBY:
            keywords += ['order by']
        return keywords

    @property
    def and_ors(self):
        andors = []
        for condition in self.WHERE:
            if condition.cond_op:
                andors += [condition.cond_op]
        for condition in self.HAVING:
            if condition.cond_op:
                andors += [condition.cond_op]
        return andors

    def from_query(self, query):
        query = query.replace(';','')
        if ' - ' in query or ' + ' in query or ' / ' in query:
            raise NotImplementedError(f"Doesn't support arithmetic in query : {query}")
        if 'AS ' in query:
            aliases = re.findall(r'(?<=AS ).\w+', query)
            for alias in aliases:
                query = query.replace(f'{alias}.','')
                query = query.replace(f'AS {alias}','')
        clauses = ['SELECT','FROM','WHERE','GROUP BY','HAVING','ORDER BY']
        clauses = [clause for clause in clauses if clause in query]
        query_split = re.split(f'({"|".join(clauses)})',query)[1:]
        self.TABLE = str.lower(query_split[3]).strip()
        for i in range(0,len(query_split),2):
            clause = query_split[i]
            statement = query_split[i+1]
            if clause == 'SELECT':
                for column in statement.split(','):
                    agg, distinct = '',''
                    column = str.lower(column).strip()
                    if 'distinct(' in column:
                        distinct, column = column.split('(')
                        column = column.replace('(','').replace(')','')
                    if '(' in column:
                        agg = column.split('(')[0]
                        agg = agg.replace('distinct','').strip()
                        column = column.split('(')[1].split(')')[0].strip()
                    if 'distinct' in column:
                        distinct, column = column.split()
                    column = self.database.get_column(column, self.TABLE)
                    self.COLS.append(ColumnSelect(column, agg=agg, distinct=distinct))
            elif clause == 'WHERE':
                if ' BETWEEN ' in statement:
                    col = statement.split(' BETWEEN ')
                    intervals = col[1].split(' AND ')
                    col = col[0].strip(' ')
                    statement = col + ' BETWEEN ' + intervals[0] +  ' ' + intervals[1]
                conditional_ops = re.findall('( AND | OR | BETWEEN )',statement)
                conditions = re.split(' AND | OR ',statement)
                for condition, conditional_op in zip_longest(conditions, conditional_ops, fillvalue=""):
                    if conditional_op == ' BETWEEN ':
                        column, op, value, valueless = condition.split(' ')
                        conditional_op = ''
                    else:
                        column, op, value = re.findall(r'(.*\(.*?\)|\'.*?\'|".*?"|NOT LIKE|\S+)',condition)
                        valueless = ""
                    value = str.lower(value.strip('\'"%'))
                    valueless = str.lower(valueless.strip('\'"%'))
                    column = str.lower(column).strip()
                    conditional_op = conditional_op.strip()
                    column = self.database.get_column(column, self.TABLE)
                    self.WHERE.append(Condition(column, op, value, conditional_op,"","",valueless))
            elif clause == 'GROUP BY':
                for column in statement.split(','):
                    column = str.lower(column).replace('(','').replace(')','').strip()
                    column = self.database.get_column(column, self.TABLE)
                    column = ColumnSelect(column, '', '')
                    self.GROUPBY.append(column)
            elif clause == 'HAVING':
                if ' BETWEEN ' in statement:
                    col = statement.split(' BETWEEN ')
                    intervals = col[1].split(' AND ')
                    col = col[0].strip(' ')
                    statement = col + ' BETWEEN ' + intervals[0] +  ' ' + intervals[1]
                conditional_ops = re.findall('( AND | OR | BETWEEN )',statement)
                conditions = re.split(' AND | OR ',statement)
                for condition, conditional_op in zip_longest(conditions, conditional_ops, fillvalue=""):
                    if conditional_op == ' BETWEEN ':
                        column, op, value, valueless = condition.split(' ')
                        conditional_op = ''
                    else:
                        column, op, value = re.findall(r'(.*\(.*?\)|\'.*?\'|".*?"|NOT LIKE|\S+)',condition)
                        valueless=""
                    agg, distinct = '', ''
                    column = str.lower(column)
                    if '(' in column:
                        agg = column.split('(')[0].strip()
                        column = column.split('(')[1].split(')')[0]
                    if 'distinct' in column:
                        distinct, column = column.split()
                    value = str.lower(value.strip('\'"%'))
                    valueless = str.lower(valueless.strip('\'"%'))
                    conditional_op = conditional_op.strip()
                    column = self.database.get_column(column, self.TABLE)
                    self.HAVING.append(Condition(column, op, value, conditional_op, agg, distinct,valueless))
            elif clause == 'ORDER BY':
                for column in statement.split(','):
                    agg, distinct = '', ''
                    if '(' in column:
                        agg = column.split('(')[0].strip()
                        col = column.split('(')[1].split(')')[0].strip()
                    else:
                        col = column.split()[0].strip()
                    col = str.lower(col)
                    if 'distinct' in col:
                        distinct, col = col.split()
                    orderby_op = re.findall(f'({"|".join(SQL_ORDERBY_OPS[:-1])})', column)
                    if orderby_op:
                        self.ORDERBY_OP += orderby_op
                        if 'LIMIT' in orderby_op[0]:
                            fnd = re.findall(r'\d+', statement)
                            self.LIMIT_VALUE = fnd[-1]
                    else:
                        self.ORDERBY_OP += [""]
                    agg = str.lower(agg)
                    column = self.database.get_column(col, self.TABLE)
                    column = ColumnSelect(column, agg, distinct)
                    self.ORDERBY.append(column)

    def generate_history(self):
        history_dict = {'col':[], 'agg':[], 'andor':[], 'keyword':[], 'op':[], 'value':[], 'having':[], 'decasc':[], 'distinct':[]}
        history = ['select']
        history_dict['keyword'] += history.copy()
        history_dict['col'] += [history.copy()]
        for column in self.COLS:
            history += [' '.join(column.column.to_list())]
            history_dict['agg'] += [history.copy()]
            if column.agg:
                history += [column.agg]
            history_dict['col'] += [history.copy()]

            history_dict['distinct'] += [history.copy()]
            if column.distinct:
                history += [column.distinct]
        if self.WHERE:
            history += ['where']
            for condition in self.WHERE:
                history += [' '.join(condition.column.to_list())]
                history_dict['op'] += [history.copy()]
                history += [condition.op]
                if condition.op == 'BETWEEN':
                    if condition.value:
                        history += [condition.value]
                    history_dict['value'] += [history.copy()]
                else:
                    history_dict['value'] += [history.copy()]
                    if condition.value:
                        history += [condition.value]
                history_dict['andor'] += [history.copy()]
                if condition.cond_op:
                    history += [condition.cond_op]
            history_dict['col'] += [history.copy()]
        if self.GROUPBY:
            history += ['group by']
            for groupby in self.GROUPBY:
                history += [' '.join(groupby.column.to_list())]
            history_dict['col'] += [history.copy()]
        history_dict['having'] += [history.copy()]
        if self.HAVING:
            history += ['having']
            for condition in self.HAVING:
                history += [' '.join(condition.column.to_list())]
                history_dict['agg'] += [history.copy()]
                if condition.column_select.agg:
                    history += [condition.column_select.agg]
                history_dict['op'] += [history.copy()]
                history += [condition.op]
                history_dict['value'] += [history.copy()]
                if condition.value:
                    history += [condition.value]
                history_dict['andor'] += [history.copy()]
                if condition.cond_op:
                    history += [condition.cond_op]
            history_dict['col'] += [history.copy()]
        if self.ORDERBY:
            history += ['order by']
            for orderby in self.ORDERBY:
                history += [' '.join(orderby.column.to_list())]
                history_dict['agg'] += [history.copy()]
                if orderby.agg:
                    history += [orderby.agg]
            history_dict['col'] += [history.copy()]
        for orderby_op in self.ORDERBY_OP:
            history_dict['decasc'] += [history.copy()]
            if orderby_op:
                history += [orderby_op]
        return history_dict

    def __str__(self):
        """Convert object to string representation of SQL"""
        string_cols = [str(col) for col in self.COLS]
        string_where = [str(where) for where in self.WHERE]
        string_group = [str(group) for group in self.GROUPBY]
        string_having = [str(having) for having in self.HAVING]
        string_order = [f"{str(order)} {orderop} {limitvalue}" for order, orderop, limitvalue in zip_longest(self.ORDERBY, self.ORDERBY_OP, [self.LIMIT_VALUE], fillvalue="") if self.ORDERBY]
        if not self.TABLE :
            self.TABLE = self.COLS[0].column.table_name
        sql_string = f"SELECT {','.join(string_cols)} FROM {self.TABLE}"
        if string_where:
            sql_string += f" WHERE {' '.join(string_where)}"
        if string_group:
            sql_string += f" GROUP BY {','.join(string_group)}"
        if string_having:
            sql_string += f" HAVING {' '.join(string_having)}"
        if string_order:
            sql_string += f" ORDER BY {','.join(string_order)}"
        sql_string = sql_string.replace('( ','(').replace('  ',' ')
        return sql_string

class ColumnSelect():
    column = None
    agg = ""
    distinct = ""
    def __init__(self, column, agg="", distinct=""):
        self.column = column
        self.agg = agg
        self.distinct = distinct

    def __str__(self):
        assert self.column, "column name can't be empty"
        assert self.agg in SQL_AGG, f"{self.agg} is not an SQL aggregator"
        assert self.distinct in SQL_DISTINCT_OP, f"{self.distinct} is not an SQL distinct operator"
        if self.agg:
            return f"{self.agg}({self.distinct} {self.column})"
        return f"{self.distinct} {self.column}"

    def __eq__(self, other):
        if not isinstance(other, ColumnSelect):
            return NotImplemented
        return str(self) == str(other)

    def __hash__(self):
        return hash(str(self))

class Condition():
    column_select = None
    op = ""
    value = ""
    cond_op = ""
    @property
    def column(self):
        return self.column_select.column

    @property
    def agg(self):
        return self.column_select.agg
    @agg.setter
    def agg(self, value):
        self.column_select.agg = value

    @property
    def distinct(self):
        return self.column_select.distinct

    @distinct.setter
    def distinct(self, value):
        self.column_select.distinct = value

    def __init__(self, column, op="", value="", cond_op="", agg="", distinct="",valueless=""):
        self.column_select = ColumnSelect(column, agg, distinct)
        self.op = op
        self.value = value
        self.cond_op = cond_op
        self.valueless = valueless

    def __str__(self):
        assert self.op in SQL_OPS, f"{self.op} is not an SQL operation"
        assert self.cond_op in SQL_COND_OPS, f"{self.cond_op} is not an SQL conditional operator (AND/OR)"

        if self.column.column_type == 'text':
            if "BETWEEN" in self.op:
                return f'{self.column_select} {self.op} "%{self.value}%" {SQL_COND_OPS[0]} {self.valueless}'
            elif "LIKE" in self.op:
                return f'{self.column_select} {self.op} "%{self.value}%" {self.cond_op}'
            else:
                return f'{self.column_select} {self.op} "{self.value}" {self.cond_op}'
        if "BETWEEN" in self.op:
            return f"{self.column_select} {self.op} {self.value} {SQL_COND_OPS[0]} {self.valueless}"
        else:
            return f"{self.column_select} {self.op} {self.value} {self.cond_op}"

    def __eq__(self, other):
        if not isinstance(other, Condition):
            return NotImplemented
        return str(self) == str(other)

    def __hash__(self):
        return hash(str(self))

SQL_TYPES = ("text","number", "others")

class DataBase():
    def __init__(self, data):
        self.tables = []
        self.tables_dict = {}
        if isinstance(data, dict):
            self.from_dict(data)

    def from_dict(self, data_dict):
        self.db_name = data_dict['db_id']
        self.primary_keys = data_dict['primary_keys']
        columns_all = []
        column_types_all = []
        table_names = data_dict['table_names_original']
        for (table_id, column_name), column_type in zip(data_dict['column_names_original'], data_dict['column_types']):
            column_name = str.lower(column_name)
            if table_id >= len(columns_all):
                columns_all.append([])
                column_types_all.append([])
            if table_id>=0:
                columns_all[table_id].append(column_name)
                column_types_all[table_id].append(column_type)

        for table_name, columns, column_types in zip(table_names, columns_all, column_types_all):
            table_name =  str.lower(table_name)
            columns.append('*')
            column_types.append('text')
            table = Table(table_name, columns, column_types)
            self.tables.append(table)
            self.tables_dict[table_name] = table

    def to_list(self):
        lst = []
        for table in self.tables:
            lst += [[col_type, table.table_name,col_name] for col_name, col_type in zip(table.columns, table.column_types)]
        return lst

    def get_column(self, column, table):
        return self.tables_dict[table].column_dict[column]

    def get_column_from_idx(self, idx):
        columns = []
        for table in self.tables:
            columns += list(table.column_dict.values())
        return columns[idx]

    def get_idx_from_column(self, column):
        columns = self.to_list()
        return columns.index(column.to_list())

class Table():
    def __init__(self, table_name, column_names, column_types):
        self.column_dict = {}
        for column_name, column_type in zip(column_names, column_types):
            col = Column(column_name, table_name, column_type)
            self.column_dict[column_name] = col
        self.table_name = table_name
        self.columns = column_names
        self.column_types = column_types

class Column():
    def __init__(self, column_name, table_name, column_type, database_name=""):
        self.column_name = column_name
        self.table_name = table_name
        self.column_type = column_type
        self.database_name = database_name

    def __str__(self):
        return self.column_name

    def __repr__(self):
        return str(self)

    def to_list(self):
        return [self.column_type, self.table_name,self.column_name]


import cv2
import numpy as np
from skimage.morphology import skeletonize
from util import *
from branches import *
# from analysis import skeleton, multi_hit_miss
from analysis.skeleton import fast_skeletonize
from analysis.hitmiss import old_get_end_points, get_image_convolve, get_branch_point_matches, old_scan_for_end, scan_for_end, scan_for_branch

# create the membrane properties
min_membrane_threshold = 25  # the min threshold (0-255) for the membrane to be considered valid
min_membrane_length = 40  # the min membrane length
min_membrane_area = 15  # the min area of the membrane (currently not used)
max_membrane_width = 50  # the max width of the membrane (currently not used)
max_corner_edge_distance = 10  # distance for a corner to be the edge of the image
max_corner_branch_distance = 10  # distance for a corner and branch distance to be considered valid
max_corner_distance = 150  # max distance that corners can be from each other
dilate_membrane = 3
epsilon_membrane = 1
in_membrane_checks = 5

def process_membrane(layer):
    threshed = cv2.threshold(layer, min_membrane_threshold, 255, cv2.THRESH_BINARY)[1]

    """
    dilated = cv2.dilate(threshed, np.ones((dilate_membrane, dilate_membrane), np.int8), iterations=1)
    dilated = cv2.blur(dilated, (3, 3))
    dilated = cv2.medianBlur(dilated, 7)
    dilated = cv2.threshold(dilated, 5, 255, cv2.THRESH_BINARY)[1]
    # dilated = cv2.bilateralFilter(dilated, 13, 125, 125)
    # cv2.imshow('test', dilated)
    """

    skeleton = fast_skeletonize((threshed / 255).astype(np.uint8))
    branch_points = scan_for_branch(skeleton, row_first=False)
    skeleton = skeleton.astype(np.uint8) * 255

    """
    skeleton = skeletonize(threshed / 255)
    testing = multi_hit_miss(skeleton)
    branch_points = detect_branch_points(skeleton)
    skeleton = skeleton.astype(np.uint8) * 255
    """

    # destroy the branch connections
    for x, y in branch_points:
        cv2.rectangle(skeleton, (x - 3, y - 3), (x + 3, y + 3), 0, -1)

    # subdivide each skeleton contour and find the best two edges of each contour
    contours = cv2.findContours(skeleton, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[1]
    height, width = layer.shape[:2]
    left, top, right, bottom = 0, 0, width - 1, height - 1
    corner_lines = []
    padding = 10
    for cont in contours:
        x, y, w, h = cv2.boundingRect(cont)
        single_contour = np.zeros((h + 2 * padding, w + 2 * padding, 1), np.uint8)
        offset = np.array([(int(p_x - x + padding), int(p_y - y + padding)) for p_x, p_y in cont.reshape(-1, 2)],
                          np.int32)
        cv2.drawContours(single_contour, [offset], 0, 255, 1)
        # edges = cv2.dilate(single_contour, np.ones((5, 5), np.uint8), iterations=1)

        test_ind = 0
        corners = []
        while test_ind < 3:  # test a max of 3 branches
            passed = True
            # end_points = detect_end_points((single_contour / 255).reshape(single_contour.shape[:2]).astype(np.bool))
            # corns = cv2.goodFeaturesToTrack(edges, 2 + test_ind, 0.3, 20)
            end_points = scan_for_end((single_contour / 255).reshape(single_contour.shape[:2]).astype(np.uint8), row_first=False)

            corners = []
            if end_points is not None:
                failed = 0
                for p_x, p_y in end_points:
                    # p_x, p_y = corner.ravel()
                    p_x, p_y = int(p_x + x - padding), int(p_y + y - padding)

                    """
                    # make sure it's not a branch point
                    on_edge = True
                    for branch in branch_points:
                        if point_distance((p_x, p_y), branch) < max_corner_branch_distance:
                            on_edge = False
                            failed += 1
                            break

                    if on_edge:
                    """
                    corners.append((p_x, p_y))
                if failed == test_ind + 1:
                    passed = False

            if passed:
                break

            test_ind += 1

        # we need to have two corners to continue or we're stuck in a loop
        is_loop = len(corners) < 2

        """
        if len(corners) < 2:
            continue
        """

        vectors = cont.reshape(-1, 2)

        if is_loop:
            corner_lines.append((vectors, (vectors[0], vectors[-1])))
        else:
            first = closest_to(corners[0], vectors)
            second = closest_to(corners[1], vectors)
            start = min(first, second)
            end = max(first, second)
            corner_lines.append((vectors[start:end], (vectors[start], vectors[end])))

    # revisit the lines with corners and try to attach nearby contours
    overlap_lines = []
    ind_line = 0
    connected_lines = []
    connected_corners = []
    for line, corners in corner_lines:
        c_line = list(line.reshape(-1, 2))
        for corner in corners:
            closest = sys.maxsize
            closest_point = None
            is_end = False
            for o_line, o_corners in corner_lines[ind_line + 1:]:
                for o_corner in o_corners:
                    dist = point_distance(corner, o_corner)
                    x, y = tuple(corner)
                    if x - max_corner_edge_distance <= left or x + max_corner_edge_distance > right or \
                            y - max_corner_edge_distance <= top or y + max_corner_edge_distance >= bottom:
                        continue
                    elif dist < closest and dist < max_corner_distance:
                        closest = dist
                        closest_point = (o_line, o_corner)
                        is_end = bool(tuple(o_corner) == tuple(o_corners[-1]))

            if closest_point is not None and \
                    not (tuple(corner) in connected_corners or tuple(closest_point[1]) in connected_corners):
                s_line = list(closest_point[0].reshape(-1, 2))
                is_first_end = bool(tuple(corner) == tuple(corners[-1]))

                # order the lines properly
                if is_first_end and not is_end:
                    c_line.extend(s_line)
                elif is_first_end and is_end:
                    c_line.extend(list(reversed(s_line)))
                elif not is_first_end and not is_end:
                    c_line = list(reversed(c_line))
                    c_line.extend(s_line)
                else:
                    temp = c_line[:]
                    c_line = s_line
                    c_line.extend(temp)

                # add it to the already connected corners and lines
                connected_corners.extend([tuple(corner), tuple(closest_point[1])])
                connected_lines.append((c_line, closest_point[0]))

        # process the revised line to make sure it's up to spec
        line = np.array(c_line, np.int32)
        length = cv2.arcLength(line, False)
        if length >= min_membrane_length:
            smooth_contours = cv2.approxPolyDP(line, epsilon_membrane, False).reshape(-1, 2)
            overlap_lines.append(smooth_contours)
        ind_line += 1

    """
    revised_lines = []
    # remove any overlapping or redundant connections made by the previous corner connections
    for ind, line in enumerate(overlap_lines):
        similar_lines = []
        for sub_line in overlap_lines[ind + 1:]:
            if np.isin(line, sub_line).any():
                similar_lines.append(sub_line)

        longest_line = None
        longest_length = 0
        for line in similar_lines:
            length = cv2.arcLength(line, False)
            if length > longest_length:
                longest_length = length
                longest_line = line

        revised_lines.append(line if longest_line is None else longest_line)
    """

    overlap_image = np.zeros((height, width), np.uint8)

    # draw the connected overlapping lines
    for line in overlap_lines:
        draw_lines(overlap_image, line, 255, 1, False)

    # draw small circles at the connected corners to smooth out the line
    for corner in connected_corners:
        cv2.circle(overlap_image, corner, 1, 255, -1)

    # determine the none connected corners
    nonconnected_corners = []
    for _, corners in corner_lines:
        for corner in corners:
            if tuple(corner) not in connected_corners:
                nonconnected_corners.append(tuple(corner))

    contours = cv2.findContours(overlap_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[1]
    revised_lines = []
    lengths = []
    for cont in contours:
        vectors = cont.reshape(-1, 2)
        closest_corners = []

        for test in range(2):
            closest_corner = (0, 0)
            closest_length = sys.maxsize
            for corner in nonconnected_corners:
                if corner not in closest_corners:
                    length = point_distance(corner, vectors[closest_to(corner, vectors)])
                    if length < closest_length:
                        closest_length = length
                        closest_corner = corner
            closest_corners.append(closest_corner)

        first = closest_to(closest_corners[0], vectors)
        second = closest_to(closest_corners[1], vectors)
        start = min(first, second)
        end = max(first, second)
        line = vectors[start:end]
        revised_lines.append(line)
        lengths.append(cv2.arcLength(line, False))

    """
    # process the dilated membrane
    contours = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[1]
    height, width = layer.shape[:2]
    left, top, right, bottom = 0, 0, width - 1, height - 1
    lines = []

    lengths = []
    # process all of the lines
    for cont in contours:
        length = cv2.arcLength(cont, False) / 2
        area = cv2.contourArea(cont, False)
        if length >= min_membrane_length and area >= min_membrane_area:
            total_length += length
            cX, cY = center_mass(cont)

            # find the start and end points
            ind = 0
            cont = cont.reshape(-1, 2)
            num = cont.shape[0]
            start = cont[0]
            s_i = 0
            e_i = num - 1
            is_middle = False
            on_edge = False
            prev_rad = []
            while ind < num - 1:
                pt1 = tuple(cont[ind])
                pt2 = tuple(cont[ind + 1])
                if pt2[0] == start[0] and pt2[1] == start[1]:
                    break

                deg = point_rad(pt1, pt2)
                if (pt2[0] - 1 <= left or pt2[0] + 1 >= right) and deg < np.pi / 4:
                    if is_middle and not on_edge and (ind - s_i) > max_membrane_width:
                        e_i = ind + 1
                        break
                    else:
                        s_i = ind
                        is_middle = True
                        on_edge = True
                elif (pt2[1] - 1 <= top or pt2[1] + 1 >= bottom) and deg > np.pi / 4:
                    if is_middle and not on_edge and (ind - s_i) > max_membrane_width:
                        e_i = ind + 1
                        break
                    else:
                        s_i = ind
                        is_middle = True
                        on_edge = True
                else:
                    on_edge = False

                # check if the last
                # if len(

                ind += 1

            smooth_contours = cv2.approxPolyDP(cont[s_i:e_i], epsilon_membrane, False).reshape(-1, 2)
            lines.append(((cX, cY), length, area, smooth_contours))

    for _, corners in corner_lines:
        for x, y in corners:
            cv2.circle(skeleton, (x, y), 7, 255, -1)
    # conts = [np.array(cont, np.int32) for cont in revised_lines]
    for line in revised_lines:
        draw_lines(skeleton, line, 100, 3)
    # cv2.drawContours(skeleton, conts, -1, 100, 3)
    ilog(skeleton, delay=0)
    # exit(0)
    """

    return revised_lines, contours, lengths


from django.shortcuts import render
import razorpay

from django.views.decorators.csrf import csrf_exempt

from razorpay_second.settings import (Raz_Public_Key, Raz_Secret_Key)

from .models import Coffee

# Create your views here.

def home(request):
    if request.method == "POST":
        name = request.POST.get("name")
        amount = int(request.POST.get("amount")) * 100
        client = razorpay.Client(auth=(Raz_Public_Key, Raz_Secret_Key))
        payment = client.order.create(
            {
                'amount': amount,
                'currency': 'INR',
                'payment_capture': '1'
            }
        )
        print('payment: ', payment)

        coffee = Coffee(name=name, amount=amount, payment_id=payment['id'])
        coffee.save()
        return render(request, "index.html", {'payment': payment})

    return render(request, "index.html")

@csrf_exempt
def success(request):
    if request.method == "POST":
        a = request.POST
        print('a: ', a)
    return render(request, "success.html")


from typing import List, Optional

class ListingFile:
    def __init__(self, data: Optional[str] = None):
        self.data: Optional[str] = data
        self.releases: List[str] = []

        self.parse()

    def get_releases(self) -> List[str]:
        return self.releases

    def parse(self) -> None:
        if not self.data:
            return

        lines: List[str] = self.data.split("\n")

        for line in lines:
            line = line.strip()

            # empty
            if not line:
                continue

            # ignore comments
            if line and line[0] == "#":
                continue

            self.releases.append(line)

        self.releases.sort()


# 倒序排列
'''
# inverse permutation
# 将一个数组进行倒序

n =  int(input('确定数组的长度：\n'))

a = [i for i in range(n)]
b = [0 for i in range(n)]
print(a)
for ii in range(n):
    b[n-ii-1] = a[ii]
print(b)

for i in range(n):
    if a[b[i]] == b[a[i]] == n-i-1:
        print(True)
'''

# 这个是书上的解答，有点理解不了
'''
import stdio
import sys
import stdarray

# Accept a permutation of integers from the command line and write the
# inverse permutation to standard output.

# Accept the permutation.
perm = []
for i in range(1, len(sys.argv)):
    perm += [int(sys.argv[i])]
n = len(perm)

# Make sure the permutation is valid.
exists = stdarray.create1D(n, False)
for i in range(n):
    if (perm[i] < 0) or (perm[i] >= n) or exists[perm[i]]:
        stdio.writeln("Not a permutation")
        sys.exit(0)
    exists[perm[i]] = True

# Invert the permutation.
permInverted = [0] * n
for i in range(n):
    permInverted[perm[i]] = i

# Write the inverted permutation.
for element in permInverted:
    stdio.write(str(element) + ' ')
stdio.writeln()
'''

# 哈达玛矩阵
# Hadamard matrix
# 已提取成单独文件

'''###########################################################'''

# 谣言 Rumor

# # Alice 与其他 n 个客人（包括 Bob）开一个派对，Bob 制造了一个关于 Alice 的谣言，并告诉其中的一个客人
# # 第一次听到的人会立即告诉下一个人（除 Alice 和告诉他的人之外）
# # 第二次听到的人则会停止传播这个谣言

# # 估计谣言停止传播前，除Alice之外都听到这个谣言的概率，同时估计听到这个谣言的客人预计数量

# # 类似于有放回的随机抽样

# import random

# n = int(input('参加party的人数：'))
# m = int(input('party开启的次数：'))

# # 听到谣言的客人的数量的数组
# Rumors = []

# # 执行 m 次
# for r in range(m):

    # # 构建及初始化人员数组
    # rumors = [False for i in range(n)]

    # # 随机Bob的位置，开始谣言
    # r1 = random.randrange(n)
    # rumors[r1] = True
    # # 变量说明：r1 ==> 谣言的开始的位置或者刚完成传播的位置；r2 ==> 正要传播谣言的人；r3 ==> 将被谣言传播的人
    # r2 = r1

    # # 听到谣言的客人的数量
    # Rumor = 1

    # # 构建循环
    # while True:
        # r3 = random.randrange(n)
        # if r1 != r3 and not rumors[r3]:
            # rumors[r3] = True
            # # 位置变换，要传播谣言者 晋升 为刚完成传播者，将被谣言传播者 晋升 要传播谣言者
            # r1 = r2
            # r2 = r3
            # Rumor += 1
        # # 刚完成谣言传播者与将要被谣言传播的人的情况剔除
        # elif r1 == r3:
            # continue
        # else:
            # break

    # Rumors.append(Rumor)

# # 结果计算

# # 所有人都听到谣言
# all = 0

# for RR in Rumors:
    # if  RR == n:
        # all += 1

# print(Rumors)
# print('所有人都听到谣言的概率：{}'.format(all/m))
# print('同时听到谣言的人数：{}'.format(sum(Rumors)/m))

# 总感觉自己写的程序超级长

'''#######################################################'''

# 重复值查找 Find a duplicate
# 给定一个包含 n 个元素的数组，元素值位于 1 到 n 之间
# 实现：判断数组的元素是否存在重复，要求不使用其他数组，但可改变已知数组的内容

# 创建一个数组，元素在 1 到 n 之间随机，长度为 n
# 依据要求：将数组进行排序，然后通过循环，如果 a[i] == a[i+1] 成立，则该数组存在重复的元素

# 这里就牵扯的数组排序的问题了
# 传说中的 八大排序法 ———— 有待学习研究

# 用于产生乱序序列
import random,math
# 用于测试运行的时间，主要用到其中的 datetime.datetime.now() 函数
# 通过前后时间相减，在调用 .seconds() 方法即可得到运行的时间
import datetime

# 创建一个乱序的数组
lst = [x for x in range(47, 0, -1)]
random.shuffle(lst)
lst1 = lst[:]
lst2 = lst[:]
lst3 = lst[:]

''' #### 冒泡排序法 Bubble Sort #### '''

# 思路：通过邻位比较，大的上升或者小的上升（比较双方依据规则交换位置）
# 通过双循环，就可以将数组完成升序或者降序排序
# 升序

def Bubble_Sort(lst):

    # 只需比较 len(lst) - 1 次就够了
    for i in range(len(lst) - 1):
        # 添加一个标记，如果整个循环，均没有发生位置交换，则说明已完成排序，则跳出循环（此为优化版，我借鉴的）
        Flag = True
        # 内部循环：循环截止：len(lst1) - 1 - i ，下标索引超过：len(lst1) - 1 - i 就是已经冒泡确定位置的
        for j in range(len(lst) - 1 - i):
            # 大于冒泡得到升序，小于冒泡得到降序
            if lst1[j] > lst[j + 1]:
                lst[j],lst[j + 1] = lst[j + 1],lst[j]
                Flag = False

        if Flag:
            return lst

    return lst

''' #### 选择排序（Selection sort） #### '''

# 是一种简单直观的排序算法。它的工作原理大致是将乱序的数组的元素最小（大）元素一个个取出然后按顺序放置。
# 升序

def selection_sort(lst):
    n = len(lst)
    # 外部循环，循环 n - 1 此就可以完成所有元素的比较与位置变换
    for i in range(n - 1):
        max = i
        # 内部循环：从 i + 1 位置开始，与 i 位置的元素进行比较，
        for j in range(i + 1, n):
            # 通过循环，获取最大值的索引
            if lst[max] < lst[j]:
                max = j
        # 将最大值与第 i 位置的元素进行位置调换
        lst[i],lst[max] = lst[max],lst[i]
    # 循环完成，返回结果
    return lst

''' #### 插入排序（Insertion Sort） #### ''' # 此排序方法有运行时间的比较
# 一个乱序的序列，默认第一个元素有序，将此序列分成两段，前面的有序，后面的乱序
# 将乱序的序列最后一个元素与前面有序的元素依次比较，在合适的位置插入，重复操作，即可完成排序
# 列表的元素值插入和切片操作：
    # 1、单个下标索引得到的值是一个元素，不是列表，切片操作得到的是列表，相加的时候要考虑到这一点
    # 2、切片操作的范围：包括开始位置，不包括结束位置 ==> [a,b)，需要注意结束位置的索引值
# 升序
nn0 = 0
def insertion_sort(lst,nn0):
    n = len(lst)
    # 循环 n - 1 次即可完成排序
    for i in range(n - 1):
        # 判定 lst[n - 1] 是否是已完成排序序列的最大值，是的话直接完成插入操作，重新开始排序
        if lst[n - 1] >= lst[i]:
            lst = lst[:i + 1] + [lst[n - 1]] + lst[i + 1:n - 1]
            nn0 += 1
            continue
        # 内部循环：依次比较，如果小于等于lst[j]，则进行插入操作，跳出内部循环，重新开始
        for j in range(0,i+1):
            if lst[n - 1] <= lst[j]:
                lst = lst[:j] + [lst[n - 1]] + lst[j:n - 1]
                nn0 += 1
                break

    return nn0,lst

# a = datetime.datetime.now()
# print(a)
# print(insertion_sort(lst,nn0)[0])
# b = datetime.datetime.now()
# print(b)
# print((b-a).seconds)
# print('#############################################')

#   ''' ### 上面是我自己写的，将无序序列的最后一个元素与前面的有序序列（从前向后）比较后插入正确位置 ###'''
#   ''' ### 下面是网上的思路，将无序序列的第一个元素与前面的有序序列（从后向前）比较后插入正确位置 ###'''
#   代码段稍有区别：我的是通过序列切片的方法实现，网上的是通过元素位置调换实现的（有点类似冒泡）
#   将通过一个比较大的序列排序，对比运行时间来看，那种的运行效率更高
nn1 = 0
def insertion_sort_1(lst,nn1):
    n = len(lst)
    for i in range(1,n):
        # 从后往前开始比较
        for j in range(i,0,-1):
            # 判定位置
            if lst[j] < lst[j - 1]:
                lst[j],lst[j - 1] = lst[j - 1],lst[j]
                nn1 += 1
            elif lst[j] >= lst[j - 1]:
                break
    return nn1,lst

# a1 = datetime.datetime.now()
# print(a1)
# print(insertion_sort_1(lst1,nn1)[0])
# b1 = datetime.datetime.now()
# print(b1)
# print((b1-a1).seconds)
# print('#############################################')
nn2 = 0
def insertion_sort_2(lst,nn2):
    n = len(lst)
    for i in range(1,n):
        # 判定即将开始插入的元素是否大于有序序列的最大值，不大于则开始内部循环
        if lst[i] < lst[i - 1]:
            temp = lst[i] # 保存 i 位置的值
            index = i # 保存变化的下标值
            # 从后往前开始比较，从 i - 1 开始与要插入的值比较，如果插入值要小，则进行位置变换
            # 位置变换：将大的元素往后一位保存至 j + 1 的位置，然后将空出的下标 j 保存到 index中
            for j in range(i-1,-1,-1):
                # 判定位置
                if lst[j] > temp:
                    lst[j + 1] = lst[j]
                    index = j
                    nn2 += 1
                else:
                    break
            # 内部循环结束后，将插入值 tamp 保存到空出的下标 index 当中，完成一轮插入排序
            lst[index] = temp
    return nn2,lst

# a2 = datetime.datetime.now()
# print(a2)
# print(insertion_sort_2(lst2,nn2)[0])
# b2 = datetime.datetime.now()
# print(b2)
# print((b2-a2).seconds)
# print('#############################################')
'''
经过运行时间测试，第一种的运行速度是最快的，第三种慢上几秒，第二种要比第一种慢上一倍左右
总结一下：
    1、第二种排序中用到了类似冒泡排序的方法，两两交换比较费计算
    2、第一种是通过直接找到插入的位置，通过切片的方式重新拼接得到新的序列
    3、第三种通过将插入的元素的值提取出来，变相将此位置空出来，通过循环，将大的值一位一位的往后移动，同时将空出位置的下标值保存到 index 变量中
       找到插入的位置后，该位置的值以往后移了一位，将位置空了出来，将插入值通过空白的下标保存到这个位置，完成一次循环

    由此可见：冒泡排序，两两交换，运行效率最低
    至于第一种为什么是最快的，不知道是不是走到空间换时间的路子还有待考证（我现在还是搞不清）
'''

################################################

''' #### 希尔排序（Shell sort） #### '''
# 插入排序法和冒泡排序法的结合版
# 冒泡排序法的步长是 1 ，临近的两个元素两两交换
# 希尔排序：通过一个逐渐缩小的步长来把间隔值是步长的元素的两个值进行比较和位置交换，直到步长变成 1 ，在进行冒泡排序
# 在步长变小的过程中，通过较少的比较，可以得到一个相对有序的序列，当步长为 1 时，计算量也不会很大
# 相应的，步长的选取对希尔排序的运行速度有一定的影响
# 要确保最后的步长为 1 ，无法得到想要的结果

# for 循环版
def shell_sort(lst):
    n = len(lst)
    # 确定步长
    mm = round(math.log(n,2))-1
    for m in range(mm,-1,-1):
        span = 2**m - 1
        # 根据步长，将数据分组，确定循环次数
        for i in range(span):
            # 遍历取间隔为span的元素
            for j in range(i + span,n,span):
                # 如果后面的数小于前面的数，开始循环
                if lst[j] < lst[j - span]:
                    # 计入开始循环时的初始位置的值及该位置的下标
                    index = j
                    temp = lst[j]
                    # 开始循环遍历，如果后面的数比前面的小，前面的数保存到后面位置上
                    for k in range(j - span, -1, -span):
                        if lst[k] > temp:
                            lst[k + span] = lst[k]
                            index = k
                        else:
                            break
                    lst[index] = temp

    return lst

a3 = datetime.datetime.now()
print(a3)
print(shell_sort(lst3))
b3 = datetime.datetime.now()
print(b3)
print((b3-a3).seconds)

#  while 循环版
nn4 = 0
def shell_sort_1(list,nn4):
    n = len(list)
    # 初始步长
    ii = round(math.log(n,2)) - 1
    gap = 2**ii - 1
    while gap > 0:
        for i in range(gap, n):
            # 每个步长进行插入排序
            temp = list[i]
            j = i
            # 插入排序
            while j >= gap and list[j - gap] > temp:
                list[j] = list[j - gap]
                j -= gap
                nn4 += 1
            list[j] = temp
        # 得到新的步长
        ii -= 1
        gap = 2**ii - 1
    return nn4,list

# a4 = datetime.datetime.now()
# print(a4)
# print(shell_sort_1(lst1,nn4)[0])
# print(shell_sort_1(lst1,nn4)[1])
# b4 = datetime.datetime.now()
# print(b4)
# print((b4-a4).seconds)

''' #### 归并排序（Merge sort） #### '''

# 归并排序
# 将一个无序的序列进行多次分段，小的分段进行排序后向上合并有序的序列，多次合并操作完成整个序列的排序
# 主要应用场景：将两个已排序的序列合并成一个有序的序列，此排序方法依赖归并操作
# 构建一个长度等于两个序列的的数组，依次从头开始比较，将最小（大）的提取出来，放入到已构建的数组中，被提取的数组下标加 1

# 连个有序序列归并操作
# merge_lst_a = [i for i in range(1,20,2)]
# merge_lst_b = [i for i in range(0,20,2)]
# aa = len(merge_lst_a)
# bb = len(merge_lst_b)
# cc = aa + bb
# merge_lst_c = [0 for i in range(cc)]
# print(merge_lst_a)
# print(merge_lst_b)

# j = 0
# k = 0
# for i in range(cc):
    # if j >= aa:
        # merge_lst_c[i] = merge_lst_b[k]
        # k += 1
    # elif k >= bb:
        # merge_lst_c[i] = merge_lst_a[j]
        # j += 1
    # elif merge_lst_a[j] <= merge_lst_b[k]:
        # merge_lst_c[i] = merge_lst_a[j]
        # j += 1
    # elif merge_lst_a[j] > merge_lst_b[k]:
        # merge_lst_c[i] = merge_lst_b[k]
        # k += 1

# print(merge_lst_c)
######################################################
# 合并
def merge1(l_lst,r_lst):
    result = []
    if n == 1:
        return lst
    l,r = 0,0
    while l < len(l_lst) and r < len(r_lst):
        if l_lst[l] <= r_lst[r]:
            result.append(l_lst[l])
            l += 1
        else:
            result.append(r_lst[r])
            r += 1
    result += l_lst[l:]
    result += r_lst[r:]

    return result

# 分组
def merge_sort1(lst):
    n = len(lst)
    steps = 2
    while steps < n:
        for i in range(0,n,steps):
            if i + steps <= n:
                lst[i:i + steps] =  merge(lst[i:i + steps])
            else:
                lst[i:] = merge(lst[i:])
        steps *= 2
    return lst

# print(lst)
# print(merge_sort(lst))

########################################
'''归并排序中用到的递归，需要好好的学习一下，目前不是很清楚'''
########################################

def merge_sort(list):
    # 认为长度不大于1的数列是有序的
    if len(list) <= 1:
        return list
    # 二分列表
    middle = int(len(list) // 2)
    left = merge_sort(list[:middle])   # 递归#######################
    right = merge_sort(list[middle:])  # 递归#######################
    # 最后一次合并
    return merge(left, right)
# 合并
def merge(left, right):
    l,r=0,0
    result=[]
    while l < len(left) and r < len(right):
        if left[l] < right[r]:
            result.append(left[l])
            l+=1
        else:
            result.append(right[r])
            r +=1
    result += left[l:]
    result += right[r:]
    return result

a5 = datetime.datetime.now()
print(a5)
print(merge_sort(lst2))
b5 = datetime.datetime.now()
print(b5)
print((b5-a5).seconds)

## 运行结果表明：在此乱序序列的排序中，归并排序 速度快于 希尔排序


import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

def F32005 (X):
    '''F3_2005绘图函数'''
    dim = X.shape[0]
    f_bias_3 = -450

    # np.dot : np.dot()函数主要有两个功能，向量点积和矩阵乘
    result = 0
    for i in range(dim):
        Z = X
        # print(Z)
        result =  result + ((1000000)**(i/dim-1)) * Z[i]**2
        # print( result)
    return  result + f_bias_3

def F3Plot():
    fig = plt.figure(1) #定义figure
    ax = Axes3D(fig) #将figure变为3d
    # 遍历解空间
    x1=np.arange(-100,100,2) #定义x1，范围为[-100,100],间隔为2
    x2=np.arange(-100,100,2) #定义x2，范围为[-100,100],间隔为2
    X1,X2=np.meshgrid(x1,x2) #生成网格

    nSize = x1.shape[0]
    # 初始化空间
    Z=np.zeros([nSize,nSize])

    for i in range(nSize):
        for j in range(nSize):
            #构造F1输入
            X=[X1[i,j],X2[i,j]]
            #将格式由list转换为np.array
            X=np.array(X)
            # 计算F1的值
            Z[i, j] = F32005(X)
    #绘制3D曲面
    # rstride:行之间的跨度  cstride:列之间的跨度
    # rstride:行之间的跨度  cstride:列之间的跨度
    # cmap参数可以控制三维曲面的颜色组合
    ax.plot_surface(X1, X2, Z, rstride = 1, cstride = 1, cmap = plt.get_cmap('rainbow'))
    ax.contour(X1, X2, Z, zdir='z', offset=0)#绘制等高线
    ax.set_xlabel('X1')#x轴说明
    ax.set_ylabel('X2')#y轴说明
    ax.set_zlabel('Z')#z轴说明
    ax.set_title('F1_space')
    plt.show()

F3Plot()


from absl.testing import parameterized
import numpy as np

from tensorflow.python.eager import context
from tensorflow.python.eager.polymorphic_function import polymorphic_function
from tensorflow.python.framework import constant_op
from tensorflow.python.framework import dtypes
from tensorflow.python.framework import ops
from tensorflow.python.framework import random_seed as random_seed_lib
from tensorflow.python.framework import test_util
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import gradient_checker
from tensorflow.python.ops import gradient_checker_v2
from tensorflow.python.ops import variables
from tensorflow.python.platform import test

class ExtractImagePatchesGradTest(test.TestCase, parameterized.TestCase):
  """Gradient-checking for ExtractImagePatches op."""

  _TEST_CASES = [
      {
          'in_shape': [2, 5, 5, 3],
          'ksizes': [1, 1, 1, 1],
          'strides': [1, 2, 3, 1],
          'rates': [1, 1, 1, 1],
      },
      {
          'in_shape': [2, 7, 7, 3],
          'ksizes': [1, 3, 3, 1],
          'strides': [1, 1, 1, 1],
          'rates': [1, 1, 1, 1],
      },
      {
          'in_shape': [2, 8, 7, 3],
          'ksizes': [1, 2, 2, 1],
          'strides': [1, 1, 1, 1],
          'rates': [1, 1, 1, 1],
      },
      {
          'in_shape': [2, 7, 8, 3],
          'ksizes': [1, 3, 2, 1],
          'strides': [1, 4, 3, 1],
          'rates': [1, 1, 1, 1],
      },
      {
          'in_shape': [1, 15, 20, 3],
          'ksizes': [1, 4, 3, 1],
          'strides': [1, 1, 1, 1],
          'rates': [1, 2, 4, 1],
      },
      {
          'in_shape': [2, 7, 8, 1],
          'ksizes': [1, 3, 2, 1],
          'strides': [1, 3, 2, 1],
          'rates': [1, 2, 2, 1],
      },
      {
          'in_shape': [2, 8, 9, 4],
          'ksizes': [1, 2, 2, 1],
          'strides': [1, 4, 2, 1],
          'rates': [1, 3, 2, 1],
      },
  ]

  def testGradient(self):
    # Set graph seed for determinism.
    random_seed = 42
    random_seed_lib.set_random_seed(random_seed)

    with self.cached_session():
      for test_case in self._TEST_CASES:
        np.random.seed(random_seed)
        in_shape = test_case['in_shape']
        in_val = constant_op.constant(
            np.random.random(in_shape), dtype=dtypes.float32)
        # Avoid `dangerous-default-value` pylint error by creating default
        # args to `extract` as tuples.
        ksizes = tuple(test_case['ksizes'])
        strides = tuple(test_case['strides'])
        rates = tuple(test_case['rates'])

        for padding in ['VALID', 'SAME']:

          def extract(in_val,
                      ksizes=ksizes,
                      strides=strides,
                      rates=rates,
                      padding=padding):
            return array_ops.extract_image_patches(in_val, ksizes, strides,
                                                   rates, padding)

          err = gradient_checker_v2.max_error(
              *gradient_checker_v2.compute_gradient(extract, [in_val]))
          self.assertLess(err, 1e-4)

  @parameterized.parameters(set((True, context.executing_eagerly())))
  def testConstructGradientWithLargeImages(self, use_tape):
    with test_util.AbstractGradientTape(use_tape=use_tape) as tape:
      batch_size = 4
      # Prevent OOM by setting reasonably large image size (b/171808681).
      height = 512
      width = 512
      ksize = 5
      shape = (batch_size, height, width, 1)
      images = variables.Variable(
          np.random.uniform(size=np.prod(shape)).reshape(shape), name='inputs')
      tape.watch(images)
      patches = array_ops.extract_image_patches(images,
                                                ksizes=[1, ksize, ksize, 1],
                                                strides=[1, 1, 1, 1],
                                                rates=[1, 1, 1, 1],
                                                padding='SAME')
      # Github issue: #20146
      # tf.image.extract_image_patches() gradient very slow at graph
      # construction time.
      gradients = tape.gradient(patches, images)
      # Won't time out.
      self.assertIsNotNone(gradients)

  def _VariableShapeGradient(self, test_shape_pattern):
    """Use test_shape_pattern to infer which dimensions are of

    variable size.
    """
    # Testing shape gradient requires graph mode.
    with ops.Graph().as_default():
      # Set graph seed for determinism.
      random_seed = 42
      random_seed_lib.set_random_seed(random_seed)

      with self.test_session():
        for test_case in self._TEST_CASES:
          np.random.seed(random_seed)
          in_shape = test_case['in_shape']
          test_shape = [
              x if x is None else y
              for x, y in zip(test_shape_pattern, in_shape)
          ]
          in_val = array_ops.placeholder(shape=test_shape, dtype=dtypes.float32)

          feed_dict = {in_val: np.random.random(in_shape)}
          for padding in ['VALID', 'SAME']:
            out_val = array_ops.extract_image_patches(in_val,
                                                      test_case['ksizes'],
                                                      test_case['strides'],
                                                      test_case['rates'],
                                                      padding)
            out_val_tmp = out_val.eval(feed_dict=feed_dict)
            out_shape = out_val_tmp.shape

            err = gradient_checker.compute_gradient_error(
                in_val, in_shape, out_val, out_shape)
            self.assertLess(err, 1e-4)

  def test_BxxC_Gradient(self):
    self._VariableShapeGradient([-1, None, None, -1])

  def test_xHWx_Gradient(self):
    self._VariableShapeGradient([None, -1, -1, None])

  def test_BHWC_Gradient(self):
    self._VariableShapeGradient([-1, -1, -1, -1])

  def test_AllNone_Gradient(self):
    self._VariableShapeGradient([None, None, None, None])

  def testJitCompile(self):
    with test_util.AbstractGradientTape(use_tape=True) as tape:
      shape = (4, 512, 512, 1)
      ksize = 5

      images = variables.Variable(np.random.uniform(size=shape), name='inputs')
      tape.watch(images)

      # Github issues: #59058, #59061
      # tf.image.extract_image_patches() does not support backward pass
      # when compiled with XLA.
      extract_image_patches_jit = polymorphic_function.function(
          array_ops.extract_image_patches, jit_compile=True
      )
      patches = extract_image_patches_jit(
          images,
          ksizes=[1, ksize, ksize, 1],
          strides=[1] * 4,
          rates=[1] * 4,
          padding='SAME',
      )

      gradients = tape.gradient(patches, images)
      self.assertIsNotNone(gradients)

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


from post.models import Post, Tag
from rest_framework import serializers
from .constants import constant

class TagSerializer(serializers.ModelSerializer):
    class Meta:
        model = Tag
        fields = ('id', 'name')

class PostSerializer(serializers.ModelSerializer):

    class Meta:
        model = Post
        fields = '__all__'
        read_only_fields = ('created', 'tags')

    # def get_validation_exclusions(self, *args, **kwargs):
    #     exclusions = super(PostSerializer, self).get_validation_exclusions()
    #
    #     return exclusions + ['test']

    def create(self, validated_data):
        print("validated_data", validated_data)
        str_tags = self.initial_data['tags']

        tag_list = str_tags.split(",")

        instance = Post.objects.create(**validated_data)

        tags = Tag.objects.filter(id__in=tag_list)
        for tag in tags:
            instance.tags.add(tag)

        return instance

class PostObjSerializer():
    def __init__(self, post_obj):
        self.obj = {
            "pk": post_obj.pk,
            "title": post_obj.title,
            "post_url": post_obj.post_url,
            "desc": post_obj.desc,
            "thumbnail_link": post_obj.thumbnail_link,
            "url": constant["url_post"]+str(post_obj.id),
            "tags": []
        }

        tags = post_obj.tags.all()
        if tags:
            self.obj["tags"] = [{"name": entry.name, "id": entry.id, "url": constant["url_tag"]+str(entry.id)}
                                for entry in tags]

    def run(self):
        return self.obj


import argparse
import numpy as np

parser = argparse.ArgumentParser("Find the submarine location")
parser.add_argument('--filename', dest='filename', default='input')
args = parser.parse_args()

with open(args.filename, 'r') as f:
    lines = f.readlines()

num_drawns = [int(x) for x in lines[0].split(',')]

grids = []

def read_one_grid(grid_text):
    grid = []
    for l, vals in enumerate(grid_text):
        grid.append([int(x) for x in vals.split()])
    return grid

end_of_grids = False
nb_grids = 0
while(not end_of_grids):
    current_index = nb_grids * 6 + 2
    if current_index >= len(lines):
        break
    grids.append(read_one_grid(lines[current_index : current_index + 5]))
    nb_grids += 1

check_grid = np.zeros((len(grids),5,5))
grids = np.asarray(grids)

for num in num_drawns:
    check_grid[grids == num] = 1
    good_line = np.nonzero(check_grid.all(axis=2))
    good_col = np.nonzero(check_grid.all(axis=1))
    if len(good_line[0]):
        winner_grid = good_line[0]
        break
    elif len(good_col[0]):
        winner_grid = good_col[0]
        break

non_zero_tot = grids[winner_grid][(check_grid[winner_grid] == 0).nonzero()].sum()
print('non_zero_tot :', non_zero_tot, 'product :', non_zero_tot * num)