"""QGIS Unit tests for QgsFieldValidator.

.. note:: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
__author__ = 'Alessandro Pasotti'
__date__ = '31/01/2018'
__copyright__ = 'Copyright 2018, The QGIS Project'

import os
import shutil
import tempfile

from qgis.PyQt.QtCore import QLocale, QVariant
from qgis.PyQt.QtGui import QValidator
from qgis.core import QgsVectorLayer
from qgis.gui import QgsFieldValidator
import unittest
from qgis.testing import start_app, QgisTestCase

from utilities import unitTestDataPath

TEST_DATA_DIR = unitTestDataPath()

start_app()

class TestQgsFieldValidator(QgisTestCase):

    @classmethod
    def setUpClass(cls):
        """Run before all tests."""
        super().setUpClass()
        testPath = TEST_DATA_DIR + '/' + 'bug_17878.gpkg'
        # Copy it
        tempdir = tempfile.mkdtemp()
        testPathCopy = os.path.join(tempdir, 'bug_17878.gpkg')
        shutil.copy(testPath, testPathCopy)
        cls.vl = QgsVectorLayer(testPathCopy + '|layername=bug_17878', "test_data", "ogr")
        assert cls.vl.isValid()

    @classmethod
    def tearDownClass(cls):
        """Run after all tests."""
        cls.vl = None
        super().tearDownClass()

    def _fld_checker(self, field):
        """
        Expected results from validate
        QValidator::Invalid 0 The string is clearly invalid.
        QValidator::Intermediate 1 The string is a plausible intermediate value.
        QValidator::Acceptable 2 The string is acceptable as a final result; i.e. it is valid.
        """
        DECIMAL_SEPARATOR = QLocale().decimalPoint()
        OTHER_SEPARATOR = ',' if DECIMAL_SEPARATOR == '.' else '.'

        validator = QgsFieldValidator(None, field, '0.0', '')

        def _test(value, expected):
            ret = validator.validate(value, 0)
            self.assertEqual(ret[0], expected)
            if value:
                self.assertEqual(validator.validate('-' + value, 0)[0], expected, '-' + value)

        # NOTE!!! This should ALWAYS be valid, but the behavior changed in Qt > 5.12.
        # accordingly here we can only run the test if in a locale with decimal separator as dot.
        # The previous tests were moved to test_disabled_tests.py for now, until the QgsFieldValidator
        # class can be reworked to fix this regression.

        if DECIMAL_SEPARATOR != ',':
            _test('0.1234', QValidator.Acceptable)

        # Apparently we accept comma only when locale say so
        if DECIMAL_SEPARATOR != '.':
            _test('0,1234', QValidator.Acceptable)

        # If precision is > 0, regexp validator is used (and it does not support sci notation)
        if field.precision() == 0:
            # NOTE!!! This should ALWAYS be valid, but the behavior changed in Qt > 5.12.
            # accordingly here we can only run the test if in a locale with decimal separator as dot.
            # The previous tests were moved to test_disabled_tests.py for now, until the QgsFieldValidator
            # class can be reworked to fix this regression.
            if DECIMAL_SEPARATOR != ',':
                _test('12345.1234e+123', QValidator.Acceptable)
                _test('12345.1234e-123', QValidator.Acceptable)

            if DECIMAL_SEPARATOR != '.':
                _test('12345,1234e+123', QValidator.Acceptable)
                _test('12345,1234e-123', QValidator.Acceptable)
            _test('', QValidator.Acceptable)

            # Out of range
            _test('12345.1234e+823', QValidator.Intermediate)
            _test('12345.1234e-823', QValidator.Intermediate)
            if DECIMAL_SEPARATOR != '.':
                _test('12345,1234e+823', QValidator.Intermediate)
                _test('12345,1234e-823', QValidator.Intermediate)

        # Invalid
        _test('12345-1234', QValidator.Invalid)
        _test('onetwothree', QValidator.Invalid)

        int_field = self.vl.fields()[self.vl.fields().indexFromName('int_field')]
        self.assertEqual(int_field.precision(), 0)  # this is what the provider reports :(
        self.assertEqual(int_field.length(), 0)  # not set
        self.assertEqual(int_field.type(), QVariant.Int)

        validator = QgsFieldValidator(None, int_field, '0', '')

        # Valid
        _test('0', QValidator.Acceptable)
        _test('1234', QValidator.Acceptable)
        _test('', QValidator.Acceptable)

        # Invalid
        _test('12345-1234', QValidator.Invalid)
        _test(f'12345{DECIMAL_SEPARATOR}1234', QValidator.Invalid)
        _test('onetwothree', QValidator.Invalid)

    def test_doubleValidator(self):
        """Test the double with default (system) locale"""
        field = self.vl.fields()[self.vl.fields().indexFromName('double_field')]
        self.assertEqual(field.precision(), 0)  # this is what the provider reports :(
        self.assertEqual(field.length(), 0)  # not set
        self.assertEqual(field.type(), QVariant.Double)
        self._fld_checker(field)

    def test_doubleValidatorCommaLocale(self):
        """Test the double with german locale"""
        QLocale.setDefault(QLocale(QLocale.German, QLocale.Germany))
        self.assertEqual(QLocale().decimalPoint(), ',')
        field = self.vl.fields()[self.vl.fields().indexFromName('double_field')]
        self._fld_checker(field)

    def test_doubleValidatorDotLocale(self):
        """Test the double with english locale"""
        QLocale.setDefault(QLocale(QLocale.English))
        self.assertEqual(QLocale().decimalPoint(), '.')
        field = self.vl.fields()[self.vl.fields().indexFromName('double_field')]
        self._fld_checker(field)

    def test_precision(self):
        """Test different precision"""
        QLocale.setDefault(QLocale(QLocale.English))
        self.assertEqual(QLocale().decimalPoint(), '.')
        field = self.vl.fields()[self.vl.fields().indexFromName('double_field')]
        field.setPrecision(4)
        self._fld_checker(field)

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


from robotpy_toolkit_7407 import Subsystem
from robotpy_toolkit_7407.motors import SparkMax
from robotpy_toolkit_7407.pneumatics.pistons import DoubleSolenoidPiston

import config

class Intake(Subsystem):
    def __init__(self):
        super().__init__()
        self.intake_motor = SparkMax(config.intake_motor_id)

        self.intake_piston = DoubleSolenoidPiston(
            config.pneumatics_control_module,
            config.intake_piston_forwardChannel,
            config.intake_piston_reverseChannel,
        )

        self.intake_active = False
        self.intake_speed = config.default_intake_speed

    def init(self):
        self.intake_motor.init()

    def intake_enable(self, intake_reversed: bool = False):
        self.intake_piston.extend()
        self.intake_active = True
        self.intake_motor.set_raw_output(
            self.intake_speed
            * (-1 if intake_reversed else 1)
            * (-1 if config.intake_inverted else 1)
        )

    def enable_intake_motor(self, intake_reversed: bool = False):
        self.intake_motor.set_raw_output(
            self.intake_speed
            * (-1 if intake_reversed else 1)
            * (-1 if config.intake_inverted else 1)
        )

    def disable_intake_motor(self):
        self.intake_motor.set_raw_output(0)

    def intake_disable(self):
        self.intake_piston.retract()
        self.intake_active = False
        self.intake_motor.set_raw_output(0)


from typing import Optional, Any
import argparse
import logging
import lsprotocol.types as lsp_types
from pygls.server import LanguageServer
import logging
from . import commands, features
from .colorful_log_handler import ColorfulHandler

LOGGER = logging.getLogger(__name__)

def init_language_server() -> LanguageServer:
    language_server = LanguageServer("tentiris", "v0.1")

    def register_feature(
        tentiris_server, feature_name: str, f, options: Optional[Any] = None
    ):
        @tentiris_server.feature(feature_name, options)
        def wrapper(*args, **keys):
            return f(tentiris_server, *args, **keys)

        return wrapper

    def register_command(tentiris_server, command_name: str, f):
        @tentiris_server.command(command_name)
        def wrapper(*args, **keys):
            return f(tentiris_server, *args, **keys)

        return wrapper

    def register_thread_command(tentiris_server, command_name: str, f):
        @tentiris_server.thread()
        @tentiris_server.command(command_name)
        def wrapper(*args, **keys):
            return f(tentiris_server, *args, **keys)

        return wrapper

    register_feature(
        language_server,
        lsp_types.TEXT_DOCUMENT_COMPLETION,
        features.completions,
        lsp_types.CompletionOptions(trigger_characters=[","]),
    )
    register_command(
        language_server,
        "countDownBlocking",
        commands.count_down_10_seconds_blocking,
    )
    register_command(
        language_server,
        "countDownNonBlocking",
        commands.count_down_10_seconds_non_blocking,
    )
    register_feature(
        language_server, lsp_types.TEXT_DOCUMENT_DID_CHANGE, features.did_change
    )
    register_feature(
        language_server, lsp_types.TEXT_DOCUMENT_DID_CLOSE, features.did_close
    )
    register_feature(
        language_server, lsp_types.TEXT_DOCUMENT_DID_OPEN, features.did_open
    )
    register_feature(
        language_server,
        lsp_types.TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL,
        features.semantic_tokens,
        lsp_types.SemanticTokensLegend(token_types=["operator"], token_modifiers=[]),
    )
    register_command(language_server, "progress", commands.progress)
    register_command(
        language_server,
        "registerCompletions",
        commands.register_completions,
    )
    register_command(
        language_server,
        "showConfigurationAsync",
        commands.show_configuration_async,
    )
    register_command(
        language_server,
        "showConfigurationCallback",
        commands.show_configuration_callback,
    )
    register_thread_command(
        language_server, "showConfigurationThread", commands.show_configuration_thread
    )
    register_command(
        language_server,
        "unregisterCompletions",
        commands.unregister_completions,
    )

    return language_server

def main():
    logging.basicConfig(level=logging.WARN, handlers=[ColorfulHandler()])

    # args
    parser = argparse.ArgumentParser()
    parser.description = "simple json server example"
    parser.add_argument("--tcp", action="store_true", help="Use TCP server")
    parser.add_argument("--ws", action="store_true", help="Use WebSocket server")
    parser.add_argument("--host", default="127.0.0.1", help="Bind to this address")
    parser.add_argument("--port", type=int, default=32123, help="Bind to this port")
    args = parser.parse_args()

    # language server
    language_server = init_language_server()
    if args.tcp:
        language_server.start_tcp(args.host, args.port)
    elif args.ws:
        language_server.start_ws(args.host, args.port)
    else:
        language_server.start_io()

if __name__ == "__main__":
    main()


from sklearn import svm
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, confusion_matrix
from imblearn.over_sampling import SMOTE
from sklearn.preprocessing import MinMaxScaler
import warnings
from collections import Counter
warnings.filterwarnings('ignore')
import seaborn as sns
import matplotlib.pyplot as plt
from keras import Sequential
from keras.layers import Dense
import pickle
from sklearn.externals import joblib
from sklearn.pipeline import make_pipeline

df = pd.read_csv('bankloan.csv')
df = df.dropna()
#df.isna().any()
df = df.drop('Loan_ID', axis=1)
df['LoanAmount'] = (df['LoanAmount'] *1000).astype(int)
print(Counter(df['Loan_Status'])) #'Y' l/df[ 'Loan_Status ' .size

pre_y = df['Loan_Status']
pre_X = df.drop('Loan_Status', axis =1)
dm_X = pd.get_dummies(pre_X)
dm_y = pre_y.map(dict(Y=1, N=0))
#print(dm_X.head())

smote = SMOTE(ratio='minority')
X1,y = smote.fit_sample(dm_X, dm_y)
sc = MinMaxScaler()
X = sc.fit_transform(X1)
print(Counter(y))

filename = 'minmaxscaler.pkl'
joblib.dump(sc, filename)

X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.2,random_state=42, shuffle=True)

classifier = Sequential()
classifier.add(Dense(200, activation='relu' , kernel_initializer='random_normal', input_dim=X_test.shape[1]))
classifier.add(Dense(400, activation='relu' , kernel_initializer='random_normal'))
classifier.add(Dense(4, activation='relu' , kernel_initializer='random_normal'))
classifier.add(Dense(1, activation='sigmoid' , kernel_initializer='random_normal'))

classifier.compile(optimizer='adam', loss= 'binary_crossentropy', metrics= ['accuracy'])
classifier.fit(X_train, y_train, batch_size=20, epochs=50, verbose=0)
eval_model= classifier.evaluate(X_train, y_train)
print(eval_model)

y_pred = classifier.predict(X_test)
y_pred = (y_pred>0.5)

cm = confusion_matrix(y_test, y_pred)
ax = plt.subplot()
sns.heatmap(cm, annot=True, ax = ax);
ax.set_xlabel('Predicted');
ax.set_ylabel('Actual');
ax.set_title('Confusion Matrix');
ax.xaxis.set_ticklabels(['No','Yes'])
ax.yaxis.set_ticklabels(['No','Yes'])

#filename = 'loan_model.pkl'
#joblib.dump(classifier, filename)

#predict
sc = joblib.load('minmaxscaler.pkl')
mdl = joblib.load('loan_model.pkl')

X = pd.read_csv('bankloan.csv', nrows= 5)
X = X.drop('Loan_ID', axis=1)
X = X.dropna()
X['LoanAmount'] = (X['LoanAmount'] *1000).astype(int)
print("here", X.head())

X_test = sc.fit_transform(X)
y_pred = mdl.predict(X_test)
y_pred = (y_pred>0.58)
print(y_pred)

# from sklearn.model_selection import StratifiedKFold
# kfold = StratifiedKFold(n_splits=3, shuffle=True, random_state=0)
# cvscores = []
#
# for train, test in kfold.split(X, y):
#     model = Sequential()
#     model.add(Dense(200, input_dim=17, activation='relu'))
#     model.add(Dense(400, activation='relu'))
#     model.add(Dense(4, activation='sigmoid'))
#
#     model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
#
#     model.fit(X[train], y[train], epochs=100, verbose=0)
#
#     scores = model.evaluate(X[test], y[test], verbose=0)
#     print("%s: %.2f%%" % (model.metrics_name[1], scores[1]*100))
#     cvscores.append(scores[1] * 100)
# print("%.2f%% (+/- %.2f%%)" % (np.mean(cvscores), np.std(cvscores)))


import os
import requests
from pprint import pprint
"""
API Apple
Скачиваем картинки для альбомов и сохраняем их в папку covers
"""

URL = 'https://itunes.apple.com/search'
params = {
    'term': 'coldplay'
}

res = requests.get(URL, params)

print('status_code', res.status_code)
print('raise_for_status', res.raise_for_status())
# print('content', res.content)  # content получает данные в формате для бинарника (типо картинки)
print('json', res.json().keys())
data = res.json()['results']
print('data', data)
for item in data:
    # print(f'{item["trackName"]} - {item["artistName"]} - {item["artworkUrl100"]}')
    print('{} - {} - {}'.format(item['trackName'], item['artistName'], item['artworkUrl100']))
    filename = '{} - {}'.format(item['trackName'], item['artistName']) + '.jpg'
    filename_path = os.path.join('covers', filename)
    with open(filename_path, 'wb') as text:
        img_res = requests.get(item['artworkUrl100'])
        text.write(img_res.content)
        print('Сохранено в {}'.format(filename_path))


import paho.mqtt.publish as publish
import time

# Set up the MQTT broker and topic
MQTT_BROKER = "test.mosquitto.org"
MQTT_TOPIC = "example/topic"

# Define the data as a list
data = [214, 12, 33, 22, 32, 0,16, 21, 0, 0, 0, 230, 0]

# Loop and send the data via MQTT every second
while True:
    # Convert the list to a string and send it via MQTT
    payload = str(data)
    publish.single(MQTT_TOPIC, payload, hostname=MQTT_BROKER)
    print("Data sent via MQTT.")
    print(type(data))

    # Wait for 1 second before sending the next data
    time.sleep(1)


# 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.

import uuid

from openstack import exceptions
from openstack.tests.functional import base
from openstack import utils

class TestZoneShare(base.BaseFunctionalTest):
    def setUp(self):
        super(TestZoneShare, self).setUp()
        self.require_service('dns')
        if not self.user_cloud:
            self.skipTest("The demo cloud is required for this test")

        # Note: zone deletion is not an immediate operation, so each time
        # chose a new zone name for a test
        # getUniqueString is not guaranteed to return unique string between
        # different tests of the same class.
        self.ZONE_NAME = 'example-{0}.org.'.format(uuid.uuid4().hex)

        # Make sure the API under test has shared zones support
        if not utils.supports_version(self.conn.dns, '2.1'):
            self.skipTest(
                'Designate API version does not support shared zones.'
            )

        self.zone = self.operator_cloud.dns.create_zone(
            name=self.ZONE_NAME,
            email='joe@example.org',
            type='PRIMARY',
            ttl=7200,
            description='example zone for sdk zone share tests',
        )
        self.addCleanup(
            self.operator_cloud.dns.delete_zone,
            self.zone,
            delete_shares=True,
        )

        self.project_id = self.operator_cloud.session.get_project_id()
        self.demo_project_id = self.user_cloud.session.get_project_id()

    def test_create_delete_zone_share(self):
        zone_share = self.operator_cloud.dns.create_zone_share(
            self.zone, target_project_id=self.demo_project_id
        )
        self.addCleanup(
            self.operator_cloud.dns.delete_zone_share,
            self.zone,
            zone_share,
        )

        self.assertEqual(self.zone.id, zone_share.zone_id)
        self.assertEqual(self.project_id, zone_share.project_id)
        self.assertEqual(self.demo_project_id, zone_share.target_project_id)
        self.assertIsNotNone(zone_share.id)
        self.assertIsNotNone(zone_share.created_at)
        self.assertIsNone(zone_share.updated_at)

    def test_get_zone_share(self):
        orig_zone_share = self.operator_cloud.dns.create_zone_share(
            self.zone,
            target_project_id=self.demo_project_id,
        )
        self.addCleanup(
            self.operator_cloud.dns.delete_zone_share,
            self.zone,
            orig_zone_share,
        )

        zone_share = self.operator_cloud.dns.get_zone_share(
            self.zone,
            orig_zone_share,
        )

        self.assertEqual(self.zone.id, zone_share.zone_id)
        self.assertEqual(self.project_id, zone_share.project_id)
        self.assertEqual(self.demo_project_id, zone_share.target_project_id)
        self.assertEqual(orig_zone_share.id, zone_share.id)
        self.assertEqual(orig_zone_share.created_at, zone_share.created_at)
        self.assertEqual(orig_zone_share.updated_at, zone_share.updated_at)

    def test_find_zone_share(self):
        orig_zone_share = self.operator_cloud.dns.create_zone_share(
            self.zone, target_project_id=self.demo_project_id
        )
        self.addCleanup(
            self.operator_cloud.dns.delete_zone_share,
            self.zone,
            orig_zone_share,
        )

        zone_share = self.operator_cloud.dns.find_zone_share(
            self.zone,
            orig_zone_share.id,
        )

        self.assertEqual(self.zone.id, zone_share.zone_id)
        self.assertEqual(self.project_id, zone_share.project_id)
        self.assertEqual(self.demo_project_id, zone_share.target_project_id)
        self.assertEqual(orig_zone_share.id, zone_share.id)
        self.assertEqual(orig_zone_share.created_at, zone_share.created_at)
        self.assertEqual(orig_zone_share.updated_at, zone_share.updated_at)

    def test_find_zone_share_ignore_missing(self):
        zone_share = self.operator_cloud.dns.find_zone_share(
            self.zone,
            'bogus_id',
        )
        self.assertIsNone(zone_share)

    def test_find_zone_share_ignore_missing_false(self):
        self.assertRaises(
            exceptions.ResourceNotFound,
            self.operator_cloud.dns.find_zone_share,
            self.zone,
            'bogus_id',
            ignore_missing=False,
        )

    def test_list_zone_shares(self):
        zone_share = self.operator_cloud.dns.create_zone_share(
            self.zone,
            target_project_id=self.demo_project_id,
        )
        self.addCleanup(
            self.operator_cloud.dns.delete_zone_share,
            self.zone,
            zone_share,
        )

        target_ids = [
            o.target_project_id
            for o in self.operator_cloud.dns.zone_shares(self.zone)
        ]
        self.assertIn(self.demo_project_id, target_ids)

    def test_list_zone_shares_with_target_id(self):
        zone_share = self.operator_cloud.dns.create_zone_share(
            self.zone,
            target_project_id=self.demo_project_id,
        )
        self.addCleanup(
            self.operator_cloud.dns.delete_zone_share,
            self.zone,
            zone_share,
        )

        target_ids = [
            o.target_project_id
            for o in self.operator_cloud.dns.zone_shares(
                self.zone, target_project_id=self.demo_project_id
            )
        ]
        self.assertIn(self.demo_project_id, target_ids)


from bbpyp.common.model.deeply_copyable import DeeplyCopyable
from bbpyp.common.exception.bbpyp_value_error import BbpypValueError

class CollectionUtil:
    @staticmethod
    def add_items(collection, *items):
        if hasattr(collection, 'update'):
            collection.update(items)
        elif hasattr(collection, 'append'):
            for item in items:
                collection.append(item)
        elif hasattr(collection, 'add'):
            for item in items:
                collection.add(item)

    @staticmethod
    def add_types_to_deepcopy_direct_assignment_list(*types_to_be_directly_assigned):
        CollectionUtil.add_items(DeeplyCopyable._DEEPLY_COPYABLE_ASSIGN_TYPES,
                                 *types_to_be_directly_assigned)

    @staticmethod
    def reversed_index(collection, item, from_position=None):
        from_position = from_position if from_position is not None else len(collection) - 1
        for index in reversed(range(0, from_position + 1)):
            if collection[index] == item:
                return index
        raise BbpypValueError("item", item, "is not in collection" if from_position == len(
            collection) - 1 else f"is not in collection before position {from_position}")

    @staticmethod
    def reversed_first_index(collection, items, from_position=None):
        from_position = from_position if from_position is not None else len(collection) - 1

        for index in reversed(range(0, from_position + 1)):
            if collection[index] in items:
                return index
        raise BbpypValueError("items", items, "are not in collection" if from_position == len(
            collection) - 1 else f"are not in collection before position {from_position}")


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

###lib required:pdfminer3k,python_docx
import sys,io,re,os
from pdfminer.pdfinterp import PDFResourceManager, process_pdf
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from io import StringIO
from io import open
from docx import Document
from configparser import ConfigParser
from concurrent.futures import ProcessPoolExecutor
sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='utf-8')

def read_from_pdf(file_path):
    with open(file_path,'rb') as file:
        resource_manager=PDFResourceManager()
        return_str=StringIO()
        lap_params=LAParams()
        device=TextConverter(resource_manager,return_str,laparams=lap_params)
        process_pdf(resource_manager,device,file)
        device.close()
        content=return_str.getvalue()
        return_str.close()
        return content

def readPDF(pdfFile):
    rsrcmgr = PDFResourceManager()
    retstr = StringIO()
    laparams = LAParams()
    device = TextConverter(rsrcmgr, retstr, laparams=laparams)
    process_pdf(rsrcmgr, device, pdfFile)
    device.close()
    content = retstr.getvalue()
    retstr.close()
    return content

def save2txt(out_file,txt_content):
    with open(out_file,"w",encoding='utf-8') as f:
        f.write(txt_content)

def save_text_to_word(content,file_path):
    doc = Document()
    for line in content.split('\n'):
        paragraph=doc.add_paragraph()
        paragraph.add_run(remove_control_characters(line))
    doc.save(file_path)

def remove_control_characters(content):
    mpa=dict.fromkeys(range(32))
    return content.translate(mpa)

def pdf_to_word(pdf_file_path,word_file_path):
    content=read_from_pdf(pdf_file_path)
    save_text_to_word(content,word_file_path)

def main():
    if len(sys.argv)<2:
        print (f"\n\tpython {sys.argv[0]} <input_pdf>\n")
        sys.exit(0)
    else:
        txt_out_file=sys.argv[1].replace("pdf","txt")
        docx_out_file=sys.argv[1].replace("pdf","docx")

        ####pdf转成txt
        pdf_content = readPDF(open(sys.argv[1], 'rb'))
        save2txt(txt_out_file,pdf_content)

        ####pdf转成word
        with ProcessPoolExecutor(max_workers=1) as executor:
            result=executor.submit(pdf_to_word,sys.argv[1],docx_out_file)

if __name__=='__main__':
    main()


# -*- encoding: utf-8 -*-

import pygame
pygame.mixer.pre_init()
pygame.mixer.init()

# DATA PATHS
#
# Images: data / image / type / id
# Sounds: data / audio / id
#
# REAL PATHS
#
# Images: ./data/assets/sound/id.png
# Sounds: ./data/audio/id.wav
# Fonts: ./data/fonts

def init(data: dict, on_step=None):
    def _step():
        if on_step:
            on_step.__call__()

    # Setting up the terrain
    data["data"] = {}
    data["data"]["image"] = {}
    data["data"]["image"]["action"] = []
    data["data"]["image"]["sound"] = []
    data["data"]["audio"] = []

    print("Loading assets...")

    i = 2
    for t in ["action", "sound"]:
        for a in data["id"][t]:
            data["data"]["image"][t].append(pygame.image.load(f"data/assets/{t}/{a}.png"))
            _step()
            i += 1
    data["data"]["image"]["pause"] = [pygame.image.load("data/assets/empty.png")]

    print("Loading sounds...")
    i = 1
    for s in data["id"]["sound"]:
        data["data"]["audio"].append(pygame.mixer.Sound(f"data/audio/{s}.wav"))
        _step()
        i += 1

    print("Done.\n")


import Rhino as rc

#find a point between A and B
D = A + t * (B - A)

#find mid point between A and B
C1 = A + 0.5 * (D - A)

#find mid point between D and B
C2 = D + 0.5 * (B - D)

#find spheres radius
r1 = A.DistanceTo(C1) #C1 - A
r2 = B.DistanceTo(C2)

#create spheres and assing to output
s1 = rc.Geometry.Sphere(C1, r1)
s2 = rc.Geometry.Sphere(C2, r2)


import unittest

from tests.FakeView import FakeView
from tests.FakeViewInsane import FakeViewInsane
from controller.GameManager import GameManager
from model.card.insaneCard.DeepOnes import DeepOnes
from model.card.insaneCard.GoldenMead import GoldenMead
from model.card.insaneCard.HoundOfTindalos import HoundOfTindalos
from model.card.saneCard.Investigators import Investigators
from model.card.saneCard.ProfessorHenryArmitage import ProfessorHenryArmitage
from model.card.saneCard.GreatRaceOfYith import GreatRaceOfYith

class TestDeepOnes(unittest.TestCase) :
    def test_value3Sane(self) :
        gm = GameManager(FakeView(None), 2)
        gm.startNewRound()

        gm.players[0].pickUp(Investigators())
        # The FakeView automatically respond 3 so I place Great Race Of Yith (value 3).
        gm.players[1].hand = [GreatRaceOfYith()]

        gm.play(1)

        # The other player should be kicked out
        self.assertTrue(gm.players[1].knockedOut)

    def test_noValue3Sane(self) :
        gm = GameManager(FakeView(None), 2)
        gm.startNewRound()

        gm.players[0].pickUp(Investigators())
        # Is the other player doesn't have any card with value 3.
        gm.players[1].hand = [ProfessorHenryArmitage()]

        gm.play(1)

        self.assertFalse(gm.players[1].knockedOut)

    def test_value1(self) :
        gm = GameManager(FakeViewInsane(None), 2)
        gm.startNewRound()

        gm.players[0].hand = []
        gm.players[0].pickUp(GoldenMead())
        gm.players[0].pickUp(DeepOnes())
        gm.players[0].addDiscardedCard(GoldenMead())

        # The other player must have a card with a value of one.
        gm.players[1].hand = []
        gm.players[1].pickUp(Investigators())

        gm.play(1)

        self.assertTrue(gm.players[1].knockedOut)

    def test_value3Insane(self) :
        gm = GameManager(FakeViewInsane(None), 2)
        gm.startNewRound()

        gm.players[0].hand = []
        gm.players[0].pickUp(GoldenMead())
        gm.players[0].pickUp(DeepOnes())
        gm.players[0].addDiscardedCard(GoldenMead())

        gm.players[1].hand = []
        gm.players[1].pickUp(HoundOfTindalos())

        gm.play(1)

        self.assertTrue(gm.players[1].knockedOut)

    def test_noValue3Insane(self) :
        gm = GameManager(FakeViewInsane(None), 2)
        gm.startNewRound()

        gm.players[0].hand = []
        gm.players[0].pickUp(GoldenMead())
        gm.players[0].pickUp(DeepOnes())
        gm.players[0].addDiscardedCard(GoldenMead())

        gm.players[1].hand = []
        gm.players[1].pickUp(GoldenMead())

        gm.play(1)

        self.assertFalse(gm.players[1].knockedOut)


#!/usr/bin/python
import xml.etree.ElementTree as ET
import argparse
import os
import HTMLParser

from pprint import pprint
ns = '{http://checklists.nist.gov/xccdf/1.1}'
dc = '{http://purl.org/dc/elements/1.1/}'
h = HTMLParser.HTMLParser()

objRef = {}
# def show_root_info(self):
	# for item in self.root.items():
		# for n, field in enumerate(item):
			# if n == 0:
				# p = field.index('}')
				# print(f'{field[p+1:] :20}: ', end='')
			# else:
				# print(field)

def parseRule(rule):
	rules = {}
	rules.update( rule.attrib.items())
	for rItem in rule:
		tag = rItem.tag.replace(ns,'')
		if 'reference' in tag or 'check' in tag:
			for sub in rItem:
				if 'reference' in tag:
					subtag = sub.tag.replace(dc,'')
				else:
					subtag = sub.tag.replace(ns,'')
				if sub.text is not None:
					rules[subtag] = sub.text
		else:
			itemDic = {}
			if len(rItem.attrib) > 0:
				itemDic.update(rule.attrib.items())
			if rItem.text is not None:
				itemDic['text'] = rItem.text
		rules[tag] = itemDic
	return rules

def parseStig(xmlfile):
	# create element tree object
	tree = ET.parse(xmlfile.name)
	root = tree.getroot()
	groupitems = []

	# iterate news items
	for item in root.findall('./{http://checklists.nist.gov/xccdf/1.1}Group'):
		#pprint(item.attrib['id'])
		group = {'fileName' : xmlfile.name, 'id': item.attrib['id']}
		for child in item:
			if('Rule' in child.tag):
				group['Rule'] = parseRule(child)
			else:
				tag = child.tag.replace(ns,'')
				group[tag] = child.text
			#group[child.tag] = child.attrib
		# append news dictionary to news items list
		objRef[item.attrib['id']] = group
		groupitems.append(group)
	# return news items list
	return groupitems

def buildAudit(stigData, auditFile):
	f = open(str(auditFile),"w+")
	f.write('<check_type:"Cisco"> \n')

	for item in stigData :
		print('<?xml version="1.0"?><collection>'+ h.unescape(item['Rule']['description']['text']).encode('utf8') +'</collection>')
		textXml = ET.fromstring('<?xml version="1.0"?><collection>'+ h.unescape(item['Rule']['description']['text']).replace('&','').encode('utf8') +'</collection>')
		ruleDict = {}
		for elem in textXml.iter():
			pprint({elem.tag: 'nothing' if elem.text is None else elem.text})
			ruleDict.update({elem.tag: 'nothing' if elem.text is None else elem.text})

		refDic = {'Rule-ID': item['Rule']['check']['id'],"Vuln-ID":item['id'],"STIG-ID":item['Rule']['version']['text']}

		f.write('\n<item>\n')
		f.write('  type \t: CONFIG_CHECK \n')
		f.write('  description \t: "' + item['Rule']['version']['text'] +' - ' + item['title'] +'"\n')
		f.write('  info \t: "' + item['Rule']['title'] +'\n\n'+ ruleDict['VulnDiscussion'].encode('utf8') +'"\n')
		f.write('  solution \t: "' + item['Rule']['fixtext']['text'].encode('utf8') +'"\n')
		f.write('  reference \t: "'+ ','.join("{0}|{1}".format(key,val.replace("'",'')) for (key,val) in refDic.items()) +'"\n')
		f.write('  see_also \t: "https://iasecontent.disa.mil/stigs/zip/'+ item['fileName'] +'"\n')
		f.write('  context \t: \n')
		f.write('  item \t: \n')
		f.write('\n</item>\n\n')

	f.close()
##
##AUDIT Fields
## Title, Description, Rule: id, severity, weight, version, title, description
def main():
	parser = argparse.ArgumentParser(description='Process a STIG xml into a nessus audit file')
	parser.add_argument('stig', metavar='N', type=argparse.FileType('r'), help='the stig file you want converted')
	parser.add_argument('auditFile', metavar='N', type=str, help='the output auditFile')
	args = parser.parse_args()
	stig = parseStig(args.stig)
	buildAudit(stig, args.auditFile)
	#pprint(stig)

if __name__ == "__main__":

	# calling main function
	main()


import math
from itertools import zip_longest
from typing import Type, Union, Set, List, Tuple
import networkx as nx
from networkx.classes.filters import no_filter

from weaveio.hierarchy import Multiple, Hierarchy, OneOf, Graphable

def normalise_relation(h):
    if not isinstance(h, Multiple):
        h = OneOf(h)
    h.instantate_node()
    relation, node = h, h.node
    return relation, node

def get_all_subclasses(cls: Type) -> List[Type]:
    all_subclasses = []
    for subclass in cls.__subclasses__():
        all_subclasses.append(subclass)
        all_subclasses.extend(get_all_subclasses(subclass))
    return all_subclasses

def collapse_classes_to_superclasses(graph, classes):
    """
    Given a list of classes, return the shortest list of classes possible by merging classes together.
    A merge is only possible if they share a base class
    class B(A) and class C(A) can be merged -> class A
    In graph terms, this is equivalent to finding islands (connected components) and returning
     the shallowest node that has a path to all leaves (the head(s))
    """
    G = nx.subgraph_view(graph, filter_node=lambda n: n != Hierarchy and n in classes,
                         filter_edge=lambda *e: graph.edges[e]['type'] == 'subclassed_by')
    for ns in nx.connected_components(G.to_undirected()):
        subgraph = nx.subgraph(G, ns)
        for n in subgraph.nodes:
            if not subgraph.in_degree(n):
                yield n

def hierarchies_from_hierarchy(hier: Type[Hierarchy], done=None, templates=False) -> Set[Type[Hierarchy]]:
    if done is None:
        done = []
    hierarchies = set()
    todo = {h.node if isinstance(h, Multiple) else h for h in hier.parents + hier.children + hier.produces}
    if not templates:
        todo = {h for h in todo if not h.is_template}
    else:
        todo.update({h for h in todo for hh in get_all_class_bases(h) if issubclass(hh, Hierarchy)})
    for new in todo:
        if isinstance(new, Multiple):
            new.instantate_node()
            h = new.node
        else:
            h = new
        if h not in done and h is not hier:
            hierarchies.update(hierarchies_from_hierarchy(h, done, templates))
            done.append(h)
    hierarchies.add(hier)
    return hierarchies

def expand_template_relation(relation):
    """
    Returns a list of relations that relate to each non-template class
    e.g.
    >>> expand_template_relation(Multiple(L1StackedSpectrum))
    [Multiple(L1SingleSpectrum), Multiple(L1StackSpectrum), Multiple(L1SuperstackSpectrum)]
    """
    if not relation.node.is_template:
        return [relation]
    subclasses = [cls for cls in get_all_subclasses(relation.node) if not cls.is_template and issubclass(cls, Hierarchy)]
    return [Multiple(subclass, 0, relation.maxnumber, relation.constrain, relation.relation_idname, relation.one2one) for subclass in subclasses]

def shortest_simple_paths(G, source, target, weight):
    try:
        return nx.shortest_simple_paths(G, source, target, weight)
    except nx.NetworkXNoPath:
        return None

def pick_shortest_multiedge(G, a, b, weight=None):
    edges = set(G.out_edges(a, keys=True)) & set(G.in_edges(b, keys=True))
    if not edges:
        raise nx.NetworkXNoPath("No path found between %s and %s" % (a, b))
    if weight is not None:
        return min(edges, key=lambda e: G.edges[e][weight])
    return edges.pop()

def edges_from_path(G, path, weight=None):
    return list(map(lambda e: pick_shortest_multiedge(G, *e, weight=weight), zip(path[:-1], path[1:])))

def find_forking_path(graph, top, bottom, weight=None):
    done = set()
    parents = nx.subgraph_view(graph, filter_edge=lambda *e: graph.edges[e]['type'] != 'is_a')
    is_a_graph = nx.subgraph_view(graph, filter_edge=lambda *e: graph.edges[e]['type'] == 'is_a')
    gen = nx.all_shortest_paths(graph, bottom, top, weight)
    try:
        todo = [next(gen)]
    except nx.NetworkXNoPath:
        return []
    while todo:
        _path = todo.pop()
        edges = edges_from_path(graph, _path, weight)
        types = [graph.edges[edge]['type'] for edge in edges]
        path = [_path[0]]
        for i, (edge, typ) in enumerate(zip(edges, types)):
            if typ == 'is_a' and edge[1] != top:
                # try to find a path using the superclass
                subpaths = find_forking_path(parents, top, edge[0], weight)
                if subpaths:
                    for subpath in subpaths:
                        done.add((*path[:-1], *subpath))
                else:  # otherwise expand all classes
                    subclasses = [i for i in get_all_subclasses(edge[0]) if not i.is_template]
                    if top in subclasses:
                        inheritance_path = nx.shortest_path(is_a_graph, edge[0], top)
                        done.add((*path, *inheritance_path[1:]))
                    else:
                        for subclass in subclasses:
                            inheritance_path = nx.shortest_path(is_a_graph, edge[0], subclass)
                            for subpath in find_forking_path(graph, top, subclass, weight):
                                done.add((*path, *inheritance_path[1:-1], *subpath))
                break
            else:
                path.append(edge[1])
        else:  # only append here, if we've cycled through all edges without breaking
            done.add(tuple(path))
    return done

def find_paths(graph, a, b, weight='weight') -> Set[Tuple[Type[Hierarchy]]]:
    """
    Returns a set of paths from a to b
    Not all paths are guaranteed to be valid, for example:
        l2superstack.ob yields paths of which `L2superstack-...-L1Single-...-ob` is one.
        This path is invalid, but it is included anyway because it is one of a set
        (through single,stack,superstack,supertarget).
        When queried, invalid paths will yield 0 results so it is not a problem.
    """
    *sorted_nodes, G, use_children = graph.sort_deepest(a, b)
    G = G.reverse()
    _paths = find_forking_path(G, *sorted_nodes, weight)
    _paths = {(p[0], p[0]) if len(p) == 1 else p for p in _paths}
    # put in requested order (a-->b)
    # now remove chains of is_a
    # so x-l1spectrum-l1stacked-l1stack becomes x-l1stack
    reduced_paths = set()
    for ip, path in enumerate(_paths):
        edges = edges_from_path(G, path, weight)
        reduced_path = [edge[0] for edge in edges if G.edges[edge]['type'] not in ['is_a', 'subclassed_by']]
        reduced_path = (*reduced_path, path[-1])
        if not use_children:
            reduced_path = reduced_path[::-1]  # reverse it because the actual database has only parent relations
            edges = (graph.short_edge(e[1], e[0], weight) for e in edges[::-1])
        reduced_paths.add((reduced_path, tuple(edges)))
    return reduced_paths

class HierarchyGraph(nx.MultiDiGraph):
    """
    A multidigraph where edges have keys
    """
    def initialise(self):
        hiers = get_all_subclasses(Hierarchy)
        for h in hiers:
            self._add_hierarchy(h)
        self.remove_node(Hierarchy)
        self._assign_edge_weights()

    def to_neo4j(self, graph):
        node_type = 'AbstractNode'
        for node in self.nodes:
            graph.execute(f"""MERGE (n:{node.__name__}{node_type}:{node_type}) ON CREATE
            SET n.factors = $factors, n.identifier_builder = $identifier_builder, n.singular_name=$singular_name,
             n.plural_name = $plural_name, n.idname = $idname, n.products = $products""",
                          factors=node.factors, singular_name=node.singular_name, plural_name=node.plural_name,
                          idname=node.idname, identifier_builder=node.identifier_builder, products=node.products)
        for edge in self.edges:
            rel = {k: v for k, v in self.edges[edge].items() if not isinstance(v, Multiple)}
            try:
                rel.update(self.edges[edge]['relation'].to_reldict())
            except KeyError:
                rel['singular'] = False
            if 'constrain' in rel:
                rel['constrain'] = [i.__name__ for i in rel['constrain']]
            graph.execute(f"""MATCH (a:{edge[0].__name__}{node_type})
            MATCH (b:{edge[1].__name__}{node_type})
            MERGE (a)-[r:{rel.pop('type')}]->(b)
            ON CREATE SET r = $rel
            """, rel=rel)

    def add_edge(self, u_for_edge, v_for_edge, idname=None, **attr):
        """
        Create an edge if the edge (uniquely identified by attributes) doesn't exist
        the edge key will be an unused integer or the idname of the relation
        if idname is given, it will be used and attr is not checked for uniqueness (only ever 1 edge)
        if idname is not given, attr is checked for uniqueness and key is the number of the same edges
        """
        if not attr:
            return super(HierarchyGraph, self).add_edge(u_for_edge, v_for_edge, idname)
        hsh = hash(tuple(attr.items()))
        if idname is not None:
            # use idname as unique key
            key = super(HierarchyGraph, self).add_edge(u_for_edge, v_for_edge, idname, hsh=hsh, **attr)
            # and make a "general" link as well
            if (u_for_edge, v_for_edge, '*') in self.edges:
                self.edges[u_for_edge, v_for_edge, '*']['singular'] = False
                self.edges[u_for_edge, v_for_edge, '*']['actual_number'] += attr['actual_number']
            else:
                super(HierarchyGraph, self).add_edge(u_for_edge, v_for_edge, '*', hsh=hsh, **attr)
            return key
        if u_for_edge in self and v_for_edge in self:
            edges = set(self.out_edges(u_for_edge, keys=True)) & set(self.in_edges(v_for_edge, keys=True))
        else:
            edges = set()
        if hsh not in (self.edges[e]['hsh'] for e in edges):
            # use an incremented integer as a unique key only if the edge is unique in attr and (u,v)
            return super(HierarchyGraph, self).add_edge(u_for_edge, v_for_edge, hsh=hsh, **attr)

    def surrounding_nodes(self, n):
        return list(self.parents.successors(n)) + list(self.parents.predecessors(n)) + [n]

    def _add_parent(self, child: Type[Hierarchy], parent: Union[Type[Hierarchy], Multiple]):
        relation, parent = normalise_relation(parent)
        relstyle = 'solid' if relation.maxnumber == 1 else 'dashed'
        self.add_edge(child, parent, singular=relation.maxnumber == 1, one2one=relation.one2one,
                       optional=relation.minnumber == 0, style=relstyle, actual_number=relation.maxnumber, type='is_child_of')
        if relation.one2one:
            self.add_edge(parent, child, singular=True, optional=relation.minnumber == 0, style='solid',
                          type='is_parent_of', one2one=relation.one2one,
                          relation=relation, actual_number=relation.maxnumber)
        else:
            self.add_edge(parent, child, singular=False, optional=relation.minnumber == 0, style='dashed',
                          type='is_parent_of', one2one=relation.one2one,
                          relation=relation, actual_number=relation.maxnumber)

    def _add_child(self, parent: Type[Hierarchy], child: Union[Type[Hierarchy], Multiple]):
        relation, child = normalise_relation(child)
        relstyle = 'solid' if relation.maxnumber == 1 else 'dashed'
        self.add_edge(parent, child, singular=relation.maxnumber == 1, one2one=relation.one2one,
                       optional=relation.minnumber == 0, type='is_parent_of',
                       relation=relation, style=relstyle, actual_number=relation.maxnumber)
        self.add_edge(child, parent, singular=True, optional=relation.minnumber == 0,  one2one=relation.one2one,
                      style='solid', type='is_child_of', actual_number=relation.maxnumber)

    def _add_self_reference(self, relation):
        relation, h = normalise_relation(relation)
        relstyle = 'solid' if relation.maxnumber == 1 else 'dashed'
        self.add_edge(h, h, singular=relation.maxnumber == 1, optional=relation.minnumber == 0,
                      one2one=relation.one2one, style=relstyle, actual_number=relation.maxnumber, type='is_parent_of')

    def _add_inheritance(self, hierarchy, base):
        self.add_edge(base, hierarchy, type='subclassed_by', actual_number=math.inf, style='dotted', optional=False,
                      one2one=False)
        self.add_edge(hierarchy, base, type='is_a', actual_number=0, style='dotted', optional=False, one2one=False)

    def _assign_edge_weights(self):
        for u, v, k, d in self.edges(data=True, keys=True):
            if d['type'] == 'is_a':
                weight = 0
            elif d['type'] == 'subclassed_by':
                weight = math.inf
            elif d['singular']:
                weight = 0
            else:
                weight = d['actual_number']
            self.edges[u, v, k]['weight'] = weight

    def _add_hierarchy(self, hierarchy: Type[Hierarchy]):
        """
        For a given hierarchy, traverse all its required inputs (parents and children)
        """
        self.add_node(hierarchy)
        for parent in hierarchy.parents:
            if normalise_relation(hierarchy)[1] is parent:
                self._add_self_reference(parent)
            else:
                self._add_parent(hierarchy, parent)
        for child in hierarchy.children:
            if normalise_relation(hierarchy)[1] is child:
                self._add_self_reference(child)
            else:
                self._add_child(hierarchy, child)
        for inherited in hierarchy.__bases__:
            if issubclass(inherited, Hierarchy):
                self._add_inheritance(hierarchy, inherited)

    def ancestor_subgraph(self, source):
        nodes = nx.ancestors(self.parents_and_subclassed_by, source)
        nodes.add(source)
        return nx.subgraph(self, nodes).copy()

    def subgraph_view(self, filter_node=no_filter, filter_edge=no_filter) -> 'HierarchyGraph':
        return nx.subgraph_view(self, filter_node, filter_edge)  # type: HierarchyGraph

    @property
    def inheritance(self):
        return self.subgraph_view(filter_edge=lambda *e: self.edges[e]['type'] == 'is_a').copy()

    @property
    def parents_and_subclassed_by(self):
        allowed = ['is_parent_of', 'subclassed_by']
        return self.subgraph_view(filter_edge=lambda *e: any(i == self.edges[e]['type'] for i in allowed)).copy()

    @property
    def parents(self):
        return self.subgraph_view(filter_edge=lambda *e: self.edges[e]['type'] == 'is_parent_of').copy()

    @property
    def children(self):
        return self.subgraph_view(filter_edge=lambda *e: self.edges[e]['type'] == 'is_child_of').copy()

    @property
    def parents_and_inheritance(self):
        return self.subgraph_view(filter_edge=lambda *e: self.edges[e]['type'] == 'is_parent_of' or 'is_a' == self.edges[e]['type']).copy()

    @property
    def children_and_inheritance(self):
        return self.subgraph_view(filter_edge=lambda *e: self.edges[e]['type'] == 'is_child_of' or 'is_a' == self.edges[e]['type']).copy()

    @property
    def traversal(self):
        def func(u, v):
            edge = self.edges[u, v]
            typ = edge['type']
            return (typ == 'is_parent_of') or (typ == 'is_a') or edge['one2one']
        return self.subgraph_view(filter_edge=func)

    @property
    def nonoptional(self):
        return self.subgraph_view(filter_edge=lambda *e: not self.edges[e]['optional']).copy()

    def sort_deepest(self, a, b):
        """Returns [a, b] or [b, a], in order of increasing depth in the graph"""
        if a is b:
            return a, b, self.parents_and_inheritance, False
        if a not in self:
            raise nx.NodeNotFound(f"Node {a} not found in graph {self}")
        if b not in self:
            raise nx.NodeNotFound(f"Node {b} not found in graph {self}")
        if b in nx.ancestors(self.parents_and_inheritance, a):
            return b, a, self.parents_and_inheritance, False
        elif a in nx.ancestors(self.parents_and_inheritance, b):
            return a, b, self.parents_and_inheritance, False
        elif a in nx.ancestors(self.children_and_inheritance, b):
            return a, b, self.children_and_inheritance, True
        elif b in nx.ancestors(self.children_and_inheritance, a):
            return b, a, self.children_and_inheritance, True
        else:
            raise nx.NetworkXNoPath(f"There is no path between {a} and {b}")

    def short_edge(self, a, b, weight=None):
        """return the shortest edge in the multidigraph for a given digraph edge """
        return pick_shortest_multiedge(self, a, b, weight)

    @property
    def singular(self):
        return self.subgraph_view(filter_edge=lambda *e: self.edges[e]['weight'] == 0)

    @property
    def plural(self):
        return self.subgraph_view(filter_edge=lambda *e: self.edges[e]['weight'] > 0)

    def find_paths(self, a, b, singular):
        """
        Returns a set of paths from a to b
        Not all paths are guaranteed to be valid, for example:
            l2superstack.ob yields paths of which `L2superstack-...-L1Single-...-ob` is one.
            This path is invalid, but it is included anyway because it is one of a set
            (through single,stack,superstack,supertarget).
            When queried, invalid paths will silently yield 0 results so it is not a problem.
        """
        try:
            return find_paths(self.singular.nonoptional, a, b)
        except nx.NetworkXNoPath:
            try:
                return find_paths(self.singular, a, b)
            except nx.NetworkXNoPath as e:
                if singular:
                    raise e
                try:
                    return find_paths(self.nonoptional, a, b)
                except nx.NetworkXNoPath:
                    return find_paths(self, a, b)

    def edge_weights(self, path) -> List[int]:
        return [self.edges[self.short_edge(*e, 'weight')]['weight'] for e in nx.utils.pairwise(path)]

    def edge_path_is_singular(self, edges):
        return not any(self.edges[e]['weight'] > 0 for e in edges)

    def path_is_singular(self, path) -> bool:
        return not any(e > 0 for e in self.edge_weights(path))

def get_all_class_bases(cls: Type[Graphable]) -> Set[Type[Graphable]]:
    new = set()
    for b in cls.__bases__:
        if b is Graphable or not issubclass(b, Graphable):
            continue
        new.add(b)
        new.update(get_all_class_bases(b))
    return new


def HoarePartition(arr, p, r):
    pivot = arr[p]
    i, j = p-1, r+1
    while True:
        i = i + 1
        while arr[i] < pivot:
            i = i + 1

        j = j - 1
        while arr[j] > pivot:
            j = j - 1

        if i >= j:
            return j

        arr[i], arr[j] = arr[j], arr[i]

def QuickSortTailCallElimination(arr, p, r):
    while p < r:
        q = HoarePartition(arr, p, r)
        QuickSortTailCallElimination(arr, p, q)
        p = q + 1

arr = [8, 4, 7, 9, 3, 10, 59]
QuickSortTailCallElimination(arr, 0, len(arr)-1)
print(arr)

Module 1/7. Sorting/9. QuickSortTailCallElimination.py


import json
import numpy as np
import os
import time
import torch
from pathlib import Path
from torch.utils.data import DataLoader
from tqdm import tqdm

import explaignn.heterogeneous_answering.graph_neural_network.dataset_gnn as dataset
from explaignn.heterogeneous_answering.graph_neural_network.gnn_factory import GNNFactory
from explaignn.heterogeneous_answering.heterogeneous_answering import HeterogeneousAnswering
from explaignn.library.utils import get_logger

torch.autograd.set_detect_anomaly(True)

START_DATE = time.strftime("%y-%m-%d_%H-%M", time.localtime())

class GNNModule(HeterogeneousAnswering):
    def __init__(self, config, iteration=None):
        super(GNNModule, self).__init__(config)
        self.logger = (
            get_logger(f"{__name__}_{iteration}", config)
            if iteration
            else get_logger(__name__, config)
        )

        self.gnn = GNNFactory.get_gnn(config)
        total_params = sum(p.numel() for p in self.gnn.parameters() if p.requires_grad)
        self.logger.info(f"Initialized model with {total_params} parameters.")
        self.model_loaded = False

    def train(self, sources=("kb", "text", "table", "info"), train_path=None, dev_path=None):
        """
        Train the model on generated HA data (skip instances for which answer is not there).
        Code inspired by: https://www.geeksforgeeks.org/training-neural-networks-with-validation-using-pytorch/.
        """
        self.logger.info(f"Loading data...")
        self.logger.info(f"Config: {json.dumps(self.config, indent=4)}")

        # set paths
        data_dir = self.config["path_to_intermediate_results"]
        qu = self.config["qu"]
        ers = self.config["ers"]
        sources_str = "_".join(sources)
        model_dir = os.path.dirname(self.config["gnn_model_path"])
        method_name = self.config["name"]

        # load parameters
        train_batch_size = self.config["gnn_train_batch_size"]
        eval_batch_size = self.config["gnn_eval_batch_size"]
        epochs = self.config["gnn_epochs"]
        lr = float(self.config["gnn_learning_rate"])
        weight_decay = float(self.config["gnn_weight_decay"])

        # load data
        if not train_path:
            train_path = os.path.join(
                data_dir, qu, ers, sources_str, f"train_ers-{method_name}.jsonl"
            )
        train_data = dataset.DatasetGNN(self.config, data_path=train_path, train=True)
        train_loader = DataLoader(
            train_data, batch_size=train_batch_size, shuffle=True, collate_fn=dataset.collate_fn
        )
        self.logger.info(f"Length train data: {len(train_data)}")

        if not dev_path:
            dev_path = os.path.join(data_dir, qu, ers, sources_str, f"dev_ers-{method_name}.jsonl")
        dev_data = dataset.DatasetGNN(self.config, data_path=dev_path, train=False)
        dev_loader = DataLoader(
            dev_data, batch_size=eval_batch_size, shuffle=True, collate_fn=dataset.collate_fn
        )
        self.logger.info(f"Length dev data: {len(dev_data)}")

        # initialize optimization
        optimizer = torch.optim.AdamW(self.gnn.parameters(), lr=lr, weight_decay=weight_decay)

        # start training loop
        min_dev_loss = np.inf
        min_dev_qa = -1
        steps = 0

        self.logger.info(f"Starting training...")

        for epoch in range(epochs):
            # training (for epoch)
            train_loss = 0.0
            self.gnn.train()
            for batch_index, instances in enumerate(tqdm(train_loader)):
                # move data to gpu (if possible)
                GNNModule._move_to_cuda(instances)
                # clear the gradients
                optimizer.zero_grad()
                # make prediction / forward pass
                output = self.gnn(instances, train=True)

                # update weights
                loss = output["loss"]
                loss.backward()
                torch.nn.utils.clip_grad_norm_(self.gnn.parameters(), self.config["gnn_clipping_max_norm"])
                optimizer.step()
                # calculate loss
                train_loss += loss.item()
                steps += 1
                self.logger.debug(f"Steps: {steps}, loss: {loss.item()}, aggregated loss: {train_loss}")

                # free up GPU space
                del instances

            # validation (for epoch)
            dev_loss = 0.0
            dev_qa_metrics = list()
            self.gnn.eval()
            with torch.no_grad():
                for batch_index, instances in enumerate(tqdm(dev_loader)):
                    # move data to gpu (if possible)
                    GNNModule._move_to_cuda(instances)
                    # make prediction / forward pass
                    output = self.gnn(instances, train=False)
                    # compute loss
                    loss = output["loss"]
                    # calculate loss
                    dev_loss += loss.item()
                    # aggregate QA metrics
                    qa_metrics = output["qa_metrics"]
                    dev_qa_metrics += qa_metrics

                    # free up GPU space
                    del instances

            # aggregate result
            avg_train_loss = train_loss / len(train_loader)
            avg_dev_loss = dev_loss / len(dev_loader)
            if dev_qa_metrics:
                avg_qa_metrics = {
                    key: f"{(sum([res[key] for res in dev_qa_metrics]) / len([res[key] for res in dev_qa_metrics])):.3f}"
                    for key in ["p_at_1", "mrr", "h_at_5", "answer_presence"]
                }
                avg_qa_metrics["num_questions"] = len(dev_qa_metrics)
            else:
                avg_qa_metrics = None

            # log results
            training_res = f"Epoch: {epoch+1}, Training loss: {avg_train_loss:.3f}."
            self.logger.info(training_res)
            dev_res = f"Epoch: {epoch+1}, Dev loss: {avg_dev_loss:.3f}."
            self.logger.info(dev_res)
            qa_metrics = f"Epoch: {epoch+1}, Dev QA metrics: {avg_qa_metrics}."
            self.logger.info(qa_metrics)
            decisive_metric = self.config["gnn_decisive_metric"]
            avg_dev_qa = float(avg_qa_metrics[decisive_metric])

            # save model if performance on dev improved
            if avg_dev_qa > min_dev_qa:
                self.logger.info(
                    f"""Saving the model! Dev performance ({decisive_metric}) increased ({min_dev_qa:.3f}--->{avg_dev_qa:.3f}).
                    Dev loss ({min_dev_loss:.3f}--->{avg_dev_loss:.3f})."""
                )
                min_dev_loss = avg_dev_loss
                min_dev_qa = avg_dev_qa

                # saving the model to standard path
                Path(model_dir).mkdir(parents=True, exist_ok=True)
                torch.save(self.gnn.state_dict(), self.config["gnn_model_path"])

                # saving the model (for not over-writing results)
                model_path = os.path.join(model_dir, f"model-{START_DATE}.bin")
                torch.save(self.gnn.state_dict(), model_path)

                # saving the config
                config_path = os.path.join(model_dir, f"config-{START_DATE}.json")
                with open(config_path, "w") as fp:
                    fp.write(json.dumps(self.config, indent=4))

                # saving the current result
                result_path = os.path.join(model_dir, f"result-{START_DATE}.res")
                with open(result_path, "w") as fp:
                    fp.write(f"{training_res}\n")
                    fp.write(f"{dev_res}\n")
                    fp.write(f"{qa_metrics}\n\n")

        # done
        self.logger.info(f"Finished training.")

    def inference_on_turns(self, turns, sources=("kb", "text", "table", "info"), train=False, use_tqdm=True):
        """Run inference on a multiple turns."""
        self.logger.info("Running inference_on_turns function!")
        self.load()

        if use_tqdm:
            p_bar = tqdm(total=len(turns))

        with torch.no_grad():
            batch_size = self.config["gnn_eval_batch_size"]

            # run inference
            instances = dataset.DatasetGNN.prepare_turns(self.config, turns, train=False)
            start_index = 0

            while start_index < len(instances):
                end_index = min(start_index + batch_size, len(instances))
                batch_instances = instances[start_index:end_index]
                batch = dataset.collate_fn(batch_instances)
                # move data to gpu (if possible)
                GNNModule._move_to_cuda(batch)
                output = self.gnn(batch, train=False)

                for i, _ in enumerate(batch_instances):
                    instance_index = start_index + i
                    turn = turns[instance_index]

                    # store
                    turn["ranked_answers"] = output["answer_predictions"][i]["ranked_answers"]

                    # add top-evidences within iterative GNN
                    if "gnn_max_output_evidences" in self.config:
                        top_evidences = output["evidence_predictions"][i]["top_evidences"]
                        turn["top_evidences"] = list(top_evidences)
                    else:
                        del turn["top_evidences"]

                    # obtain metrics
                    if "answers" in turn:  # e.g. for demo answers are not known
                        turn["p_at_1"] = output["qa_metrics"][i]["p_at_1"]
                        turn["mrr"] = output["qa_metrics"][i]["mrr"]
                        turn["h_at_5"] = output["qa_metrics"][i]["h_at_5"]
                        turn["answer_presence"] = output["qa_metrics"][i]["answer_presence"]

                    # delete other information
                    if "question_entities" in turn:
                        del turn["question_entities"]
                    if "silver_SR" in turn:
                        del turn["silver_SR"]
                    if "silver_relevant_turns" in turn:
                        del turn["silver_relevant_turns"]
                    if "silver_answering_evidences" in turn:
                        del turn["silver_answering_evidences"]
                    if "instance" in turn:
                        del turn["instance"]
                start_index += batch_size

                if use_tqdm:
                    p_bar.update(batch_size)
        return turns

    def inference_on_turn(self, turn, sources=("kb", "text", "table", "info"), train=False):
        """Run inference on a single turn."""
        return self.inference_on_turns([turn], sources, train, use_tqdm=False)[0]

    @staticmethod
    def _move_to_cuda(obj):
        if torch.cuda.is_available():
            for key, value in obj.items():
                if not type(obj[key]) is torch.Tensor:
                    continue
                obj[key] = obj[key].cuda()

    def load(self):
        """Load the model."""
        # only load if not already done so
        if not self.model_loaded:
            model_path = self.config["gnn_model_path"]
            if torch.cuda.is_available():
                state_dict = torch.load(model_path)
                if "encoder.encoder_linear.weight" in state_dict: del(state_dict["encoder.encoder_linear.weight"])
                if "encoder.encoder_linear.bias" in state_dict: del(state_dict["encoder.encoder_linear.bias"])
                self.gnn.load_state_dict(state_dict)
            else:
                state_dict = torch.load(model_path, map_location="cpu")
                if "encoder.encoder_linear.weight" in state_dict: del(state_dict["encoder.encoder_linear.weight"])
                if "encoder.encoder_linear.bias" in state_dict: del(state_dict["encoder.encoder_linear.bias"])
                self.gnn.load_state_dict(state_dict)
            self.gnn.eval()
            self.model_loaded = True


import sys
import argparse

from dotenv import load_dotenv

import chromadb

from chromadb.config import Settings

from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.llms import OpenAI
from langchain.chains import RetrievalQA
from langchain.document_loaders import TextLoader

# Parse Arguments

parser = argparse.ArgumentParser(
    prog=sys.argv[0],
    description="Loads and/or queries data into/from ChromaDB using OpenAI",
    allow_abbrev=True
)

parser.add_argument("-l", "--load", help="load file", type=str, action="append")
parser.add_argument("-q", "--query", help="ask question", type=str, action="append")
parser.add_argument("-v", "--verbose", help="enable verbose mode", action="store_true")
args = parser.parse_args()

if (not args.load or len(args.load) == 0) and (not args.query or len(args.query) == 0):
    print(f"no file(s) to load and no queries specified")
    parser.print_usage()
    exit(1)

def print_verbose(message):
    if args.verbose:
        print(message)

# Load Configuration

load_dotenv()

# Setup Database Access

chroma_settings = Settings(chroma_api_impl="rest", chroma_server_host="localhost", chroma_server_http_port="8000")
chroma_client = chromadb.Client(chroma_settings)

# Load New Data

documents_to_load = []
if args.load:
    for fn in args.load:
        print_verbose(f"reading({fn})")
        loader = TextLoader(fn)
        for doc in loader.load():
            documents_to_load.append(doc)

# Access vector store and create new embeddings if needed

embeddings = OpenAIEmbeddings()
if len(documents_to_load) > 0:
    # see https://github.com/hwchase17/langchain/issues/1310 for using chunk size to help with Rate Limit errors
    print_verbose("RecursiveCharacterTextSplitter")
    text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
    print_verbose("text_splitter.split_documents")
    texts = text_splitter.split_documents(documents_to_load)
    print_verbose("Chroma.from_documents")
    vectordb = Chroma.from_documents(texts, embeddings, client=chroma_client)
else:
    print_verbose("Chroma")
    vectordb = Chroma(embedding_function=embeddings, client=chroma_client)

# Ask questions

if args.query:
    qa = RetrievalQA.from_chain_type(
        llm=OpenAI(),
        chain_type="stuff",
        retriever=vectordb.as_retriever()
    )
    for q in args.query:
        print_verbose(f"running query: {q}")
        answer = qa.run(q)
        print_verbose("the answer is:")
        print(answer)


"""Entry point."""

import sys
import traceback

from docknv.logger import Logger, LoggerError
from docknv.wrapper import FailedCommandExecution, StoppedCommandExecution

from .custom import MalformedCommand
from .shell import Shell

def docknv_entry_point():
    """Entry point for docknv."""
    shell = Shell()

    try:
        return shell.run(sys.argv[1:])
    except BaseException as e:
        if isinstance(e, (LoggerError, SystemExit)):
            sys.exit(1)
        elif isinstance(
            e,
            (
                FailedCommandExecution,
                StoppedCommandExecution,
                MalformedCommand,
            ),
        ):
            Logger.error(str(e), crash=False)
            sys.exit(1)
        else:
            Logger.error(traceback.format_exc(), crash=False)
            sys.exit(1)


def solution(number, k):
    answer = ''

    cnt = 0
    stack = [number[0]]

    i = 1
    while cnt != k:
        if i == len(number) or stack and stack[-1] < number[i]:
            stack.pop()
            cnt += 1
            continue
        stack.append(number[i])
        i += 1

    stack.append(number[i:])
    answer = ''.join(stack)

    return answer

# '94'
print(solution("1924", 2))
# '3234'
print(solution("1231234", 3))
# '775841'
print(solution("4177252841", 4))
# '987'
print(solution("98765", 2))


#!/usr/bin/env python
# -*- coding: utf-8 -*-
""" Command line tool to merge possibly overlapping flux.dat files from hotstart runs
"""
import argparse
import numpy as np

def combine_flux(infiles,outfile,prefer_last=False):
    """ Merge possibly overlapping flux.dat files from hostart runs
    """
    filedata = []
    for f in infiles:
        try:
            filedata.append(np.loadtxt(f))
        except:
            print("Problem reading file: {}".format(f))
            raise
    nfile = len(filedata)
    starts = np.array([fd[ 0,0] for fd in filedata])
    ends   = np.array([fd[-1,0] for fd in filedata])
    sorder = np.argsort(starts)
    eorder = np.argsort(ends)
    if np.any(np.not_equal(sorder,eorder)):
        raise ValueError("input files are ambiguously ordered (one lies inside another)")
    if np.any(sorder[1:]<sorder[:-1]):
        raise ValueError("Files out of order. This is the apparent order of inputs: {}".format(sorder))

    nstation = filedata[0].shape[1] -1
    writeformat = ["%16.6f"] + nstation*["%14.4e"]

    ndxlast = filedata[-1].shape[0]
    if prefer_last:
        sblock = np.full(len(filedata), 0, dtype=np.int64)
        eblock = [np.searchsorted(filedata[i][:,0],starts[i+1]) for i in range(nfile-1)] + [ndxlast]
    else:
        sblock = [0] + [np.searchsorted(filedata[i][:,0],ends[i-1],side="right") for i in range(1,nfile)]
        eblock = [filedata[i].shape[0] for i in range(len(filedata))]

    blocks2merge = [d[s:e] for d,s,e in zip(filedata,sblock,eblock)]
    for m in blocks2merge: print(m.shape)
    merged = np.vstack(tuple(blocks2merge))

    ddt = np.diff(merged[:,0],n=2)
    if np.max(ddt) > 1.e-4:
        raise ValueError("The continuity of time in the files is wrong. Successive time steps should differ by less than 1e-4")

    np.savetxt(outfile,merged,delimiter=" ",fmt=writeformat)

def test_combine_flux():
    full = open("flux_small.dat","r")
    breaks = [60,120,200]
    b = 0
    fnames=[]
    lines = full.readlines()
    for i,e in enumerate(breaks):
        fname = "flux{}.dat.".format(i)
        fnames.append(fname)
        out = open(fname,"w")
        for line in lines[b:(e+10)]:
            out.write(line+"\n")
        b=e
        out.close()
    fout = "flux_comb.dat"
    combine_flux(fnames,fout,prefer_last=False)

def create_arg_parser():
    parser = argparse.ArgumentParser(description="Merge possibly-overlapping flux.dat files from hotstarted runs. ")
    parser.add_argument('--prefer_last', action='store_true')
    parser.add_argument('--output',
                        help="output file")
    parser.add_argument('files',type=argparse.FileType('r'),nargs="+",
                        help="List of input files in chronological order")

    return parser

def main():
    """ Driver to parse arguments
    """
    parser = create_arg_parser()
    args = parser.parse_args()
    filelist = args.files
    inputs = [x.name for x in filelist]
    prefer_last = args.prefer_last
    output = args.output
    if output in inputs:
        raise ValueError("Cannot overwrite input file names")
    combine_flux(filelist,output,prefer_last)

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


from typing import List

class Solution:
    def merge(self, intervals: List[List[int]]) -> List[List[int]]:
        if not intervals:
            return []

        result = []
        sorted_intervals = sorted(intervals)
        low, high = sorted_intervals[0]
        for interval_low, interval_high in sorted_intervals[1:]:
            if (
                (interval_low <= low and interval_high >= low and interval_high <= high)
                or (
                    interval_low >= low
                    and interval_low <= high
                    and interval_high >= high
                )
                or (interval_low <= low and interval_high >= high)
                or (interval_low >= low and interval_high <= high)
            ):
                high = max(high, interval_high)
                low = min(low, interval_low)
            else:
                result.append([low, high])
                low = interval_low
                high = interval_high
        result.append([low, high])
        return result


import torch
import torch.nn.functional as F

def bl_matmul(mat_a, mat_b):
    return torch.einsum('mij,jk->mik', mat_a, mat_b)

def compute_permu_matrix(s: torch.FloatTensor, tau=1):

    device = s.get_device()
    mat_as = s - s.permute(0, 2, 1)
    mat_as = torch.abs(mat_as)
    n = s.shape[1]
    one = torch.ones(n, 1).to(device)

    b = bl_matmul(mat_as, one @ one.transpose(0, 1))
    k = torch.arange(n) + 1
    d = (n + 1 - 2 * k).float().detach().requires_grad_(True).unsqueeze(0).to(device)

    c = bl_matmul(s, d)
    mat_p = (c - b).permute(0, 2, 1)
    mat_p = F.softmax(mat_p / tau, -1)

    return mat_p

def prop_any_correct(p1, p2):
    z1 = torch.argmax(p1, axis=-1)
    z2 = torch.argmax(p2, axis=-1)
    eq = torch.eq(z1, z2).float()
    correct = torch.mean(eq, axis=-1)
    return torch.mean(correct)

def prop_correct(p1, p2):
    z1 = torch.argmax(p1, axis=-1)
    z2 = torch.argmax(p2, axis=-1)
    eq = torch.eq(z1, z2)
    correct = torch.all(eq, axis=-1).float()
    return torch.sum(correct)

def top_k_correct(ranking, ranking_true, k):
    return sum(ranking[i] in ranking_true[:k] for i in range(k))


def count_letters_repetition(text):
    char_count = {}
    max_count = 0
    for char in text:
        if char.isalpha():
            if char not in char_count:
                char_count[char.lower()] = 1
            else:
                char_count[char.lower()] += 1
            if max_count < char_count[char.lower()]:
                max_count = char_count[char.lower()]

    most_common_letters = [char for char, count in char_count.items() if count == max_count]

    return (most_common_letters, max_count)

if __name__ == '__main__':
    text = input("This is the text: ")

    most_common_letters, repetitions = count_letters_repetition(text)

    print(f"Most common letters in the text are: {', '.join(most_common_letters)} with {repetitions} repetitions each.")


import key2vec

path = './data/glove.6B/glove.6B.50d.txt'
glove = key2vec.glove.Glove(path)
with open('./test.txt', 'r') as f:
    test = f.read()
m = key2vec.key2vec.Key2Vec(test, glove)
m.extract_candidates()
m.set_theme_weights()
m.build_candidate_graph()
ranked = m.page_rank_candidates()

for row in ranked:
    print('{}. {}'.format(row.rank, row.text))


import rtree

class PathIndex:
    def __init__(self, path_graph):
        self.idx = rtree.index.Index()
        self.path_graph = path_graph
        for index, coordinate in path_graph.iter_starts_with_index():
            self.idx.add(index, coordinate + coordinate)

    def get_nearest(self, coordinate):
        return next(self.idx.nearest(coordinate))

    def delete(self, index):
        coordinate = self.path_graph.get_coordinates(index)
        self.idx.delete(index, coordinate + coordinate)

    def delete_pair(self, index):
        self.delete(index)
        self.delete(self.path_graph.get_disjoint(index))

def greedy_walk(path_graph):
    path_index = PathIndex(path_graph)
    location = path_graph.get_coordinates(path_graph.ORIGIN)
    while True:
        try:
            next_point = path_index.get_nearest(location)
        except StopIteration:
            break
        location = path_graph.get_coordinates(next_point, True)
        path_index.delete_pair(next_point)
        yield next_point

from collections import Counter

def check_valid_solution(solution, graph):
    """Check that the solution is valid: every path is visited exactly once."""
    expected = Counter(
        i for (i, _) in graph.iter_starts_with_index()
        if i < graph.get_disjoint(i)
    )
    actual = Counter(
        min(i, graph.get_disjoint(i))
        for i in solution
    )

    difference = Counter(expected)
    difference.subtract(actual)
    difference = {k: v for k, v in difference.items() if v != 0}
    if difference:
        print('Solution is not valid!'
              'Difference in node counts (expected - actual): {}'.format(difference))
        return False
    return True

def get_route_from_solution(solution, graph):
    """Converts a solution (a list of node indices) into a list
    of paths suitable for rendering."""

    # As a guard against comparing invalid "solutions",
    # ensure that this solution is valid.
    assert check_valid_solution(solution, graph)

    return [graph.get_path(i) for i in solution]


import pytest
from kubernetes.client import V2beta2CrossVersionObjectReference
from kubernetes.client import V2beta2ExternalMetricSource
from kubernetes.client import V2beta2ExternalMetricStatus
from kubernetes.client import V2beta2MetricIdentifier
from kubernetes.client import V2beta2MetricSpec
from kubernetes.client import V2beta2MetricStatus
from kubernetes.client import V2beta2MetricTarget
from kubernetes.client import V2beta2MetricValueStatus
from kubernetes.client import V2beta2ObjectMetricSource
from kubernetes.client import V2beta2PodsMetricSource
from kubernetes.client import V2beta2PodsMetricStatus
from kubernetes.client import V2beta2ResourceMetricSource
from kubernetes.client import V2beta2ResourceMetricStatus
from kubernetes.client.models.v2beta2_object_metric_status import (
    V2beta2ObjectMetricStatus,
)

from paasta_tools.instance.hpa_metrics_parser import HPAMetricsParser

@pytest.fixture
def parser():
    return HPAMetricsParser(hpa=None)

def test_parse_target_external_metric_value(parser):
    metric_spec = V2beta2MetricSpec(
        type="External",
        external=V2beta2ExternalMetricSource(
            metric=V2beta2MetricIdentifier(name="foo"),
            target=V2beta2MetricTarget(
                type="Value",
                average_value=12,
            ),
        ),
    )
    status = parser.parse_target(metric_spec)
    assert status["name"] == "foo"
    assert status["target_value"] == "12"

def test_parse_target_external_metric_average_value(parser):
    # The parser handles this case, but it's not currently
    # used in kubernetes_tools
    metric_spec = V2beta2MetricSpec(
        type="External",
        external=V2beta2ExternalMetricSource(
            metric=V2beta2MetricIdentifier(name="foo"),
            target=V2beta2MetricTarget(
                type="AverageValue",
                average_value=0.5,
            ),
        ),
    )
    status = parser.parse_target(metric_spec)
    assert status["name"] == "foo"
    assert status["target_value"] == "0.5"

def test_parse_target_pod_metric(parser):
    metric_spec = V2beta2MetricSpec(
        type="Pods",
        pods=V2beta2PodsMetricSource(
            metric=V2beta2MetricIdentifier(name="foo"),
            target=V2beta2MetricTarget(
                type="AverageValue",
                average_value=0.5,
            ),
        ),
    )
    status = parser.parse_target(metric_spec)
    assert status["name"] == "foo"
    assert status["target_value"] == "0.5"

def test_parse_target_resource_metric(parser):
    metric_spec = V2beta2MetricSpec(
        type="Resource",
        resource=V2beta2ResourceMetricSource(
            name="cpu",
            target=V2beta2MetricTarget(
                type="Utilization",
                average_utilization=0.5,
            ),
        ),
    )
    status = parser.parse_target(metric_spec)
    assert status["name"] == "cpu"
    assert status["target_value"] == "0.5"

def test_parse_target_object_metric(parser):
    metric_spec = V2beta2MetricSpec(
        type="Object",
        object=V2beta2ObjectMetricSource(
            metric=V2beta2MetricIdentifier(name="some-metric"),
            described_object=V2beta2CrossVersionObjectReference(
                api_version="apps/v1", kind="Deployment", name="deployment"
            ),
            target=V2beta2MetricTarget(
                type="Value",
                value=1,
            ),
        ),
    )
    status = parser.parse_target(metric_spec)
    assert status["name"] == "some-metric"
    assert status["target_value"] == "1"

def test_parse_current_external_metric_value(parser):
    metric_status = V2beta2MetricStatus(
        type="External",
        external=V2beta2ExternalMetricStatus(
            current=V2beta2MetricValueStatus(
                value=4,
            ),
            metric=V2beta2MetricIdentifier(name="foo"),
        ),
    )
    status = parser.parse_current(metric_status)
    assert status["name"] == "foo"
    assert status["current_value"] == "4"

def test_parse_current_external_metric_average_value(parser):
    # The parser handles this case, but it's not currently
    # used in kubernetes_tools
    metric_status = V2beta2MetricStatus(
        type="External",
        external=V2beta2ExternalMetricStatus(
            current=V2beta2MetricValueStatus(
                average_value=0.4,
            ),
            metric=V2beta2MetricIdentifier(name="foo"),
        ),
    )
    status = parser.parse_current(metric_status)
    assert status["name"] == "foo"
    assert status["current_value"] == "0.4"

def test_parse_current_pod_metric(parser):
    metric_status = V2beta2MetricStatus(
        type="Pods",
        pods=V2beta2PodsMetricStatus(
            current=V2beta2MetricValueStatus(
                average_value=0.4,
            ),
            metric=V2beta2MetricIdentifier(name="foo"),
        ),
    )
    status = parser.parse_current(metric_status)
    assert status["name"] == "foo"
    assert status["current_value"] == "0.4"

def test_parse_current_resource_metric(parser):
    metric_status = V2beta2MetricStatus(
        type="Resource",
        resource=V2beta2ResourceMetricStatus(
            current=V2beta2MetricValueStatus(
                average_utilization=0.4,
            ),
            name="cpu",
        ),
    )
    status = parser.parse_current(metric_status)
    assert status["name"] == "cpu"
    assert status["current_value"] == "0.4"

def test_parse_current_object_metric(parser):
    metric_status = V2beta2MetricStatus(
        type="Object",
        object=V2beta2ObjectMetricStatus(
            current=V2beta2MetricValueStatus(value=0.1),
            metric=V2beta2MetricIdentifier(name="some-metric"),
            described_object=V2beta2CrossVersionObjectReference(
                api_version="apps/v1", kind="Deployment", name="deployment"
            ),
        ),
    )

    status = parser.parse_current(metric_status)
    assert status["name"] == "some-metric"
    assert status["current_value"] == "0.1"

def test_parse_current_empty_string_metric(parser):
    metric_status = V2beta2MetricStatus(
        type="",
    )

    status = parser.parse_current(metric_status)
    assert status is None