import operator
from itertools import islice

import contexttimer
import pytest
from mypy_boto3_sqs import Client as SQSClient

from tests.test_queue.robot import Command, CommandReceiver, ReceiverAndSender

def test_pause(receiver_and_sender: ReceiverAndSender):
    """Wait a bit if the queue is empty."""
    receiver, _sender = receiver_and_sender

    assert receiver.iteration_timeout == 3

    with contexttimer.Timer() as timer:
        receiver._pause_while_iterating_over_queue()

        elapsed_time = timer.elapsed

    assert round(elapsed_time) <= receiver.iteration_timeout

def test_iterate_imperative(receiver_and_sender: ReceiverAndSender):
    """The `for` loop construct can iterate by messages in queue."""
    receiver, sender = receiver_and_sender

    sent_commands = [Command.RIGHT, Command.FORWARD, Command.LEFT, Command.JUMP]

    sender.send_many(sent_commands)

    received_commands = []
    for message in receiver:
        received_commands.append(message.value)

        receiver.acknowledge(message)

        if message.value == Command.JUMP:
            break

    assert received_commands == sent_commands

def test_iterate_functional(receiver_and_sender: ReceiverAndSender):
    """The `for` loop construct can iterate by messages in queue."""
    receiver, sender = receiver_and_sender

    sent_commands = [Command.RIGHT, Command.FORWARD, Command.LEFT, Command.JUMP]

    sender.send_many(sent_commands)

    # We have to limit the number of messages we are interested in,
    # or .receive() will hang forever.
    messages = islice(receiver, len(sent_commands))

    # Now let's acknowledge those messages.
    messages = map(receiver.acknowledge, messages)

    # And let's see what they are.
    received_commands = list(map(operator.attrgetter('value'), messages))

    assert received_commands == sent_commands

class NotPausingReceiver(CommandReceiver):
    """Receiver with overridden pause method."""

    def _pause_while_iterating_over_queue(self) -> None:
        """Do not pause, raise instead."""
        raise ValueError('foo!')

def test_empty_queue(mock_sqs_client: SQSClient):
    """Test empty queue."""
    sqs_queue_url = mock_sqs_client.create_queue(
        QueueName='robot_commands',
        Attributes={
            'VisibilityTimeout': '3',
        },
    )['QueueUrl']

    receiver = NotPausingReceiver(url=sqs_queue_url)

    with pytest.raises(ValueError):
        for sqs_message in receiver:
            assert sqs_message is not None


# -*- coding: utf-8 -*-

from setuptools import find_packages, setup

__description__ = 'Api REST Python Flask'
__long_description__ = 'This is an api for SW Universe B2W chalenge'

__author__ = 'Anderson Picollo'
__author_email__ = 'andersonpicollo@gmail.com'

testing_extras = [
    'pytest',
    'pytest-cov',
]

setup(
    name='swdesafio',
    author=__author__,
    author_email=__author_email__,
    packages=find_packages(),

    description=__description__,
    long_description=__long_description__,
    url='https://github.com/andersonpicollo/swdesafio',
    keywords='API, REST, Flask, MongoDB',
    include_package_data=True,
    zip_safe=False,
    setup_requires=['pytest-runner'],
    tests_require=['pytest'],
    extras_require={
        'testing': testing_extras,
    },
)


"""
===================
Demo Axis Direction
===================

"""

import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.axisartist.angle_helper as angle_helper
import mpl_toolkits.axisartist.grid_finder as grid_finder
from matplotlib.projections import PolarAxes
from matplotlib.transforms import Affine2D

import mpl_toolkits.axisartist as axisartist

from mpl_toolkits.axisartist.grid_helper_curvelinear import \
    GridHelperCurveLinear

# nodebox section
if __name__ == '__builtin__':
    # were in nodebox
    import os
    import tempfile
    W = 800
    inset = 20
    size(W, 600)
    plt.cla()
    plt.clf()
    plt.close('all')
    def tempimage():
        fob = tempfile.NamedTemporaryFile(mode='w+b', suffix='.png', delete=False)
        fname = fob.name
        fob.close()
        return fname
    imgx = 20
    imgy = 0
    def pltshow(plt, dpi=150):
        global imgx, imgy
        temppath = tempimage()
        plt.savefig(temppath, dpi=dpi)
        dx,dy = imagesize(temppath)
        w = min(W,dx)
        image(temppath,imgx,imgy,width=w)
        imgy = imgy + dy + 20
        os.remove(temppath)
        size(W, HEIGHT+dy+40)
else:
    def pltshow(mplpyplot):
        mplpyplot.show()
# nodebox section end

def setup_axes(fig, rect):
    """
    polar projection, but in a rectangular box.
    """

    # see demo_curvelinear_grid.py for details
    tr = Affine2D().scale(np.pi/180., 1.) + PolarAxes.PolarTransform()

    extreme_finder = angle_helper.ExtremeFinderCycle(20, 20,
                                                     lon_cycle=360,
                                                     lat_cycle=None,
                                                     lon_minmax=None,
                                                     lat_minmax=(0, np.inf),
                                                     )

    grid_locator1 = angle_helper.LocatorDMS(12)
    grid_locator2 = grid_finder.MaxNLocator(5)

    tick_formatter1 = angle_helper.FormatterDMS()

    grid_helper = GridHelperCurveLinear(tr,
                                        extreme_finder=extreme_finder,
                                        grid_locator1=grid_locator1,
                                        grid_locator2=grid_locator2,
                                        tick_formatter1=tick_formatter1
                                        )

    ax1 = axisartist.Subplot(fig, rect, grid_helper=grid_helper)
    ax1.axis[:].toggle(ticklabels=False)

    fig.add_subplot(ax1)

    ax1.set_aspect(1.)
    ax1.set_xlim(-5, 12)
    ax1.set_ylim(-5, 10)

    return ax1

def add_floating_axis1(ax1):
    ax1.axis["lat"] = axis = ax1.new_floating_axis(0, 30)
    axis.label.set_text(r"$\theta = 30^{\circ}$")
    axis.label.set_visible(True)

    return axis

def add_floating_axis2(ax1):
    ax1.axis["lon"] = axis = ax1.new_floating_axis(1, 6)
    axis.label.set_text(r"$r = 6$")
    axis.label.set_visible(True)

    return axis

fig = plt.figure(1, figsize=(8, 4))
fig.clf()
fig.subplots_adjust(left=0.01, right=0.99, bottom=0.01, top=0.99,
                    wspace=0.01, hspace=0.01)

for i, d in enumerate(["bottom", "left", "top", "right"]):
    ax1 = setup_axes(fig, rect=241++i)
    axis = add_floating_axis1(ax1)
    axis.set_axis_direction(d)
    ax1.annotate(d, (0, 1), (5, -5),
                 xycoords="axes fraction", textcoords="offset points",
                 va="top", ha="left")

for i, d in enumerate(["bottom", "left", "top", "right"]):
    ax1 = setup_axes(fig, rect=245++i)
    axis = add_floating_axis2(ax1)
    axis.set_axis_direction(d)
    ax1.annotate(d, (0, 1), (5, -5),
                 xycoords="axes fraction", textcoords="offset points",
                 va="top", ha="left")

pltshow(plt)


from sqlalchemy import or_
from flask import Blueprint, request, jsonify, current_app, send_from_directory

from core.database import db
from core.anunciantes.models import Anunciante
from core.categorias.models import Categoria
from core.image_upload import handle_image_upload

anunciantes_blueprint = Blueprint("anunciantes", __name__)

@anunciantes_blueprint.route('/', methods=['GET', 'POST'])
def index_anunciantes():
    if request.method == 'POST':
        anunciante = save_advertiser_profile(request.json)
        return jsonify(anunciante.serialize)
    id_categoria = int(request.args.get('id_categoria', '0'))
    if id_categoria == 0:
        anunciantes = Anunciante.query.all()
    else:
        anunciantes = Anunciante.query.filter_by(id_categoria=id_categoria)
    return jsonify([anunciante.serialize for anunciante in anunciantes])

@anunciantes_blueprint.route('/fotos', methods=["GET", "POST"])
def image_upload():
    return handle_image_upload(request,
                               save_path=current_app.config['ADVERTISER_MEDIA_PATH'],
                               success_path='.get_advertiser_image')

@anunciantes_blueprint.route('/foto/<filename>')
def get_advertiser_image(filename):
    return send_from_directory(current_app.config['ADVERTISER_MEDIA_PATH'], filename)

@anunciantes_blueprint.route('/search')
def search_advertiser():
    search_query = '%' + request.args.get('q') + '%'
    q = db.session.query(Anunciante) \
        .outerjoin(Categoria, Anunciante.id_categoria==Categoria.id_categoria) \
        .filter(or_(Anunciante.nome_fantasia.like(search_query), Categoria.descricao.like(search_query)))
    return jsonify([anunciante.serialize for anunciante in q])

def save_advertiser_profile(json):
    new_advertiser = False
    advertiser = Anunciante.query.filter_by(guid_anunciante=json["guid_anunciante"]).first()
    if not advertiser:
        advertiser = Anunciante()
        new_advertiser = True
    advertiser.guid_anunciante = json["guid_anunciante"]
    advertiser.nome_fantasia = json["nome_fantasia"]
    advertiser.logradouro = json["logradouro"]
    advertiser.numero = json["numero"]
    advertiser.bairro = json["bairro"]
    advertiser.telefone = json["telefone"]
    advertiser.celular = json["celular"]
    advertiser.email = json["email"]
    advertiser.id_cidade = json['id_cidade']
    advertiser.id_categoria = json["id_categoria"]
    advertiser.picture_file = json.get("picture_file", None)
    if new_advertiser:
        db.session.add(advertiser)
    db.session.commit()
    return advertiser


import numpy as np
import matplotlib.pyplot as plt

root = 'model6_r_0p1_to_1_500_nolensing_no_temp_no_scalar_label_rescale_10_do_label_shift_yes_rescale_0p1_0p1_no_pretrain_at_epoch_59'
plot_dir = './plots/' + root + '/'
plot_data_dir = plot_dir + 'plot_data/'
pred_means = np.genfromtxt(plot_data_dir + 'pred_means.dat')
pred_stds = np.genfromtxt(plot_data_dir + 'pred_stds.dat')
true_values = np.genfromtxt(plot_data_dir + 'true_values.dat')
len_same_values = np.genfromtxt(plot_data_dir + 'len_same_values.dat')
predictions_all = np.genfromtxt(plot_data_dir + 'predictions_all.dat')

r = np.zeros(int(np.sum(len_same_values)))
ii = 0
for i in np.arange(true_values.shape[0]):
    for j in  np.arange(len_same_values[i]):
        r[ii] = true_values[i] # might change to true_values[i,:] if n_params >1
        ii = ii + 1
print(r.shape)
print('r', r)
print(true_values[0],true_values[1], true_values[-1])
print('r[:55]', r[:55])
print('len_same_values', len_same_values)
r_pred = predictions_all
print('r_pred', r_pred)
err = r - r_pred
abs_err = np.abs(err)
print('err', err)

#r = np.array([0.12, 0.13, 0.2, 0.25, 0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0])+0.05
#err = r/10.0
#err[1] = 0.1
#r_pred = r + r/10.0
#print('r, err', r, err)

bins = np.linspace(0.1,1.0,10)
print('bins = ', bins)
ind_bin = np.digitize(r,bins,right=False)
bin_center = (bins[1:]+bins[:-1])/2.0
print('bin center = ', bin_center)
print('ind_bin', ind_bin)
print('heyehye')

err_binned = np.zeros(bin_center.size)
for i in np.arange(1, bin_center.size+1):
    err_binned[i-1] = np.mean(abs_err[np.where(ind_bin==i)])
    if err_binned[i-1] == np.nan:
        err_binned[i-1] = 0.0
    print('i = ', i)
    print('np.where(ind_bin==i)', np.where(ind_bin==i))
    print('abs_err[np.where(ind_bin==i)]', abs_err[np.where(ind_bin==i)])
    print('err_binned', err_binned)

print('\n Making figures now')

fig, ax = plt.subplots()
ax.plot(r, err, 'x')
ax.set_xlabel(r'$r$')
ax.set_ylabel('error on r')
plotname = plot_dir + 'plot_r_error_vs_r.pdf'
plt.savefig(plotname)
print('Saved figure: ', plotname)

fig, ax = plt.subplots()
ax.plot(bin_center, err_binned, '.')
ax.set_xlabel(r'$r$')
ax.set_ylabel('binned error on r')
plotname = plot_dir + 'plot_binned_r_error_vs_r.pdf'
plt.savefig(plotname)
print('Saved figure: ', plotname)

fig, ax = plt.subplots()
ax.plot(r, r, 'r-')
ax.plot(r, r_pred, 'bx') #no error bars yet
ax.set_xlabel(r'$r$')
ax.set_ylabel(r'$r_{\mathrm{pred}}$')
plotname = plot_dir + 'plot_r_pred_vs_r_no_error_bar.pdf'
plt.savefig(plotname)
print('Saved figure: ', plotname)


import matplotlib.pyplot as plt

def plot_df(df, title, size):
    df.plot(kind='bar', stacked=False, width=1, logy=True, figsize=size, legend=False)
    plt.title(title)
    plt.legend(loc='center left', bbox_to_anchor=(1, 0.5), prop={'size': 8})
    plt.tight_layout()
    plt.tick_params(axis='both', labelsize=8)
    plt.show()

def plot_3d(data, title, x_axis, y_axis, z_axis, size):
    fig = plt.figure(figsize=size)
    ax = fig.gca(projection='3d')
    index = 0
    shapes = ['o', 'v', 's', 'x', '*', 'D', 'P', '^', '1', 'p', '+', 'X', '<', '>']
    colours = ['b', 'g', 'r', 'c', 'y', 'k', 'm', 'tab:brown']
    for name, row in data.iterrows():
        ax.scatter(row[x_axis], row[y_axis], row[z_axis], label=name, c=colours[index % len(colours)], marker=shapes[index // len(colours)])
        index += 1
    ax.set_xlabel(x_axis, fontsize=8)
    ax.set_ylabel(y_axis, fontsize=8)
    ax.set_zlabel(z_axis, fontsize=8)
    ax.tick_params(axis='both', labelsize=8)
    fig.suptitle(title)
    plt.legend(loc='center left', bbox_to_anchor=(1, 0.5), prop={'size': 8}, ncol=2)
    plt.tight_layout()
    plt.show()


__author__ = 'root'
from dbservices import servicechecklogs
from opsviewapi.models import ServiceCheckLog
from exc.exceptions import ServiceCheckLogError
from django.utils import timezone
import logging

logger = logging.getLogger(__name__)

def write_service_check_log(log_obj=None, time_stamp=None, device_info=None, description=None, status=None,
                            device_name=None, error_code=None):
    if time_stamp is None:
        time_stamp = timezone.now()

    if log_obj is None:
        log_obj = ServiceCheckLog(time_stamp=time_stamp, device_info=device_info, description=description,
                                  status=status, device_name=device_name, error_code=error_code)

    try:
        servicechecklogs.insert_update_log(log_obj=log_obj)
    except ServiceCheckLogError as ex:
        logger.warning(ex)

def delete_service_check_log(dev_name):
    try:
        servicechecklogs.delete_log(device_name=dev_name)
    except ServiceCheckLogError as ex:
        logger.warning(ex)


__author__ = u'Jon Hill'
__copyright__ = u'Copyright 2012, Jon Hill'
__credits__ = [u'Jon Hill']

__license__ = 'BSD'
__version__ = '0.1'
__maintainer__ = u'Jon Hill'
__email__ = 'jon@jonhill.ca'
__status__ = 'Development'

import signals


# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

from django.conf import settings

class CorsHeaderMiddleware(object):
    """Add a CORS header if running in debug mode."""

    def process_response(self, request, response):
        if settings.DEBUG:
            response['Access-Control-Allow-Origin'] = '*'
        return response


from Method import Get
import os

''' perfor(package,num,id) ,package表示包名，num表示数据采样的个数，
    id=0取三种维度的数据，id=1表示取cpu数据，id=2表示取内存数据，id=3表示取流量数据
 '''

def perfor(package,num,id):
    data = []
    if id == 0:
        data0=[]
        data1=[]
        data2=[]
        for i in range(num):
            a = Get.get_cpu(package)
            data0.append(a)
            b = Get.get_mem(package)
            data1.append(b)
            c = Get.get_net(package)
            data2.append(c)
        data.append(data0)
        data.append(data1)
        data.append(data2)
        Get.get_netcost(data2)
    elif id == 1:
        for i in range(num):
            a = Get.get_cpu(package)
            data.append(a)
    elif id == 2:
        for i in range(num):
            b = Get.get_mem(package)
            data.append(b)
    elif id == 3:
        for i in range(num):
            c = Get.get_net(package)
            data.append(c)
        Get.get_netcost(data)
    else:
        print("请输入正确的id")
    dict={id:data}
    return dict

if __name__ == '__main__':
    package = "com.jingdong.app.mall"
    os.system("adb shell am start -n %s/.main.MainActivity" % (package))
    x=perfor(package,3,0)
    print(x)


# -*- coding: utf-8 -*-

import sys

reload(sys)
sys.setdefaultencoding('utf-8')
sys.path.append("..")

from SpiderFrame import Global as gl
#import Global as gl

class StructData(object):
    """
    base class for target data from html
    """
    # _database_struct define the structure of table, which storage this kind of data.
    # it is a list, whose elements aret tuple. tuple's format is (attr_name, type, constrain).
    # for example, if there is an attribute self.id, and id is an unique integer. so, the tuple
    # is ("id", "int", "primary key") or ("id", "int", "unique"). if there's another attribute
    # self.name, and has no constrain on it. So the tuple is ("name", "varchar(256)").
    # see MySQL for more information about type and constrain

    _database_struct = []
    _attr_count = None
    _primary_k = None

    def __init__(self):
        return super(StructData, self).__init__()

    @classmethod
    def table_struct(cls):
        """
        create the structure of table
        """
        assert cls._database_struct != [], \
               "check the _database_struct, make sure its count of elements is equal to the count of instance attributes"
        cls._attr_count = len(cls._database_struct)
        temp = []
        for item in cls._database_struct:
            if len(item) > 2:
                value = " %s %s %s"%item
                if 'primary' in item[2].lower():
                    cls._primary_k = item[0]
            else:
                value = " %s %s"%item
            temp.append(value)
        if cls._primary_k is None:
            raise RuntimeError("table %s has no primary key"%cls.__name__)
        structor = """create table %s ( %s );"""%(cls.__name__, ','.join(temp))
        return structor

    @classmethod
    def register(cls):
        """
        add this class to table list of database
        """
        gl.g_dbtable.append(cls.table_struct())

    def format(self):
        value = [self.__dict__[item[0]] for item in self._database_struct]
        return tuple(value)


from __future__ import print_function
import os, sys
from IPython.core.display import display, HTML
import shutil
import requests
import threading
import glob
import math
import matplotlib.pyplot as plt
from matplotlib.dates import date2num, AutoDateFormatter, AutoDateLocator

from utilities import hydroshare

is_py2 = sys.version[0] == '2'
if not is_py2:
    msg = 'The ts_utils function currently only works with Python 2.X'
    raise Exception(msg)
else:
    # set this for future python3 compatibility
    input = raw_input

    from odm2api.ODMconnection import dbconnection
    from odm2api.ODM2.services.readService import *
    from odm2api.ODM2.services.createService import *

class timeseries():
    def __init__(self):
        self.hydroshare = hydroshare.hydroshare()
        self.odm2db = None
        self._session = None
        self.read = None
        self.write = None
        self.tsresults = {}
        self.tsvalues = {}

    def content(self):
        return self.hydroshare.content

    def loadDatabase(self):
        if self.odm2db is None:
            display(HTML('Failed to load the database. Please make sure that the content for this resource contains a *.sqlite file.'))

        # load odm2 database
        self._session = dbconnection.createConnection('sqlite', self.odm2db)
        self.read = ReadODM2(self._session)
        self.write = CreateODM2(self._session)

    def readResults(self):
        res = self.read.getResults()
        self.tsresults = {r.ResultID:r for r in res}
        return self.tsresults

    def readTsValues(self, ids = []):

        if len(self.tsresults.keys()) == 0:
            self.readResults()

        # assemble a list if ids to download data for
        resids = self.tsresults.keys() if len(ids) == 0 else ids

        # download values for each result
        for resid in resids:
            res = self.tsresults[resid]
            print('Processing -> ' + ': '.join([res.VariableObj.VariableNameCV,
                                             res.FeatureActionObj.SamplingFeatureObj.SamplingFeatureName]))
            self.tsvalues[resid] = self.read.getResultValues(resid)

    def previewTs(self, ids=[], rows=5):

        if len(self.tsresults.keys()) == 0:
            self.readResults()

        # assemble a list if ids to download data for
        resids = self.tsresults.keys() if len(ids) == 0 else ids

        get_ids = [tsid for tsid in resids if tsid not in self.tsvalues.keys()]
        if len(get_ids) > 0:
            print('Need to prepare the data for one or more of these result ids')
            self.readTsValues(get_ids)
        if len(get_ids) > 0 :print('\n')

        for tsid in resids:
            dv = self.tsvalues[tsid]['DataValue']
            dt = self.tsvalues[tsid]['ValueDateTime']
            res = self.tsresults[tsid]
            title = ' %s ' % (': '.join([res.VariableObj.VariableNameCV,
                                         res.FeatureActionObj.SamplingFeatureObj.SamplingFeatureName]))
            restext = ' ResultID: %s' % tsid
            headtext ='DataValue \t ValueDateTime'

            # print timeseries header
            line_len = len(title)+4
            sepline = '-'* line_len
            print('-%s-' % sepline)
            print('%s%s' % (restext,' '*(line_len-len(restext))))
            print('%s%s' % (title,' '*(line_len-len(title))))
            print('-%s-' % sepline)

            # print timeseries values
            sys.stdout.write("%-25s %-25s \n" % ('DataValue','ValueDateTime'))
            for i in range(5):
                sys.stdout.write("%-25s %-25s \n" % (dt[i], dv[i]))
            print('\n')

    def subplotTimeSeries(self, ids=[], cols=1):
        # assemble a list if ids to download data for
        resids = self.tsresults.keys() if len(ids) == 0 else ids

        get_ids = [tsid for tsid in resids if tsid not in self.tsvalues.keys()]
        if len(get_ids) > 0:
            print('Need to prepare the data for one or more of these result ids')
            self.readTsValues(get_ids)
        if len(get_ids) > 0 :print('\n')

        # create the figure
        rows = math.ceil(float(len(resids)) / float(cols))
        fig = plt.figure(figsize=(15,rows*5))
        fig.subplots_adjust(hspace=.5)

        # plot the results, each in its own subplot
        for i in range(1, len(resids)+1):
            ax = fig.add_subplot(rows, cols, i)
            res = self.tsresults[resids[i-1]]
            tsval = self.tsvalues[resids[i-1]]

            x = list(self.tsvalues[resids[i-1]]['ValueDateTime'])
            y = list(self.tsvalues[resids[i-1]]['DataValue'])
            title = res.FeatureActionObj.SamplingFeatureObj.SamplingFeatureName
            col_width=80/cols - 4
            subtitle = title[:col_width]+' ...' if len(title) > col_width else title
            ax.set_title(subtitle, fontsize=14)

            ax.plot_date(x,y,'-')
            ax.set_ylabel(res.VariableObj.VariableNameCV + " (" + res.UnitsObj.UnitsAbbreviation + ")")

            locator = AutoDateLocator()
            ax.xaxis.set_major_locator(locator)
            ax.xaxis.set_major_formatter(AutoDateFormatter(locator))
            labels = ax.get_xticklabels()
            plt.setp(labels, rotation=30, fontsize=10)

            ax.grid(True)

    def plotTimeSeries(self, ids=[]):
        # assemble a list if ids to download data for
        resids = self.tsresults.keys() if len(ids) == 0 else ids

        get_ids = [tsid for tsid in resids if tsid not in self.tsvalues.keys()]
        if len(get_ids) > 0:
            print('Need to prepare the data for one or more of these result ids')
            self.readTsValues(get_ids)
        if len(get_ids) > 0 :print('\n')

        # create the figure
        fig = plt.figure(figsize=(15,5))
        ax = fig.add_subplot(1,1,1)

        # plot the results
        for i in range(1, len(resids)+1):
            x = list(self.tsvalues[resids[i-1]]['ValueDateTime'])
            y = list(self.tsvalues[resids[i-1]]['DataValue'])
            res = self.tsresults[resids[i-1]]
            l = res.FeatureActionObj.SamplingFeatureObj.SamplingFeatureName
            ax.plot(x,y, label=l[:30])

        ax.set_ylabel(res.VariableObj.VariableNameCV + " (" + res.UnitsObj.UnitsAbbreviation + ")")
        locator = AutoDateLocator()
        ax.xaxis.set_major_locator(locator)
        ax.xaxis.set_major_formatter(AutoDateFormatter(locator))
        labels = ax.get_xticklabels()
        plt.setp(labels, rotation=30, fontsize=10)

        ax.grid(True)

        # add a legend
        plt.legend()
        box = ax.get_position()
        ax.set_position([box.x0, box.y0, box.width * 0.8, box.height])
        ax.legend(loc='center left', bbox_to_anchor=(1, 0.9))

    def getTimeSeriesResource(self, resourceid=None, destination='.'):
        """
        Downloads the content of HydroShare resource to the JupyterHub userspace

        Args:
            resourceid: id of the HydroShare resource to query
            destination: path relative to /user/[username]/notebooks/data

        """
        try:
            res_meta = self.hydroshare.hs.getSystemMetadata(resourceid)

            if res_meta['resource_type'].lower() != 'timeseriesresource':
                display(HTML('Attempting to download resource of type %s.
 The'
                                 '`getTimeSeriesResource` function can only be used to download resources'
                                 'of type TimeSeriesResource.
Please specify a TimeSeries resource to download'
                                 % res_meta['resource_type']))
                return  None
        except Exception as e:
            display(HTML('Failed to retrieve resource content from HydroShare: %s' % e))
            return None

        # set the download path
        default_dl_path = os.environ['DATA']
        dst = os.path.abspath(os.path.join(default_dl_path, destination))
        download = True

        # get the hydroshare resource.  This puts the result into hs.content
        self.hydroshare.getResourceFromHydroShare(resourceid, destination)

        # load the odm2db into memory
        try:
            # get the sqlite file associated with the resource
            odm2dbName = next(k for k in self.content().keys() if k[-6:] == 'sqlite')
            self.odm2db = self.content()[odm2dbName]
            self.loadDatabase()
        except:
            print(self.content())
            display(HTML('Failed to find a database associated with this resource.  Please make sure that the content for this resource contains a *.sqlite file.'))
            return None


from tkinter import *
import time
import os
from tkinter.messagebox import showinfo
import warnings
from tkinter import messagebox as mb

warnings.filterwarnings('ignore')

rt=Tk()
rt.geometry("1600x800+0+0")
rt.title("TIC TAC TOE")
rt.configure(bg='light green')
########################################################################################################################
Tops=Frame(rt,width = 1600,height = 50,bg='light green',relief=SUNKEN)
Tops.pack(side=TOP)

f1=Frame(rt,width = 550,height = 700,bg='light green',relief=SUNKEN)
f1.pack(side=LEFT)

f2=Frame(rt,width = 300,height = 700,bg='light green',relief=SUNKEN)
f2.pack(side=RIGHT)
########################################################################################################################
lblInfo=Label(Tops,font=("arial",30,"bold"),text="WELCOME TO THE GAME TIC TAC TOE",bg="light green",fg="dark green",bd=10,anchor="w")
lblInfo.pack()

localtime=time.asctime(time.localtime(time.time()))#DATE TIME FUNCTION

lblDateTime=Label(Tops,font=("arial",20,"bold"),text=localtime,bg="light green",fg="dark green",bd=10,anchor="w")
lblDateTime.pack()

lblInfo=Label(Tops,font=("arial",23,"bold"),text="",bg="light green",fg="dark green",bd=10,anchor="w")
lblInfo.pack()

lblInfo=Label(Tops,font=("arial",23,"bold"),text="PRESS START BUTTON TO START THE GAME ",bg="light green",fg="dark green",bd=10,anchor="w")
lblInfo.pack()
#########################################################################################################################
def start():
    global root
    root=Toplevel(rt)
    root.title("TIC TAC TOE")
    root.configure(bg="light green")
    global numbers
    global x

    numbers=[1,2,3,4,5,6,7,8,9]
    # y='X' for player1 and 'O' for player2
    y=""
    # x is the counter to keep counting the number of chances
    x=0
    #boards is a list to store the mark with respect to the cell number
    boards=["board"]*10

    def result(boards,mark):
        return ((boards[1] == boards[2] == boards [3] == mark)
                or (boards[4] == boards[5] == boards [6] == mark)
                or (boards[7] == boards[8] == boards [9] == mark)
                or (boards[1] == boards[4] == boards [7] == mark)
                or (boards[2] == boards[5] == boards [8] == mark)
                or (boards[3] == boards[6] == boards [9] == mark)
                or (boards[1] == boards[5] == boards [9] == mark)
                or (boards[3] == boards[5] == boards [7] == mark))

    def define_sign(number):
        global x,y,numbers
        """ Checking which button has been clicked and checking if the button has been already clicked or not to avoid over-writing"""
        if number==1 and number in numbers:
            numbers.remove(number)

            # If the value of x is even, Person1 will play and vivee versa
            if x%2==0:
                y='X'
                boards[number]=y
            elif x%2!=0:
                y='O'
                boards[number]=y
            #Using config, we write mark the button with appropriate value.
            b1.config(text=y)
            x=x+1
            mark=y
            # Here we are calling the result() to decide whether we have got the winner or not
            if(result(boards,mark) and mark=='X' ):
                #If Player1 is the winner show a dialog box stating the winner
                showinfo("Result","Player1 wins")
                #Call the destroy function to close the GUI
                call()
            elif(result(boards,mark) and mark=='O'):
                showinfo("Result","Player2 wins")
                call()

        if number==2 and number in numbers:
            numbers.remove(number)
            if x%2==0:
                y='X'
                boards[number]=y
            elif x%2!=0:
                y='O'
                boards[number]=y

            b2.config(text=y)
            x=x+1
            mark=y
            if(result(boards,mark)and mark=='X' ):
                showinfo("Result","Player1 wins")
                call()
            elif(result(boards,mark)and mark=='O' ):
                showinfo("Reuslt","Player2 wins")
                call()

        if number==3 and number in numbers:
            numbers.remove(number)
            if x%2==0:
                y='X'
                boards[number]=y

            elif x%2!=0:
                y='O'
                boards[number]=y
            b3.config(text=y)
            x=x+1
            mark=y
            if(result(boards,mark)and mark=='X'):
                showinfo("Result","Player1 wins")
                call()
            elif(result(boards,mark) and mark=='O'):
                showinfo("Result","Player2 wins")
                call()

        if number==4 and number in numbers:
            numbers.remove(number)
            if x%2==0:
                y='X'
                boards[number]=y

            elif x%2!=0:
                y='O'
                boards[number]=y
            b4.config(text=y)
            x=x+1
            mark=y
            if(result(boards,mark)and mark=='X'):
                showinfo("Result","Player1 wins")
                call()
            elif(result(boards,mark) and mark=='O'):
                showinfo("Result","Player2 wins")
                call()

        if number==5 and number in numbers:
            numbers.remove(number)
            if x%2==0:
                y='X'
                boards[number]=y
            elif x%2!=0:
                y='O'
                boards[number]=y

            b5.config(text=y)
            x=x+1
            mark=y
            if(result(boards,mark)and mark=='X' ):
                showinfo("Result","Player1 wins")
                call()
            elif(result(boards,"O")and mark=='O'):
                showinfo("Result","Player2 wins")
                call()

        if number==6 and number in numbers:
            numbers.remove(number)
            if x%2==0:
                y='X'
                boards[number]=y
            elif x%2!=0:
                y='O'
                boards[number]=y

            b6.config(text=y)
            x=x+1
            mark=y
            if(result(boards,mark) and mark=='X'):
                showinfo("Result","Player1 wins")
                call()
            elif(result(boards,mark)and mark=='O'):
                showinfo("Result","Player2 wins")
                call()

        if number==7 and number in numbers:
            numbers.remove(number)
            if x%2==0:
                y='X'
                boards[number]=y

            elif x%2!=0:
                y='O'
                boards[number]=y

            b7.config(text=y)
            x=x+1
            mark=y
            if(result(boards,mark) and mark=='X' ):
                showinfo("Result","Player1 wins")
                call()
            elif(result(boards,mark) and mark=='O'):
                print("Player2 wins")
                showinfo("Result","Player2 wins")
                call()

        if number==8 and number in numbers:
            numbers.remove(number)
            if x%2==0:
                y='X'
                boards[number]=y

            elif x%2!=0:
                y='O'
                boards[number]=y

            b8.config(text=y)
            x=x+1
            mark=y
            if(result(boards,mark) and mark=='X'):
                print("Player1 wins")
                showinfo("Result","Player1 wins")
                call()
            elif(result(boards,"O")and mark=='O'):
                print("Player2 wins")
                showinfo("Result","Player2 wins")
                call()
        if number==9 and number in numbers:
            numbers.remove(number)
            if x%2==0:
                y='X'
                boards[number]=y

            elif x%2!=0:
                y='O'
                boards[number]=y

            b9.config(text=y)
            x=x+1
            mark=y
            if(result(boards,mark) and mark=='X'):
                print("Player1 wins")
                showinfo("Result","Player1 wins")
                call()
            elif(result(boards,mark) and mark=='O'):
                print("Player2 wins")
                showinfo("Result","Player2 wins")
                call()

        # If we have not got any winner, display the dialogbox stating the match has bee tied.
        if(x>8 and result(boards,'X')==False and result(boards,'O')==False):
            showinfo("Result","Match Tied")

            call()

    label1=Label(root,text="Player1 : X",font=("arial",15,"bold"),bg="light green",fg="dark green",bd=10,anchor="w")
    label1.grid(row=0,column=1)

    l2=Label(root,text="Player2 : O",font=("arial",15,"bold"),bg="light green",fg="dark green",bd=10,anchor="w")
    l2.grid(row=0,column=2)

    b1=Button(root,width=20,height=10,command=lambda:define_sign(1))
    b1.grid(row=1,column=1)
    b2=Button(root,width=20,height=10,command=lambda:define_sign(2))
    b2.grid(row=1,column=2)
    b3=Button(root,width=20,height=10,command=lambda: define_sign(3))
    b3.grid(row=1,column=3)
    b4=Button(root,width=20,height=10,command=lambda: define_sign(4))
    b4.grid(row=2,column=1)
    b5=Button(root,width=20,height=10,command=lambda: define_sign(5))
    b5.grid(row=2,column=2)
    b6=Button(root,width=20,height=10,command=lambda: define_sign(6))
    b6.grid(row=2,column=3)
    b7=Button(root,width=20,height=10,command=lambda: define_sign(7))
    b7.grid(row=3,column=1)
    b8=Button(root,width=20,height=10,command=lambda: define_sign(8))
    b8.grid(row=3,column=2)
    b9=Button(root,width=20,height=10,command=lambda: define_sign(9))
    b9.grid(row=3,column=3)
    root.mainloop()

lblInfo=Label(Tops,font=("arial",23,"bold"),text="",bg="light green",fg="dark green",bd=10,anchor="w")
lblInfo.pack()

btn15=Button(rt,padx=16,pady=16,bd=8,fg="dark green",font=("arial",18,"bold"),text="START",bg="light green",
                    command=start,anchor="w",width=10,height=0,compound="c")
btn15.place(x=220,y=420)
def call():
	res = mb.askquestion('Exit Application', 'Do you really want to exit')

	if res == 'yes' :
		rt.destroy()

	else :
		mb.showinfo('Return', 'Returning to main application')

btn16=Button(rt,padx=16,pady=16,bd=8,fg="dark green",font=("arial",18,"bold"),text="Quit",bg="light green",
                    command=call,anchor="w",width=10,height=0,compound="c")
btn16.place(x=620,y=420)

rt.mainloop()


import base64
import json
import time
import cv2
import requests

server_config = {
    "camera_id": 0,
    "push_server": "http://localhost:5000"
}

def draw_picture(src_picture, results):
    for result in results:
        label, confidence, top, left, bottom, right = result
        src_picture = cv2.putText(
            src_picture,
            "{0}: {1}".format(label, confidence),
            (left, bottom),
            cv2.FONT_HERSHEY_COMPLEX, 1, (0, 0, 255), 10
        )
        src_picture = cv2.rectangle(
            src_picture, (left, top), (right, bottom), (255, 0, 0), 10)
    return src_picture

def send_request(src_picture, results, draw=True):
    if draw:
        src_picture = draw_picture(src_picture, results)
    try:
        retval, buffer = cv2.imencode('.jpg', src_picture)
        jpg_as_text = base64.b64encode(buffer)
        requests.post(
            server_config['push_server'],
            data={
                "machine": server_config["camera_id"],
                "timestamp": time.time(),
                "picture": jpg_as_text,
                "box": json.dumps(results)
            }
        )
        print("Detection sent to {0}".format(server_config["push_server"]))
    except requests.exceptions.ConnectionError:
        print("Unable to connect to {0}".format(server_config["push_server"]))


# coding: utf-8
# Copyright 2013 The Font Bakery Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# See AUTHORS.txt for the list of Authors and LICENSE.txt for the License.
from __future__ import print_function

from datetime import datetime
import os
import glob
import io
from flask import current_app
import itsdangerous
from collections import OrderedDict

ROOT = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..'))
DATA_ROOT = os.path.join(ROOT, 'data')

import sys
if sys.version < '3':
    import codecs

    def u(x):
        return codecs.unicode_escape_decode(x)[0]
else:
    def u(x):
        return x

def get_current_time():
    return datetime.utcnow()

def pretty_date(dt, default=None):
    """
    Returns string representing "time since" e.g.
    3 days ago, 5 hours ago etc.
    Ref: https://bitbucket.org/danjac/newsmeme/src/a281babb9ca3/newsmeme/
    """

    if default is None:
        default = 'just now'

    now = datetime.utcnow()
    diff = now - dt

    periods = (
        (diff.days / 365, 'year', 'years'),
        (diff.days / 30, 'month', 'months'),
        (diff.days / 7, 'week', 'weeks'),
        (diff.days, 'day', 'days'),
        (diff.seconds / 3600, 'hour', 'hours'),
        (diff.seconds / 60, 'minute', 'minutes'),
        (diff.seconds, 'second', 'seconds'),
    )

    for period, singular, plural in periods:

        if not period:
            continue

        if period == 1:
            return u'%d %s ago' % (period, singular)
        else:
            return u'%d %s ago' % (period, plural)

    return default

def signify(text):
    signer = itsdangerous.Signer(current_app.secret_key)
    return signer.sign(text)

class RedisFd(object):
    """Redis File Descriptor class, publish writen data to redis channel in parallel to file"""
    def __init__(self, name, mode='a'):
        self.fd = open(name, mode)
        self.fd.write("Start: Start of log\n")  # end of log

    def write(self, data, prefix=''):
        self.fd.write("%s%s" % (prefix, data))
        self.fd.flush()

    def close(self):
        self.fd.write("End: End of log\n")  # end of log
        self.fd.close()

def project_fontaine(project, build):
    from fontaine.font import Font

    param = {'login': project.login, 'id': project.id,
        'revision': build.revision, 'build': build.id}

    _out = os.path.join(DATA_ROOT, '%(login)s/%(id)s.out/%(build)s.%(revision)s/' % param)

    # Its very likely that _out exists, but just in case:
    if os.path.exists(_out):
        os.chdir(_out)
    else:
        # This is very unlikely, but should it happen, just return
        return

    # Run pyFontaine on all the TTF fonts
    fonts = {}
    for filename in glob.glob("*.ttf"):
        fontaine = Font(filename)
        fonts[filename] = fontaine

    # Make a plain dictionary, unlike the fancy data structures used by pyFontaine :)
    family = {}
    for fontfilename, fontaine in fonts.iteritems():
        # Use the font file name as a key to a dictionary of char sets
        family[fontfilename] = {}
        for charset, coverage, percentcomplete, missingchars in fontaine.get_orthographies():
            # Use each char set name as a key to a dictionary of this font's coverage details
            charsetname = charset.common_name
            family[fontfilename][charsetname] = {}
            family[fontfilename][charsetname]['coverage'] = coverage  # unsupport, fragmentary, partial, full
            family[fontfilename][charsetname]['percentcomplete'] = percentcomplete  # int
            family[fontfilename][charsetname]['missingchars'] = missingchars  # list of ord numbers
            # Use the char set name as a key to a list of the family's average coverage
            if not charsetname in family:
                family[charsetname] = []
            # Append the char set percentage of each font file to the list
            family[charsetname].append(percentcomplete)  # [10, 32, 40, 40] etc
            # And finally, if the list now has all the font files, make it the mean average percentage
            if len(family[charsetname]) == len(fonts.items()):
                family[charsetname] = sum(family[charsetname]) / len(fonts.items())
    # Make a plain dictionary with just the bits we want on the dashboard
    totals = {}
    totals['gwf'] = family.get('GWF latin', None)
    totals['al3'] = family.get('Adobe Latin 3', None)
    # Store it in the $(id).state.yaml file
    project.config['local']['charsets'] = totals
    project.save_state()

    # fonts.itervalues() emits <fontaine.font.Font instance at 0x106123c68> objects that we return for the rfiles.html template
    return fonts.itervalues()

def sortFont(fonts):
    sortedfonts = []
    for font in fonts:
        fontMetadata = OrderedDict()
        fontMetadata["name"] = font["name"]
        fontMetadata["style"] = font["style"]
        fontMetadata["weight"] = font["weight"]
        fontMetadata["filename"] = font["filename"]
        fontMetadata["postScriptName"] = font["postScriptName"]
        fontMetadata["fullName"] = font["fullName"]
        fontMetadata["copyright"] = font["copyright"]
        sortedfonts.append(fontMetadata)
    return sortedfonts

def sortMetadata(old):
    ordered = OrderedDict()
    ordered["name"] = old["name"]
    ordered["designer"] = old["designer"]
    ordered["license"] = old["license"]
    ordered["visibility"] = old["visibility"]
    ordered["category"] = old["category"]
    ordered["size"] = old["size"]
    ordered["fonts"] = sortFont(old["fonts"])
    ordered["subsets"] = sorted(old["subsets"])
    ordered["dateAdded"] = old["dateAdded"]
    return ordered

def striplines(jsontext):
    lines = jsontext.split("\n")
    newlines = []
    for line in lines:
        newlines.append("%s\n" % (line.rstrip()))
    return "".join(newlines)

def saveMetadata(metadata, path):
    # flask json serializer doesn't support OrderedDict
    import json
    data = json.loads(u(metadata))
    ready_data = sortMetadata(data)
    dump = json.dumps(ready_data, indent=2, ensure_ascii=True)
    strip_dump = striplines(dump)
    with io.open(path, 'w', encoding='utf-8') as f:
        f.write(u(strip_dump))


# Copyright 2016, Howard Zeng
# All rights reserved

import sys

gDICTIONARY_FILE = None
gPLACEHOLDER = None
gDICTIONARY = None
gPREFIX_TREE_DICTIONARY = None

class cPrefixTree:

    def __init__(self):
        self.root = []
        self.isWord = False
        for i in range(26):
            self.root.append(None)

    def insertKey(self, iWord):
        if len(iWord) == 0:
            self.isWord = True
        else:
            # 65 is ord('A')
            letterOrd = ord(iWord[0]) - 65
            if self.root[letterOrd] == None:
                newTree = cPrefixTree()
                newTree.insertKey(iWord[1:])
                self.root[letterOrd] = newTree
            else:
                self.root[letterOrd].insertKey(iWord[1:])

    def getPrefix(self, iLetter):
        return self.root[ord(iLetter) - 65]

    def keyExists(self, iWord):
        if len(iWord) == 0:
            return True
        else:
            letterOrd = ord(iWord[0]) - 65
            if self.root[letterOrd] == None:
                return False
            else:
                return keyExists(iWord[1:])

def buildPrefixTree(iDictionaryFile):
    global gDICTIONARY_FILE
    global gPLACEHOLDER
    global gDICTIONARY
    global gPREFIX_TREE_DICTIONARY

    gDICTIONARY_FILE = iDictionaryFile
    gPLACEHOLDER = '-'
    gDICTIONARY = []
    gPREFIX_TREE_DICTIONARY = cPrefixTree()

    with open(gDICTIONARY_FILE) as f:
        lines = f.readlines()

    for line in lines:
        gDICTIONARY.append(line.strip('\n'))

    for word in gDICTIONARY:
        gPREFIX_TREE_DICTIONARY.insertKey(word)

# Traverses grid in all of the 8 directions on a 2d grid
def traverse(iSolutionGoesHere, iGrid, iXCoord, iYCoord, iLettersLeft, iRows, iCols, iWord, iSteps, iPrefixTree):
    global gPLACEHOLDER
    global gDICTIONARY

    if (iXCoord >= iCols) or (iYCoord >= iRows) or (iXCoord < 0) or (iYCoord < 0) or (iGrid[iXCoord][iYCoord] == gPLACEHOLDER):
        return False

    if [iXCoord, iYCoord] in iSteps:
        return False

    newSteps = list(iSteps)
    newSteps.append([iXCoord, iYCoord])
    iWord += iGrid[iXCoord][iYCoord]
    iLettersLeft -= 1
    letter = iWord[-1]
    iPrefixTree = iPrefixTree.getPrefix(letter)

    if iPrefixTree == None:
        return False

    if iLettersLeft == 0:
        if iPrefixTree.isWord == True:
            return [iGrid, iWord, newSteps]
        else:
            return False

    solution = traverse(iSolutionGoesHere, iGrid, iXCoord + 1, iYCoord, iLettersLeft, iRows, iCols, iWord, newSteps, iPrefixTree)
    if solution:
        iSolutionGoesHere.append(solution)

    solution = traverse(iSolutionGoesHere, iGrid, iXCoord - 1, iYCoord, iLettersLeft, iRows, iCols, iWord, newSteps, iPrefixTree)
    if solution:
        iSolutionGoesHere.append(solution)

    solution = traverse(iSolutionGoesHere, iGrid, iXCoord, iYCoord + 1, iLettersLeft, iRows, iCols, iWord, newSteps, iPrefixTree)
    if solution:
        iSolutionGoesHere.append(solution)

    solution = traverse(iSolutionGoesHere, iGrid, iXCoord, iYCoord - 1, iLettersLeft, iRows, iCols, iWord, newSteps, iPrefixTree)
    if solution:
        iSolutionGoesHere.append(solution)

    solution = traverse(iSolutionGoesHere, iGrid, iXCoord + 1, iYCoord + 1, iLettersLeft, iRows, iCols, iWord, newSteps, iPrefixTree)
    if solution:
        iSolutionGoesHere.append(solution)

    solution = traverse(iSolutionGoesHere, iGrid, iXCoord + 1, iYCoord - 1, iLettersLeft, iRows, iCols, iWord, newSteps, iPrefixTree)
    if solution:
        iSolutionGoesHere.append(solution)

    solution = traverse(iSolutionGoesHere, iGrid, iXCoord - 1, iYCoord + 1, iLettersLeft, iRows, iCols, iWord, newSteps, iPrefixTree)
    if solution:
        iSolutionGoesHere.append(solution)

    solution = traverse(iSolutionGoesHere, iGrid, iXCoord - 1, iYCoord - 1, iLettersLeft, iRows, iCols, iWord, newSteps, iPrefixTree)
    if solution:
        iSolutionGoesHere.append(solution)

def pushDownGrid(iGrid, iNumRows, iNumCols):
    global gPLACEHOLDER

    for row in range(iNumRows-1):
        for col in range(iNumCols):
            if iGrid[row+1][col] == gPLACEHOLDER:
                for tempRow in reversed(range(row+1)):
                    iGrid[tempRow+1][col] = iGrid[tempRow][col]
                iGrid[0][col] = gPLACEHOLDER

def main(args):
    global gPLACEHOLDER
    global gPREFIX_TREE_DICTIONARY

    # For enumeration
    eGRID = 0
    eWORDS = 1
    eSTEPS = 2

    eXCOORD = 0
    eYCOORD = 1

    if len(args) != 1:
        print("ERROR: You should only have 1 argument which is the input file (it's probably input.txt)")
        return

    inputFile = args[0]
    numRows = 4
    numCols = 4
    numWords = 4
    numLetters = [5,3,3,5]

    with open(inputFile) as f:
        info = f.readlines()

    # Extract the dictionary file (first line of the input file)
    buildPrefixTree(info[0].strip('\n'))

    # Extract information of the number of rows, columns, and words (second line of the input file)
    rcw = info[1].strip('\n').split(" ")
    if len(rcw) != 3:
        print("ERROR: The first line of " + inputFile + " should contain only <Number of Rows> <Number of Columns> <Number of Words>")
        return

    numRows = int(rcw[0])
    numCols = int(rcw[1])
    numWords = int(rcw[2])

    # Extract the number of letters in each word (third line of the input file)
    numLetters = info[2].strip('\n').split(" ")
    for i in range(len(numLetters)):
        numLetters[i] = int(numLetters[i])

    if len(numLetters) != numWords:
        print("ERROR: The second line of " + inputFile + " should have the same number of numbers as the number of words")
        return

    # Extract the letter grid (the rest of the lines)
    info = info[3:]

    grid = []
    for row in info:
        row = row.strip('\n')
        line = row.split(" ")
        grid.append(line)

    possibleSolutions = [ [grid,[]] ]

    for passes in range(numWords):
        tempSolution2 = []
        for ps in possibleSolutions:
            tempSolutions = []
            for row in range(numRows):
                for col in range(numCols):
                    solution = traverse(tempSolutions, ps[eGRID], row, col, numLetters[passes], numRows, numCols, "", [], gPREFIX_TREE_DICTIONARY)
                    if solution:
                        tempSolutions.append(solution)

            # Create new solution list with the letters fallen down
            # and discard the old solution list
            for tempSol in tempSolutions:
                wordList = list(ps[eWORDS])
                wordList.append(tempSol[eWORDS])

                # Print out position of the letters taken at each step
                #print wordList
                #print tempSol[eSTEPS]

                # Create new copy of the temporary intermediate solution
                newGrid = []
                for row in range(numRows):
                    tempRow = list(tempSol[eGRID][row])
                    newGrid.append(tempRow)

                for stepTaken in tempSol[eSTEPS]:
                    x = stepTaken[eXCOORD]
                    y = stepTaken[eYCOORD]
                    newGrid[x][y] = gPLACEHOLDER

                # Simulate the letters falling down
                pushDownGrid(newGrid, numRows, numCols)
                tempSolution2.append([newGrid, wordList])

                # Print out each intermediate step
                #for row in range(numRows):
                #    print newGrid[row]

        possibleSolutions = tempSolution2

    # Print out final solution
    possibleSolutions.sort()
    for ps in possibleSolutions:
        print(ps[eWORDS])

if __name__ == "__main__":
    main(sys.argv[1:])


#!/usr/bin/python
from __future__ import print_function, unicode_literals, with_statement
import sys, os, os.path as path, platform, shutil, glob, subprocess, json
import pprint
pp = pprint.PrettyPrinter(indent=4)
try:
	from urllib.request import urlopen, Request
	from urllib.error import HTTPError
except ImportError:
	from urllib2 import urlopen, Request, HTTPError

try:
	import tkinter
	from tkinter import filedialog
	from tkinter import Listbox
	from tkinter import messagebox
	from tkinter import Checkbutton
	from tkinter import IntVar
except ImportError:
	import Tkinter as tkinter
	import tkFileDialog as filedialog
	import tkMessageBox as messagebox
	from Tkinter import Listbox
	from Tkinter import Checkbutton
	from Tkinter import IntVar

# Python 2 Compatibility
try: input = raw_input
except NameError: pass

try:
	"".decode("utf-8")
	def decodeStr(string):
		return string.decode("utf-8")
except AttributeError:
	def decodeStr(string):
		return string

def printErrorMessage(text):
	"""
	Prints message in red if stdout is a tty
	"""
	if sys.stdout.isatty:
		print("\x1b[1m\x1b[31m" + text + "\x1b[0m")
	else:
		print(text)

def exitWithError():
	""" On Windows, prevent window closing immediately when exiting with error. Other plaforms just exit. """
	print("ERROR: The installer cannot continue. Press any key to exit...")
	if IS_WINDOWS:
		input()
	sys.exit(1)

def findWorkingExecutablePath(executable_paths, flags):
	"""
	Try to execute each path in executable_paths to see which one can be called and returns exit code 0
	The 'flags' argument is any extra flags required to make the executable return 0 exit code
	:param executable_paths: a list [] of possible executable paths (eg. "./7za", "7z")
	:param flags: any extra flags like "-h" required to make the executable have a 0 exit code
	:return: the path of the valid executable, or None if no valid executables found
	"""
	with open(os.devnull, 'w') as os_devnull:
		for path in executable_paths:
			try:
				if subprocess.call([path, flags], stdout=os_devnull) == 0:
					print("Found valid executable:", path)
					return path
			except:
				pass

	return None
################################################## Global Variables#####################################################

# The installer info version this installer is compatibile with
# Increment it when you make breaking changes to the json files
JSON_VERSION = 1

# Global variable controlling use of IPV6, toggled by a checkbox in the GUI. By default, IPV6 is NOT used.
class GlobalSettings:
	def __init__(self):
		self.USE_IPV6 = False

GLOBAL_SETTINGS = GlobalSettings()

###################################### Executable detection and Installation ###########################################

# If you double-click on the file in Finder on macOS, it will not open with a path that is near the .py file
# Since we want to properly find things like `./aria2c`, we should move to that path first.
dirname = os.path.dirname(sys.argv[0])
if dirname.strip():
	os.chdir(dirname)

# Define constants used throughout the script. Use function calls to enforce variables as const
IS_WINDOWS = platform.system() == "Windows"
IS_LINUX = platform.system() == "Linux"
IS_MAC = platform.system() == "Darwin"

#query available executables. If any installation of executables is done in the python script, it must be done
#before this executes
ARIA_EXECUTABLE = findWorkingExecutablePath(["./aria2c", "./.aria2c", "aria2c"], '-h')
if ARIA_EXECUTABLE is None:
	# TODO: automatically download and install dependencies
	print("ERROR: aria2c executable not found (aria2c). Please install the dependencies for your platform.")
	exitWithError()

SEVEN_ZIP_EXECUTABLE = findWorkingExecutablePath(["./7za", "./.7za", "7za", "./7z", "7z"], '-h')
if SEVEN_ZIP_EXECUTABLE is None:
	# TODO: automatically download and install dependencies
	print("ERROR: 7-zip executable not found (7za or 7z). Please install the dependencies for your platform.")
	exitWithError()

#when calling this function, use named arguments to avoid confusion!
def aria(downloadDir=None, inputFile=None, url=None):
	"""
	Calls aria2c with some default arguments:
	TODO: list what each default argument does as comments next to arguments array?

	:param downloadDir: The directory to store the downloaded file(s)
	:param inputFile: The path to a file containing multiple URLS to download (see aria2c documentation)
	:return Returns the exit code of the aria2c call
	"""
	arguments = [
		ARIA_EXECUTABLE,
		"--file-allocation=none",
		'--continue=true',
		'--retry-wait=5',
		'-m 0',
		'-x 8',
		'-s 8',
		'-j 1',
		'--follow-metalink=mem',  #always follow metalinks, for now
		'--check-integrity=true', #check integrity when using metalink
	]

	if not GLOBAL_SETTINGS.USE_IPV6:
		arguments.append('--disable-ipv6=true')

	#Add an extra command line argument if the function argument has been provided
	if downloadDir:
		arguments.append('-d ' + downloadDir)

	if inputFile:
		arguments.append('--input-file=' + inputFile)

	if url:
		arguments.append(url)

	return subprocess.call(arguments)

def sevenZipExtract(archive_path, outputDir=None):
	arguments = [SEVEN_ZIP_EXECUTABLE, "x", archive_path, "-aoa"]
	if outputDir:
		arguments.append('-o' + outputDir)
	return subprocess.call(arguments)

####################################### TKINTER Functions and Classes ##################################################
# see http://effbot.org/tkinterbook/tkinter-dialog-windows.htm
class ListChooserDialog:

	def __init__(self, parent, listEntries, guiPrompt, allowManualFolderSelection, forceFolderOnlyChoosing=False):
		"""
		NOTE: do not call this constructor directly. Use the ListChooserDialog.showDialog function instead.
		"""
		self.forceFolderOnlyChoosing = forceFolderOnlyChoosing

		self.top = tkinter.Toplevel(parent)
		defaultPadding = {"padx":20, "pady":10}

		# Set a description for this dialog (eg "Please choose a game to mod"
		tkinter.Label(self.top, text=guiPrompt).pack()

		# Define the main listbox to hold the choices given by the 'listEntries' parameter
		listboxFrame = tkinter.Frame(self.top)

		# Define a scrollbar and a listbox. The yscrollcommand is so that the listbox can control the scrollbar
		scrollbar = tkinter.Scrollbar(listboxFrame, orient=tkinter.VERTICAL)
		self.listbox = Listbox(listboxFrame, selectmode=tkinter.BROWSE, yscrollcommand=scrollbar.set)

		# Also configure the scrollbar to control the listbox, and pack it
		scrollbar.config(command=self.listbox.yview)
		scrollbar.pack(side=tkinter.RIGHT, fill=tkinter.Y)

		# Setting width to 0 forces auto-resize of listbox see: https://stackoverflow.com/a/26504193/848627
		for item in listEntries:
			self.listbox.insert(tkinter.END, item)
		self.listbox.config(width=0)
		self.listbox.pack(side=tkinter.LEFT, fill=tkinter.BOTH, expand=1)

		# Finally, pack the Frame so its contents are displayed on the dialog
		listboxFrame.pack(**defaultPadding)

		# If the user is allowed to choose a directory manually, add directory chooser button
		if allowManualFolderSelection:
			b2 = tkinter.Button(self.top, text="Choose Folder Manually", command=self.showDirectoryChooser)
			b2.pack(**defaultPadding)

		# Add an 'OK' button. When pressed, the dialog is closed
		b = tkinter.Button(self.top, text="OK", command=self.ok)
		b.pack(**defaultPadding)

		# This variable stores the returned value from the dialog
		self.result = None

	def showDirectoryChooser(self):
		if IS_MAC and not self.forceFolderOnlyChoosing:
			self.result = filedialog.askopenfilename(filetypes=[(None, "com.apple.application")])
		else:
			self.result = filedialog.askdirectory()
		self.top.destroy()

	def ok(self):
		"""
		This function is called when the 'OK' button is pressed. It retrieves the value of the currently selected item,
		then closes the dialog
		:return:
		"""
		selected_value = None

		if len(self.listbox.curselection()) > 0:
			selected_index = self.listbox.curselection()[0]
			selected_value = self.listbox.get(selected_index)

		self.result = selected_value

		self.top.destroy()

	@staticmethod
	def showDialog(rootGUIWindow, choiceList, guiPrompt, allowManualFolderSelection, forceFolderOnlyChoosing=False):
		"""
		Static helper function to show dialog and get a return value. Arguments are the same as constructor
		:param rootGUIWindow: the parent tkinter object of the dialog (can be root window)
		:param choiceList: a list of strings that the user is to choose from
		:param guiPrompt: the description that will be shown on the dialog
		:param allowManualFolderSelection: if true, user is allowed to select a folder manually.
		:return: returns the value the user selected (string), or None if none available
		"""
		d = ListChooserDialog(rootGUIWindow, choiceList, guiPrompt, allowManualFolderSelection, forceFolderOnlyChoosing)
		rootGUIWindow.wait_window(d.top)
		return d.result

########################################## Installer Functions  and Classes ############################################
class Installer:
	def __init__(self, directory, info):
		"""
		Installer Init

		:param str directory: The directory of the game
		:param dict info: The info dictionary from server JSON file for the requested target
		"""
		self.directory = directory
		self.info = info

		if IS_MAC:
			self.dataDirectory = path.join(self.directory, "Contents/Resources/Data")
		else:
			self.dataDirectory = path.join(self.directory, info["dataname"])

		self.assetsDir = path.join(self.dataDirectory, "StreamingAssets")

		possibleSteamPaths = [
			path.join(self.directory, "steam_api.dll"),
			path.join(self.directory, "Contents/Plugins/CSteamworks.bundle"),
			path.join(self.directory, "libsteam_api.so")
		]

		self.isSteam = False
		for possibleSteamPath in possibleSteamPaths:
			if path.exists(possibleSteamPath):
				self.isSteam = True

		self.downloadDir = info["name"] + "Download"

	def backupUI(self):
		"""
		Backs up the `sharedassets0.assets` file
		"""
		uiPath = path.join(self.dataDirectory, "sharedassets0.assets")
		backupPath = path.join(self.dataDirectory, "sharedassets0.assets.backup")
		if path.exists(uiPath) and not path.exists(backupPath):
			os.rename(uiPath, backupPath)

	def cleanOld(self):
		"""
		Removes folders that shouldn't persist through the install
		(CompiledUpdateScripts, CG, and CGAlt)
		"""
		oldCG = path.join(self.assetsDir, "CG")
		oldCGAlt = path.join(self.assetsDir, "CGAlt")
		compiledScriptsPattern = path.join(self.assetsDir, "CompiledUpdateScripts/*.mg")

		for mg in glob.glob(compiledScriptsPattern):
			os.remove(mg)

		if path.isdir(oldCG):
			shutil.rmtree(oldCG)

		if path.isdir(oldCGAlt):
			shutil.rmtree(oldCGAlt)

	def download(self):
		"""
		Downloads the required files for the mod.
		- The JSON file contains the list of files for each platform to download (see the constructor of this class).
		- This function first selects the appropriate section of the JSON file, depending on the current platform
		- Then, the URLs listed in the JSON file are written out to a file called 'downloadList.txt'
		- Finally, aria2c is called to download the files listed in 'downloadList.txt'
		"""
		if IS_WINDOWS:
			try:
				files = self.info["files"]["win"]
			except KeyError:
				if self.isSteam:
					files = self.info["files"]["win-steam"]
				else:
					files = self.info["files"]["win-mg"]
		else:
			try:
				files = self.info["files"]["unix"]
			except KeyError:
				if self.isSteam:
					files = self.info["files"]["unix-steam"]
				else:
					files = self.info["files"]["unix-mg"]
		try:
			os.mkdir(self.downloadDir)
		except OSError:
			pass
		fileList = open("downloadList.txt", "w")
		for file in files:
			fileList.write(file + "\n")
		fileList.close()

		aria(downloadDir=self.downloadDir, inputFile='downloadList.txt')

		os.remove("downloadList.txt")

	def extractFiles(self):
		"""
		Extracts downloaded files using 7zip: "Overwrite All existing files without prompt."
		"""
		for file in sorted(os.listdir(self.downloadDir)):
			sevenZipExtract(path.join(self.downloadDir, file))

	def moveFilesIntoPlace(self, fromDir=None, toDir=None):
		"""
		Moves files from the directory they were extracted to
		to the game data folder

		fromDir and toDir are for recursion, leave them at their defaults to start the process
		"""
		if fromDir is None: fromDir = self.info["dataname"]
		if toDir is None: toDir = self.dataDirectory

		for file in os.listdir(fromDir):
			src = path.join(fromDir, file)
			target = path.join(toDir, file)
			if path.isdir(src):
				if not path.exists(target):
					os.mkdir(target)
				self.moveFilesIntoPlace(fromDir=src, toDir=target)
			else:
				if path.exists(target):
					os.remove(target)
				shutil.move(src, target)
		os.rmdir(fromDir)

	def cleanup(self):
		"""
		General cleanup and other post-install things

		Removes downloaded 7z files
		On mac, modifies the application Info.plist with new values if available
		"""
		try:
			shutil.rmtree(self.downloadDir)
		except OSError:
			pass

		if IS_MAC:
			# Allows fixing up application Info.plist file so that the titlebar doesn't show `Higurashi01` as the name of the application
			# Can also add a custom CFBundleIdentifier to change the save directory (e.g. for Console Arcs)
			infoPlist = path.join(self.directory, "Contents/Info.plist")
			infoPlistJSON = subprocess.check_output(["plutil", "-convert", "json", "-o", "-", infoPlist])
			parsed = json.loads(infoPlistJSON)
			if "CFBundleName" in self.info and parsed["CFBundleName"] != self.info["CFBundleName"]:
				subprocess.call(["plutil", "-replace", "CFBundleName", "-string", self.info["CFBundleName"], infoPlist])
			if "CFBundleIdentifier" in self.info and parsed["CFBundleIdentifier"] != self.info["CFBundleIdentifier"]:
				subprocess.call(["plutil", "-replace", "CFBundleIdentifier", "-string", self.info["CFBundleIdentifier"], infoPlist])

def getModList(jsonURL):
	"""
	Gets the list of available mods from the 07th Mod server

	:return: A list of mod info objects
	:rtype: list[dict]
	"""
	try:
		file = urlopen(Request(jsonURL, headers={"User-Agent": ""}))
	except HTTPError as error:
		print(error)
		print("Couldn't reach 07th Mod Server to download patch info")
		print("Note that we have blocked Japan from downloading (VPNs are compatible with this installer, however)")
		exitWithError()

	info = json.load(file)
	file.close()
	try:
		version = info["version"]
		if version > JSON_VERSION:
			printErrorMessage("Your installer is out of date.")
			printErrorMessage("Please download the latest version of the installer and try again.")
			print("\nYour installer is compatible with mod listings up to version " + str(JSON_VERSION) + " but the latest listing is version " + str(version))
			exitWithError()
	except KeyError:
		print("Warning: The mod info listing is missing a version number.  Things might not work.")
		return info
	return info["mods"]

def findPossibleGamePathsWindows():
	"""
	Blindly retrieve all game folders in the `Steam\steamappps\common` folder (no filtering is performed)
	TODO: scan other locations than just the steamapps folder
	:return: a list of absolute paths, which are the folders in the `Steam\steamappps\common` folder
	:rtype: list[str]
	"""
	try:
		import winreg
	except ImportError:
		import _winreg as winreg

	registrySteamPath = None
	try:
		registryKey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r'Software\Valve\Steam')
		registrySteamPath, _regType = winreg.QueryValueEx(registryKey, 'SteamPath')
		winreg.CloseKey(registryKey)
	except WindowsError:
		print("findPossibleGamePaths: Couldn't read Steam registry key - Steam not installed?")
		return []

	# normpath added so returned paths have consistent slash directions (registry key has forward slashes on Win...)
	try:
		for root, dirs, _files in os.walk(os.path.join(registrySteamPath, r'steamapps\common')):
			return [os.path.normpath(os.path.join(root, x)) for x in dirs]
	except:
		print("findPossibleGamePaths: Couldn't open registry key folder - Steam folder deleted?")
		return []

def findPossibleGamePaths(gameName):
	"""
	If supported, searches the computer for things that might be Higurashi games
	Currently only does things on Mac OS and Windows
	TODO: Find ways to search for games on Linux

	:param str gameName: The name of the game to search for (should be either "Higurashi" or "Umineko"), used to reduce the time spent searching on Mac OS
	:return: A list of game paths that might be Higurashi games
	:rtype: list[str]
	"""
	allPossibleGamePaths = []

	if IS_WINDOWS:
		allPossibleGamePaths.extend(findPossibleGamePathsWindows())

	if IS_MAC:
		# mdfind is kind of slow, don't run it more than we have to
		if gameName == "Higurashi":
			allPossibleGamePaths.extend(
				x for x in subprocess
					.check_output(["mdfind", "kind:Application", "Higurashi"])
					.decode("utf-8")
					.split("\n") if x
			)
		elif gameName == "Umineko":
			for gamePath in subprocess.check_output(["mdfind", "kind:Application", "Umineko"]).decode("utf-8").split("\n"):
				# GOG installer makes a `.app` that contains the actual game at `/Contents/Resources/game`
				gogPath = path.join(gamePath, "Contents/Resources/game")
				if path.exists(gogPath):
					allPossibleGamePaths.append(gogPath)
		else:
			print("Warning: ran findPossibleGamePaths with an unknown game")

	#if all methods fail, return empty list
	return sorted(allPossibleGamePaths)

def getGameNameFromGamePath(gamePath, modList):
	"""
	Given the path to a game folder, gets the name of the game in the folder, ONLY if a mod exists for that game
	The returned name will match the 'dataname' field in the JSON file, or be None type if no name could be determined.

	:param str gamePath: The path to the game folder
	:param list[dict] modList: The list of available mods (used for finding game names)
	:return: The name of the game , or None if no game was matched
	:rtype: str or None
	"""
	name = None

	if IS_MAC:
		try:
			info = subprocess.check_output(["plutil", "-convert", "json", "-o", "-", path.join(gamePath, "Contents/Info.plist")])
			parsed = json.loads(info)
			name = parsed["CFBundleExecutable"] + "_Data"
		except (OSError, KeyError):
			return None
	else:
		#create a set data structure, containing all the mod data folder names
		allModDataFolders = set([mod["dataname"] for mod in modList])
		try:
			for file in os.listdir(gamePath):
				if file in allModDataFolders:
					name = file
					break
		except:
			print("getGameNameFromGamePath failed on path [{}]".format(gamePath))

	if name is None:
		return None

	for mod in modList:
		if mod["dataname"] == name:
			return mod["target"]
	return None

def promptChoice(rootGUIWindow, choiceList, guiPrompt, canOther=False, forceFolderOnlyChoosing=False):
	"""
	Prompts the user to choose from a list
	:param list[str] choiceList: The list of choices
	:param str guiPrompt: The prompt to use in GUI mode
	:param str textPrompt: The prompt to use in CLI mode.  Note that the user will be directed to select from a list of integers representing options so please mention that.
	:param bool canOther: Whether or not to give the user an Other option, which will instruct them to give a path to an application
	:param str textPromptWithOther: The text prompt to use if there's both options and the `Other` option available.  If `canOther` is true, `textPrompt` will be used if there are only options (so it's just Other) and this will be used otherwise.  If `canOther` is false, this will be ignored.
	:return: The string that the user selected, or if canOther is true, possibly a path that was not in the option list
	:rtype: str
	"""
	result = ListChooserDialog.showDialog(rootGUIWindow, choiceList, guiPrompt, allowManualFolderSelection=canOther, forceFolderOnlyChoosing=forceFolderOnlyChoosing)
	if not result:
		exitWithError()

	return decodeStr(result)

def printSupportedGames(modList):
	"""
	Prints a list of games that have mods available for them
	:param list[dict] modList: The list of available mods
	"""
	print("Supported games:")
	for game in set(x["target"] for x in modList):
		print("  " + game)

def main():
	print("Getting latest mod info...")
	modList = getModList("https://raw.githubusercontent.com/07th-mod/resources/master/higurashiInstallData.json")
	foundGames = [path for path in findPossibleGamePaths("Higurashi") if getGameNameFromGamePath(path, modList) is not None]

	#gameToUse is the path to the game install directory, for example "C:\games\Steam\steamapps\common\Higurashi 02 - Watanagashi"
	gameToUse = promptChoice(
		rootGUIWindow = rootWindow,
		choiceList=foundGames,
		guiPrompt="Please choose a game to mod",
		canOther=True
	)

	#target name, for example 'Watanagashi', that the user has selected
	targetName = getGameNameFromGamePath(gameToUse, modList)
	if not targetName:
		print(gameToUse + " does not appear to be a supported higurashi game.")
		printSupportedGames(modList)
		exitWithError()

	print("targetName", targetName)

	# Using the targetName (eg. 'Watanagashi'), check which mods have a matching name
	# Multiple mods may be returned (eg the 'full' patch and 'voice only' patch may have the same 'target' name
	possibleMods = [x for x in modList if x["target"] == targetName]
	if len(possibleMods) > 1:
		modName = promptChoice(
			rootGUIWindow = rootWindow,
			choiceList=[x["name"] for x in possibleMods],
			guiPrompt="Please choose a mod to install")
		mod = [x for x in possibleMods if x["name"] == modName][0]
	else:
		mod = possibleMods[0]

	installer = Installer(gameToUse, mod)
	print("Downloading...")
	installer.download()
	print("Extracting...")
	installer.backupUI()
	installer.cleanOld()
	installer.extractFiles()
	print("Moving files into place...")
	installer.moveFilesIntoPlace()
	print("Done!")
	installer.cleanup()

################################################## UMINEKO INSTALL #####################################################

UMINEKO_ANSWER_MODS = ["mod_voice_only", "mod_full_patch", "mod_adv_mode"]
UMINEKO_QUESTION_MODS = ["mod_voice_only", "mod_full_patch", "mod_1080p"]
umi_debug_mode = False

# You can use the 'exist_ok' of python3 to do this already, but not in python 2
def makeDirsExistOK(directoryToMake):
	try:
		os.makedirs(directoryToMake)
	except OSError:
		pass

def tryShowFolder(path):
	"""
	Tries to show a given path in the system file browser
	NOTE: this function call does not block! (uses subprocess.Popen)
	:param path: the path to show
	:return: true if successful, false otherwise
	"""
	try:
		if IS_WINDOWS:
			return subprocess.Popen(["explorer", path]) == 0
		elif IS_MAC:
			return subprocess.Popen(["open", path]) == 0
		else:
			return subprocess.Popen(["xdg-open", path]) == 0
	except:
		return False

def uminekoDownload(downloadTempDir, url_list):
	print("Downloading:{} to {}".format(url_list, downloadTempDir))
	makeDirsExistOK(downloadTempDir)

	for url in url_list:
		print("will try to download {} into {} ".format(url, downloadTempDir))
		if not umi_debug_mode:
			if aria(downloadTempDir, url=url) != 0:
				print("ERROR - could not download [{}]. Installation Stopped".format(url))
				exitWithError()

def uminekoExtractAndCopyFiles(fromDir, toDir):
	"""
	This function extracts all archives from the "fromDir" to the "toDir". It also will copy any files in the "fromDir"
	to the "toDir". Finally, if there are any *.utf files in the fromDir, they will be renamed to 0.u in the "toDir"
	depending on the operating system.

	NOTE: this function makes some assumptions about the archive files:
	- all archive files have either the extension .7z, .zip (or both)
	- the archives are intended to be extracted in the order: 'graphics' 'voices' 'update', then any other type of archive

	:param fromDir: source directory to copy/extract files from
	:param toDir: destination directory to place copied/extracted files
	:return: None
	"""
	def sortingFunction(filenameAnyCase):
		filename = filenameAnyCase.lower()
		if 'graphics' in filename:
			return 0
		elif 'voices' in filename:
			return 1
		elif 'update' in filename:
			return 2
		else:
			return 3

	print("extracting from {} to {}".format(fromDir, toDir))

	archives = []
	otherFiles = []

	for filename in os.listdir(fromDir):
		if '.7z' in filename.lower() or '.zip' in filename.lower():
			archives.append(filename)
		else:
			otherFiles.append(filename)

	#sort the archive files so they are extracted in the correct order
	archives.sort(key=sortingFunction)

	for archive_name in archives:
		archive_path = path.join(fromDir, archive_name)
		print("Trying to extract file {} to {}".format(archive_path, toDir))
		if not umi_debug_mode:
			if sevenZipExtract(archive_path, outputDir=toDir) != 0:
				print("ERROR - could not extract [{}]. Installation Stopped".format(archive_path))
				exitWithError()

	#copy all non-archive files to the game folder. If a .utf file is found, rename it depending on the OS
	for sourceFilename in otherFiles:
		fileNameNoExt, extension = os.path.splitext(sourceFilename)

		destFilename = sourceFilename

		#on any OS besides MAC, rename 0.utf files to 0.u files. On mac, leave filenames unchanged.
		if not IS_MAC and extension.lower() == '.utf':
			destFilename = fileNameNoExt + '.u'

		sourceFullPath = os.path.join(fromDir, sourceFilename)
		destFullPath = os.path.join(toDir, destFilename)

		print("Trying to copy", sourceFullPath, "to", destFullPath)
		shutil.copy(sourceFullPath, destFullPath)

def deleteAllInPathExceptSpecified(paths, extensions, searchStrings):
	"""
	Deletes all files in the specified paths, unless they have both a desired extension and a desired search string.
	NOTE: if file has multiple extensions, all will be matched. Eg. .zip.001 will match the extension 'zip' and '001'

	:param paths: A list[] of paths which will have its files deleted according to the below critera
	:param extensions: files to keep must have one of the extensions in this list[] (without the '.', such as 'zip')
	:param searchStrings: files to keep must contain these search strings.
	:return:
	"""
	for path in paths:
		if not os.path.isdir(path):
			print("removeFilesWithExtensions: {} is not a dir or doesn't exist - skipping".format(path))
			continue

		for fileAnyCase in os.listdir(path):
			splitFileName = fileAnyCase.lower().split('.')

			hasCorrectExtension = False
			for extension in splitFileName[1:]:
				if extension in extensions:
					hasCorrectExtension = True

			hasCorrectSearchString = False
			if not searchStrings:
				hasCorrectSearchString = True
			else:
				for searchString in searchStrings:
					if searchString in splitFileName[0]:
						hasCorrectSearchString = True

			# Keep the file if it has both the correct extension and search string. Otherwise, delete it
			fullDeletePath = os.path.join(path, fileAnyCase)
			if hasCorrectExtension and hasCorrectSearchString:
				print("Keeping file:", fullDeletePath)
			else:
				print("Deleting file:", fullDeletePath)
				if not umi_debug_mode:
					os.remove(fullDeletePath)

def backupOrRemoveFiles(folderToBackup):
	"""
	Backs up files for both question and answer arcs
	If a backup already exists, the file is instead removed

	:param folderToBackup: Folder to scan for files. Backups will be placed in the same folder, with extension '.backup'
	:return:
	"""
	pathsToBackup = ['Umineko5to8.exe', 'Umineko5to8', 'Umineko5to8.app',
	                 'Umineko1to4.exe', 'Umineko1to4', 'Umineko1to4.app',
	                 '0.utf', '0.u']

	for pathToBackup in pathsToBackup:
		fullFilePath = os.path.join(folderToBackup, pathToBackup)
		backupPath = fullFilePath + '.backup'

		#only process the file if it exists on disk
		if not os.path.isfile(fullFilePath) and not os.path.isdir(fullFilePath):
			continue

		# backup the file/folder if no backup has been performed previously - otherwise delete the file
		if os.path.isfile(backupPath) or os.path.isdir(backupPath):
			print("backupOrRemoveFiles: removing", fullFilePath, "as backup already exists")
			if os.path.isfile(backupPath):
				os.remove(fullFilePath)
			else:
				shutil.rmtree(fullFilePath)
		else:
			print("backupOrRemoveFiles: backing up", fullFilePath)
			shutil.move(fullFilePath, backupPath)

def installUmineko(gameInfo, modToInstall, gamePath, isQuestionArcs):
	print("User wants to install", modToInstall)
	print("game info:", gameInfo)
	print("game path:", gamePath)

	# do a quick verification that the directory is correct before starting installer
	if not os.path.isfile(os.path.join(gamePath, "arc.nsa")):
		print("There is no 'arc.nsa' in the game folder. Are you sure the correct game folder was selected?")
		print("ERROR - wrong game path. Installation Stopped.")
		exitWithError()

	# Create aliases for the temp directories, and ensure they exist beforehand
	downloadTempDir = path.join(gamePath, "temp")
	advDownloadTempDir = path.join(gamePath, "temp_adv")

	if path.isdir(downloadTempDir):
		print("Information: Temp directories already exist - continued or overwritten install")

		if "voice_only" in modToInstall:
			continueInstallation = messagebox.askyesno("Voice Only Warning",
			                       "We have detected you have run the 'Voice Only' installer before.\n\n" +
			                       "If you switching from 'full patch' to 'voice only', please quit the " +
			                       "installer and completely delete the game directory, then re-install the game\n\n" +
			                       "If you are just upgrading or continuing your voice only install, you can continue the installlation.\n\n" +
			                       "Continue the installation?")

			if not continueInstallation:
				print("User cancelled install (Voice Only)")
				exitWithError()

	makeDirsExistOK(downloadTempDir)
	makeDirsExistOK(advDownloadTempDir)

	# Wipe non-checksummed install files in the temp folder. Print if not a fresh install.
	deleteAllInPathExceptSpecified([downloadTempDir, advDownloadTempDir],
	                               extensions=['7z', 'zip'],
	                               searchStrings=['graphic', 'voice'])

	# Backup/clear the .exe and script files
	backupOrRemoveFiles(gamePath)

	def makeExecutable(executablePath):
		current = os.stat(executablePath)
		os.chmod(executablePath, current.st_mode | 0o111)

	# Download and extract files for Question/Answer Arcs
	if isQuestionArcs:
		if modToInstall == "mod_voice_only":
			uminekoDownload(downloadTempDir, url_list=gameInfo["files"]["voice_only"])
		elif modToInstall == "mod_full_patch":
			uminekoDownload(downloadTempDir, url_list=gameInfo["files"]["full"])
		elif modToInstall == "mod_1080p":
			if IS_WINDOWS:
				uminekoDownload(downloadTempDir, url_list=gameInfo["files"]["1080p_windows"])
			else:
				uminekoDownload(downloadTempDir, url_list=gameInfo["files"]["1080p_linux_mac"])
		else:
			print("ERROR - unknown mod")
			exitWithError()

		uminekoExtractAndCopyFiles(fromDir=downloadTempDir, toDir=gamePath)

		# need to un-quarantine .app file on MAC
		if IS_MAC:
			subprocess.call(["xattr", "-d", "com.apple.quarantine", os.path.join(gamePath, "Umineko1to4.app")])

		makeExecutable(os.path.join(gamePath, "Umineko1to4"))
		makeExecutable(os.path.join(gamePath, "Umineko1to4.app/Contents/MacOS/umineko4"))
	else:
		if modToInstall == "mod_voice_only":
			uminekoDownload(downloadTempDir, url_list=gameInfo["files"]["voice_only"])
			uminekoExtractAndCopyFiles(fromDir=downloadTempDir, toDir=gamePath)
		elif modToInstall == "mod_full_patch":
			uminekoDownload(downloadTempDir, url_list=gameInfo["files"]["full"])
			uminekoExtractAndCopyFiles(fromDir=downloadTempDir, toDir=gamePath)
		elif modToInstall == "mod_adv_mode":
			uminekoDownload(downloadTempDir, url_list=gameInfo["files"]["full"])
			uminekoExtractAndCopyFiles(fromDir=downloadTempDir, toDir=gamePath)
			uminekoDownload(advDownloadTempDir, url_list=gameInfo["files"]["adv"])
			uminekoExtractAndCopyFiles(fromDir=advDownloadTempDir, toDir=gamePath)
		else:
			print("ERROR - unknown mod")
			exitWithError()

		# need to un-quarantine .app file on MAC
		if IS_MAC:
			subprocess.call(["xattr", "-d", "com.apple.quarantine", os.path.join(gamePath, "Umineko5to8.app")])

		makeExecutable(os.path.join(gamePath, "Umineko5to8"))
		makeExecutable(os.path.join(gamePath, "Umineko5to8.app/Contents/MacOS/umineko8"))

	# write batch file to let users launch game in debug mode
	with open(os.path.join(gamePath, "Umineko1to4_DebugMode.bat"), 'w') as f:
		f.writelines(["Umineko1to4.exe --debug", "pause"])
	with open(os.path.join(gamePath, "Umineko5to8_DebugMode.bat"), 'w') as f:
		f.writelines(["Umineko5to8.exe --debug", "pause"])

	# Patched game uses mysav folder, which Steam can't see so can't get incompatible saves by accident.
	# Add batch file which reverses this behaviour by making a linked folder from (saves->mysav)
	with open(os.path.join(gamePath, "EnableSteamSync.bat"), 'w') as f:
		f.writelines(["mklink saves mysav /J", "pause"])

	# For now, don't copy save data

	# Open the temp folder so users can delete/backup any temp install files
	if IS_WINDOWS:
		tryShowFolder(downloadTempDir)
		if 'adv' in modToInstall:
			tryShowFolder(advDownloadTempDir)

def mainUmineko():

	# Given a game path, returns the corresponding game install information for that path
	# In the JSON, this is one of the elements of the top level array
	# It will return 'None' if the game path is invalid (not an Umineko game). Use this feature to scan for valid game paths.
	def getUminekoGameInformationFromGamePath(modList, gamePath):
		for uminekoGameInfo in modList:
			try:
				for filename in os.listdir(gamePath):
					if uminekoGameInfo['dataname'].lower() in filename.lower():
						return uminekoGameInfo
			except:
				print("getGameNameFromGamePath failed on path [{}]".format(gamePath))

		return None

	print("Getting latest mod info (Umineko)...")
	modList = getModList("https://raw.githubusercontent.com/07th-mod/resources/master/uminekoInstallData.json")

	gamePathList = [gamePath for gamePath in findPossibleGamePaths("Umineko") if getUminekoGameInformationFromGamePath(modList, gamePath) is not None]
	print("Detected {} game folders: {}".format(len(gamePathList), gamePathList))

	userSelectedGamePath = promptChoice(
		rootGUIWindow=rootWindow,
		choiceList= gamePathList,
		guiPrompt="Please choose a game to mod",
		canOther=True,
		forceFolderOnlyChoosing=True,
	)

	print("Selected game folder: [{}]".format(userSelectedGamePath))
	gameInfo = getUminekoGameInformationFromGamePath(modList, userSelectedGamePath)
	print("Selected Game Information:")
	pp.pprint(gameInfo)

	isQuestionArcs = None
	modNames = None
	if gameInfo['name'] == 'UminekoAnswer':
		modNames = UMINEKO_ANSWER_MODS
		isQuestionArcs = False
	elif gameInfo['name'] == 'UminekoQuestion':
		modNames = UMINEKO_QUESTION_MODS
		isQuestionArcs = True
	else:
		print("Unknown Umineko game [{}]".format(gameInfo['name']))
		exitWithError()

	# ask user which mod they want to apply to their game
	userSelectedMod = promptChoice(
		rootGUIWindow=rootWindow,
		choiceList=modNames,
		guiPrompt="Please choose which mod to install for " + gameInfo['displayName'],
		canOther=False
	)

	installUmineko(gameInfo, userSelectedMod, userSelectedGamePath, isQuestionArcs)

def check07thModServerConnection():
	"""
	Makes sure that we can connect to the 07th-mod server
	(Patches will fail to download if we can't)
	"""
	try:
		testFile = urlopen(Request("http://07th-mod.com/", headers={"User-Agent": ""}))
		testFile.close()
	except HTTPError as error:
		print(error)
		print("Couldn't reach 07th Mod Server.  The installer will not be able to download patch files.")
		print("Note that we have blocked Japan from downloading (VPNs are compatible with this installer, however)")
		exitWithError()

check07thModServerConnection()

rootWindow = tkinter.Tk()

def closeAndStartHigurashi():
	rootWindow.withdraw()
	main()
	rootWindow.destroy()

def closeAndStartUmineko():
	rootWindow.withdraw()
	mainUmineko()
	installFinishedMessage = "Install Finished. Temporary install files have been displayed - please delete the " \
							 "temporary files after checking the mod has installed correctly."
	print(installFinishedMessage)
	messagebox.showinfo("Install Completed", installFinishedMessage)
	rootWindow.destroy()

# Add an 'OK' button. When pressed, the dialog is closed
defaultPadding = {"padx": 20, "pady": 10}
b = tkinter.Button(rootWindow, text="Install Higurashi Mods", command=closeAndStartHigurashi)
b.pack(**defaultPadding)
b = tkinter.Button(rootWindow, text="Install Umineko Mods", command=closeAndStartUmineko)
b.pack(**defaultPadding)

tkinter.Label(rootWindow, text="Advanced Settings").pack()

# Add a checkbox to enable/disable IPV6. IPV6 is disabled by default due to some
# installations failing when IPV6 is used due to misconfigured routers/other problems.
use_ipv6_var = IntVar()
def onIPV6CheckboxToggled():
	GLOBAL_SETTINGS.USE_IPV6 = use_ipv6_var.get()
c = Checkbutton(rootWindow, text="Enable IPv6", var=use_ipv6_var, command=onIPV6CheckboxToggled)
c.pack()

rootWindow.mainloop()


'''
Given an unsorted array of integers, find the length of longest increasing subsequence.

For example,
Given [10, 9, 2, 5, 3, 7, 101, 18],
The longest increasing subsequence is [2, 3, 7, 101], therefore the length is 4. Note that there may be more than one LIS combination, it is only necessary for you to return the length.

Your algorithm should run in O(nˆ2) complexity.

Follow up: Could you improve it to O(n log n) time complexity?
'''
# O(nˆ2)
class Solution(object):
    def lengthOfLIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if not nums or len(nums) == 0: return 0
        dp = [1 for i in xrange(len(nums))]
        for i in xrange(len(nums)):
            for j in xrange(i):
                if nums[j] < nums[i]:
                    dp[i] = max(dp[j]+1, dp[i])
        return max(dp)

'''
LIS问题是这样描述的：在一个数列中寻找一个序列，使得序列中的任意两个数a[i]和a[j]满足，若i < j，必有a[i] < a[j]。有一个很直接的动态规划思想是：设dp[i]表示以第i个数为结尾的最长递增子序列的长度，则状态转移方程为：dp[i] = max{dp[j] + 1}, 1 <= j < i, a[j] < a[i]，复杂度为O(n2)O(n2)。其实这里还有一个很直接的优化，即：考虑两个数a[x]和a[y], x < y, a[x] < a[y]且dp[x] = dp[y]，那么当dp[t]一样时，显然选取a[x]有可能得到更好的答案。此时可以按照dp[t] = k进行分类，只需保留dp[t] = k的所有a[t]中的最小值。设d[k]记录这个值，则d[k] = min{a[t], dp[t] = k}。

这时注意到d的两个特点：1. d[k]在计算过程中单调不升； 2. d数组是有序的，d[1]<d[2]<..d[n]。
利用这两个性质，可以借助单调队列的思想很方便的求解，设当前已求出的最长上升子序列的长度为len（初始时为1），每次读入一个新元素x，入队规则如下：
1. 若x > d[len]，则直接加入到d的末尾，且len ++；
2. 否则，在d中二分查找，找到第一个比x小的数d[k]，令d[k + 1] = x。
'''
# O(nlgn)
class Solution(object):
    def lengthOfLIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if not nums or len(nums) == 0: return 0
        dp = []
        for i in xrange(len(nums)):
            pos = bisect.bisect_left(dp, nums[i])
            if pos < len(dp):
                dp[pos] = nums[i]
            else:
                dp.append(nums[i])
        return len(dp)


'''
Leetcode 162. Find Peak Element

A peak element is an element that is greater than its neighbors.
Given an input array nums, where nums[i] ≠ nums[i+1], find a peak element and return its index.
The array may contain multiple peaks, in that case return the index to any one of the peaks is fine.
You may imagine that nums[-1] = nums[n] = -∞.
'''

def findPeakElement(nums):
    """
    :type nums: List[int]
    :rtype: int
    """
    if len(nums) < 2:
        return 0
    for i in range(len(nums)-1):
        if i +1 == len(nums) - 1:
            return i + 1
        if nums[i+1] < nums[i]:
            return nums.index(nums[i])


import os

print("path " + os.path.abspath('.'))

os.getcwd()

os.chdir('../files')

os.getcwd()

provices = []
citys = []

if os.path.exists('city_list_4.txt'):
    try:
        data = open('city_list_x.txt')

        for line in data:

            (provice, city) = line.split(":", 1)
            if provice != '':
               provices.append(provice)
               citys.append(city.strip())
    except FileNotFoundError as error:
            print("FileNotFoundError error = " + str(error))
    except ValueError:
        print('ValueError')
        pass
    except:
        print("in except")
        pass

    data.close()

else:
    print('no file exist')

os.chdir('../output')

os.getcwd()

try:

    out_provices = open('provices.data', 'w')
    out_citys = open('citys.data', 'w')

    '''
        connect strings like this
    '''
    print('my', 'provices = ', provices, end="", file=out_provices)
    print('\n')
    print('my', 'citys = ', citys, end="", file=out_citys)

except Exception:
    print('Exception')

finally:
    out_provices.close()
    out_citys.close()

    print('python execute finished')


import numpy as np
import math
# This class provides switch functionality. You only need to look at
# this if you want to know how this works. It only needs to be defined
# once, no need to muck around with its internals.
class switch(object):
    def __init__(self, value):
        self.value = value
        self.fall = False

    def __iter__(self):
        """Return the match method once, then stop"""
        yield self.match
        raise StopIteration

    def match(self, *args):
        """Indicate whether or not to enter a case suite"""
        if self.fall or not args:
            return True
        elif self.value in args: # changed for v1.5, see below
            self.fall = True
            return True
        else:
            return False

def Listing_01():
# Listing 04.01 if statement example
    x = np.random.randint(8, size=1)
    print('x = ' + str(x))
    if x == 7:
        state = "Weekend"
    elif x == 1:
        state = "Weekend"
    else:
        state = "Weekday"
    print('state = ' + state)
    return state

def Listing_02():
# Listing 04.02 Script with if statements
    grade = np.random.randint(40, 101, size=1)
    print('grade = ' + str(grade))
    if grade >= 90:
        letter = 'A'
    elif grade >= 80:
        letter = 'B'
    elif grade >= 70:
        letter = 'C'
    elif grade >= 60:
        letter = 'D'
    else:
        letter = 'F'
    print("grade " + str(grade) + ' gets a grade of ' + letter)
    return letter

def Listing_03():
#  Listing 04.03 The if statement with a logical vector
    A = [True, True, False]
    if all(A):
        print('did not execute')
    if any(A):
        print('any (default) will execute')
    if A:
        print('any (default) will execute')
    A[2] = True;
    if A:
        print('will now execute')
    return A

def Listing_04():
#  Listing 04.04 Example of a switch statement
#    month = int(input('month number? '))
    month = np.random.randint(1,13, size=1)
    print('month = ' + str(month))
    for case in switch(month):
       if case(9, 4, 6, 11):
       # Sept, Apr, June, Nov
           days = 30;
           break
       if case(2): # Feb
#            answer = input('is this a leap year? ')
#            leapYear = (len(answer) > 0) and (answer[0] == 'y')
            rn = np.random.randint(2, size=1)
            leapYear = rn%2 == 1;
            if leapYear:
               days = 29;
            else:
               days = 28;
            break
       if case(1, 3, 5, 7, 8, 10, 12):
            # other months
            days = 31;
            break
       if case():
            print('bad month index')
            break
    print('month ' + str(month) + " has " + str(days) + ' days')

def Listing_05():
# Listing 04.05 Example of a for statement
    A = [6, 12, 6, 91, 13, 6] # initial vector
    print('A = ' + str(A))
    theMax = A[0]; # set initial max value
    for x in A: # iterate through A
        if x > theMax: # test each element
            theMax = x;
    print('max(A) is ' + str(theMax));

def Listing_06():
# Listing 04.06 for statement using indexing
    A = np.random.randint(100, size=10)
    print('A = ' + str(A))
    theMax = A[0];
    theIndex = 0;
    for index in np.arange(0,len(A)):
        x = A[index];
        if x > theMax:
            theMax = x;
            theIndex = index;
    print('the max value in A is ' + str(theMax) +
                            ' at ' + str(theIndex));

def Listing_07():
# Listing 04.07 while statement example
    A = np.random.randint(100, size=10)
    print('A = ' + str(A))
    theMax = A[0];
    theIndex = 0;
    index = 0;
    while index < len(A):
        x = A[index];
        if x > theMax:
           theMax = x;
           theIndex = index;
        index = index + 1;
    print('the max value in A is ' + str(theMax)
                + ' at ' + str(theIndex));

def Listing_08():
# Listing 04.08 Loop-and-a-half example
    R = 1;
    while R > 0:
        R = np.random.randint(10, size=1)
        if R > 0:
            area = math.pi * R**2;
            circum = 2 * math.pi * R;
            print('radius = ' + str(R)
                + 'area = ' + str(area)
                + '; circum = ' + str(circum));

def Listing_09():
# Listing 04.09 Script to compute liquid levels
    another_tank = True;
    while another_tank:
        H = np.random.rand() * 20;
        r = np.random.rand() * 20;
        more_heights = True;
        print('Height %0.2f; radius %0.2f' %(H, r))
        while more_heights:
            h = np.random.rand() * H;
            if h < r:
                v = (1/3)*math.pi*h**2.*(3*r-h);
            elif h < H-r:
                v = (2/3)*math.pi*r**3 + math.pi*r**2*(h-r);
            elif h <= H:
                v = (4/3)*math.pi*r**3 + math.pi*r**2*(H-2*r)
                - (1/3)*math.pi*(H-h)**2*(3*r-H+h);
            else:
                print('liquid level too high')
                continue
            print( '    rad %0.2f ht %0.2f level %0.2f vol %0.2f' %
                (r, H, h, v));
            it = np.random.randint(20, size=1);
            more_heights = it > 3;
        it = np.random.randint(20, size=1);
        another_tank = it > 3

print("\nListing_01\n")
A = Listing_01();
print("\nListing_02\n")
A = Listing_02();
print("\nListing_03\n")
A = Listing_03();
print("\nListing_04\n")
A = Listing_04();
print("\nListing_05\n")
A = Listing_05();
print("\nListing_06\n")
A = Listing_06();
print("\nListing_07\n")
A = Listing_07();
print("\nListing_08\n")
A = Listing_08();
print("\nListing_09\n")
A = Listing_09();


def countingSort(arr):
    # Write your code here
    rtn = [0 for i in range(100)]
    for i in arr:
        rtn[i] += 1
    return rtn

arr = [3, 0, 6, 2, 7, 3, 3]
print(countingSort(arr))

# d = {
#     'one': 1,
#     'two': 2,
#     'two_alt': 2,
#     'three': 3
# }
# val = 3
# d_rev = [k for k, v in d.items() if v == val]
# print(d_rev)