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

from odoo import models, fields, api, SUPERUSER_ID
from odoo.exceptions import AccessError, ValidationError, UserError

# class HrAppraisalComment(models.Model):
#     _name = "hr.appraisal.comment"
#
#     name = fields.Char('Comment')
#     user_id = fields.Many2one('res.users', default=lambda self: self.env.user.id)
#     related_objective = fields.Many2one('hr.appraisal.objective', 'Related Objective')
#     related_appraisal = fields.Many2one('hr.appraisal', 'Related Appraisal')
#
#     def write(self, vals):
#         if self.user_id.id != self.env.user.id:
#             if len(vals) == 1 and not vals.get('related_appraisal') and not vals.get('related_objective'):
#                 raise UserError('Only comment owner can modified!')
#             elif len(vals) > 1:
#                 raise UserError('Only comment owner can modified!')
#         return super(HrAppraisalComment, self).write(vals)

class HrAppraisalPeriod(models.Model):
    _name = 'hr.appraisal.period'

    name = fields.Char('Period')

    from_date = fields.Date('From Date')
    to_date = fields.Date('To Date')
    year = fields.Char(
        string='Year',
        required=False)

    @api.onchange('from_date', 'to_date')
    def _onchange_date(self):
        for rec in self:
            if rec.from_date and rec.to_date:
                rec.name = "Appraisal %s / %s" % (rec.from_date, rec.to_date)

class HrAppraisal(models.Model):
    _inherit = "hr.appraisal"

    def _default_stage_id(self):
        return self.env['hr.appraisal.stage'].search([], order='sequence asc', limit=1).id

    appraisal_objectives = fields.One2many('hr.appraisal.objective', 'related_appraisal',
                                           domain=[('state', '!=', 'deleted')], string='Appraisal Objectives')
    appraisal_edit_objectives = fields.One2many('hr.appraisal.objective', 'related_appraisal',
                                                domain=[('state', '!=', 'deleted')], string='Appraisal Edit Objectives')
    deleted_appraisal_objectives = fields.One2many('hr.appraisal.objective', 'related_appraisal',
                                                   domain=[('state', '=', 'deleted')],
                                                   string='Deleted Appraisal Objectives')
    appraisal_training = fields.One2many('hr.training', 'related_appraisal', string='Appraisal Training')

    appraisal_form = fields.Many2one('hr.appraisal.form', 'Appraisal Form', required=False)

    related_period = fields.Many2one(related='appraisal_form.period_id')

    employee_grade = fields.Integer(related='employee_id.job_id.job_grade.level', string="Employee Grade", store=True)
    contract_subgroup = fields.Many2one(related='employee_id.contract_id.contract_subgroup', string="Employee Type")

    # comments = fields.One2many('hr.appraisal.comment', 'related_appraisal', 'Comments')

    current_manager = fields.Many2one('hr.employee', 'Current Manager', related='employee_id.parent_id')

    stage_id = fields.Many2one('hr.appraisal.stage', 'Stage', ondelete='restrict', tracking=True,
                               copy=False, index=True,
                               group_expand='_read_group_stage_ids',
                               default=_default_stage_id)

    appraisal_manager = fields.Many2one('hr.employee', 'Appraisal Manager',
                                        domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]")

    total_sum_weight = fields.Float('Total Weight Sum', compute="_calculate_total_weight")

    employee_overall_rating = fields.Float('Employee Rating', compute="calculate_employee_overall_rating", store=True)

    employee_overall_rating_rounded = fields.Float('Employee Rating Rounded', compute="calculate_employee_overall_rating", store=True)

    overall_rating = fields.Float('Manager Rating', compute="calculate_overall_rating", store=True)

    overall_rating_rounded = fields.Float('Manager Rating Rounded', compute="calculate_overall_rating", store=True)

    hr_overall_rating = fields.Float('HR Final Rating', default=0.0)

    hr_overall_rating_final = fields.Float('HR Overall Rating Final', compute="calculate_hr_overall_rating", store=True)

    manager_comment = fields.Text('Manager Comment')

    employee_comment = fields.Text('Employee Comment')

    hr_comment = fields.Text('HR Comment')

    survey_id = fields.Many2one('survey.survey', string="Survey",
                                domain=[('category', '=', 'hr_appraisal')], readonly=True
                                )
    response_id = fields.Many2one('survey.user_input', "Response", ondelete="set null", readonly=True,
                                  )

    employee_oc_id = fields.Many2one(related='employee_id.department_id')
    employee_system_id = fields.Char(related='employee_id.system_id')
    employee_strata_id = fields.Char(related='employee_id.strata_id')
    employee_job_title = fields.Char(related='employee_id.contract_id.job_title.name', string="Job Title", store=True)
    group = fields.Many2one(related='employee_id.contract_id.group', store=True)
    department = fields.Many2one(related='employee_id.contract_id.department', store=True)
    section = fields.Many2one(related='employee_id.contract_id.section', store=True)
    subsection = fields.Many2one(related='employee_id.contract_id.subsection', store=True)

    total_count_objectives = fields.Float('Total Count Objectives', compute="_calculate_total_count")

    previous_stage_id = fields.Many2one(
        comodel_name='hr.appraisal.stage',
        string='Previous Stage',
        required=False, compute='get_previous_stage')
    next_stage_id = fields.Many2one(
        comodel_name='hr.appraisal.stage',
        string='Next Stage',
        required=False, compute='get_next_stage')
    year = fields.Char(related='related_period.year', store=True)
    can_complete = fields.Boolean(related='stage_id.can_complete')
    is_completed = fields.Boolean(
        string='Is Completed',
        required=False, default=False)

    # pip fields
    area_development = fields.Text('Employee Areas of Development')

    first_manager_review = fields.Text('1st Month Review By Manager Comments')
    first_employee_review = fields.Text('1st Month Employee Review')

    second_manager_review = fields.Text('2nd Month Review By Manager Comments')
    second_employee_review = fields.Text('2nd Month Employee Review')

    third_manager_review = fields.Text('3rd Month Review By Manager Comments')
    third_employee_review = fields.Text('3rd Month Employee Review')

    manager_final_decision = fields.Selection(string='Manager Final Decision',
                                              selection=[('pass', 'Pass PIP'),
                                                         ('fail', 'Fail PIP')])
    manager_final_comments = fields.Text('Manager Final Comments')

    def action_complete_appraisal(self):
        # todo
        pass

    def get_previous_stage(self):
        self = self.sudo()
        for rec in self:
            stage = self.env['hr.appraisal.stage'].search(
                [('sequence', '>', rec.stage_id.sequence), ('id', 'in', rec.appraisal_form.all_stages.ids)],
                order='sequence asc',
                limit=1)
            if stage:
                rec.previous_stage_id = stage.id
            else:
                rec.previous_stage_id = False

    def get_next_stage(self):
        self = self.sudo()
        for rec in self:
            stage = self.env['hr.appraisal.stage'].search(
                [('sequence', '<', rec.stage_id.sequence), ('id', 'in', rec.appraisal_form.all_stages.ids)],
                order='sequence desc', limit=1)
            if stage:
                rec.next_stage_id = stage.id
            else:
                rec.next_stage_id = False

    @api.onchange('appraisal_form')
    def _onchange_appraisal_form(self):
        for rec in self:
            if rec.appraisal_form:
                if rec.appraisal_form.period_id:
                    rec.date_close = rec.appraisal_form.period_id.to_date
                if rec.appraisal_form.default_survey_id:
                    rec.survey_id = rec.appraisal_form.default_survey_id.id
                if rec.appraisal_form.starting_stage:
                    rec.stage_id = rec.appraisal_form.starting_stage.id
                if rec.appraisal_form.default_related_objective:
                    rec.appraisal_objectives.unlink()
                    for line in rec.appraisal_form.default_related_objective:
                        linecopy = line.copy()
                        linecopy.related_appraisal_forms = None
                        linecopy.fixed = True
                        rec.appraisal_objectives |= linecopy

    @api.onchange('employee_id')
    def _onchange_employee_id(self):
        for rec in self:
            rec = rec.sudo()
            if rec.employee_id:
                rec.current_manager = rec.employee_id.parent_id.id
                rec.appraisal_manager = rec.employee_id.parent_id.id

    @api.onchange('current_manager')
    def _onchange_manager_id(self):
        for rec in self:
            rec = rec.sudo()
            if not rec.stage_id.can_complete:
                rec.appraisal_manager = rec.current_manager.id
        # return {'domain': {
        #     'appraisal_form': [('from_grade_num', '<=', rec.employee_grade),
        #                        ('to_grade_num', '>=', rec.employee_grade),
        #                        ('related_contract_subgroup.id', '=', (rec.contract_subgroup.id)),
        #                        ]}}
        # return {'domain': {
        #     'appraisal_form': [('grade_ids.id', '=', (rec.employee_grade.id)),
        #                        ('related_contract_subgroup.id', '=', (rec.contract_subgroup.id)),
        #                        ]}}

    def action_start_survey(self):
        self.ensure_one()
        # create a response and link it to this applicant
        if not self.response_id:
            response = self.survey_id._create_answer(partner=self.env.user.partner_id)
            self.response_id = response.id
        else:
            response = self.response_id
        # grab the token of the response and start surveying
        action = self.survey_id.with_context(survey_token=response.token).action_start_survey()
        action.update({'target': 'new'})
        return action

    def action_print_survey(self):
        """ If response is available then print this response otherwise print survey form (print template of the survey) """
        self.ensure_one()
        if not self.response_id:
            action = self.survey_id.action_print_survey()
            action.update({'target': 'new'})
            return action
        else:
            response = self.response_id
            action = self.survey_id.with_context(survey_token=response.token).action_print_survey()
            action.update({'target': 'new'})
            return action

    @api.depends('appraisal_objectives.employee_rating', 'appraisal_objectives.weight')
    def calculate_employee_overall_rating(self):
        for rec in self:
            total = sum([(int(x.employee_rating) * (x.weight / 100)) for x in rec.appraisal_objectives])
            rounded = rec.appraisal_form.calculation_rules.filtered(
                lambda x: x.from_value <= total and x.to_value >= total).value
            rec.employee_overall_rating = total
            rec.employee_overall_rating_rounded = rounded

    @api.depends('appraisal_objectives.manager_rating', 'appraisal_objectives.weight')
    def calculate_overall_rating(self):
        for rec in self:
            total = sum([(int(x.manager_rating) * (x.weight / 100)) for x in rec.appraisal_objectives])
            rounded = rec.appraisal_form.calculation_rules.filtered(
                lambda x: x.from_value <= total and x.to_value >= total).value
            rec.overall_rating = total
            rec.overall_rating_rounded = rounded

    @api.depends('overall_rating_rounded', 'hr_overall_rating')
    def calculate_hr_overall_rating(self):
        for rec in self:
            if rec.hr_overall_rating:
                rec.hr_overall_rating_final = rec.hr_overall_rating
            else:
                rec.hr_overall_rating_final = rec.overall_rating_rounded

    @api.onchange('hr_overall_rating')
    def oncahnge_hr_overall_rating(self):
        for rec in self:
            if rec.hr_overall_rating:
                rec.hr_overall_rating_final = rec.hr_overall_rating

    # @api.constrains('appraisal_objectives')
    def _check_objective_counts(self):
        if len(self.appraisal_objectives) > self.appraisal_form.max_objective or len(
                self.appraisal_objectives) < self.appraisal_form.min_objective:
            raise ValidationError("Objective must be between %s and %s" % (
                self.appraisal_form.min_objective, self.appraisal_form.max_objective))

    def check_total_weight(self):
        if sum(self.appraisal_objectives.mapped('weight')) < self.appraisal_form.total_weight or sum(
                self.appraisal_objectives.mapped('weight')) > self.appraisal_form.total_weight:
            raise ValidationError("Total Objective Weight must be equal to %s" % (self.appraisal_form.total_weight))

    def approve_all_objectives(self):
        for rec in self:
            if rec.appraisal_form.validate_weight:
                rec.check_total_weight()
            rec.appraisal_objectives.state_approve()

    @api.depends('appraisal_edit_objectives.weight')
    def _calculate_total_weight(self):
        for rec in self:
            rec.total_sum_weight = sum(rec.appraisal_objectives.mapped('weight'))

    @api.depends('appraisal_edit_objectives')
    def _calculate_total_count(self):
        for rec in self:
            rec.total_count_objectives = len(self.appraisal_edit_objectives)

    @api.model
    def _read_group_stage_ids(self, stages, domain, order):
        # retrieve job_id from the context and write the domain: ids + contextual columns (job or default)
        search_domain = []
        stage_ids = stages._search(search_domain, order=order, access_rights_uid=SUPERUSER_ID)
        return stages.browse(stage_ids)

    def stage_changed_notification(self):
        for rec in self:
            rec.message_notify(
                partner_ids=rec.employee_id.user_partner_id.ids,
                body=("New stage %s") % (
                    rec.stage_id.name),
                subject="Appraisal")
            rec.message_notify(
                partner_ids=rec.appraisal_manager.user_partner_id.ids,
                body=("%s - New Stage %s") % (
                    rec.employee_id.name, rec.stage_id.name),
                subject="Appraisal")

    def check_survey_done(self):
        for rec in self:
            if rec.stage_id.employee_take_survey or rec.stage_id.manager_take_survey or rec.stage_id.users_take_survey:
                if not rec.response_id:
                    raise ValidationError('Survey Must be filled before moving Forward!')

    def check_survey_done(self):
        for rec in self:
            if rec.stage_id.employee_take_survey or rec.stage_id.manager_take_survey or rec.stage_id.users_take_survey:
                if not rec.response_id:
                    raise ValidationError('Survey Must be filled before moving Forward!')

    def check_comments_added(self):
        for rec in self:
            if rec.stage_id.employee_can_comment_form_hr or rec.stage_id.manager_can_comment_form_hr or rec.stage_id.users_can_comment_form_hr:
                if not rec.hr_comment:
                    raise ValidationError('HR Comment on the appraisal form is required before moving forward')
            if rec.stage_id.employee_can_comment_form_manager or rec.stage_id.manager_can_comment_form_manager or rec.stage_id.users_can_comment_form_manager:
                if not rec.manager_comment:
                    raise ValidationError('Manager Comment on the appraisal form is required before moving forward')
            if rec.stage_id.employee_can_comment_form_employee or rec.stage_id.manager_can_comment_form_employee or rec.stage_id.users_can_comment_form_employee:
                if not rec.employee_comment:
                    raise ValidationError('Employee Comment on the appraisal form is required before moving forward')
            if rec.stage_id.employee_can_comment_objective_hr or rec.stage_id.manager_can_comment_objective_hr or rec.stage_id.users_can_comment_objective_hr:
                for line in rec.appraisal_edit_objectives:
                    if not line.hr_comment:
                        raise ValidationError('HR Comments on each objective is required before moving forward')
            if rec.stage_id.employee_can_comment_objective_manager or rec.stage_id.manager_can_comment_objective_manager or rec.stage_id.users_can_comment_objective_manager:
                for line in rec.appraisal_edit_objectives:
                    if not line.manager_comment:
                        raise ValidationError(
                            'Manager Comments on each objective is required before moving forward')
            if rec.stage_id.employee_can_comment_objective_employee or rec.stage_id.manager_can_comment_objective_employee or rec.stage_id.users_can_comment_objective_employee:
                for line in rec.appraisal_edit_objectives:
                    if not line.employee_comment:
                        raise ValidationError(
                            'Employee Comments on each objective is required before moving forward')
            if rec.stage_id.employee_rating_manager_add or rec.stage_id.manager_rating_manager_add or rec.stage_id.users_rating_manager_add:
                for line in rec.appraisal_edit_objectives:
                    if line.manager_rating == '0':
                        raise ValidationError('Manager Ratings on each objective is required before moving forward')
            if rec.stage_id.employee_rating_employee_add or rec.stage_id.manager_rating_employee_add or rec.stage_id.users_rating_employee_add:
                for line in rec.appraisal_edit_objectives:
                    if line.employee_rating == '0':
                        raise ValidationError(
                            'Employee Ratings on each objective is required before moving forward')

            if rec.stage_id.employee_area_development_add or rec.stage_id.manager_area_development_add or rec.stage_id.users_area_development_add:
                if not rec.area_development:
                    raise ValidationError(
                        'Employee Areas of Development on the appraisal form is required before moving forward')
            if rec.stage_id.employee_first_manager_review_add or rec.stage_id.manager_first_manager_review_add or rec.stage_id.users_first_manager_review_add:
                if not rec.first_manager_review:
                    raise ValidationError(
                        '1st Month Review By Manager Comments on the appraisal form is required before moving forward')
            if rec.stage_id.employee_first_employee_review_add or rec.stage_id.manager_first_employee_review_add or rec.stage_id.users_first_employee_review_add:
                if not rec.first_employee_review:
                    raise ValidationError(
                        '1st Month Employee Review on the appraisal form is required before moving forward')
            if rec.stage_id.employee_second_manager_review_add or rec.stage_id.manager_second_manager_review_add or rec.stage_id.users_second_manager_review_add:
                if not rec.second_manager_review:
                    raise ValidationError(
                        '2nd Month Review By Manager Comments on the appraisal form is required before moving forward')
            if rec.stage_id.employee_second_employee_review_add or rec.stage_id.manager_second_employee_review_add or rec.stage_id.users_second_employee_review_add:
                if not rec.second_employee_review:
                    raise ValidationError(
                        '2nd Month Employee Review on the appraisal form is required before moving forward')
            if rec.stage_id.employee_third_manager_review_add or rec.stage_id.manager_third_manager_review_add or rec.stage_id.users_third_manager_review_add:
                if not rec.third_manager_review:
                    raise ValidationError(
                        '3rd Month Review By Manager Comments on the appraisal form is required before moving forward')
            if rec.stage_id.employee_third_employee_review_add or rec.stage_id.manager_third_employee_review_add or rec.stage_id.users_third_employee_review_add:
                if not rec.third_employee_review:
                    raise ValidationError(
                        '3rd Month Employee Review on the appraisal form is required before moving forward')
            if rec.stage_id.employee_manager_final_decision_add or rec.stage_id.manager_manager_final_decision_add or rec.stage_id.users_manager_final_decision_add:
                if not rec.manager_final_decision:
                    raise ValidationError(
                        'Manager Final Decision on the appraisal form is required before moving forward')
            if rec.stage_id.employee_manager_final_comments_add or rec.stage_id.manager_manager_final_comments_add or rec.stage_id.users_manager_final_comments_add:
                if not rec.manager_final_comments:
                    raise ValidationError(
                        'Manager Final Comments on the appraisal form is required before moving forward')

    def check_trainings_added(self):
        for rec in self:
            if rec.stage_id.employee_can_modifiy_training or rec.stage_id.manager_can_modifiy_training or rec.stage_id.users_can_modifiy_training:
                if len(rec.appraisal_training) == 0:
                    raise ValidationError('Trainings are required before moving forward')

    def move_next_stage(self):
        self = self.sudo()
        if self.appraisal_form.validate_weight:
            self.check_total_weight()
        self._check_objective_counts()
        self.check_survey_done()
        self.check_comments_added()
        self.check_trainings_added()
        stage = self.env['hr.appraisal.stage'].search(
            [('sequence', '>', self.stage_id.sequence), ('id', 'in', self.appraisal_form.all_stages.ids)],
            order='sequence asc',
            limit=1)
        if stage:
            self.stage_id = stage.id
            self.stage_changed_notification()
            if stage.can_complete:
                self.action_complete_appraisal()
            view = self.env.ref('sh_message.sh_message_wizard')
            view_id = view and view.id or False
            context = dict(self._context or {})
            context['message'] = 'Thank you, the form has been submitted to next stage.'
            return {
                'name': 'Success',
                'type': 'ir.actions.act_window',
                'view_type': 'form',
                'view_mode': 'form',
                'res_model': 'sh.message.wizard',
                'views': [(view.id, 'form')],
                'view_id': view_id,
                'target': 'new',
                'context': context,
            }

    def log_or_move_previous_stage(self):
        self = self.sudo()
        if self.stage_id.log_note_backward:
            return {
                'type': 'ir.actions.act_window',
                'name': 'Log Reason',
                'res_model': 'log.note.wizard',
                'view_mode': 'form',
                'target': 'new',
                'view_id': self.env.ref('hr_appraisal_custom.log_note_wizard_view_form').id,
                'context': {
                    'default_related_appraisal': self.id,
                }
            }
        self.move_previous_stage()

    def move_previous_stage(self):
        stage = self.env['hr.appraisal.stage'].search(
            [('sequence', '<', self.stage_id.sequence), ('id', 'in', self.appraisal_form.all_stages.ids)],
            order='sequence desc', limit=1)
        if stage:
            self.stage_id = stage.id
            self.stage_changed_notification()

    can_move_forward = fields.Boolean('Can Move Forward', compute='_check_stage_rule_move_forward')

    def _check_stage_rule_move_forward(self):
        if (self.employee_id.user_id == self.env.user and self.stage_id.employee_allowed_forward) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_allowed_forward) \
                or self.env.user in self.stage_id.users_allowed_forward:
            self.can_move_forward = True
        else:
            self.can_move_forward = False

    can_move_previous = fields.Boolean('Can Move Previous', compute='_check_stage_rule_move_previous')

    def _check_stage_rule_move_previous(self):
        if (self.employee_id.user_id == self.env.user and self.stage_id.employee_allowed_backward) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_allowed_backward) \
                or self.env.user in self.stage_id.users_allowed_backward:
            self.can_move_previous = True
        else:
            self.can_move_previous = False

    can_add_objectives = fields.Boolean('Can Add Objectives', compute='_check_stage_rule_add_objectives')

    def _check_stage_rule_add_objectives(self):
        if (self.employee_id.user_id == self.env.user and self.stage_id.employee_can_add_objective) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_can_add_objective) \
                or self.env.user in self.stage_id.users_can_add_objective:
            self.can_add_objectives = True
        else:
            self.can_add_objectives = False

    can_edit_appraisal = fields.Boolean('Can Edit Appraisal', compute='_check_stage_rule_edit_appraisal')

    def _check_stage_rule_edit_appraisal(self):
        if (self.employee_id.user_id == self.env.user and self.stage_id.employee_allowed_edit) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_allowed_edit) \
                or self.env.user in self.stage_id.users_allowed_edit:
            self.can_edit_appraisal = True
        else:
            self.can_edit_appraisal = False

    can_comment_hr = fields.Boolean('Can HR Comment', compute='_check_stage_rule_hr_comment')

    def _check_stage_rule_hr_comment(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_can_comment_form_hr) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_can_comment_form_hr) \
                or self.env.user in self.stage_id.users_can_comment_form_hr:
            self.can_comment_hr = True
        else:
            self.can_comment_hr = False

    can_comment_manager = fields.Boolean('Can Manager Comment', compute='_check_stage_rule_manager_comment')

    def _check_stage_rule_manager_comment(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_can_comment_form_manager) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_can_comment_form_manager) \
                or self.env.user in self.stage_id.users_can_comment_form_manager:
            self.can_comment_manager = True
        else:
            self.can_comment_manager = False

    can_comment_employee = fields.Boolean('Can Employee Comment', compute='_check_stage_rule_employee_comment')

    def _check_stage_rule_employee_comment(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_can_comment_form_employee) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_can_comment_form_employee) \
                or self.env.user in self.stage_id.users_can_comment_form_employee:
            self.can_comment_employee = True
        else:
            self.can_comment_employee = False

    can_see_comment_hr = fields.Boolean('Can See HR Comment', compute='_check_stage_rule_hr_see_comment')

    def _check_stage_rule_hr_see_comment(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_can_see_comment_form_hr) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_can_see_comment_form_hr) \
                or self.env.user in self.stage_id.users_can_see_comment_form_hr:
            self.can_see_comment_hr = True
        else:
            self.can_see_comment_hr = False

    can_see_comment_manager = fields.Boolean('Can See Manager Comment', compute='_check_stage_rule_manager_see_comment')

    def _check_stage_rule_manager_see_comment(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_can_see_comment_form_manager) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_can_see_comment_form_manager) \
                or self.env.user in self.stage_id.users_can_see_comment_form_manager:
            self.can_see_comment_manager = True
        else:
            self.can_see_comment_manager = False

    can_see_comment_employee = fields.Boolean('Can See Employee Comment',
                                              compute='_check_stage_rule_employee_see_comment')

    def _check_stage_rule_employee_see_comment(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_can_see_comment_form_employee) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_can_see_comment_form_employee) \
                or self.env.user in self.stage_id.users_can_see_comment_form_employee:
            self.can_see_comment_employee = True
        else:
            self.can_see_comment_employee = False

    can_training = fields.Boolean('Can Edit Training', compute='_check_stage_rule_training')

    def _check_stage_rule_training(self):
        if (self.employee_id.user_id == self.env.user and self.stage_id.employee_can_modifiy_training) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_can_modifiy_training) \
                or self.env.user in self.stage_id.users_can_modifiy_training:
            self.can_training = True
        else:
            self.can_training = False

    can_approve_objectives = fields.Boolean('Can Approve Objectives', compute='_check_stage_rule_approve_objectives')

    def _check_stage_rule_approve_objectives(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_can_approve_approve) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_can_approve_approve) \
                or self.env.user in self.stage_id.users_can_approve_approve:
            self.can_approve_objectives = True
        else:
            self.can_approve_objectives = False

    can_take_survey = fields.Boolean('Can Take Survey', compute='_check_stage_rule_take_survey')

    def _check_stage_rule_take_survey(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_take_survey) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_take_survey) \
                or self.env.user in self.stage_id.users_take_survey:
            self.can_take_survey = True
        else:
            self.can_take_survey = False

    can_print_survey = fields.Boolean('Can See Survey', compute='_check_stage_rule_see_survey')

    def _check_stage_rule_see_survey(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_see_survey) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_see_survey) \
                or self.env.user in self.stage_id.users_see_survey:
            self.can_print_survey = True
        else:
            self.can_print_survey = False

    can_rate_hr = fields.Boolean('Can HR Rate', compute='_check_stage_rule_hr_rate')

    def _check_stage_rule_hr_rate(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_rating_hr_add) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_rating_hr_add) \
                or self.env.user in self.stage_id.users_rating_hr_add:
            self.can_rate_hr = True
        else:
            self.can_rate_hr = False

    can_see_rate_hr = fields.Boolean('Can See HR Rate', compute='_check_stage_rule_hr_see_rate')

    def _check_stage_rule_hr_see_rate(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_rating_hr_see) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_rating_hr_see) \
                or self.env.user in self.stage_id.users_rating_hr_see:
            self.can_see_rate_hr = True
        else:
            self.can_see_rate_hr = False

    can_see_rate_manager = fields.Boolean('Can See Manager Rate', compute='_check_stage_rule_manager_see_rate')

    def _check_stage_rule_manager_see_rate(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_rating_manager_see) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_rating_manager_see) \
                or self.env.user in self.stage_id.users_rating_manager_see:
            self.can_see_rate_manager = True
        else:
            self.can_see_rate_manager = False

    can_see_rate_employee = fields.Boolean('Can See Employee Rate', compute='_check_stage_rule_employee_see_rate')

    def _check_stage_rule_employee_see_rate(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_rating_employee_see) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_rating_employee_see) \
                or self.env.user in self.stage_id.users_rating_employee_see:
            self.can_see_rate_employee = True
        else:
            self.can_see_rate_employee = False

    can_see_comment_objective_hr = fields.Boolean('Can See HR Comment',
                                                  compute='_check_stage_rule_hr_see_objective_comment')

    def _check_stage_rule_hr_see_objective_comment(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_can_see_comment_objective_hr) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_can_see_comment_objective_hr) \
                or self.env.user in self.stage_id.users_can_see_comment_objective_hr:
            self.can_see_comment_objective_hr = True
        else:
            self.can_see_comment_objective_hr = False

    can_see_comment_objective_manager = fields.Boolean('Can See Manager Comment',
                                                       compute='_check_stage_rule_manager_see_objective_comment')

    def _check_stage_rule_manager_see_objective_comment(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_can_see_comment_objective_manager) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_can_see_comment_objective_manager) \
                or self.env.user in self.stage_id.users_can_see_comment_objective_manager:
            self.can_see_comment_objective_manager = True
        else:
            self.can_see_comment_objective_manager = False

    can_see_comment_objective_employee = fields.Boolean('Can See Employee Comment',
                                                        compute='_check_stage_rule_employee_see_objective_comment')

    def _check_stage_rule_employee_see_objective_comment(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_can_see_comment_objective_employee) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_can_see_comment_objective_employee) \
                or self.env.user in self.stage_id.users_can_see_comment_objective_employee:
            self.can_see_comment_objective_employee = True
        else:
            self.can_see_comment_objective_employee = False

    can_see_rate_objective_manager = fields.Boolean('Can See Manager Rate',
                                                    compute='_check_stage_rule_manager_see_objective_rate')

    def _check_stage_rule_manager_see_objective_rate(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_rating_manager_see) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_rating_manager_see) \
                or self.env.user in self.stage_id.users_rating_manager_see:
            self.can_see_rate_objective_manager = True
        else:
            self.can_see_rate_objective_manager = False

    can_see_rate_objective_employee = fields.Boolean('Can See Employee Rate',
                                                     compute='_check_stage_rule_employee_objective_see_rate')

    def _check_stage_rule_employee_objective_see_rate(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_rating_employee_see) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_rating_employee_see) \
                or self.env.user in self.stage_id.users_rating_employee_see:
            self.can_see_rate_objective_employee = True
        else:
            self.can_see_rate_objective_employee = False

    def _get_objectives(self):
        # line = [{'name': "Objective", 'weight': "Weight", 'description': "Description", 'e_rating': "Employee Rating",
        #          'e_comment': "Employee Comment", 'm_rating': "Manager Rating",
        #          'm_comment': "Manager Comment", 'h_comment': "HR Comment",
        #          'bold': True}]
        line = []

        for obj in self.appraisal_edit_objectives.filtered(lambda x: x.state == 'active'):
            line.append(
                {'name': obj.title, 'weight': obj.weight, 'description': obj.description,
                 'e_rating': obj.employee_rating,
                 'e_comment': obj.employee_comment, 'm_rating': obj.manager_rating,
                 'm_comment': obj.manager_comment, 'h_comment': obj.hr_comment,
                 'bold': False})
            # line.append(
            #     {'name': "Objective", 'weight': "Weight", 'description': "Description", 'e_rating': "Employee Rating",
            #      'e_comment': "Employee Comment", 'm_rating': "Manager Rating",
            #      'm_comment': "Manager Comment", 'h_comment': "HR Comment",
            #      'bold': True})

        return line

    def _get_trainings(self):
        full_date_format = '%d/%m/%Y'
        line = [{'name': "Training Name", 'status': "Status", 'from_date': "From Date", 'to_date': "To Date",
                 'description': "Description", 'bold': True}]

        for obj in self.appraisal_training:
            line.append(
                {'name': obj.name, 'status': obj.status.name,
                 'from_date': obj.from_date.strftime(full_date_format) if obj.from_date else '',
                 'to_date': obj.to_date.strftime(full_date_format) if obj.to_date else '', 'description': obj.desc,
                 'bold': False})

        return line

    def _get_feedbacks(self):
        line = [
            {'name': "Name", 'user': "Responsible User", 'type': "Feedback Type", 'feedback': "Feedback", 'bold': True}]

        for obj in self.related_feedback:
            line.append(
                {'name': obj.name, 'user': obj.user_id.name,
                 'type': dict(self.related_feedback._fields['feedback_type'].selection).get(obj.feedback_type),
                 'feedback': obj.feedback,
                 'bold': False})

        return line

    can_add_area_development = fields.Boolean('Can Add Area of Development',
                                              compute='_check_stage_rule_add_area_development')

    def _check_stage_rule_add_area_development(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_area_development_add) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_area_development_add) \
                or self.env.user in self.stage_id.users_area_development_add:
            self.can_add_area_development = True
        else:
            self.can_add_area_development = False

    can_see_area_development = fields.Boolean('Can See Area of Development',
                                              compute='_check_stage_rule_see_area_development')

    def _check_stage_rule_see_area_development(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_area_development_see) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_area_development_see) \
                or self.env.user in self.stage_id.users_area_development_see:
            self.can_see_area_development = True
        else:
            self.can_see_area_development = False

    can_add_first_manager_review = fields.Boolean('Can Add 1st month Review by Manager Comments',
                                                  compute='_check_stage_rule_add_first_manager_review')

    def _check_stage_rule_add_first_manager_review(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_first_manager_review_add) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_first_manager_review_add) \
                or self.env.user in self.stage_id.users_first_manager_review_add:
            self.can_add_first_manager_review = True
        else:
            self.can_add_first_manager_review = False

    can_see_first_manager_review = fields.Boolean('Can See 1st month Review by Manager Comments',
                                                  compute='_check_stage_rule_see_first_manager_review')

    def _check_stage_rule_see_first_manager_review(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_first_manager_review_see) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_first_manager_review_see) \
                or self.env.user in self.stage_id.users_first_manager_review_see:
            self.can_see_first_manager_review = True
        else:
            self.can_see_first_manager_review = False

    can_add_first_employee_review = fields.Boolean('Can Add 1st month Employee Review',
                                                   compute='_check_stage_rule_add_first_employee_review')

    def _check_stage_rule_add_first_employee_review(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_first_employee_review_add) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_first_employee_review_add) \
                or self.env.user in self.stage_id.users_first_employee_review_add:
            self.can_add_first_employee_review = True
        else:
            self.can_add_first_employee_review = False

    can_see_first_employee_review = fields.Boolean('Can See 1st month Employee Review',
                                                   compute='_check_stage_rule_see_first_employee_review')

    def _check_stage_rule_see_first_employee_review(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_first_employee_review_see) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_first_employee_review_see) \
                or self.env.user in self.stage_id.users_first_employee_review_see:
            self.can_see_first_employee_review = True
        else:
            self.can_see_first_employee_review = False

    can_add_second_manager_review = fields.Boolean('Can Add 2nd month Review by Manager Comments',
                                                   compute='_check_stage_rule_add_second_manager_review')

    def _check_stage_rule_add_second_manager_review(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_second_manager_review_add) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_second_manager_review_add) \
                or self.env.user in self.stage_id.users_second_manager_review_add:
            self.can_add_second_manager_review = True
        else:
            self.can_add_second_manager_review = False

    can_see_second_manager_review = fields.Boolean('Can See 2nd month Review by Manager Comments',
                                                   compute='_check_stage_rule_see_second_manager_review')

    def _check_stage_rule_see_second_manager_review(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_second_manager_review_see) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_second_manager_review_see) \
                or self.env.user in self.stage_id.users_second_manager_review_see:
            self.can_see_second_manager_review = True
        else:
            self.can_see_second_manager_review = False

    can_add_second_employee_review = fields.Boolean('Can Add 2nd month Employee Review',
                                                    compute='_check_stage_rule_add_second_employee_review')

    def _check_stage_rule_add_second_employee_review(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_second_employee_review_add) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_second_employee_review_add) \
                or self.env.user in self.stage_id.users_second_employee_review_add:
            self.can_add_second_employee_review = True
        else:
            self.can_add_second_employee_review = False

    can_see_second_employee_review = fields.Boolean('Can See 2nd month Employee Review',
                                                    compute='_check_stage_rule_see_second_employee_review')

    def _check_stage_rule_see_second_employee_review(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_second_employee_review_see) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_second_employee_review_see) \
                or self.env.user in self.stage_id.users_second_employee_review_see:
            self.can_see_second_employee_review = True
        else:
            self.can_see_second_employee_review = False

    can_add_third_manager_review = fields.Boolean('Can Add 3rd month Review by Manager Comments',
                                                  compute='_check_stage_rule_add_third_manager_review')

    def _check_stage_rule_add_third_manager_review(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_third_manager_review_add) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_third_manager_review_add) \
                or self.env.user in self.stage_id.users_third_manager_review_add:
            self.can_add_third_manager_review = True
        else:
            self.can_add_third_manager_review = False

    can_see_third_manager_review = fields.Boolean('Can See 3rd month Review by Manager Comments',
                                                  compute='_check_stage_rule_see_third_manager_review')

    def _check_stage_rule_see_third_manager_review(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_third_manager_review_see) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_third_manager_review_see) \
                or self.env.user in self.stage_id.users_third_manager_review_see:
            self.can_see_third_manager_review = True
        else:
            self.can_see_third_manager_review = False

    can_add_third_employee_review = fields.Boolean('Can Add 3rd month Employee Review',
                                                   compute='_check_stage_rule_add_third_employee_review')

    def _check_stage_rule_add_third_employee_review(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_third_employee_review_add) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_third_employee_review_add) \
                or self.env.user in self.stage_id.users_third_employee_review_add:
            self.can_add_third_employee_review = True
        else:
            self.can_add_third_employee_review = False

    can_see_third_employee_review = fields.Boolean('Can See 3rd month Employee Review',
                                                   compute='_check_stage_rule_see_third_employee_review')

    def _check_stage_rule_see_third_employee_review(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_third_employee_review_see) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_third_employee_review_see) \
                or self.env.user in self.stage_id.users_third_employee_review_see:
            self.can_see_third_employee_review = True
        else:
            self.can_see_third_employee_review = False

    can_add_manager_final_decision = fields.Boolean('Can Add Manager Final Decision',
                                                    compute='_check_stage_rule_add_manager_final_decision')

    def _check_stage_rule_add_manager_final_decision(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_manager_final_decision_add) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_manager_final_decision_add) \
                or self.env.user in self.stage_id.users_manager_final_decision_add:
            self.can_add_manager_final_decision = True
        else:
            self.can_add_manager_final_decision = False

    can_see_manager_final_decision = fields.Boolean('Can See Manager Final Decision',
                                                    compute='_check_stage_rule_see_manager_final_decision')

    def _check_stage_rule_see_manager_final_decision(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_manager_final_decision_see) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_manager_final_decision_see) \
                or self.env.user in self.stage_id.users_manager_final_decision_see:
            self.can_see_manager_final_decision = True
        else:
            self.can_see_manager_final_decision = False

    can_add_manager_final_comments = fields.Boolean('Can Add Manager Final Comments',
                                                    compute='_check_stage_rule_add_manager_final_comments')

    def _check_stage_rule_add_manager_final_comments(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_manager_final_comments_add) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_manager_final_comments_add) \
                or self.env.user in self.stage_id.users_manager_final_comments_add:
            self.can_add_manager_final_comments = True
        else:
            self.can_add_manager_final_comments = False

    can_see_manager_final_comments = fields.Boolean('Can See Manager Final Comments',
                                                    compute='_check_stage_rule_see_manager_final_comments')

    def _check_stage_rule_see_manager_final_comments(self):
        if (
                self.employee_id.user_id == self.env.user and self.stage_id.employee_manager_final_comments_see) or (
                self.appraisal_manager.user_id == self.env.user and self.stage_id.manager_manager_final_comments_see) \
                or self.env.user in self.stage_id.users_manager_final_comments_see:
            self.can_see_manager_final_comments = True
        else:
            self.can_see_manager_final_comments = False


import os, sys
import bots.botsglobal as botsglobal
import bots.botslib as botslib
from datetime import datetime

def ta_infocontent(ta_info,*args,**kwargs):
    ta_info["ISA05"]="ZZ"
    ta_info["ISA07"]="ZZ"
    #ta_info["GS06"]=ta_info["alt"]
    #ta_info["ISA13"]=ta_info["alt"]
    ta_info["version"]="00306"
    now = datetime.now()
    dt = now.strftime('%y%m%d')
    ta_info["GS04"]=dt

def envelopecontent(ta_info,out,*args,**kwargs):
    now = datetime.now()
    dt = now.strftime('%y%m%d')
    out.change(where=({'BOTSID':'ISA'},{'BOTSID':'GS'},),change={'GS04': dt})


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

import numpy as np
import logging as log

from synergetics.config import config as cfg
from synergetics.neurons.LIF.LIF import LIF

class LIFRate(LIF):
  """
  http://en.wikipedia.org/wiki/Biological_neuron_model#Leaky_integrate-and-fire
  """
  def __init__(self, position, excitatory=True,
              update_rule=None,
              discover_rule=None,
              tau_rc=0.02,
              tau_th=0.002,
              reversal_potential=0,
              membrane_resistance=0.01,
              refractory_period=1):
    self._tau_rc    = tau_rc
    self._tau_th    = tau_th
    self._i_thresh  = reversal_potential/membrane_resistance
    self._t_ref     = refractory_period

    super(LIFStochastic, self).__init__(position, excitatory, update_rule, discover_rule)

  def excite(self, excitor, excitement, timestamp):
    if excitement > self._i_thresh:
      rate = 1.0/(self._t_ref - self._tau_rc*np.log(1.0 - (excitement/self._tau_th)))
    else:
      rate = 0
    if rate: self.spike(timestamp, num=rate)


#04_while_number.py

#练习：
#    1、输入一个整数，用end变量绑定，
#    打印出1~end的所有整数，(包含end)

end = int(input("请输入一个整数："))
i = 1
while i <= end:
    print(i)
    i += 1

print("程序结束！")

#2、写程序，输入两个整数，第一个用begin绑定，
#   第二个用end变量绑定，打印出begin~end的所有的整数

begin = int(input("请输入第一个整数："))
end = int(input("请输入第二个整数："))

i = begin
while i <= end:
    print(i)
    i += 1

print("程序结束！")


import torch
from torch.autograd import grad
from torch.autograd.functional import hessian

def propose_step(loss, x):
    """
    Proposes a step to be evaluated by {replace here}.

    :param torch.Tensor loss: A scalar function ``x`` to be minimized.
    :param torch.Tensor x: A dependent variable with rightmost size of 2.

    :list proposed_step: List of proposed steps for each parameter in x

    Note:
    For the moment I assume that every parameter is a vector (in the mathematical sense)
    """

    if loss.shape != ():
        raise ValueError('Expected loss to be a scalar, actual shape{}'.format(loss.shape))

    x = list(x)
    proposed_step = []
    g = grad(loss, x, create_graph=True)

    # We need to compute the hessians idependently in case the have different shapes
    # For the moment I am assuming that every parameter is a row
    # We can probably handle this later

    for i, param in enumerate(x):
        hessian_rows = [grad(g[i][j], param, retain_graph=True)[0] for j in range(len(param))]
        H = torch.stack(hessian_rows)
        H_inverse = torch.inverse(H)
        proposed_step.append(- H_inverse @ g[i])

    return proposed_step


# -*-coding:utf-8-*-
class Solution(object):
	def findMedianSortedArrays(self, nums1, nums2):
		len1,len2 = len(nums1),len(nums2)
		length = len1 + len2
		if (length % 2 == 0):
			position =  length / 2
		else:
			position =  length / 2 + 1
		if (position == 1):
			startIndex = 0
		else:
			startIndex = position / 2 - 1
		num1,num2 =  self.partition(nums1,nums2,0,0,startIndex,startIndex,len1,len2,position)
		if (num1 is None and num2 is None):
			return None
		elif (num1 is None):
			return num2
		elif (num2 is None):
			return num1
		if (length % 2 == 0):
			return (num1 + num2) / 2.0
		return num1

	def partition(self,nums1,nums2,start1,start2,index1,index2,len1,len2,position):
		# 处理某个数组的个数为 0 的情况
		if (len1 == 0 and len2 == 0):
			return None,None
		elif (len1 == 0):
			if (len2 == 1):
				return nums2[len2 /2],None
			elif(len2 % 2== 0):
				return nums2[len2 /2 - 1],nums2[len2/2]
			else:
				return nums2[len2 /2],nums2[len2/2 + 1]
		elif (len2 == 0):
			if (len1 == 1):
				return nums1[len1 /2],None
			elif(len1 % 2 == 0):
				return nums1[len1 /2 - 1],nums1[len1/2]
			else:
				return nums1[len1 /2],nums1[len1/2+1]

		# 在某次迭代后，某个数组的总长度已经小于归并后所需的子长度
		if (index1 >= len1):
			index1 = len1 - 1
		if (index2 >= len2):
			index2 = len2 - 1

		# N 次迭代后，剩下所需子长度终于为1，结束归并。
		if (position == 1):
			if (nums1[index1] < nums2[index2]):
				if (index1 + 1 < len(nums1) and nums1[index1 + 1] <= nums2[index2]):
					return nums1[index1],nums1[index1 + 1]
				else:
					return nums1[index1],nums2[index2]
			else:
				if (index2 + 1 < len(nums2) and nums1[index1] >= nums2[index2 + 1]):
					return nums2[index2],nums2[index2 + 1]
				else:
					return nums2[index2],nums1[index1]

		# 核心的迭代过程
		if (nums1[index1] <= nums2[index2]):
			position = position - index1 + start1 - 1
			if (index1 == len1 - 1):
				return nums2[start2 + position - 1],nums2[start2 + position]
			if (position == 1):
				start1 = index1 + 1
				index1 = start1
				index2 = start2
			else:
				start1 = index1 + 1
				index1 = position / 2 + start1 - 1
				index2 = position / 2 + start2 - 1
			return self.partition(nums1,nums2,start1,start2,index1,index2,len1,len2,position)
		else:
			position = position - index2 + start2 - 1
			if (index2 == len2 - 1):
				return nums1[start1 + position - 1],nums1[start1 + position]
			if (position == 1):
				index1 = start1
				start2 = index2 + 1
				index2 = start2
			else:
				index1 = position / 2 + start1 - 1
				start2 = index2 + 1
				index2 = position / 2 + start2 - 1
			return self.partition(nums1,nums2,start1,start2,index1,index2,len1,len2,position)


from flask import Flask, render_template

app = Flask(__name__)

user = {
    'username': 'yard',
    'bio': 'A boy who love movies'
}
movies = [
    {'name': 'My Neighbor Totoro', 'year': '1988'},
    {'name': 'Three Colours trilogy', 'year': '1993'},
    {'name': 'Forrest Gump', 'year': '1994'},
    {'name': 'Perfect Blue', 'year': '1997'},
    {'name': 'The Matrix', 'year': '1999'},
    {'name': 'Memento', 'year': '2000'},
    {'name': 'The Bucket list', 'year': '2007'},
    {'name': 'Black Swan', 'year': '2010'},
    {'name': 'Gone Girl', 'year': '2014'},
    {'name': 'CoCo', 'year': '2017'}
]

@app.route('/index')
def index():
    return 'hello!'

@app.route('/watchlist')
def watchlist():
    return render_template('watchlist.html', user=user, movies=movies)

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


from selfdrive.controls.lib.pid import PIController
from selfdrive.controls.lib.drive_helpers import get_steer_max
from cereal import car
from cereal import log

class LatControlPID():
  def __init__(self, CP):
    self.factor = 1.

    self.lowpid = PIController((CP.lateralTuning.pid.kpBP, CP.lateralTuning.pid.kpV),
                            (CP.lateralTuning.pid.kiBP, CP.lateralTuning.pid.kiV),
                            k_f=CP.lateralTuning.pid.kf, pos_limit=1.0, sat_limit=CP.steerLimitTimer)

    self.pid = PIController((CP.lateralTuning.pid.kpBP, CP.lateralTuning.pid.kpV),
                            (CP.lateralTuning.pid.kiBP, CP.lateralTuning.pid.kiV),
                            k_f=CP.lateralTuning.pid.kf, pos_limit=1.0, neg_limit=-1.0,
                            sat_limit=CP.steerLimitTimer)
    self.angle_steers_des = 0.
    self.increasing = False
    self.dualpids = False

  def reset(self):
    self.pid.reset()
    self.lowpid.reset()
    self.increasing = False

  def dualPIDinit(self, CP):
    self.factor = CP.lateralParams.torqueBP[1] / CP.lateralParams.torqueBP[-1]

    self.highkpV = CP.lateralTuning.pid.kpV[1]
    self.highkiV = CP.lateralTuning.pid.kiV[1]

    self.lowpid = PIController((CP.lateralTuning.pid.kpBP, [CP.lateralTuning.pid.kpV[0]]),
                            (CP.lateralTuning.pid.kiBP, [CP.lateralTuning.pid.kiV[0]]),
                            k_f=CP.lateralTuning.pid.kf, pos_limit=1.0, sat_limit=CP.steerLimitTimer)

    self.pid = PIController((CP.lateralTuning.pid.kpBP, [self.highkpV]),
                            (CP.lateralTuning.pid.kiBP, [self.highkiV]),
                            k_f=CP.lateralTuning.pid.kf, pos_limit=1.0, sat_limit=CP.steerLimitTimer)
    self.angle_steers_des = 0.
    self.increasing = False
    self.dualpids = True

  def pidset(self, pid, descontrol, setpoint, measurement, feedforward):
    error = float(setpoint - measurement)
    p = error * pid._k_p[1][0]
    f = feedforward * pid.k_f
    i = descontrol - p - f
    pid.p = p
    pid.i = i
    pid.f = f
    pid.sat_count = 0.0
    pid.saturated = False
    pid.control = descontrol

  def update(self, active, CS, CP, path_plan):
    pid_log = log.ControlsState.LateralPIDState.new_message()
    pid_log.steerAngle = float(CS.steeringAngle)
    pid_log.steerRate = float(CS.steeringRate)

    if CS.vEgo < 0.3 or not active:
      output_steer = 0.0
      pid_log.active = False
      if len(CP.lateralTuning.pid.kpV) > 1 and not self.dualpids:
        self.dualPIDinit(CP)
      self.pid.reset()
      self.lowpid.reset()
      self.increasing = False
    else:
      self.angle_steers_des = path_plan.angleSteers  # get from MPC/PathPlanner

      steers_max = get_steer_max(CP, CS.vEgo)
      self.pid.pos_limit = steers_max
      self.pid.neg_limit = -steers_max

      self.lowpid.pos_limit = steers_max
      self.lowpid.neg_limit = -steers_max

      steer_feedforward = self.angle_steers_des   # feedforward desired angle
      if CP.steerControlType == car.CarParams.SteerControlType.torque:
        # TODO: feedforward something based on path_plan.rateSteers
        steer_feedforward -= path_plan.angleOffset   # subtract the offset, since it does not contribute to resistive torque
        steer_feedforward *= CS.vEgo**2  # proportional to realigning tire momentum (~ lateral accel)
      deadzone = 0.0

      check_saturation = (CS.vEgo > 10) and not CS.steeringRateLimited and not CS.steeringPressed
      #output_steer = self.pid.update(self.angle_steers_des, CS.steeringAngle, check_saturation=check_saturation, override=CS.steeringPressed,
      #                                feedforward=steer_feedforward, speed=CS.vEgo, deadzone=deadzone)

      output_steer = 0.0
      if not self.dualpids:
        output_steer = self.pid.update(self.angle_steers_des, CS.steeringAngle, check_saturation=check_saturation, override=CS.steeringPressed,
                                      feedforward=steer_feedforward, speed=CS.vEgo, deadzone=deadzone)
      else:
        if not self.increasing:
          raw_low_output_steer = self.lowpid.update(self.angle_steers_des, CS.steeringAngle, check_saturation=check_saturation, override=CS.steeringPressed,
                                        feedforward=steer_feedforward, speed=CS.vEgo, deadzone=deadzone)
          output_steer = raw_low_output_steer * self.factor
          #print("Lo - " + str(output_steer))
          if abs(output_steer) > (self.factor * 0.99):
            self.pidset(self.pid, output_steer, self.angle_steers_des, CS.steeringAngle,steer_feedforward)
            #self.pid.p = self.lowpid.p * self.factor
            #self.pid.i = self.lowpid.i * self.factor
            #self.pid.f = self.lowpid.f * self.factor
            #self.pid.sat_count = 0.0
            #self.pid.saturated = False
            #self.pid.control = self.lowpid.control * self.factor

            self.increasing = True
        else:
          output_steer = self.pid.update(self.angle_steers_des, CS.steeringAngle, check_saturation=check_saturation, override=CS.steeringPressed,
                                        feedforward=steer_feedforward, speed=CS.vEgo, deadzone=deadzone)
          #print("Hi - " + str(output_steer))
          if abs(output_steer) < (self.factor * 0.1) and abs(self.pid.i) < (self.factor * 0.2):
            self.pidset(self.lowpid, (output_steer / self.factor), self.angle_steers_des, CS.steeringAngle,steer_feedforward)
            #self.lowpid.p = self.pid.p / self.factor
            #self.lowpid.i = 0
            #self.lowpid.f = self.pid.f / self.factor
            #self.lowpid.sat_count = 0.0
            #self.lowpid.saturated = False
            #self.lowpid.control = self.pid.control / self.factor

            self.increasing = False
      pid_log.active = True
      pid_log.p = self.pid.p
      pid_log.i = self.pid.i
      pid_log.f = self.pid.f
      pid_log.output = output_steer
      pid_log.saturated = bool(self.pid.saturated)

    return output_steer, float(self.angle_steers_des), pid_log


import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']

input_values = [1, 2, 3, 4, 5]
squares = [1, 4, 9, 16, 25]

plt.style.use('seaborn')
fig, ax = plt.subplots()
ax.plot(input_values, squares, linewidth=3)

#设置图表标题并给坐标轴加上标签。
ax.set_title("square numbers", fontsize=18)
ax.set_xlabel("values", fontsize=14)
ax.set_ylabel("square", fontsize=14)

#设置刻度标记的大小
ax.tick_params(axis='both', labelsize=14)
plt.show()


"""
****************************************************************************************************
:copyright (c) 2019-2020 URBANopt, Alliance for Sustainable Energy, LLC, and other contributors.

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted
provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list of conditions
and the following disclaimer.

Redistributions in binary form must reproduce the above copyright notice, this list of conditions
and the following disclaimer in the documentation and/or other materials provided with the
distribution.

Neither the name of the copyright holder nor the names of its contributors may be used to endorse
or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
****************************************************************************************************
"""

import json
import os

from jinja2 import Environment, FileSystemLoader

class ETSTemplate:
    """This class will template the ETS modelica model."""

    def __init__(self, thermal_junction_properties_geojson, system_parameters_geojson, ets_from_building_modelica):
        """
        thermal_junction_properties_geojson contains the ETS at brief and at higher level;
        system_parameters_geojson contains the ETS with details                          ;
        ets_from_building_modelica contains the modelica model of ETS                    ;
        """
        super().__init__()

        self.thermal_junction_properties_geojson = thermal_junction_properties_geojson
        self.thermal_junction_properties_geojson = self.thermal_junction_properties_geojson.replace("\\", "/")

        self.system_parameters_geojson = system_parameters_geojson
        if "\\" in self.system_parameters_geojson:
            self.system_parameters_geojson = self.system_parameters_geojson.replace("\\", "/")

        self.ets_from_building_modelica = ets_from_building_modelica
        if "\\" in self.ets_from_building_modelica:
            self.ets_from_building_modelica = self.ets_from_building_modelica.replace("\\", "/")

        # get the path of modelica-buildings library
        # temporarily copied here to reduce repo size
        directory_up_one_level = os.path.abspath(os.path.join(__file__, "../.."))
        self.directory_modelica_building = os.path.join(
            directory_up_one_level + "/modelica/CoolingIndirect.mo"
        )
        if "\\" in self.directory_modelica_building:
            self.directory_modelica_building = self.directory_modelica_building.replace("\\", "/")

        # go up two levels of directory, to get the path of tests folder for ets
        # TODO: we shouldn't be writing to the test directory in this file, only in tests.
        directory_up_two_levels = os.path.abspath(os.path.join(__file__, "../../.."))
        self.directory_ets_templated = os.path.join(
            directory_up_two_levels + "/tests/output_ets"
        )
        if "\\" in self.directory_ets_templated:
            self.directory_ets_templated = self.directory_ets_templated.replace("\\", "/")

        if not os.path.isdir(self.directory_ets_templated):
            os.mkdir(self.directory_ets_templated)
        else:
            pass

        # here comes the Jinja2 function: Environment()
        # it loads all the "*.mot" files into an environment by Jinja2
        self.template_env = Environment(
            loader=FileSystemLoader(
                searchpath=os.path.join(os.path.dirname(os.path.abspath(__file__)), "templates")
            )
        )

    def check_ets_thermal_junction(self):
        """check if ETS info are in thermal-junction-geojson file"""
        with open(self.thermal_junction_properties_geojson, "r") as f:
            data = json.load(f)

        ets_general = False
        for key, value in data.items():
            if key == "definitions":
                # three levels down to get the ETS signal
                junctions = data["definitions"]["ThermalJunctionType"]["enum"]
                if "ETS" in junctions:
                    ets_general = True
            else:
                pass

        return ets_general

    def check_ets_system_parameters(self):
        """check detailed parameters of ETS"""
        with open(self.system_parameters_geojson, "r") as f:
            data = json.load(f)

        ets_parameters = False
        # four levels down to get the ets model description
        # ets_overall = data["definitions"]["building_def"]["properties"]["ets"]
        # three levels down to get the parameters
        ets_parameters = data["definitions"]["ets_parameters"]["properties"]
        # print ("est_parameters are: ", type(ets_parameters) )
        return ets_parameters

    def check_ets_from_building_modelica(self):
        """check if ETS-indirectCooling are in modelica building library"""
        ets_modelica_available = os.path.isfile(self.ets_from_building_modelica)

        return ets_modelica_available

    def to_modelica(self):
        """convert ETS json to modelica"""
        # Here come the Jinja2 function: get_template(), which reads into templated ets model.
        # CoolingIndirect.mot was manually created as a starting point, by adding stuff following Jinja2 syntax.
        # it has all the necessary parameters which need to be changed through templating.
        ets_template = self.template_env.get_template("CoolingIndirect.mot")

        # TODO: Seems like the ets_data below should allow defaults from
        #  the system parameters JSON file, correct?
        # ets model parameters are from the schema.json file, default values only.
        ets_data = self.check_ets_system_parameters()

        # Here comes the Jina2 function: render()
        file_data = ets_template.render(ets_data=ets_data)

        # write templated ETS back to modelica file , to the tests folder for Dymola test
        path_ets_templated = os.path.join(self.directory_ets_templated, "ets_cooling_indirect_templated.mo")

        if os.path.exists(path_ets_templated):
            os.remove(path_ets_templated)
        with open(path_ets_templated, "w") as f:
            f.write(file_data)

        # write templated ETS back to building-modelica folder for Dymola test
        path_writtenback = os.path.join(os.path.abspath(os.path.join(__file__, "../..")) + "/modelica/")

        if os.path.exists(os.path.join(path_writtenback, "ets_cooling_indirect_templated.mo")):
            os.remove(os.path.join(path_writtenback, "ets_cooling_indirect_templated.mo"))
        with open(os.path.join(path_writtenback, "ets_cooling_indirect_templated.mo"), "w") as f:
            f.write(file_data)

        return file_data

    def templated_ets_openloops_dymola(self):
        """after we creating the templated ets, we need to test it in Dymola under open loops.
        Here we refactor the example file: CoolingIndirectOpenLoops,
        to test our templated ets model.
        """
        file = open(
            os.path.join(os.getcwd(), "geojson_modelica_translator") + "/modelica/CoolingIndirectOpenLoops.mo", "r",
        )
        cooling_indirect_filename = "/CoolingIndirectOpenLoops_Templated.mo"

        # if the modelica example file is existed, delete it first
        path_openloops = os.path.join(os.path.abspath(os.path.join(__file__, "../..")) + "/modelica/")

        if os.path.exists(path_openloops + cooling_indirect_filename):
            os.remove(path_openloops + cooling_indirect_filename)

        # create the modelica example file for Dymola test
        # TODO: Replace this with the ModelicaFile Class --
        #  extend ModelicaFile class if does not support.
        # Theoretically it is doable using extend clause from Modelica.
        # But we need to change the original ETS model first, in order to extend.
        # This is Michael Wetter suggested approach.
        # if so, we don't need to template modelica models, but we need to connect the modelica components
        repl_dict = {}
        from_str = "model CoolingIndirectOpenLoops"
        to_str = "model CoolingIndirectOpenLoops_Templated\n"
        repl_dict[from_str] = to_str
        from_str = (
            "Buildings.Applications.DHC.EnergyTransferStations.CoolingIndirect coo("
        )
        to_str = "Buildings.Applications.DHC.EnergyTransferStations.ets_cooling_indirect_templated coo("
        repl_dict[from_str] = to_str
        from_str = "end CoolingIndirectOpenLoops;"
        to_str = "end CoolingIndirectOpenLoops_Templated;"
        repl_dict[from_str] = to_str

        with open(path_openloops + cooling_indirect_filename, "w") as examplefile:
            for f in file:
                fx = f
                for from_str, to_str in repl_dict.items():
                    # TODO: f.string() causes errors, check code
                    if fx.strip() == from_str.strip():
                        fx = f.replace(from_str, to_str)
                examplefile.write(fx)

        return examplefile

    def connect(self):
        """connect ETS-modelica to building-modelica (specifically TEASER modelica).
        This function will be modified in future"""
        pass


#!/usr/bin/env python
"""
python implementation of super_auto.f
c aligns atom in pdb file so as to minimize
c rms atom distance compared to reference pdb file
c branch off super.f that automatically seraches for matching atom pairs
21aug2020: added calculation of mean absolute dedivation (MAD)
july 2021 - for pdb inputs with duplicate atom names - e.g. from gold
prevent atoms being used > once for a match
"""
import sys
import math
import pdb_methods as pm
import numpy as np
#=====================================================
def supq(co1,co2,nat):
  """ find rotation matrix to minimix rmsd - we assume centers
  have already  been moved to the origin using method of Kearsley
  Acta Cryst (1989) A45:208 usng quaternions
  """
  #
  # calculate omega matrix of Kearsley et al.
  omega = np.zeros((4,4),'float')
  qmin = np.zeros(4,'float')
  for i in range(nat):
    # diagonal terms
    omega[0][0] += (co1[i][0] - co2[i][0])**2 + (co1[i][1] - co2[i][1])**2 + (co1[i][2] - co2[i][2])**2
    omega[1][1] += (co1[i][0] - co2[i][0])**2 + (co1[i][1] + co2[i][1])**2 + (co1[i][2] + co2[i][2])**2
    omega[2][2] += (co1[i][0] + co2[i][0])**2 + (co1[i][1] - co2[i][1])**2 + (co1[i][2] + co2[i][2])**2
    omega[3][3] += (co1[i][0] + co2[i][0])**2 + (co1[i][1] + co2[i][1])**2 + (co1[i][2] - co2[i][2])**2
    # off-diagonal terms
    omega[1][0] += (co1[i][1]+co2[i][1])*(co1[i][2]-co2[i][2]) - (co1[i][1]-co2[i][1])*(co1[i][2]+co2[i][2])
    omega[2][0] += (co1[i][2]+co2[i][2])*(co1[i][0]-co2[i][0]) - (co1[i][2]-co2[i][2])*(co1[i][0]+co2[i][0])
    omega[3][0] += (co1[i][0]+co2[i][0])*(co1[i][1]-co2[i][1]) - (co1[i][0]-co2[i][0])*(co1[i][1]+co2[i][1])
    omega[2][1] += (co1[i][0]-co2[i][0])*(co1[i][1]-co2[i][1]) - (co1[i][0]+co2[i][0])*(co1[i][1]+co2[i][1])
    omega[3][1] += (co1[i][0]-co2[i][0])*(co1[i][2]-co2[i][2]) - (co1[i][0]+co2[i][0])*(co1[i][2]+co2[i][2])
    omega[3][2] += (co1[i][1]-co2[i][1])*(co1[i][2]-co2[i][2]) - (co1[i][1]+co2[i][1])*(co1[i][2]+co2[i][2])
  #
  for i in range(4):
    for j in range(i+1,4):
      omega[i][j] = omega[j][i]
  #print('\nOmega matrix: \n',omega,'\n')
  eign,eigv = np.linalg.eig(omega)
  #print('\nEigen values: \n',eign)
  #print('\nEigen vectors: \n',eigv)
  imn = 0
  eign_mn = eign[0]
  imx = 0
  eign_mx = eign[0]
  for i in range(4):
    if(eign[i] < eign_mn):
      imn = i
      eign_mn = eign[i]
    if(eign[i] > eign_mx):
      imx = i
      eign_mx = eign[i]
  if(eign_mn < 1.e-6):
    print('Warning: eigen value close to or below 0: ',eign_mn)
  #print('min,max eign: ',eign[imn],eign[imx])
  rms_mn = math.sqrt(eign_mn/nat)
  rms_mx = math.sqrt(eign_mx/nat)
  #print('min, max rmsd possible by rotating: ',rms_mn,rms_mx)
  #print('Final RMS Deviation over selected set (A):: ',rms_mn)
  qmin[0] = - eigv[0][imn]
  for k in range(1,4):
    qmin[k] = eigv[k][imn]
  #print('min rmsd quaternion: ',qmin)
  return rms_mn,qmin

def qttomt(qt):
  """ convert quaternion to roation matrix"""
  rmt = np.zeros((3,3),'float')
  rmt[0][0] = qt[0]**2+qt[1]**2-qt[2]**2-qt[3]**2
  rmt[1][1] = qt[0]**2-qt[1]**2+qt[2]**2-qt[3]**2
  rmt[2][2] = qt[0]**2-qt[1]**2-qt[2]**2+qt[3]**2
  #
  rmt[1][0] = 2.*(qt[1]*qt[2]+qt[0]*qt[3])
  rmt[0][1] = 2.*(qt[1]*qt[2]-qt[0]*qt[3])
  #
  rmt[2][0] = 2.*(qt[1]*qt[3]-qt[0]*qt[2])
  rmt[0][2] = 2.*(qt[1]*qt[3]+qt[0]*qt[2])
  #
  rmt[2][1] = 2.*(qt[2]*qt[3]+qt[0]*qt[1])
  rmt[1][2] = 2.*(qt[2]*qt[3]-qt[0]*qt[1])
  trace = rmt[0][0] + rmt[1][1] + rmt[2][2]
  cosang = (trace - 1.)/2.
  angle = 180.*math.acos(cosang)/math.pi
  #print('angle: ',angle)
  return rmt,angle
#
#=====================================================
#main
#=====================================================
if(len(sys.argv) < 3):
  print('Usage: python super_auto.py ref_pdbfile mov_pdbfile')
  sys.exit()
#print(sys.argv)
#
# read pdb files
#
pdb_ref = pm.pdb_struct()
pdb_ref.readfile(sys.argv[1])
nref = pdb_ref.natom
print(sys.argv[1],' has ',nref,' atoms')
#
pdb_mov = pm.pdb_struct()
pdb_mov.readfile(sys.argv[2])
nmov = pdb_mov.natom
print(sys.argv[2],' has ',nmov,' atoms')
#
# write header for aligned file
#
pdb_out = open('super_auto_py.pdb','w')
head = 'REMARK  pdb file      ' + sys.argv[2] + '\n'
pdb_out.write(head)
head = 'REMARK  aligned with  ' + sys.argv[1] + '\n'
pdb_out.write(head)
#
# find matching atom pairs
#
nmatch = 0
indx1 = []
indx2 = []
used = []
for j in range(nmov):
  used.append(False)
for i in range(nref):
  for j in range(nmov):
    if(used[j]): continue # prevent using atom twice when atom names not unique
    if(i not in indx2):
      ifind = 1
      if(pdb_ref.name[i]   != pdb_mov.name[j]):   ifind = 0
      if(pdb_ref.res[i]    != pdb_mov.res[j]):    ifind = 0
      if(pdb_ref.resnum[i] != pdb_mov.resnum[j]): ifind = 0
      if(ifind == 1):
        nmatch += 1
        used[j] = True # prevent using atom twice when atom names not unique
        #print('matched ref ',i,' moving ',j)
        indx1.append(j)
        indx2.append(i)
        break
print('# of matched atom pairs: ',nmatch)
pdb_out.write('REMARK # of matched atom pairs: %6d\n'%(nmatch))
print('----')
#
# make working copy of coords
#
crd_ref = np.zeros((nmatch,3),'float')
crd_mov = np.zeros((nmatch,3),'float')
xyz = [0.,0.,0.]
#rmsd = 0.
for i in range(nmatch):
  iref = indx2[i]
  imov = indx1[i]
  print(imov,pdb_mov.name[imov],iref,pdb_ref.name[iref])
  for k in range(3):
    crd_ref[i][k]= pdb_ref.coords[iref][k]
    crd_mov[i][k]= pdb_mov.coords[imov][k]
    #del2 = (crd_mov[i][k] - crd_ref[i][k])**2
    #rmsd += del2
  #print(crd_ref[i],crd_mov[i],del2)
print('----')
#rmsd = math.sqrt(rmsd/nmatch)
#print('rmsd: ',rmsd) # check
#print(crd_ref)
#print(crd_mov)
#
# initial rmsdev, and centroids
#
rms = 0.
mad = 0.
cen_ref = [0.,0.,0.]
cen_mov = [0.,0.,0.]
trn_vec = [0.,0.,0.]
for i in range(nmatch):
  dist2 = 0.
  for k in range(3):
    cen_ref[k] += crd_ref[i][k]
    cen_mov[k] += crd_mov[i][k]
    dist2 += (crd_ref[i][k] - crd_mov[i][k])**2
    #rms += (crd_ref[i][k] - crd_mov[i][k])**2
  rms += dist2
  mad += math.sqrt(dist2)
rms = math.sqrt(rms/nmatch)
mad /= nmatch
print('Initial Rms Deviation, MAD over selected set (A):: %8.3f %8.3f'%(rms,mad))
pdb_out.write('REMARK Initial Rms Deviation, MAD over selected set (A):: %8.3f %8.3f\n'%(rms,mad))
for k in range(3):
  cen_ref[k] = cen_ref[k]/nmatch
  cen_mov[k] = cen_mov[k]/nmatch
  trn_vec[k] = cen_ref[k] - cen_mov[k]
#print('ref molc centroid: ',cen_ref)
#print('mov molc centroid: ',cen_mov)
#print('translation vector: ',trn_vec)
pdb_out.write('REMARK translation vector: %8.3f %8.3f %8.3f\n'%(trn_vec[0],trn_vec[1],trn_vec[2]))
trn_mag = math.sqrt(trn_vec[0]**2 + trn_vec[1]**2 + trn_vec[2]**2)
#
#  move molecules to the origin before finding rotation
#
rms = 0.
for i in range(nmatch):
  for k in range(3):
    crd_ref[i][k] -= cen_ref[k]
    crd_mov[i][k] -= cen_mov[k]
    rms += (crd_ref[i][k] - crd_mov[i][k])**2
rms = math.sqrt(rms/nmatch)
print('Rms Deviation after translation (A):: %8.3f'%(rms))
#
# find best rotation matrix
rms_mn,qmin = supq(crd_ref,crd_mov,nmatch)
#print('min rmsd quaternion: ',qmin)
#
# convert quaternion to rotation matrix and rotation magnitude
rotmat,angle = qttomt(qmin)
#print(rotmat)
print('Magnitude of Translation (A) & rotation (o): %8.2g %8.2f\n' % (trn_mag,angle))
pdb_out.write('REMARK Magnitude of Translation (A) & rotation (o): %8.2g %8.2f\n' % (trn_mag,angle))
#print('Final RMS Deviation over selected set (A):: ',rms_mn)
#pdb_out.write('REMARK Final Rms Deviation over selected set (A):: %8.3f\n'%(rms_mn))
#
# apply rotation to moving set so we can compute final MAD
# (and final rms again, but directly, not by minimum eigen value)
#
xyz1 = [0.,0.,0.]
rms_mn = 0.
mad_mn = 0.
for n in range(nmatch):
  for j in range(3):
    xyz1[j] = 0.
    for k in range(3):
      xyz1[j] += rotmat[j][k]*crd_mov[n][k]
  dist2 = 0.
  for k in range(3):
    dist2 += (crd_ref[n][k] - xyz1[k])**2
  rms_mn += dist2
  mad_mn += math.sqrt(dist2)
rms_mn = math.sqrt(rms_mn/nmatch)
mad_mn /= nmatch
print('Final Rms Deviation, MAD over selected set (A):: %8.3f %8.3f'%(rms_mn,mad_mn))
pdb_out.write('REMARK Final Rms Deviation, MAD over selected set (A):: %8.3f %8.3f\n'%(rms_mn,mad_mn))
#
# apply rotation and translation to entire moving set and write out new pdb file
#
for n in range(nmov):
  for k in range(3):
    xyz[k] = pdb_mov.coords[n][k] - cen_mov[k]
  for j in range(3):
    xyz1[j] = 0.
    for k in range(3):
      xyz1[j] += rotmat[j][k]*xyz[k]
  for k in range(3):
    pdb_mov.coords[n][k] =xyz1[k] +  cen_ref[k]
pm.pdb_write(pdb_out,pdb_mov)
pdb_out.close()


from django.shortcuts import render
from django.conf import settings
from django.views.decorators.cache import cache_page
from django.http import JsonResponse
from django.db.models import F

from protwis.context_processors import site_title
from news.models import News
from common.models import ReleaseNotes, ReleaseStatistics, Citation
from protein.models import Protein, ProteinCouplings
from structure.models import StructureComplexModel
from contactnetwork.models import InteractingResiduePair
from signprot.models import SignprotComplex, SignprotStructure
from googleapiclient.discovery import build
from oauth2client.service_account import ServiceAccountCredentials

@cache_page(60 * 60 * 24)
def index(request):
    request.session.flush()

    context = {}

    # title of the page
    context['site_title'] = site_title(request)['site_title']#settings.SITE_TITLE
    context['documentation_url'] = settings.DOCUMENTATION_URL

    # analytics
    context['google_analytics_key'] = settings.GOOGLE_ANALYTICS_KEY

    if settings.GOOGLE_ANALYTICS_API:
        # Based on https://developers.google.com/analytics/devguides/reporting/core/v3/quickstart/service-py
        # from googleapiclient.discovery import build
        # from oauth2client.service_account import ServiceAccountCredentials
        # Define the auth scopes to request.
        scope = 'https://www.googleapis.com/auth/analytics.readonly'
        key_file_location = settings.GOOGLE_ANALYTICS_API

        # Fetched from API -- look at original code to re-fetch if changes.
        profile_id = '77082434'

        # Authenticate and construct service.
        credentials = ServiceAccountCredentials.from_json_keyfile_name(
                key_file_location, scopes=[scope])
        # Build the service object.
        service = build('analytics', 'v3', credentials=credentials)

        users_year = service.data().ga().get(ids='ga:' + profile_id, start_date='365daysAgo', end_date='today', metrics='ga:users').execute().get('rows')[0][0]
        users_month = service.data().ga().get(ids='ga:' + profile_id, start_date='30daysAgo', end_date='today', metrics='ga:users').execute().get('rows')[0][0]

        context['users'] = "GPCRdb, GproteinDb, and ArrestinDb had {:,} different users since this date last year and {:,} users in the last 30 days (Google Analytics).".format(int(users_year), int(users_month))

    # get news
    context['news'] = News.objects.order_by('-date').all()[:3]

    # get release notes
    try:
        context['release_notes'] = ReleaseNotes.objects.all()[0]
        rel_stats = list(ReleaseStatistics.objects.filter(release=context['release_notes'])\
                    .values_list("statistics_type__name", "value"))

        # Create dictionary and process part of the results
        context['release_statistics'] = []
        if context['site_title']=='GproteinDb':
            context['release_statistics'].append({"statistics_type": "" + "Human G proteins" + "", "value": "" + "{:,}".format(Protein.objects.filter(family__parent__parent__name='Alpha', species__common_name='Human', accession__isnull=False).count()) + ""})
            context['release_statistics'].append({"statistics_type": "" + "Species orthologs" + "", "value": "" + "{:,}".format(Protein.objects.filter(family__parent__parent__name='Alpha', accession__isnull=False).count()) + ""})

            context['release_statistics'].append({"statistics_type": "Experimental structures", "value" : ""})
            signcomp = SignprotComplex.objects.all()
            context['release_statistics'].append({"statistics_type": "" + "G proteins" + "", "value": "" + "{:,}".format(signcomp.count()+SignprotStructure.objects.all().count()) + ""})
            context['release_statistics'].append({"statistics_type": "" + "GPCR-G protein complexes" + "", "value": "" + "{:,}".format(SignprotComplex.objects.all().count()) + ""})

            context['release_statistics'].append({"statistics_type": "Structure models", "value" : ""})
            context['release_statistics'].append({"statistics_type": "" + "GPCR-G protein complexes" + "", "value": "" + "{:,}".format(StructureComplexModel.objects.all().count()-SignprotComplex.objects.filter(structure__refined=True).count()) + ""})
            context['release_statistics'].append({"statistics_type": "" + "Refined complex structures" + "", "value": "" + "{:,}".format(signcomp.filter(structure__refined=True).count()) + ""})

            context['release_statistics'].append({"statistics_type": "Structure interactions", "value" : ""})
            interface_interactions_count = InteractingResiduePair.objects.filter(referenced_structure__in=signcomp.values_list('structure', flat=True)).exclude(res1__protein_conformation_id=F('res2__protein_conformation_id')).count()
            context['release_statistics'].append({"statistics_type": "" + "GPCR-G protein interface" + "", "value": "" + "{:,}".format(interface_interactions_count) + ""})

            context['release_statistics'].append({"statistics_type": "Couplings", "value" : ""})
            context['release_statistics'].append({"statistics_type": "" + "GPCR-G protein coupling" + "", "value": "" + "{:,}".format(ProteinCouplings.objects.all().count()) + ""})

            context['release_statistics'].append({"statistics_type": "Mutations", "value" : ""})
            context['release_statistics'].append({"statistics_type": "" + "Interface mutations" + "", "value": "" + "{:,}".format(54) + ""})
        else:
            rename_dictionary = {"Exp. GPCR structures" : "GPCRs", "Exp. Gprotein structures" : "G proteins", "GPCR structure models": "GPCRs", "GPCR-G protein structure models": "GPCR-G protein complexes", "Refined GPCR structures": "Refined GPCR structures"}
            first_struct = -1
            first_model = -1
            count = 0
            for entry in rel_stats:
                if first_struct < 0 and "Exp." in entry[0]:
                    first_struct = count
                elif first_model < 0 and "model" in entry[0]:
                    first_model = count

                if entry[0] in rename_dictionary:
                    context['release_statistics'].append({"statistics_type": "" + rename_dictionary[entry[0]] + "", "value": "" + "{:,}".format(entry[1]) + ""})
                else:
                    context['release_statistics'].append({"statistics_type": "" + entry[0] + "", "value": "" + "{:,}".format(entry[1]) + ""})
                count += 1

            # Adjusted formatting for release notes
            context['release_statistics'].insert(first_model, {"statistics_type": "Structure models", "value" : ""})
            context['release_statistics'].insert(first_struct, {"statistics_type": "Experimental structures", "value" : ""})

    except IndexError:
        context['release_notes'] = ''
        context['release_statistics'] = []

    return render(request, 'home/index.html', context)

@cache_page(60 * 60 * 24 * 7)
def citations_json(request):
    context = {}
    citations_q = Citation.objects.all().values_list("url", "video", "docs", "main", "page_name", "publication__title", "publication__authors", "publication__year", "publication__reference",
                                                     "publication__journal__name", "publication__web_link__index").order_by("-publication__year", "page_name")
    response = JsonResponse(list(citations_q), safe=False)
    return response


import pygame

# It seems that up to USEREVENT + 3 are already taken.
# Anyway, an event for server announces.

# It's about time for the server to advertise its presence.
E_ANNOUNCE = pygame.USEREVENT + 4
# A state change has occurred.
E_STATE = pygame.USEREVENT + 5

# Player in the lobby.
S_LOBBY = 0
# Player creating a new server.
S_CREATE = 1
# Player joining an existing game.
S_JOIN = 2
# Player in the game.
S_GAME = 3
# Player in the game, placing ships.
S_GAME_PLACING = 4
# Player in the game, waiting for their turn.
S_GAME_WAITING = 5
# Player's turn, cherry-picking the tile to bomb.
S_GAME_SHOOTING = 6

S_GAME_LAST = 6


"""!doge city: Watchdog info for all hosts
!such status <host>: Watchdog info for host
!watchdog log <host>: tails the watchdog log for that host
!orphans: Shows latest versions, and hosts that do not conform
"""

import subprocess
import re
import requests
import shlex
from requests.auth import HTTPBasicAuth
from limbo import conf
from collections import defaultdict

nagios_user = conf.nagios_user
nagios_pass = conf.nagios_pass

DB = 'mysql -A -u%s -p%s -hmysql-budget-slave.prod.adnxs.net -D optimization' % (conf.db_user, conf.db_pass)

def watchdog_status(body):
    reg = re.compile('!such[\s|_]status (.*)', re.IGNORECASE)
    match = reg.match(body)
    if not match:
        return False
    host = match.group(1)
    try:
        int(host)
        host = "{}.bm-etl-optimization.prod.lax1".format(host)
    except ValueError:
        pass
    cmd = 'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no %s "cat /var/run/watchdog.status"' % host
    stat = subprocess.check_output(cmd, shell=True)
    return stat

def all_watchdog_status(body):
    reg = re.compile('!doge[\s|_]city', re.IGNORECASE)
    match = reg.match(body)
    if not match:
        return False
    url = "https://multimonitor.nym2.adnxs.net/check_mk/view.py?service=etl-optimization-watchdog&opthostgroup=&host=&view_name=servicedesc&st0=on&st1=on&st2=on&st3=on&stp=on&output_format=python"
    response = requests.get(url, auth=HTTPBasicAuth(nagios_user, nagios_pass), verify=False)
    data = eval(response.text)
    output = ""
    for i in data:
        output += "Host: {h}\tStatus: {s}\tDoge: {d}\n".format(h=i[1], s=i[0], d=i[2])
    return "```%s```" % output

def watchdog_log(body):
    reg = re.compile('!watchdog log (.*)', re.IGNORECASE)
    match = reg.match(body)
    if not match:
        return False
    host = match.group(1)
    try:
        int(host)
        host = "{}.bm-etl-optimization.prod.lax1".format(host)
    except:
        pass
    cmd = 'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no %s "tail -n 15 /var/log/adnexus/watchdog.log"' % host
    stat = subprocess.check_output(shlex.split(cmd))
    return "\n" + stat

def orphans_get_lazy_hosts():
    query = """select distinct host
            from work_queue_task
            where host not in (select t.host
            from optimization.work_queue_task t
            join work_queue_job_cache jc
            on jc.deleted = 0 and t.job_id = jc.job_id
            WHERE t.status = 'running') order by 1
            ;"""

    command_str = 'echo "' + query + '" | ' + DB
    result = subprocess.check_output(command_str, shell=True)
    if not result:
        return []
    else:
        return result.split('\n')[1:]

def orphans(body):
    if not body.startswith('!orphans'):
        return False

    url = "https://multimonitor.nym2.adnxs.net/check_mk/view.py?service=etl-optimization-watchdog&opthostgroup=&host=&view_name=servicedesc&st0=on&st1=on&st2=on&st3=on&stp=on&output_format=python"
    response = requests.get(url, auth=HTTPBasicAuth(nagios_user, nagios_pass), verify=False)
    data = eval(response.text)
    output = ""
    max_version = ""
    state_set = set()
    # map of maps {version -> {state -> [(appname, host)]}}
    version_state_host_list_map = defaultdict(lambda: defaultdict(list))
    for i in data:
        # status = i[0]
        host = i[1]
        message = i[2]
        matches = re.finditer(r"(?P<appname>\S*)\[pid:(\S*), version:(?P<version>\S*), state:(?P<state>\S*)]", \
                                message, re.IGNORECASE)
        for match in matches:
            appname = match.group('appname')
            version = match.group('version')
            state = match.group('state')
            state_set.add(state)
            version_state_host_list_map[version][state].append((appname, host))

            if version > max_version:
                max_version = version

    output += "Latest version: {}\n".format(max_version)
    if 'RESTARTING' not in state_set and len(version_state_host_list_map) == 1:
        output += "No orphans!"
    else:
        output += "\n"

    lazy_host_list = orphans_get_lazy_hosts()

    for version, state_host_list_map in sorted(version_state_host_list_map.iteritems(), reverse=True):
        version_output = "\nVersion: {}\n".format(version)
        state_output_list = []
        for state, appname_host_list in sorted(state_host_list_map.iteritems()):
            state_output = "\tState: {}".format(state)
            if version != max_version or state == 'RESTARTING':
                worker_bees = []
                funemployed = []
                for appname, host in appname_host_list:
                    appname_host_str = "\t\t\t{0:25} {1}".format(appname, host)
                    if host in lazy_host_list:
                        funemployed.append(appname_host_str)
                    else:
                        worker_bees.append(appname_host_str)

                init_string = "\t\t\t{0:25} {1}\n".format('Application', 'Host')
                if worker_bees:
                    worker_str = init_string + "\n".join(worker_bees)
                    state_output += "\n\t\tWu-Tang Killah Bees:\n{}".format(worker_str)
                if funemployed:
                    lazy_str = init_string + "\n".join(funemployed)
                    state_output += "\n\t\tLazy Bums:\n{}".format(lazy_str)
                state_output_list.append(state_output)

        if state_output_list:
            output += version_output
            output += "\n".join(state_output_list) + "\n"
    return "```%s```" % output

def on_message(msg, server):
    text = msg.get("text", "")
    return watchdog_status(text) or all_watchdog_status(text) or orphans(text) or watchdog_log(text)