<commit_before># -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt

from __future__ import unicode_literals
import frappe, json
from frappe import _
from frappe.model.mapper import get_mapped_doc
from frappe.utils import get_url, cint
from frappe.utils.user import get_user_fullname
from frappe.utils.print_format import download_pdf
from frappe.desk.form.load import get_attachments
from frappe.core.doctype.communication.email import make
from erpnext.accounts.party import get_party_account_currency, get_party_details
from erpnext.stock.doctype.material_request.material_request import set_missing_values
from erpnext.controllers.buying_controller import BuyingController
from erpnext.buying.utils import validate_for_items

STANDARD_USERS = ("Guest", "Administrator")

class RequestforQuotation(BuyingController):
	def validate(self):
		self.validate_duplicate_supplier()
		self.validate_supplier_list()
		validate_for_items(self)
		self.update_email_id()

	def validate_duplicate_supplier(self):
		supplier_list = [d.supplier for d in self.suppliers]
		if len(supplier_list) != len(set(supplier_list)):
			frappe.throw(_("Same supplier has been entered multiple times"))

	def validate_supplier_list(self):
		for d in self.suppliers:
			prevent_rfqs = frappe.db.get_value("Supplier", d.supplier, 'prevent_rfqs')
			if prevent_rfqs:
				standing = frappe.db.get_value("Supplier Scorecard",d.supplier, 'status')
				frappe.throw(_("RFQs are not allowed for {0} due to a scorecard standing of {1}").format(d.supplier, standing))
			warn_rfqs = frappe.db.get_value("Supplier", d.supplier, 'warn_rfqs')
			if warn_rfqs:
				standing = frappe.db.get_value("Supplier Scorecard",d.supplier, 'status')
				frappe.msgprint(_("{0} currently has a {1} Supplier Scorecard standing, and RFQs to this supplier should be issued with caution.").format(d.supplier, standing), title=_("Caution"), indicator='orange')

	def update_email_id(self):
		for rfq_supplier in self.suppliers:
			if not rfq_supplier.email_id:
				rfq_supplier.email_id = frappe.db.get_value("Contact", rfq_supplier.contact, "email_id")

	def validate_email_id(self, args):
		if not args.email_id:
			frappe.throw(_("Row {0}: For supplier {0} Email Address is required to send email").format(args.idx, args.supplier))

	def on_submit(self):
		frappe.db.set(self, 'status', 'Submitted')
		for supplier in self.suppliers:
			supplier.email_sent = 0
			supplier.quote_status = 'Pending'

	def on_cancel(self):
		frappe.db.set(self, 'status', 'Cancelled')

	def send_to_supplier(self):
		for rfq_supplier in self.suppliers:
			if rfq_supplier.send_email:
				self.validate_email_id(rfq_supplier)

				# make new user if required
				update_password_link = self.update_supplier_contact(rfq_supplier, self.get_link())

				self.update_supplier_part_no(rfq_supplier)
				self.supplier_rfq_mail(rfq_supplier, update_password_link, self.get_link())
				rfq_supplier.email_sent = 1
				rfq_supplier.save()

	def get_link(self):
		# RFQ link for supplier portal
		return get_url("/rfq/" + self.name)

	def update_supplier_part_no(self, args):
		self.vendor = args.supplier
		for item in self.items:
			item.supplier_part_no = frappe.db.get_value('Item Supplier',
				{'parent': item.item_code, 'supplier': args.supplier}, 'supplier_part_no')

	def update_supplier_contact(self, rfq_supplier, link):
		'''Create a new user for the supplier if not set in contact'''
		update_password_link = ''

		if frappe.db.exists("User", rfq_supplier.email_id):
			user = frappe.get_doc("User", rfq_supplier.email_id)
		else:
			user, update_password_link = self.create_user(rfq_supplier, link)

		self.update_contact_of_supplier(rfq_supplier, user)

		return update_password_link

	def update_contact_of_supplier(self, rfq_supplier, user):
		if rfq_supplier.contact:
			contact = frappe.get_doc("Contact", rfq_supplier.contact)
		else:
			contact = frappe.new_doc("Contact")
			contact.first_name = rfq_supplier.supplier_name or rfq_supplier.supplier
			contact.append('links', {
				'link_doctype': 'Supplier',
				'link_name': rfq_supplier.supplier
			})

		if not contact.email_id and not contact.user:
			contact.email_id = user.name
			contact.user = user.name

		contact.save(ignore_permissions=True)

	def create_user(self, rfq_supplier, link):
		user = frappe.get_doc({
			'doctype': 'User',
			'send_welcome_email': 0,
			'email': rfq_supplier.email_id,
			'first_name': rfq_supplier.supplier_name or rfq_supplier.supplier,
			'user_type': 'Website User',
			'redirect_url': link
		})
		user.save(ignore_permissions=True)
		update_password_link = user.reset_password()

		return user, update_password_link

	def supplier_rfq_mail(self, data, update_password_link, rfq_link):
		full_name = get_user_fullname(frappe.session['user'])
		if full_name == "Guest":
			full_name = "Administrator"

		args = {
			'update_password_link': update_password_link,
			'message': frappe.render_template(self.message_for_supplier, data.as_dict()),
			'rfq_link': rfq_link,
			'user_fullname': full_name
		}

		subject = _("Request for Quotation")
		template = "templates/emails/request_for_quotation.html"
		sender = frappe.session.user not in STANDARD_USERS and frappe.session.user or None
		message = frappe.get_template(template).render(args)
		attachments = self.get_attachments()

		self.send_email(data, sender, subject, message, attachments)

	def send_email(self, data, sender, subject, message, attachments):
		make(subject = subject, content=message,recipients=data.email_id,
			sender=sender,attachments = attachments, send_email=True,
		     	doctype=self.doctype, name=self.name)["name"]

		frappe.msgprint(_("Email sent to supplier {0}").format(data.supplier))

	def get_attachments(self):
		attachments = [d.name for d in get_attachments(self.doctype, self.name)]
		attachments.append(frappe.attach_print(self.doctype, self.name, doc=self))
		return attachments

	def update_rfq_supplier_status(self, sup_name=None):
		for supplier in self.suppliers:
			if sup_name == None or supplier.supplier == sup_name:
				if supplier.quote_status != _('No Quote'):
					quote_status = _('Received')
					for item in self.items:
						sqi_count = frappe.db.sql("""
							SELECT
								COUNT(sqi.name) as count
							FROM
								`tabSupplier Quotation Item` as sqi,
								`tabSupplier Quotation` as sq
							WHERE sq.supplier = %(supplier)s
								AND sqi.docstatus = 1
								AND sqi.request_for_quotation_item = %(rqi)s
								AND sqi.parent = sq.name""",
							{"supplier": supplier.supplier, "rqi": item.name}, as_dict=1)[0]
						if (sqi_count.count) == 0:
							quote_status = _('Pending')
					supplier.quote_status = quote_status

@frappe.whitelist()
def send_supplier_emails(rfq_name):
	check_portal_enabled('Request for Quotation')
	rfq = frappe.get_doc("Request for Quotation", rfq_name)
	if rfq.docstatus==1:
		rfq.send_to_supplier()

def check_portal_enabled(reference_doctype):
	if not frappe.db.get_value('Portal Menu Item',
		{'reference_doctype': reference_doctype}, 'enabled'):
		frappe.throw(_("Request for Quotation is disabled to access from portal, for more check portal settings."))

def get_list_context(context=None):
	from erpnext.controllers.website_list_for_contact import get_list_context
	list_context = get_list_context(context)
	list_context["show_sidebar"] = True
	return list_context

def get_supplier_contacts(doctype, txt, searchfield, start, page_len, filters):
	return frappe.db.sql(""" select `tabContact`.name from `tabContact`, `tabDynamic Link`
		where `tabDynamic Link`.link_doctype = 'Supplier' and (`tabDynamic Link`.link_name = %(name)s
		or `tabDynamic Link`.link_name like %(txt)s) and `tabContact`.name = `tabDynamic Link`.parent
		limit %(start)s, %(page_len)s""", {"start": start, "page_len":page_len, "txt": "%%%s%%" % txt, "name": filters.get('supplier')})

# This method is used to make supplier quotation from material request form.
@frappe.whitelist()
def make_supplier_quotation(source_name, for_supplier, target_doc=None):
	def postprocess(source, target_doc):
		target_doc.supplier = for_supplier
		args = get_party_details(for_supplier, party_type="Supplier", ignore_permissions=True)
		target_doc.currency = args.currency or get_party_account_currency('Supplier', for_supplier, source.company)
		target_doc.buying_price_list = args.buying_price_list or frappe.db.get_value('Buying Settings', None, 'buying_price_list')
		set_missing_values(source, target_doc)

	doclist = get_mapped_doc("Request for Quotation", source_name, {
		"Request for Quotation": {
			"doctype": "Supplier Quotation",
			"validation": {
				"docstatus": ["=", 1]
			}
		},
		"Request for Quotation Item": {
			"doctype": "Supplier Quotation Item",
			"field_map": {
				"name": "request_for_quotation_item",
				"parent": "request_for_quotation"
			},
		}
	}, target_doc, postprocess)

	return doclist

# This method is used to make supplier quotation from supplier's portal.
@frappe.whitelist()
def create_supplier_quotation(doc):
	if isinstance(doc, basestring):
		doc = json.loads(doc)

	try:
		sq_doc = frappe.get_doc({
			"doctype": "Supplier Quotation",
			"supplier": doc.get('supplier'),
			"terms": doc.get("terms"),
			"company": doc.get("company"),
			"currency": doc.get('currency') or get_party_account_currency('Supplier', doc.get('supplier'), doc.get('company')),
			"buying_price_list": doc.get('buying_price_list') or frappe.db.get_value('Buying Settings', None, 'buying_price_list')
		})
		add_items(sq_doc, doc.get('supplier'), doc.get('items'))
		sq_doc.flags.ignore_permissions = True
		sq_doc.run_method("set_missing_values")
		sq_doc.save()
		frappe.msgprint(_("Supplier Quotation {0} created").format(sq_doc.name))
		return sq_doc.name
	except Exception:
		return None

def add_items(sq_doc, supplier, items):
	for data in items:
		if data.get("qty") > 0:
			if isinstance(data, dict):
				data = frappe._dict(data)

			create_rfq_items(sq_doc, supplier, data)

def create_rfq_items(sq_doc, supplier, data):
	sq_doc.append('items', {
		"item_code": data.item_code,
		"item_name": data.item_name,
		"description": data.description,
		"qty": data.qty,
		"rate": data.rate,
		"supplier_part_no": frappe.db.get_value("Item Supplier", {'parent': data.item_code, 'supplier': supplier}, "supplier_part_no"),
		"warehouse": data.warehouse or '',
		"request_for_quotation_item": data.name,
		"request_for_quotation": data.parent
	})

@frappe.whitelist()
def get_pdf(doctype, name, supplier_idx):
	doc = get_rfq_doc(doctype, name, supplier_idx)
	if doc:
		download_pdf(doctype, name, doc=doc)

def get_rfq_doc(doctype, name, supplier_idx):
	if cint(supplier_idx):
		doc = frappe.get_doc(doctype, name)
		args = doc.get('suppliers')[cint(supplier_idx) - 1]
		doc.update_supplier_part_no(args)
		return doc

@frappe.whitelist()
def get_item_from_material_requests_based_on_supplier(source_name, target_doc = None):
	mr_items_list = frappe.db.sql("""
		SELECT
			mr.name, mr_item.item_code
		FROM
			`tabItem` as item,
			`tabItem Supplier` as item_supp,
			`tabMaterial Request Item` as mr_item,
			`tabMaterial Request`  as mr
		WHERE item_supp.supplier = %(supplier)s
			AND item.name = item_supp.parent
			AND mr_item.parent = mr.name
			AND mr_item.item_code = item.name
			AND mr.status != "Stopped"
			AND mr.material_request_type = "Purchase"
			AND mr.docstatus = 1
			AND mr.per_ordered < 99.99""", {"supplier": source_name}, as_dict=1)

	material_requests = {}
	for d in mr_items_list:
		material_requests.setdefault(d.name, []).append(d.item_code)

	for mr, items in material_requests.items():
		target_doc = get_mapped_doc("Material Request", mr, {
			"Material Request": {
				"doctype": "Request for Quotation",
				"validation": {
					"docstatus": ["=", 1],
					"material_request_type": ["=", "Purchase"],
				}
			},
			"Material Request Item": {
				"doctype": "Request for Quotation Item",
				"condition": lambda row: row.item_code in items,
				"field_map": [
					["name", "material_request_item"],
					["parent", "material_request"],
					["uom", "uom"]
				]
			}
		}, target_doc)

	return target_doc
<commit_msg>[Minor] Title added to rfq web view (#10454)<commit_after># -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt

from __future__ import unicode_literals
import frappe, json
from frappe import _
from frappe.model.mapper import get_mapped_doc
from frappe.utils import get_url, cint
from frappe.utils.user import get_user_fullname
from frappe.utils.print_format import download_pdf
from frappe.desk.form.load import get_attachments
from frappe.core.doctype.communication.email import make
from erpnext.accounts.party import get_party_account_currency, get_party_details
from erpnext.stock.doctype.material_request.material_request import set_missing_values
from erpnext.controllers.buying_controller import BuyingController
from erpnext.buying.utils import validate_for_items

STANDARD_USERS = ("Guest", "Administrator")

class RequestforQuotation(BuyingController):
	def validate(self):
		self.validate_duplicate_supplier()
		self.validate_supplier_list()
		validate_for_items(self)
		self.update_email_id()

	def validate_duplicate_supplier(self):
		supplier_list = [d.supplier for d in self.suppliers]
		if len(supplier_list) != len(set(supplier_list)):
			frappe.throw(_("Same supplier has been entered multiple times"))

	def validate_supplier_list(self):
		for d in self.suppliers:
			prevent_rfqs = frappe.db.get_value("Supplier", d.supplier, 'prevent_rfqs')
			if prevent_rfqs:
				standing = frappe.db.get_value("Supplier Scorecard",d.supplier, 'status')
				frappe.throw(_("RFQs are not allowed for {0} due to a scorecard standing of {1}").format(d.supplier, standing))
			warn_rfqs = frappe.db.get_value("Supplier", d.supplier, 'warn_rfqs')
			if warn_rfqs:
				standing = frappe.db.get_value("Supplier Scorecard",d.supplier, 'status')
				frappe.msgprint(_("{0} currently has a {1} Supplier Scorecard standing, and RFQs to this supplier should be issued with caution.").format(d.supplier, standing), title=_("Caution"), indicator='orange')

	def update_email_id(self):
		for rfq_supplier in self.suppliers:
			if not rfq_supplier.email_id:
				rfq_supplier.email_id = frappe.db.get_value("Contact", rfq_supplier.contact, "email_id")

	def validate_email_id(self, args):
		if not args.email_id:
			frappe.throw(_("Row {0}: For supplier {0} Email Address is required to send email").format(args.idx, args.supplier))

	def on_submit(self):
		frappe.db.set(self, 'status', 'Submitted')
		for supplier in self.suppliers:
			supplier.email_sent = 0
			supplier.quote_status = 'Pending'

	def on_cancel(self):
		frappe.db.set(self, 'status', 'Cancelled')

	def send_to_supplier(self):
		for rfq_supplier in self.suppliers:
			if rfq_supplier.send_email:
				self.validate_email_id(rfq_supplier)

				# make new user if required
				update_password_link = self.update_supplier_contact(rfq_supplier, self.get_link())

				self.update_supplier_part_no(rfq_supplier)
				self.supplier_rfq_mail(rfq_supplier, update_password_link, self.get_link())
				rfq_supplier.email_sent = 1
				rfq_supplier.save()

	def get_link(self):
		# RFQ link for supplier portal
		return get_url("/rfq/" + self.name)

	def update_supplier_part_no(self, args):
		self.vendor = args.supplier
		for item in self.items:
			item.supplier_part_no = frappe.db.get_value('Item Supplier',
				{'parent': item.item_code, 'supplier': args.supplier}, 'supplier_part_no')

	def update_supplier_contact(self, rfq_supplier, link):
		'''Create a new user for the supplier if not set in contact'''
		update_password_link = ''

		if frappe.db.exists("User", rfq_supplier.email_id):
			user = frappe.get_doc("User", rfq_supplier.email_id)
		else:
			user, update_password_link = self.create_user(rfq_supplier, link)

		self.update_contact_of_supplier(rfq_supplier, user)

		return update_password_link

	def update_contact_of_supplier(self, rfq_supplier, user):
		if rfq_supplier.contact:
			contact = frappe.get_doc("Contact", rfq_supplier.contact)
		else:
			contact = frappe.new_doc("Contact")
			contact.first_name = rfq_supplier.supplier_name or rfq_supplier.supplier
			contact.append('links', {
				'link_doctype': 'Supplier',
				'link_name': rfq_supplier.supplier
			})

		if not contact.email_id and not contact.user:
			contact.email_id = user.name
			contact.user = user.name

		contact.save(ignore_permissions=True)

	def create_user(self, rfq_supplier, link):
		user = frappe.get_doc({
			'doctype': 'User',
			'send_welcome_email': 0,
			'email': rfq_supplier.email_id,
			'first_name': rfq_supplier.supplier_name or rfq_supplier.supplier,
			'user_type': 'Website User',
			'redirect_url': link
		})
		user.save(ignore_permissions=True)
		update_password_link = user.reset_password()

		return user, update_password_link

	def supplier_rfq_mail(self, data, update_password_link, rfq_link):
		full_name = get_user_fullname(frappe.session['user'])
		if full_name == "Guest":
			full_name = "Administrator"

		args = {
			'update_password_link': update_password_link,
			'message': frappe.render_template(self.message_for_supplier, data.as_dict()),
			'rfq_link': rfq_link,
			'user_fullname': full_name
		}

		subject = _("Request for Quotation")
		template = "templates/emails/request_for_quotation.html"
		sender = frappe.session.user not in STANDARD_USERS and frappe.session.user or None
		message = frappe.get_template(template).render(args)
		attachments = self.get_attachments()

		self.send_email(data, sender, subject, message, attachments)

	def send_email(self, data, sender, subject, message, attachments):
		make(subject = subject, content=message,recipients=data.email_id,
			sender=sender,attachments = attachments, send_email=True,
		     	doctype=self.doctype, name=self.name)["name"]

		frappe.msgprint(_("Email sent to supplier {0}").format(data.supplier))

	def get_attachments(self):
		attachments = [d.name for d in get_attachments(self.doctype, self.name)]
		attachments.append(frappe.attach_print(self.doctype, self.name, doc=self))
		return attachments

	def update_rfq_supplier_status(self, sup_name=None):
		for supplier in self.suppliers:
			if sup_name == None or supplier.supplier == sup_name:
				if supplier.quote_status != _('No Quote'):
					quote_status = _('Received')
					for item in self.items:
						sqi_count = frappe.db.sql("""
							SELECT
								COUNT(sqi.name) as count
							FROM
								`tabSupplier Quotation Item` as sqi,
								`tabSupplier Quotation` as sq
							WHERE sq.supplier = %(supplier)s
								AND sqi.docstatus = 1
								AND sqi.request_for_quotation_item = %(rqi)s
								AND sqi.parent = sq.name""",
							{"supplier": supplier.supplier, "rqi": item.name}, as_dict=1)[0]
						if (sqi_count.count) == 0:
							quote_status = _('Pending')
					supplier.quote_status = quote_status

@frappe.whitelist()
def send_supplier_emails(rfq_name):
	check_portal_enabled('Request for Quotation')
	rfq = frappe.get_doc("Request for Quotation", rfq_name)
	if rfq.docstatus==1:
		rfq.send_to_supplier()

def check_portal_enabled(reference_doctype):
	if not frappe.db.get_value('Portal Menu Item',
		{'reference_doctype': reference_doctype}, 'enabled'):
		frappe.throw(_("Request for Quotation is disabled to access from portal, for more check portal settings."))

def get_list_context(context=None):
	from erpnext.controllers.website_list_for_contact import get_list_context
	list_context = get_list_context(context)
	list_context["show_sidebar"] = True
	list_context["title"] = "Request for Quotation"
	return list_context

def get_supplier_contacts(doctype, txt, searchfield, start, page_len, filters):
	return frappe.db.sql(""" select `tabContact`.name from `tabContact`, `tabDynamic Link`
		where `tabDynamic Link`.link_doctype = 'Supplier' and (`tabDynamic Link`.link_name = %(name)s
		or `tabDynamic Link`.link_name like %(txt)s) and `tabContact`.name = `tabDynamic Link`.parent
		limit %(start)s, %(page_len)s""", {"start": start, "page_len":page_len, "txt": "%%%s%%" % txt, "name": filters.get('supplier')})

# This method is used to make supplier quotation from material request form.
@frappe.whitelist()
def make_supplier_quotation(source_name, for_supplier, target_doc=None):
	def postprocess(source, target_doc):
		target_doc.supplier = for_supplier
		args = get_party_details(for_supplier, party_type="Supplier", ignore_permissions=True)
		target_doc.currency = args.currency or get_party_account_currency('Supplier', for_supplier, source.company)
		target_doc.buying_price_list = args.buying_price_list or frappe.db.get_value('Buying Settings', None, 'buying_price_list')
		set_missing_values(source, target_doc)

	doclist = get_mapped_doc("Request for Quotation", source_name, {
		"Request for Quotation": {
			"doctype": "Supplier Quotation",
			"validation": {
				"docstatus": ["=", 1]
			}
		},
		"Request for Quotation Item": {
			"doctype": "Supplier Quotation Item",
			"field_map": {
				"name": "request_for_quotation_item",
				"parent": "request_for_quotation"
			},
		}
	}, target_doc, postprocess)

	return doclist

# This method is used to make supplier quotation from supplier's portal.
@frappe.whitelist()
def create_supplier_quotation(doc):
	if isinstance(doc, basestring):
		doc = json.loads(doc)

	try:
		sq_doc = frappe.get_doc({
			"doctype": "Supplier Quotation",
			"supplier": doc.get('supplier'),
			"terms": doc.get("terms"),
			"company": doc.get("company"),
			"currency": doc.get('currency') or get_party_account_currency('Supplier', doc.get('supplier'), doc.get('company')),
			"buying_price_list": doc.get('buying_price_list') or frappe.db.get_value('Buying Settings', None, 'buying_price_list')
		})
		add_items(sq_doc, doc.get('supplier'), doc.get('items'))
		sq_doc.flags.ignore_permissions = True
		sq_doc.run_method("set_missing_values")
		sq_doc.save()
		frappe.msgprint(_("Supplier Quotation {0} created").format(sq_doc.name))
		return sq_doc.name
	except Exception:
		return None

def add_items(sq_doc, supplier, items):
	for data in items:
		if data.get("qty") > 0:
			if isinstance(data, dict):
				data = frappe._dict(data)

			create_rfq_items(sq_doc, supplier, data)

def create_rfq_items(sq_doc, supplier, data):
	sq_doc.append('items', {
		"item_code": data.item_code,
		"item_name": data.item_name,
		"description": data.description,
		"qty": data.qty,
		"rate": data.rate,
		"supplier_part_no": frappe.db.get_value("Item Supplier", {'parent': data.item_code, 'supplier': supplier}, "supplier_part_no"),
		"warehouse": data.warehouse or '',
		"request_for_quotation_item": data.name,
		"request_for_quotation": data.parent
	})

@frappe.whitelist()
def get_pdf(doctype, name, supplier_idx):
	doc = get_rfq_doc(doctype, name, supplier_idx)
	if doc:
		download_pdf(doctype, name, doc=doc)

def get_rfq_doc(doctype, name, supplier_idx):
	if cint(supplier_idx):
		doc = frappe.get_doc(doctype, name)
		args = doc.get('suppliers')[cint(supplier_idx) - 1]
		doc.update_supplier_part_no(args)
		return doc

@frappe.whitelist()
def get_item_from_material_requests_based_on_supplier(source_name, target_doc = None):
	mr_items_list = frappe.db.sql("""
		SELECT
			mr.name, mr_item.item_code
		FROM
			`tabItem` as item,
			`tabItem Supplier` as item_supp,
			`tabMaterial Request Item` as mr_item,
			`tabMaterial Request`  as mr
		WHERE item_supp.supplier = %(supplier)s
			AND item.name = item_supp.parent
			AND mr_item.parent = mr.name
			AND mr_item.item_code = item.name
			AND mr.status != "Stopped"
			AND mr.material_request_type = "Purchase"
			AND mr.docstatus = 1
			AND mr.per_ordered < 99.99""", {"supplier": source_name}, as_dict=1)

	material_requests = {}
	for d in mr_items_list:
		material_requests.setdefault(d.name, []).append(d.item_code)

	for mr, items in material_requests.items():
		target_doc = get_mapped_doc("Material Request", mr, {
			"Material Request": {
				"doctype": "Request for Quotation",
				"validation": {
					"docstatus": ["=", 1],
					"material_request_type": ["=", "Purchase"],
				}
			},
			"Material Request Item": {
				"doctype": "Request for Quotation Item",
				"condition": lambda row: row.item_code in items,
				"field_map": [
					["name", "material_request_item"],
					["parent", "material_request"],
					["uom", "uom"]
				]
			}
		}, target_doc)

	return target_doc
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

from workflow import Workflow3, web
import sentry_sdk
import os
import json
import uuid
import hashlib
import time
import sys
reload(sys)
sys.setdefaultencoding('utf8')

YOUDAO_DEFAULT_KEYFROM = ('whyliam-wf-1', 'whyliam-wf-2', 'whyliam-wf-3',
                          'whyliam-wf-4', 'whyliam-wf-5', 'whyliam-wf-6',
                          'whyliam-wf-7', 'whyliam-wf-8', 'whyliam-wf-9',
                          'whyliam-wf-10', 'whyliam-wf-11')

YOUDAO_DEFAULT_KEY = (2002493135, 2002493136, 2002493137,
                      2002493138, 2002493139, 2002493140,
                      2002493141, 2002493142, 2002493143,
                      1947745089, 1947745090)

ERRORCODE_DICT = {
    "20": "要翻译的文本过长",
    "30": "无法进行有效的翻译",
    "40": "不支持的语言类型",
    "50": "无效的key",
    "60": "无词典结果，仅在获取词典结果生效",
    "101": "缺少必填的参数，出现这个情况还可能是et的值和实际加密方式不对应",
    "102": "不支持的语言类型",
    "103": "翻译文本过长",
    "104": "不支持的API类型",
    "105": "不支持的签名类型",
    "106": "不支持的响应类型",
    "107": "不支持的传输加密类型",
    "108": "appKey无效，注册账号， 登录后台创建应用和实例并完成绑定，\
        可获得应用ID和密钥等信息，其中应用ID就是appKey（ 注意不是应用密钥）",
    "109": "batchLog格式不正确",
    "110": "无相关服务的有效实例",
    "111": "开发者账号无效",
    "113": "q不能为空",
    "201": "解密失败，可能为DES,BASE64,URLDecode的错误",
    "202": "签名检验失败",
    "203": "访问IP地址不在可访问IP列表",
    "205": "请求的接口与应用的平台类型不一致，如有疑问请参考[入门指南]()",
    "206": "因为时间戳无效导致签名校验失败",
    "207": "重放请求",
    "301": "辞典查询失败",
    "302": "翻译查询失败",
    "303": "服务端的其它异常",
    "401": "账户已经欠费停",
    "411": "访问频率受限,请稍后访问",
    "412": "长请求过于频繁，请稍后访问",
    "500": "有道翻译失败"
}

ICON_DEFAULT = 'icon.png'
ICON_PHONETIC = 'icon_phonetic.png'
ICON_BASIC = 'icon_basic.png'
ICON_WEB = 'icon_web.png'
ICON_UPDATE = 'icon_update.png'
ICON_ERROR = 'icon_error.png'

def init_sentry():
    # 收集错误信息
    if os.getenv('sentry', 'False').strip():
        sentry_sdk.init(
            "https://4d5a5b1f2e68484da9edd9076b86e9b7@sentry.io/1500348")
        with sentry_sdk.configure_scope() as scope:
            user_id = get_user_id()
            scope.user = {"id": user_id}
            scope.set_tag("version", str(wf.version))

def get_user_id():
    user_id = wf.stored_data('user_id')
    if user_id == None:
        user_id = str(uuid.uuid1())
    wf.store_data('user_id', user_id)
    return user_id

def sentry_message(errorCode, msg):
    if os.getenv('sentry', 'False').strip():
        with sentry_sdk.configure_scope() as scope:
            scope.set_tag("errorCode", errorCode)
        sentry_sdk.capture_message(msg)

def get_youdao_url(query):
    # 构建有道翻译URL
    import random

    zhiyun_id = os.getenv('zhiyun_id', '').strip()
    zhiyun_key = os.getenv('zhiyun_key', '').strip()
    if zhiyun_id and zhiyun_key:
        url = get_youdao_new_url(query, zhiyun_id, zhiyun_key)
    else:
        youdao_keyfrom = os.getenv('youdao_keyfrom', '').strip()
        youdao_key = os.getenv('youdao_key', '').strip()
        if not youdao_keyfrom or not youdao_key:
            i = random.randrange(0, 11, 1)
            youdao_keyfrom = YOUDAO_DEFAULT_KEYFROM[i]
            youdao_key = YOUDAO_DEFAULT_KEY[i]
        url = get_youdao_old_url(query, youdao_keyfrom, youdao_key)
    wf.logger.debug(url)
    return url

def get_youdao_old_url(query, youdao_keyfrom, youdao_key):
    import urllib

    query = urllib.quote(str(query))
    url = 'http://fanyi.youdao.com/openapi.do?' + \
        'keyfrom=' + str(youdao_keyfrom) + \
        '&key=' + str(youdao_key) + \
        '&type=data&doctype=json&version=1.1&q=' + query
    return url

def encrypt(signStr):
    hash_algorithm = hashlib.sha256()
    hash_algorithm.update(signStr.encode('utf-8'))
    return hash_algorithm.hexdigest()

def truncate(q):
    if q is None:
        return None
    size = len(q)
    return q if size <= 20 else q[0:10] + str(size) + q[size - 10:size]

def get_youdao_new_url(query, zhiyun_id, zhiyun_key):
    import urllib
    import hashlib
    import uuid

    curtime = str(int(time.time()))
    salt = str(uuid.uuid1())
    signStr = zhiyun_id + truncate(query) + salt + curtime + zhiyun_key
    sign = encrypt(signStr)

    url = 'https://openapi.youdao.com/api' + \
        '?appKey=' + str(zhiyun_id) + \
        '&salt=' + str(salt) + \
        '&sign=' + str(sign) + \
        '&q=' + urllib.quote(str(query)) + \
        '&from=auto' + \
        '&to=auto' + \
        '&signType=v3' + \
        '&curtime=' + curtime
    return url

def fetch_translation(query):
    # 获取翻译数据
    url = get_youdao_url(query)
    try:
        rt = web.get(url).json()
        return rt
    except:
        rt = {}
        rt['errorCode'] = "500"
        return rt
    else:
        rt = {}
        rt['errorCode'] = "500"
        return rt

def save_history_data(query, title, arg, ICON_DEFAULT):
    jsonData = '{"title": "%s", "subtitle": "%s", "arg": "%s", \
        "icon": "%s"}\n' % (query, title, arg, ICON_DEFAULT)
    with open('history.log', 'a') as file:
        file.write(jsonData)

def get_history_data():
    with open('history.log', 'r') as file:
        for line in file.readlines()[-1:-10:-1]:
            try:
                line = json.loads(line)
                wf.add_item(
                    title=line['title'], subtitle=line['subtitle'],
                    arg=line['arg'], valid=True, icon=line['icon'])
            except Exception as e:
                pass

def is_expired():
    # 检查更新
    if wf.update_available:
        arg = ['', '', '', '', 'update']
        arg = '$%'.join(arg)
        wf.add_item(
            title='马上更新', subtitle='有新版本更新', arg=arg,
            valid=True, icon=ICON_UPDATE)

        arg = ['', '', '', '', 'not_update']
        arg = '$%'.join(arg)
        wf.add_item(
            title='暂不更新', subtitle='有新版本更新', arg=arg,
            valid=True, icon=ICON_ERROR)
        wf.send_feedback()
        return True
    return False

def is_English(query):
    # 检查英文翻译中文
    import re

    if re.search(ur"[\u4e00-\u9fa5]+", query):
        return False
    return True

def add_translation(query, isEnglish, rt):
    # 翻译结果
    subtitle = '翻译结果'
    translations = rt["translation"]
    for title in translations:
        arg = [query, title, query, '', ''] if isEnglish else [
            query, title, title, '', '']
        arg = '$%'.join(arg)

        save_history_data(query, title, arg, ICON_DEFAULT)

        wf.add_item(
            title=title, subtitle=subtitle, arg=arg,
            valid=True, icon=ICON_DEFAULT)

def add_phonetic(query, isEnglish, rt):
    # 发音
    if u'basic' in rt.keys():
        if rt["basic"] is not None:
            if rt["basic"].get("phonetic"):
                title = ""
                if rt["basic"].get("us-phonetic"):
                    title += ("[美: " + rt["basic"]["us-phonetic"] + "] ")
                if rt["basic"].get("uk-phonetic"):
                    title += ("[英: " + rt["basic"]["uk-phonetic"] + "] ")
                title = title if title else "[" + rt["basic"]["phonetic"] + "]"
                subtitle = '有道发音'
                arg = [query, title, query, '', ''] if isEnglish else [
                    query, title, '', query, '']
                arg = '$%'.join(arg)
                wf.add_item(
                    title=title, subtitle=subtitle, arg=arg,
                    valid=True, icon=ICON_PHONETIC)

def add_explains(query, isEnglish, rt):
    # 简明释意
    if u'basic' in rt.keys():
        if rt["basic"] is not None:
            for i in range(len(rt["basic"]["explains"])):
                title = rt["basic"]["explains"][i]
                subtitle = '简明释意'
                arg = [query, title, query, '', ''] if isEnglish else [
                    query, title, '', title, '']
                arg = '$%'.join(arg)
                wf.add_item(
                    title=title, subtitle=subtitle, arg=arg,
                    valid=True, icon=ICON_PHONETIC)

def add_web_translation(query, isEnglish, rt):
  # 网络翻译
    if u'web' in rt.keys():
        if rt["web"] is not None:
            for i in range(len(rt["web"])):
                titles = rt["web"][i]["value"]
                for title in titles:
                    subtitle = '网络翻译: ' + rt["web"][i]["key"]

                    if isEnglish:
                        key = ''.join(rt["web"][i]["key"])
                        arg = [query, title, key, '', '']
                    else:
                        value = ' '.join(rt["web"][i]["value"])
                        arg = [query, title, title, '', '']

                    arg = '$%'.join(arg)
                    wf.add_item(
                        title=title, subtitle=subtitle,
                        arg=arg, valid=True, icon=ICON_WEB)

def main(wf):
    if is_expired():
        return

    query = wf.args[0].strip()
    if not isinstance(query, unicode):
        query = query.decode('utf8')

    if query == "*":
        get_history_data()
    else:
        rt = fetch_translation(query)
        errorCode = str(rt.get("errorCode"))

        if ERRORCODE_DICT.has_key(errorCode):
            if errorCode == "500":
                sentry_message(errorCode, ERRORCODE_DICT[errorCode])
            arg = ['', '', '', '', 'error']
            arg = '$%'.join(arg)
            wf.add_item(
                title=errorCode+" "+ERRORCODE_DICT[errorCode],
                subtitle='', arg=arg,
                valid=True, icon=ICON_ERROR)

        elif errorCode == "0":
            isEnglish = is_English(query)
            add_translation(query, isEnglish, rt)
            add_phonetic(query, isEnglish, rt)
            add_explains(query, isEnglish, rt)
            add_web_translation(query, isEnglish, rt)

        else:
            sentry_message(errorCode, '有道也翻译不出来了')
            title = '有道也翻译不出来了'
            subtitle = '尝试一下去网站搜索'
            arg = [query, ' ', ' ', ' ']
            arg = '$%'.join(arg)
            wf.add_item(
                title=title, subtitle=subtitle, arg=arg,
                valid=True, icon=ICON_DEFAULT)
    wf.send_feedback()

if __name__ == '__main__':
    wf = Workflow3(update_settings={
        'github_slug': 'whyliam/whyliam.workflows.youdao',
        'frequency': 7
    })
    init_sentry()
    sys.exit(wf.run(main))
<commit_msg>修复有道api更新后无法查询多字段问题<commit_after># -*- coding: utf-8 -*-

from workflow import Workflow3, web
import sentry_sdk
import os
import json
import uuid
import hashlib
import time
import sys
reload(sys)
sys.setdefaultencoding('utf8')

YOUDAO_DEFAULT_KEYFROM = ('whyliam-wf-1', 'whyliam-wf-2', 'whyliam-wf-3',
                          'whyliam-wf-4', 'whyliam-wf-5', 'whyliam-wf-6',
                          'whyliam-wf-7', 'whyliam-wf-8', 'whyliam-wf-9',
                          'whyliam-wf-10', 'whyliam-wf-11')

YOUDAO_DEFAULT_KEY = (2002493135, 2002493136, 2002493137,
                      2002493138, 2002493139, 2002493140,
                      2002493141, 2002493142, 2002493143,
                      1947745089, 1947745090)

ERRORCODE_DICT = {
    "20": "要翻译的文本过长",
    "30": "无法进行有效的翻译",
    "40": "不支持的语言类型",
    "50": "无效的key",
    "60": "无词典结果，仅在获取词典结果生效",
    "101": "缺少必填的参数，出现这个情况还可能是et的值和实际加密方式不对应",
    "102": "不支持的语言类型",
    "103": "翻译文本过长",
    "104": "不支持的API类型",
    "105": "不支持的签名类型",
    "106": "不支持的响应类型",
    "107": "不支持的传输加密类型",
    "108": "appKey无效，注册账号， 登录后台创建应用和实例并完成绑定，\
        可获得应用ID和密钥等信息，其中应用ID就是appKey（ 注意不是应用密钥）",
    "109": "batchLog格式不正确",
    "110": "无相关服务的有效实例",
    "111": "开发者账号无效",
    "113": "q不能为空",
    "201": "解密失败，可能为DES,BASE64,URLDecode的错误",
    "202": "签名检验失败",
    "203": "访问IP地址不在可访问IP列表",
    "205": "请求的接口与应用的平台类型不一致，如有疑问请参考[入门指南]()",
    "206": "因为时间戳无效导致签名校验失败",
    "207": "重放请求",
    "301": "辞典查询失败",
    "302": "翻译查询失败",
    "303": "服务端的其它异常",
    "401": "账户已经欠费停",
    "411": "访问频率受限,请稍后访问",
    "412": "长请求过于频繁，请稍后访问",
    "500": "有道翻译失败"
}

ICON_DEFAULT = 'icon.png'
ICON_PHONETIC = 'icon_phonetic.png'
ICON_BASIC = 'icon_basic.png'
ICON_WEB = 'icon_web.png'
ICON_UPDATE = 'icon_update.png'
ICON_ERROR = 'icon_error.png'

def init_sentry():
    # 收集错误信息
    if os.getenv('sentry', 'False').strip():
        sentry_sdk.init(
            "https://4d5a5b1f2e68484da9edd9076b86e9b7@sentry.io/1500348")
        with sentry_sdk.configure_scope() as scope:
            user_id = get_user_id()
            scope.user = {"id": user_id}
            scope.set_tag("version", str(wf.version))

def get_user_id():
    user_id = wf.stored_data('user_id')
    if user_id == None:
        user_id = str(uuid.uuid1())
    wf.store_data('user_id', user_id)
    return user_id

def sentry_message(errorCode, msg):
    if os.getenv('sentry', 'False').strip():
        with sentry_sdk.configure_scope() as scope:
            scope.set_tag("errorCode", errorCode)
        sentry_sdk.capture_message(msg)

def get_youdao_url(query):
    # 构建有道翻译URL
    import random

    zhiyun_id = os.getenv('zhiyun_id', '').strip()
    zhiyun_key = os.getenv('zhiyun_key', '').strip()
    if zhiyun_id and zhiyun_key:
        url = get_youdao_new_url(query, zhiyun_id, zhiyun_key)
    else:
        youdao_keyfrom = os.getenv('youdao_keyfrom', '').strip()
        youdao_key = os.getenv('youdao_key', '').strip()
        if not youdao_keyfrom or not youdao_key:
            i = random.randrange(0, 11, 1)
            youdao_keyfrom = YOUDAO_DEFAULT_KEYFROM[i]
            youdao_key = YOUDAO_DEFAULT_KEY[i]
        url = get_youdao_old_url(query, youdao_keyfrom, youdao_key)
    wf.logger.debug(url)
    return url

def get_youdao_old_url(query, youdao_keyfrom, youdao_key):
    import urllib

    query = urllib.quote(str(query))
    url = 'http://fanyi.youdao.com/openapi.do?' + \
        'keyfrom=' + str(youdao_keyfrom) + \
        '&key=' + str(youdao_key) + \
        '&type=data&doctype=json&version=1.1&q=' + query
    return url

def encrypt(signStr):
    hash_algorithm = hashlib.sha256()
    hash_algorithm.update(signStr.encode('utf-8'))
    return hash_algorithm.hexdigest()

def truncate(q):
    if q is None:
        return None
    size = len(q)
    return q if size <= 20 else q[0:10] + str(size) + q[size - 10:size]

def is_all_chinese(strs):
    for _char in strs:
        if not '\u4e00' <= _char <= '\u9fa5':
            if not '\u00A0' == _char and not '\u0020' == _char and not '\u3000' == _char:
                return False
    return True

def get_youdao_new_url(query, zhiyun_id, zhiyun_key):
    import urllib
    import hashlib
    import uuid

    curtime = str(int(time.time()))
    salt = str(uuid.uuid1())
    signStr = zhiyun_id + truncate(query) + salt + curtime + zhiyun_key
    sign = encrypt(signStr)
    data_form = 'EN'
    data_to = 'zh-CHS'
    if is_all_chinese(query):
        data_form = 'zh-CHS'
        data_to = 'EN'

    url = 'https://openapi.youdao.com/api' + \
        '?appKey=' + str(zhiyun_id) + \
        '&salt=' + str(salt) + \
        '&sign=' + str(sign) + \
        '&q=' + urllib.quote(str(query)) + \
        '&from=' + data_form + \
        '&to=' + data_to + \
        '&signType=v3' + \
        '&curtime=' + curtime
    return url

def fetch_translation(query):
    # 获取翻译数据
    url = get_youdao_url(query)
    try:
        rt = web.get(url).json()
        return rt
    except:
        rt = {}
        rt['errorCode'] = "500"
        return rt
    else:
        rt = {}
        rt['errorCode'] = "500"
        return rt

def save_history_data(query, title, arg, ICON_DEFAULT):
    jsonData = '{"title": "%s", "subtitle": "%s", "arg": "%s", \
        "icon": "%s"}\n' % (query, title, arg, ICON_DEFAULT)
    with open('history.log', 'a') as file:
        file.write(jsonData)

def get_history_data():
    with open('history.log', 'r') as file:
        for line in file.readlines()[-1:-10:-1]:
            try:
                line = json.loads(line)
                wf.add_item(
                    title=line['title'], subtitle=line['subtitle'],
                    arg=line['arg'], valid=True, icon=line['icon'])
            except Exception as e:
                pass

def is_expired():
    # 检查更新
    if wf.update_available:
        arg = ['', '', '', '', 'update']
        arg = '$%'.join(arg)
        wf.add_item(
            title='马上更新', subtitle='有新版本更新', arg=arg,
            valid=True, icon=ICON_UPDATE)

        arg = ['', '', '', '', 'not_update']
        arg = '$%'.join(arg)
        wf.add_item(
            title='暂不更新', subtitle='有新版本更新', arg=arg,
            valid=True, icon=ICON_ERROR)
        wf.send_feedback()
        return True
    return False

def is_English(query):
    # 检查英文翻译中文
    import re

    if re.search(ur"[\u4e00-\u9fa5]+", query):
        return False
    return True

def add_translation(query, isEnglish, rt):
    # 翻译结果
    subtitle = '翻译结果'
    translations = rt["translation"]
    for title in translations:
        arg = [query, title, query, '', ''] if isEnglish else [
            query, title, title, '', '']
        arg = '$%'.join(arg)

        save_history_data(query, title, arg, ICON_DEFAULT)

        wf.add_item(
            title=title, subtitle=subtitle, arg=arg,
            valid=True, icon=ICON_DEFAULT)

def add_phonetic(query, isEnglish, rt):
    # 发音
    if u'basic' in rt.keys():
        if rt["basic"] is not None:
            if rt["basic"].get("phonetic"):
                title = ""
                if rt["basic"].get("us-phonetic"):
                    title += ("[美: " + rt["basic"]["us-phonetic"] + "] ")
                if rt["basic"].get("uk-phonetic"):
                    title += ("[英: " + rt["basic"]["uk-phonetic"] + "] ")
                title = title if title else "[" + rt["basic"]["phonetic"] + "]"
                subtitle = '有道发音'
                arg = [query, title, query, '', ''] if isEnglish else [
                    query, title, '', query, '']
                arg = '$%'.join(arg)
                wf.add_item(
                    title=title, subtitle=subtitle, arg=arg,
                    valid=True, icon=ICON_PHONETIC)

def add_explains(query, isEnglish, rt):
    # 简明释意
    if u'basic' in rt.keys():
        if rt["basic"] is not None:
            for i in range(len(rt["basic"]["explains"])):
                title = rt["basic"]["explains"][i]
                subtitle = '简明释意'
                arg = [query, title, query, '', ''] if isEnglish else [
                    query, title, '', title, '']
                arg = '$%'.join(arg)
                wf.add_item(
                    title=title, subtitle=subtitle, arg=arg,
                    valid=True, icon=ICON_PHONETIC)

def add_web_translation(query, isEnglish, rt):
  # 网络翻译
    if u'web' in rt.keys():
        if rt["web"] is not None:
            for i in range(len(rt["web"])):
                titles = rt["web"][i]["value"]
                for title in titles:
                    subtitle = '网络翻译: ' + rt["web"][i]["key"]

                    if isEnglish:
                        key = ''.join(rt["web"][i]["key"])
                        arg = [query, title, key, '', '']
                    else:
                        value = ' '.join(rt["web"][i]["value"])
                        arg = [query, title, title, '', '']

                    arg = '$%'.join(arg)
                    wf.add_item(
                        title=title, subtitle=subtitle,
                        arg=arg, valid=True, icon=ICON_WEB)

def main(wf):
    if is_expired():
        return

    query = wf.args[0].strip()
    if not isinstance(query, unicode):
        query = query.decode('utf8')

    if query == "*":
        get_history_data()
    else:
        rt = fetch_translation(query)
        errorCode = str(rt.get("errorCode"))

        if ERRORCODE_DICT.has_key(errorCode):
            if errorCode == "500":
                sentry_message(errorCode, ERRORCODE_DICT[errorCode])
            arg = ['', '', '', '', 'error']
            arg = '$%'.join(arg)
            wf.add_item(
                title=errorCode+" "+ERRORCODE_DICT[errorCode],
                subtitle='', arg=arg,
                valid=True, icon=ICON_ERROR)

        elif errorCode == "0":
            isEnglish = is_English(query)
            add_translation(query, isEnglish, rt)
            add_phonetic(query, isEnglish, rt)
            add_explains(query, isEnglish, rt)
            add_web_translation(query, isEnglish, rt)

        else:
            sentry_message(errorCode, '有道也翻译不出来了')
            title = '有道也翻译不出来了'
            subtitle = '尝试一下去网站搜索'
            arg = [query, ' ', ' ', ' ']
            arg = '$%'.join(arg)
            wf.add_item(
                title=title, subtitle=subtitle, arg=arg,
                valid=True, icon=ICON_DEFAULT)
    wf.send_feedback()

if __name__ == '__main__':
    wf = Workflow3(update_settings={
        'github_slug': 'whyliam/whyliam.workflows.youdao',
        'frequency': 7
    })
    init_sentry()
    sys.exit(wf.run(main))
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

from workflow import Workflow3, ICON_WEB, web

import sys
reload(sys)
sys.setdefaultencoding('utf8')

YOUDAO_DEFAULT_KEYFROM = ('whyliam-wf-1', 'whyliam-wf-2', 'whyliam-wf-3',
                          'whyliam-wf-4', 'whyliam-wf-5', 'whyliam-wf-6',
                          'whyliam-wf-7', 'whyliam-wf-8', 'whyliam-wf-9',
                          'whyliam-wf-10', 'whyliam-wf-11')

YOUDAO_DEFAULT_KEY = (2002493135, 2002493136, 2002493137,
                      2002493138, 2002493139, 2002493140,
                      2002493141, 2002493142, 2002493143,
                      1947745089, 1947745090)

ICON_DEFAULT = 'icon.png'
ICON_PHONETIC = 'icon_phonetic.png'
ICON_BASIC = 'icon_basic.png'
ICON_WEB = 'icon_web.png'
ICON_UPDATE = 'icon_update.png'
ICON_ERROR = 'icon_error.png'

def set_youdao_url(query):
    # 构建有道翻译URL
    import os
    import random
    import urllib

    youdao_keyfrom = os.getenv('youdao_keyfrom', '')
    youdao_key = os.getenv('youdao_key', '')
    if not youdao_keyfrom or not youdao_key:
        i = random.randrange(0, 11, 1)
        youdao_keyfrom = YOUDAO_DEFAULT_KEYFROM[i]
        youdao_key = YOUDAO_DEFAULT_KEY[i]

    query = urllib.quote(str(query))
    url = 'http://fanyi.youdao.com/openapi.do?keyfrom=' + youdao_keyfrom + \
        '&key=' + str(youdao_key) + \
        '&type=data&doctype=json&version=1.1&q=' + query
    return url

def get_web_data(query):
    # 获取翻译数据
    url = set_youdao_url(query)
    try:
        rt = web.get(url).json()
        return rt
    except:
        rt = {}
        rt['errorCode'] = 500
        return rt
    else:
        rt = {}
        rt['errorCode'] = 500
        return rt

def check_Update():
    # 检查更新
    if wf.update_available:
        arg = ['', '', '', '', 'error']
        arg = '$%'.join(arg)
        wf.add_item(
            title='有新版本更新', subtitle='', arg=arg,
            valid=True, icon=ICON_UPDATE)
    else:
        wf.add_item('有道翻译')

def check_English(query):
    # 检查英文翻译中午
    import re

    if re.search(ur"[\u4e00-\u9fa5]+", query):
        return False
    return True

def get_translation(query, isEnglish, rt):
    # 翻译结果
    subtitle = '翻译结果'
    translations = rt["translation"]
    for title in translations:
        arg = [query, title, query, '', ''] if isEnglish else [
            query, title, title, '', '']
        arg = '$%'.join(arg)
        # print arg
        wf.add_item(
            title=title, subtitle=subtitle, arg=arg,
            valid=True, icon=ICON_DEFAULT)

def get_phonetic(query, isEnglish, rt):
    # 发音
    if u'basic' in rt.keys():
        if rt["basic"].get("phonetic"):
            title = ""
            if rt["basic"].get("us-phonetic"):
                title += ("[美: " + rt["basic"]["us-phonetic"] + "] ")
            if rt["basic"].get("uk-phonetic"):
                title += ("[英: " + rt["basic"]["uk-phonetic"] + "] ")
            title = title if title else "[" + rt["basic"]["phonetic"] + "]"
            subtitle = '有道发音'
            arg = [query, title, query, '', ''] if isEnglish else [
                query, title, '', query, '']
            arg = '$%'.join(arg)
            wf.add_item(
                title=title, subtitle=subtitle, arg=arg,
                valid=True, icon=ICON_PHONETIC)

def get_explains(query, isEnglish, rt):
    # 简明释意
    if u'basic' in rt.keys():
        for i in range(len(rt["basic"]["explains"])):
            title = rt["basic"]["explains"][i]
            subtitle = '简明释意'
            arg = [query, title, query, '', ''] if isEnglish else [
                query, title, '', title, '']
            arg = '$%'.join(arg)
            wf.add_item(
                title=title, subtitle=subtitle, arg=arg,
                valid=True, icon=ICON_PHONETIC)

def get_web_translation(query, isEnglish, rt):
  # 网络翻译
    if u'web' in rt.keys():
        for i in range(len(rt["web"])):
            titles = rt["web"][i]["value"]
            for title in titles:
                subtitle = '网络翻译: ' + rt["web"][i]["key"]

                if isEnglish:
                    key = ''.join(rt["web"][i]["key"])
                    arg = [query, title, key, '', '']
                else:
                    value = ' '.join(rt["web"][i]["value"])
                    arg = [query, title, title, '', '']

                arg = '$%'.join(arg)
                wf.add_item(
                    title=title, subtitle=subtitle,
                    arg=arg, valid=True, icon=ICON_WEB)

def main(wf):
    query = wf.args[0].strip().replace("\\", "")
    if not isinstance(query, unicode):
        query = query.decode('utf8')

    if not query:
        check_Update()
        wf.send_feedback()

    rt = get_web_data(query)

    if rt.get("errorCode") == 500:
        arg = ['', '', '', '', 'error']
        arg = '$%'.join(arg)
        wf.add_item(
            title='有道翻译的API Key使用频率过高', subtitle='', arg=arg,
            valid=True, icon=ICON_ERROR)

    elif rt.get("errorCode") == 50:
        arg = ['', '', '', '', 'error']
        arg = '$%'.join(arg)
        wf.add_item(
            title='有道翻译的API Key错误', subtitle='', arg=arg,
            valid=True, icon=ICON_ERROR)

    elif rt.get("errorCode") == 0:
        isEnglish = check_English(query)
        get_translation(query, isEnglish, rt)
        get_phonetic(query, isEnglish, rt)
        get_explains(query, isEnglish, rt)
        get_web_translation(query, isEnglish, rt)

    else:
        title = '有道也翻译不出来了'
        subtitle = '尝试一下去网站搜索'
        arg = [query, ' ', ' ', ' ']
        arg = '$%'.join(arg)
        wf.add_item(
            title=title, subtitle=subtitle, arg=arg,
            valid=True, icon=ICON_DEFAULT)

    wf.send_feedback()

if __name__ == '__main__':
    wf = Workflow3(update_settings={
        'github_slug': 'liszd/whyliam.workflows.youdao',
        'frequency': 7
    })
    sys.exit(wf.run(main))
<commit_msg>adapt to the new API<commit_after># -*- coding: utf-8 -*-

from workflow import Workflow3, ICON_WEB, web

import sys
import hashlib, uuid
reload(sys)
sys.setdefaultencoding('utf8')

YOUDAO_DEFAULT_KEYFROM = ('whyliam-wf-1', 'whyliam-wf-2', 'whyliam-wf-3',
                          'whyliam-wf-4', 'whyliam-wf-5', 'whyliam-wf-6',
                          'whyliam-wf-7', 'whyliam-wf-8', 'whyliam-wf-9',
                          'whyliam-wf-10', 'whyliam-wf-11')

YOUDAO_DEFAULT_KEY = (2002493135, 2002493136, 2002493137,
                      2002493138, 2002493139, 2002493140,
                      2002493141, 2002493142, 2002493143,
                      1947745089, 1947745090)

ICON_DEFAULT = 'icon.png'
ICON_PHONETIC = 'icon_phonetic.png'
ICON_BASIC = 'icon_basic.png'
ICON_WEB = 'icon_web.png'
ICON_UPDATE = 'icon_update.png'
ICON_ERROR = 'icon_error.png'

def set_youdao_url(query):
    # 构建有道翻译URL
    import os
    import random
    import urllib

    youdao_keyfrom = os.getenv('youdao_keyfrom', '')
    youdao_key = os.getenv('youdao_key', '')
    if not youdao_keyfrom or not youdao_key:
        i = random.randrange(0, 11, 1)
        youdao_keyfrom = YOUDAO_DEFAULT_KEYFROM[i]
        youdao_key = YOUDAO_DEFAULT_KEY[i]

    salt = uuid.uuid4().hex
    sign = hashlib.md5(youdao_key + query + salt + youdao_keyfrom).hexdigest()
    query = urllib.quote(str(query))

    url = 'http://openapi.youdao.com/api?appKey=' + str(youdao_key) + \
        '&salt=' + str(salt) + \
        '&sign=' + str(sign) + \
        '&q=' + query

    return url

def get_web_data(query):
    # 获取翻译数据
    url = set_youdao_url(query)
    try:
        rt = web.get(url).json()
        return rt
    except:
        rt = {}
        rt['errorCode'] = 500
        return rt
    else:
        rt = {}
        rt['errorCode'] = 500
        return rt

def check_Update():
    # 检查更新
    if wf.update_available:
        arg = ['', '', '', '', 'error']
        arg = '$%'.join(arg)
        wf.add_item(
            title='有新版本更新', subtitle='', arg=arg,
            valid=True, icon=ICON_UPDATE)
    else:
        wf.add_item('有道翻译')

def check_English(query):
    # 检查英文翻译中午
    import re

    if re.search(ur"[\u4e00-\u9fa5]+", query):
        return False
    return True

def get_translation(query, isEnglish, rt):
    # 翻译结果
    subtitle = '翻译结果'
    translations = rt["translation"]
    for title in translations:
        arg = [query, title, query, '', ''] if isEnglish else [
            query, title, title, '', '']
        arg = '$%'.join(arg)
        # print arg
        wf.add_item(
            title=title, subtitle=subtitle, arg=arg,
            valid=True, icon=ICON_DEFAULT)

def get_phonetic(query, isEnglish, rt):
    # 发音
    if u'basic' in rt.keys():
        if rt["basic"].get("phonetic"):
            title = ""
            if rt["basic"].get("us-phonetic"):
                title += ("[美: " + rt["basic"]["us-phonetic"] + "] ")
            if rt["basic"].get("uk-phonetic"):
                title += ("[英: " + rt["basic"]["uk-phonetic"] + "] ")
            title = title if title else "[" + rt["basic"]["phonetic"] + "]"
            subtitle = '有道发音'
            arg = [query, title, query, '', ''] if isEnglish else [
                query, title, '', query, '']
            arg = '$%'.join(arg)
            wf.add_item(
                title=title, subtitle=subtitle, arg=arg,
                valid=True, icon=ICON_PHONETIC)

def get_explains(query, isEnglish, rt):
    # 简明释意
    if u'basic' in rt.keys():
        for i in range(len(rt["basic"]["explains"])):
            title = rt["basic"]["explains"][i]
            subtitle = '简明释意'
            arg = [query, title, query, '', ''] if isEnglish else [
                query, title, '', title, '']
            arg = '$%'.join(arg)
            wf.add_item(
                title=title, subtitle=subtitle, arg=arg,
                valid=True, icon=ICON_PHONETIC)

def get_web_translation(query, isEnglish, rt):
  # 网络翻译
    if u'web' in rt.keys():
        for i in range(len(rt["web"])):
            titles = rt["web"][i]["value"]
            for title in titles:
                subtitle = '网络翻译: ' + rt["web"][i]["key"]

                if isEnglish:
                    key = ''.join(rt["web"][i]["key"])
                    arg = [query, title, key, '', '']
                else:
                    value = ' '.join(rt["web"][i]["value"])
                    arg = [query, title, title, '', '']

                arg = '$%'.join(arg)
                wf.add_item(
                    title=title, subtitle=subtitle,
                    arg=arg, valid=True, icon=ICON_WEB)

def main(wf):
    query = wf.args[0].strip().replace("\\", "")
    if not isinstance(query, unicode):
        query = query.decode('utf8')

    if not query:
        check_Update()
        wf.send_feedback()

    rt = get_web_data(query)

    if rt.get("errorCode") in (500, u'500'):
        arg = ['', '', '', '', 'error']
        arg = '$%'.join(arg)
        wf.add_item(
            title='有道翻译的API Key使用频率过高', subtitle='', arg=arg,
            valid=True, icon=ICON_ERROR)

    elif rt.get("errorCode") in (50, u'50'):
        arg = ['', '', '', '', 'error']
        arg = '$%'.join(arg)
        wf.add_item(
            title='有道翻译的API Key错误', subtitle='', arg=arg,
            valid=True, icon=ICON_ERROR)

    elif rt.get("errorCode") in (0, u'0'):
        isEnglish = check_English(query)
        get_translation(query, isEnglish, rt)
        get_phonetic(query, isEnglish, rt)
        get_explains(query, isEnglish, rt)
        get_web_translation(query, isEnglish, rt)

    else:
        title = '有道也翻译不出来了'
        subtitle = '尝试一下去网站搜索'
        arg = [query, ' ', ' ', ' ']
        arg = '$%'.join(arg)
        wf.add_item(
            title=title, subtitle=subtitle, arg=arg,
            valid=True, icon=ICON_DEFAULT)

    wf.send_feedback()

if __name__ == '__main__':
    wf = Workflow3(update_settings={
        'github_slug': 'liszd/whyliam.workflows.youdao',
        'frequency': 7
    })
    sys.exit(wf.run(main))
<|endoftext|>


<commit_before>#!/usr/bin/python

################################################################################
# Project: Raspi Traffic Control
# Script Usage: raspitraffic.py
# Created: 2017-04-02
# Author: Kenny Robinson, @almostengr, www.bitsecondtech.com
# Description: Core script which all the functions for controlling the lights
# are contained.
################################################################################

from time import sleep
from random import randint
import RPi.GPIO as GPIO
import lcddriver
import random
import subprocess

# DEBUGGING MODE, DISABLED=0, ENABLED=1
DEBUG=0

# LIST ALL OF THE PINS USED
pinOutList = [23, 21, 19]

# DEFINE THE GPIO NUMBERS AND VARIABLES FOR THE EASTBOUND TRAFFIC
EAST_CR = 23
EAST_CY = 21
EAST_CG = 19

# DEFINE CONSTANTS
LAMPON=GPIO.LOW
LAMPOFF=GPIO.HIGH
FLASHER_DELAY=.7

# display=lcddriver.lcd()
selection = 0
phaseflasher = 0
phasenum = 0
inColor = "red"

def setup():
# SET UP GPIO PINS
	GPIO.setmode(GPIO.BOARD)

	# disable GPIO warnings when not debugging
	if DEBUG == 0:
		GPIO.setwarnings(False)

	# loop through each of the pins and define it.
	# turn on all the lights once setup
	for i in pinOutList:
		debug_message("Setting up and activiating pin " + str(i))
		GPIO.setup(i, GPIO.OUT)

	debug_message("Waiting")
	sleep(1)

	# turn off all the lights
	for i in pinOutList:
		GPIO.output(i, GPIO.HIGH)
		debug_message("Turning off pin " + str(i))

	lcd_message("Done performing setup", "")

	return 0

def debug_message(message):
# LOG ADDITIONAL MESSAGES TO THE SCREEN/LOG FILE WHEN TESTING
	if DEBUG == 1:
		log_message("DEBUG: " + message)
	return 0

def log_message(message):
# print message on computer screen
	print message
	return 0

def lcd_message(line1, line2):
# Displays the message on the LCD screen and computer screen
	log_message(line1 + " | " + line2)
	return 0

def run_red_light_green_light(yellowon):
# SEQUENCE FOR RED LIGHT GREEN LIGHT GAME.

	red_time=randint(1, 10)
	green_time=randint(1, 3)
	yellow_time=FLASHER_DELAY

	eblight(LAMPON, LAMPOFF, LAMPOFF)
	debug_message("Red Time: " + str(red_time))
	lcd_message("Red Light!", "Dont move!")
	sleep(red_time)

	eblight(LAMPOFF, LAMPOFF, LAMPON)
	debug_message("Green Time: " + str(green_time))
	lcd_message("Green Light!", "Run!")
	sleep(green_time)

	if yellowon == 1:
		eblight(LAMPOFF, LAMPON, LAMPOFF)
		debug_message("Yellow Time: " + str(yellow_time))
		lcd_message("Yellow Light!", "Slow!")
		sleep(yellow_time)

def run_signal(country):
# runs the light using normal signal
	phaseflasher=0

	east_grn_time=random.randint(5, 30)
	east_yel_time=random.randint(2, 5)
	east_red_time=random.randint(5, 30)

	# red
	eblight(LAMPON, LAMPOFF, LAMPOFF)
	for ttime in range(east_red_time, 0, -1):
		lcd_message("Red", "Time Remain: " + str(ttime) + "s")
		sleep(1)

	# red-yellow for UK only
	if country == "UK":
		eblight(LAMPON, LAMPON, LAMPOFF)
		for ttime in range(east_yel_time, 0, -1):
			lcd_message("Red-Yellow", "Time Remain: " + str(ttime) + "s")
			sleep(1)

	# green
	eblight(LAMPOFF, LAMPOFF, LAMPON)
	for ttime in range(east_grn_time, 0, -1):
		lcd_message("Green", "Time Remain: " + str(ttime) + "s")
		sleep(1)

        # flash green
        if country == "normalflashgreen":
            for i in range(4, randint(5,10)):
                phaseflasher = run_flasher("green", phaseflasher)

	# yellow
	eblight(LAMPOFF, LAMPON, LAMPOFF)
	for ttime in range(east_yel_time, 0, -1):
		lcd_message("Yellow", "Time Remain: " + str(ttime) + "s")
		sleep(1)

	# red
	eblight(LAMPON, LAMPOFF, LAMPOFF)
	for ttime in range(east_red_time, 0, -1):
		lcd_message("Red", "Time Remain: " + str(ttime) + "s")
		sleep(1)

	# change flasher color
	if inColor == "red":
		inColor = "yellow"
		# lcd_message("Yellow Flasher", "")
	else:
		inColor = "red"
		# lcd_message("Red Flasher", "")

	# flasher
	flashrangemax=randint(6,30)
	for i in range(1,flashrangemax):
		phaseflasher = run_flasher(inColor, phaseflasher)

def run_flasher(color, phase):
# flash the lights
	if color == "red":
		if phase == 1:
			eblight(LAMPOFF, LAMPOFF, LAMPOFF)
			lcd_message("Flashing Red", "")
			phase = 2
		else:
			eblight(LAMPON, LAMPOFF, LAMPOFF)
			lcd_message("Flashing Red Off", "")
			phase = 1

	elif color == "yellow":
		if phase == 3:
			eblight(LAMPOFF, LAMPOFF, LAMPOFF)
			lcd_message("Flashing Yellow", "")
			phase = 4
		else:
			eblight(LAMPOFF, LAMPON, LAMPOFF)
			lcd_message("Flashing Yellow Off", "")
			phase = 3

	elif color == "green":
		if phase == 7:
			eblight(LAMPOFF, LAMPOFF, LAMPOFF)
			lcd_message("Flashing Green", "")
			phase = 8
		else:
			eblight(LAMPOFF, LAMPOFF, LAMPON)
			lcd_message("Flashing Green Off", "")
			phase = 7

	sleep(FLASHER_DELAY)
	return phase

def calc_yellow_time(grade):
# CALCULATE THE AMOUNT OF YELLOW LIGHT TIME
        speed = randint(25,80)
	yel_time = 1 + ((1.47 * speed) / (2 * (10 + (0 / 100) * 32.2)))
	return yel_time

def eblight(cirred, ciryel, cirgrn):
# CONTROLS THE LAMPS ON THE EASTBOUND LIGHT. DOESNT HAVE LEFT TURN
	GPIO.output(EAST_CR, cirred)
	GPIO.output(EAST_CY, ciryel)
	GPIO.output(EAST_CG, cirgrn)

def allon(phase):
# TURNS ON THE LIGHTS BASED ON THE ARGUMENT PROVIDED
	if phase == "all":
		eblight(LAMPON, LAMPON, LAMPON)
		lcd_message("ALL LIGHTS ON", "")
	elif phase == "red":
		eblight(LAMPON, LAMPOFF, LAMPOFF)
		lcd_message("ALL REDS ON", "")
	elif phase == "yellow":
		eblight(LAMPOFF, LAMPON, LAMPOFF)
		lcd_message("ALL YELLOWS ON", "")
	elif phase == "green":
		eblight(LAMPOFF, LAMPOFF, LAMPON)
		lcd_message("ALL GREENS ON", "")
	else:
		log_message("Doing nothing")

	sleep(3)

def alloff():
# TURNS OFF ALL OF THE LIGHTS
	lcd_message("ALL LIGHTS OFF", "")
	eblight(LAMPOFF, LAMPOFF, LAMPOFF)
	sleep(3)

# configure everything
setup()

# loop forever
while True:
	debug_message("Debug mode enabled")

	try:
		try:
		# Read the data file
			file = open("/tmp/traffic.txt", "r")
			selection = file.readline()
			file.close()

		except IOError:
			# if the file doesn't exist, then create it and give public permissions
			file = open("/tmp/traffic.txt", "w")
			subprocess.call(['chmod', '0777', '/tmp/traffic.txt'])
			file.close()

		if selection == "":
		# default value if nothing has been selected
			run_signal("US")

		elif selection == "allon":
		# all lights on
			allon("all")

		elif selection == "alloff":
		# all lights off
			alloff()

		elif selection == "flashred":
		# flash red
			lcd_message("Flashing Red", "")
			phaseflasher=run_flasher("red", phaseflasher)

		elif selection == "flashyel":
		# flash yellow
			lcd_message("Flashing Yellow", "")
			phaseflasher = run_flasher("yellow", phaseflasher)

		elif selection == "flashgrn":
		# flash green
			lcd_message("Flashing Green", "")
			phaseflasher=run_flasher("green", phaseflasher)

		elif selection == "ustraffic":
		# US signal pattern
			run_signal("US")

		elif selection == "uktraffic":
		# UK signal pattern
			run_signal("UK")

                elif selection == "normalflashgreen":
                # signal pattern with flashing green
                        run_signal("normalflashgreen")

		elif selection == "redlightgreenlight":
			run_red_light_green_light(0)

		elif selection == "redlightgreenlight2":
			run_red_light_green_light(1)

		elif selection == "restart":
		# restart the Raspberry Pi
			subprocess.call(["sudo", "restart"])

		elif selection == "shutdown":
		# shutdown the Raspberry Pi
			subprocess.call(["sudo", "shutdown", "-h", "now"])

	except KeyboardInterrupt:
		log_message("Exiting")
	        GPIO.cleanup()

<commit_msg>Added catch all for exceptions<commit_after>#!/usr/bin/python

################################################################################
# Project: Raspi Traffic Control
# Script Usage: raspitraffic.py
# Created: 2017-04-02
# Author: Kenny Robinson, @almostengr, www.bitsecondtech.com
# Description: Core script which all the functions for controlling the lights
# are contained.
################################################################################

from time import sleep
from random import randint
import RPi.GPIO as GPIO
import lcddriver
import random
import subprocess

# DEBUGGING MODE, DISABLED=0, ENABLED=1
DEBUG=0

# LIST ALL OF THE PINS USED
pinOutList = [23, 21, 19]

# DEFINE THE GPIO NUMBERS AND VARIABLES FOR THE EASTBOUND TRAFFIC
EAST_CR = 23
EAST_CY = 21
EAST_CG = 19

# DEFINE CONSTANTS
LAMPON=GPIO.LOW
LAMPOFF=GPIO.HIGH
FLASHER_DELAY=.7

# display=lcddriver.lcd()
selection = 0
phaseflasher = 0
phasenum = 0
global inColor
inColor = "red"

def setup():
# SET UP GPIO PINS
	GPIO.setmode(GPIO.BOARD)

	# disable GPIO warnings when not debugging
	if DEBUG == 0:
		GPIO.setwarnings(False)

	# loop through each of the pins and define it.
	# turn on all the lights once setup
	for i in pinOutList:
		debug_message("Setting up and activiating pin " + str(i))
		GPIO.setup(i, GPIO.OUT)

	debug_message("Waiting")
	sleep(1)

	# turn off all the lights
	for i in pinOutList:
		GPIO.output(i, GPIO.HIGH)
		debug_message("Turning off pin " + str(i))

	lcd_message("Done performing setup", "")

	return 0

def debug_message(message):
# LOG ADDITIONAL MESSAGES TO THE SCREEN/LOG FILE WHEN TESTING
	if DEBUG == 1:
		log_message("DEBUG: " + message)
	return 0

def log_message(message):
# print message on computer screen
	print message
	return 0

def lcd_message(line1, line2):
# Displays the message on the LCD screen and computer screen
	log_message(line1 + " | " + line2)
	return 0

def run_red_light_green_light(yellowon):
# SEQUENCE FOR RED LIGHT GREEN LIGHT GAME.

	red_time=randint(1, 10)
	green_time=randint(1, 3)
	yellow_time=FLASHER_DELAY

	eblight(LAMPON, LAMPOFF, LAMPOFF)
	debug_message("Red Time: " + str(red_time))
	lcd_message("Red Light!", "Dont move!")
	sleep(red_time)

	eblight(LAMPOFF, LAMPOFF, LAMPON)
	debug_message("Green Time: " + str(green_time))
	lcd_message("Green Light!", "Run!")
	sleep(green_time)

	if yellowon == 1:
		eblight(LAMPOFF, LAMPON, LAMPOFF)
		debug_message("Yellow Time: " + str(yellow_time))
		lcd_message("Yellow Light!", "Slow!")
		sleep(yellow_time)

def run_signal(country):
# runs the light using normal signal
	phaseflasher=0

	east_grn_time=random.randint(5, 30)
	east_yel_time=random.randint(2, 5)
	east_red_time=random.randint(5, 30)

	# red
	eblight(LAMPON, LAMPOFF, LAMPOFF)
	for ttime in range(east_red_time, 0, -1):
		lcd_message("Red", "Time Remain: " + str(ttime) + "s")
		sleep(1)

	# red-yellow for UK only
	if country == "UK":
		eblight(LAMPON, LAMPON, LAMPOFF)
		for ttime in range(east_yel_time, 0, -1):
			lcd_message("Red-Yellow", "Time Remain: " + str(ttime) + "s")
			sleep(1)

	# green
	eblight(LAMPOFF, LAMPOFF, LAMPON)
	for ttime in range(east_grn_time, 0, -1):
		lcd_message("Green", "Time Remain: " + str(ttime) + "s")
		sleep(1)

        # flash green
        if country == "normalflashgreen":
            for i in range(4, randint(5,10)):
                phaseflasher = run_flasher("green", phaseflasher)

	# yellow
	eblight(LAMPOFF, LAMPON, LAMPOFF)
	for ttime in range(east_yel_time, 0, -1):
		lcd_message("Yellow", "Time Remain: " + str(ttime) + "s")
		sleep(1)

	# red
	eblight(LAMPON, LAMPOFF, LAMPOFF)
	for ttime in range(east_red_time, 0, -1):
		lcd_message("Red", "Time Remain: " + str(ttime) + "s")
		sleep(1)

	# change flasher color
	if inColor == "red":
		inColor = "yellow"
		# lcd_message("Yellow Flasher", "")
	else:
		inColor = "red"
		# lcd_message("Red Flasher", "")

	# flasher
	flashrangemax=randint(6,30)
	for i in range(1,flashrangemax):
		phaseflasher = run_flasher(inColor, phaseflasher)

def run_flasher(color, phase):
# flash the lights
	if color == "red":
		if phase == 1:
			eblight(LAMPOFF, LAMPOFF, LAMPOFF)
			lcd_message("Flashing Red", "")
			phase = 2
		else:
			eblight(LAMPON, LAMPOFF, LAMPOFF)
			lcd_message("Flashing Red Off", "")
			phase = 1

	elif color == "yellow":
		if phase == 3:
			eblight(LAMPOFF, LAMPOFF, LAMPOFF)
			lcd_message("Flashing Yellow", "")
			phase = 4
		else:
			eblight(LAMPOFF, LAMPON, LAMPOFF)
			lcd_message("Flashing Yellow Off", "")
			phase = 3

	elif color == "green":
		if phase == 7:
			eblight(LAMPOFF, LAMPOFF, LAMPOFF)
			lcd_message("Flashing Green", "")
			phase = 8
		else:
			eblight(LAMPOFF, LAMPOFF, LAMPON)
			lcd_message("Flashing Green Off", "")
			phase = 7

	sleep(FLASHER_DELAY)
	return phase

def calc_yellow_time(grade):
# CALCULATE THE AMOUNT OF YELLOW LIGHT TIME
        speed = randint(25,80)
	yel_time = 1 + ((1.47 * speed) / (2 * (10 + (0 / 100) * 32.2)))
	return yel_time

def eblight(cirred, ciryel, cirgrn):
# CONTROLS THE LAMPS ON THE EASTBOUND LIGHT. DOESNT HAVE LEFT TURN
	GPIO.output(EAST_CR, cirred)
	GPIO.output(EAST_CY, ciryel)
	GPIO.output(EAST_CG, cirgrn)

def allon(phase):
# TURNS ON THE LIGHTS BASED ON THE ARGUMENT PROVIDED
	if phase == "all":
		eblight(LAMPON, LAMPON, LAMPON)
		lcd_message("ALL LIGHTS ON", "")
	elif phase == "red":
		eblight(LAMPON, LAMPOFF, LAMPOFF)
		lcd_message("ALL REDS ON", "")
	elif phase == "yellow":
		eblight(LAMPOFF, LAMPON, LAMPOFF)
		lcd_message("ALL YELLOWS ON", "")
	elif phase == "green":
		eblight(LAMPOFF, LAMPOFF, LAMPON)
		lcd_message("ALL GREENS ON", "")
	else:
		log_message("Doing nothing")

	sleep(3)

def alloff():
# TURNS OFF ALL OF THE LIGHTS
	lcd_message("ALL LIGHTS OFF", "")
	eblight(LAMPOFF, LAMPOFF, LAMPOFF)
	sleep(3)

# configure everything
setup()

# loop forever
while True:
	debug_message("Debug mode enabled")

	try:
		try:
		# Read the data file
			file = open("/tmp/traffic.txt", "r")
			selection = file.readline()
			file.close()

		except IOError:
			# if the file doesn't exist, then create it and give public permissions
			file = open("/tmp/traffic.txt", "w")
			subprocess.call(['chmod', '0777', '/tmp/traffic.txt'])
			file.close()

		if selection == "":
		# default value if nothing has been selected
			run_signal("US")

		elif selection == "allon":
		# all lights on
			allon("all")

		elif selection == "alloff":
		# all lights off
			alloff()

		elif selection == "flashred":
		# flash red
			lcd_message("Flashing Red", "")
			phaseflasher=run_flasher("red", phaseflasher)

		elif selection == "flashyel":
		# flash yellow
			lcd_message("Flashing Yellow", "")
			phaseflasher = run_flasher("yellow", phaseflasher)

		elif selection == "flashgrn":
		# flash green
			lcd_message("Flashing Green", "")
			phaseflasher=run_flasher("green", phaseflasher)

		elif selection == "ustraffic":
		# US signal pattern
			run_signal("US")

		elif selection == "uktraffic":
		# UK signal pattern
			run_signal("UK")

                elif selection == "normalflashgreen":
                # signal pattern with flashing green
                        run_signal("normalflashgreen")

		elif selection == "redlightgreenlight":
			run_red_light_green_light(0)

		elif selection == "redlightgreenlight2":
			run_red_light_green_light(1)

		elif selection == "restart":
		# restart the Raspberry Pi
			subprocess.call(["sudo", "restart"])

		elif selection == "shutdown":
		# shutdown the Raspberry Pi
			subprocess.call(["sudo", "shutdown", "-h", "now"])

	except KeyboardInterrupt:
		log_message("Exiting")
	        GPIO.cleanup()

	except Exception:
		log_message("Exception thrown")
		while True:
			phaseflasher=run_flasher("yellow", phaseflasher)
		GPIO.cleanup()

<|endoftext|>


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

"""Base class of classification algorithms for free-form text answers"""

from abc import abstractmethod

class BaseClassificationAlgorithm(object):
    """A base class for classifiers that uses supervised learning to match
    free-form text answers to answer groups. The classifier trains on answers
    that exploration editors have assigned to an answer group. Given a new
    answer, it predicts the answer group.

    Below are some concepts used in this class.
    training_data: list of 'training_data'. Each training_data is represented
        by a 2-element list. The first item of the list is the single training
        data, and the second item is a list of labels that the data should
        be matched.
    predicting_data: list of 'predicting_data'. Each element of the list
        represents a single 'predicting_data'.
    label - An answer group that the doc should correspond to. If a doc is
        being added to train a model, labels are provided. If a doc is being
        added for prediction purposes, no labels are provided. If a doc does
        not match any label, the doc should have only one label, '_default'.

    Attributes:
        DEFAULT_LABEL: str. The label used to characterize a word with no label
            assigned to it.
    """

    DEFAULT_LABEL = '_default'

    def __init__(self):
        self.training_data = []

    @abstractmethod
    def from_dict(self, model):
        """Initializes the properties of this classifier from a dict
          constructed using to_dict().

          Args:
              model: A dict representing the classifier.
        """
        pass

    @abstractmethod
    def to_dict(self, model):
        """Returns a dict representing this classifier.

        Returns:
            dict. A representation of the state of the classifier.
        """
        pass

    @abstractmethod
    def predict(self, predicting_data):
        """Returns the predicted label from the predicting_data's prediction
        report.

        Args:
            predicting_data: list of 'predicting_data'.

        Returns:
            list of str. The labels predicted by the classifier
            for the given 'predicting_data'.
        """
        pass

    def train(self, training_data):
        """Loads examples for training.

        Args:
            training_data: list of 'training_data'. Each training_data is
                represented by a 2-element list. The first item of the list
                is the single training data, and the second item is a list
                of labels that the data should be matched.
        """
        pass
<commit_msg>remove useless variables<commit_after># coding: utf-8
#
# Copyright 2015 The Oppia Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS-IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Base class of classification algorithms for free-form text answers"""

from abc import abstractmethod

class BaseClassificationAlgorithm(object):
    """A base class for classifiers that uses supervised learning to match
    free-form text answers to answer groups. The classifier trains on answers
    that exploration editors have assigned to an answer group. Given a new
    answer, it predicts the answer group.

    Below are some concepts used in this class.
    training_data: list of 'training_data'. Each training_data is represented
        by a 2-element list. The first item of the list is the single training
        data, and the second item is a list of labels that the data should
        be matched.
    predicting_data: list of 'predicting_data'. Each element of the list
        represents a single 'predicting_data'.
    label - An answer group that the doc should correspond to. If a doc is
        being added to train a model, labels are provided. If a doc is being
        added for prediction purposes, no labels are provided. If a doc does
        not match any label, the doc should have only one label, '_default'.

    Attributes:
        DEFAULT_LABEL: str. The label used to characterize a word with no label
            assigned to it.
    """

    DEFAULT_LABEL = '_default'

    def __init__(self):
        pass

    @abstractmethod
    def from_dict(self, model):
        """Initializes the properties of this classifier from a dict
          constructed using to_dict().

          Args:
              model: A dict representing the classifier.
        """
        pass

    @abstractmethod
    def to_dict(self, model):
        """Returns a dict representing this classifier.

        Returns:
            dict. A representation of the state of the classifier.
        """
        pass

    @abstractmethod
    def predict(self, predicting_data):
        """Returns the predicted label from the predicting_data's prediction
        report.

        Args:
            predicting_data: list of 'predicting_data'.

        Returns:
            list of str. The labels predicted by the classifier
            for the given 'predicting_data'.
        """
        pass

    def train(self, training_data):
        """Loads examples for training.

        Args:
            training_data: list of 'training_data'. Each training_data is
                represented by a 2-element list. The first item of the list
                is the single training data, and the second item is a list
                of labels that the data should be matched.
        """
        pass
<|endoftext|>


<commit_before># python skirmish/skirmish.py imcs://MiniCheese:cheese@svcs.cs.pdx.edu:3589/accept?id=6260 "run python3 Game.py imcs np"
# python skirmish/skirmish.py "run python3 Game.py np imcs" imcs://MiniCheese:cheese@svcs.cs.pdx.edu:3589/accept?id=6255

# PlayOnline.py w 6200 np
import argparse
import sys
import subprocess

parser = argparse.ArgumentParser(description='Play a game of chess online!')
parser.add_argument('-o', '--offer', action="store_true")
parser.add_argument('-a', '--accept', metavar='id')
parser.add_argument('color', choices=['w', 'b'])
parser.add_argument('our_player', help='command line arguments to our player')
args = parser.parse_args()

BASE_URL = "imcs://MiniCheese:cheese@svcs.cs.pdx.edu:3589"
ACCEPT = "/accept?id={id}"
OFFER = "/offer"

# Players white and black can be one of the following options:

#   "-"                       (communicate with standard in/out)

#   "run COMMAND"             (use standard in/out of the specified shell command)

#   "imcs://user:pass@host:port/PATH", where path is one of:
#       /offer                (offer a game of the player's color)
#       /accept?arg=val[&..]  (accept game with the following allowed parameters)
#         id=N                  (game has id number N)
#         name=STR              (player has name STR)
#         rating=N              (player has rating N)
# """

commandline = ["python2", "skirmish/skirmish.py"]

# commandline for our player
our_player_cmd = ["run", "python3", "Game.py"]
if args.color == 'w':
    our_player_cmd += [args.our_player, 'skirmish']
else:
    our_player_cmd += ['skirmish', args.our_player]
our_player_cmd = " ".join(our_player_cmd)

# commandline for the server player
imcs_player_cmd = BASE_URL
if args.offer:
    imcs_player_cmd += OFFER
elif args.accept:
    imcs_player_cmd += ACCEPT.format(id=args.accept)
else:
    print("you have to either specifie accept or offer")
    sys.exit(0)

# final commandline for skirmish
if args.color == 'w':
    commandline.append(our_player_cmd)
    commandline.append(imcs_player_cmd)
else:
    commandline.append(imcs_player_cmd)
    commandline.append(our_player_cmd)

print(commandline)

subprocess.Popen(commandline)<commit_msg>Activated verbosity for skirmish. Changed subpocess call.<commit_after># python skirmish/skirmish.py imcs://MiniCheese:cheese@svcs.cs.pdx.edu:3589/accept?id=6260 "run python3 Game.py imcs np"
# python skirmish/skirmish.py "run python3 Game.py np imcs" imcs://MiniCheese:cheese@svcs.cs.pdx.edu:3589/accept?id=6255

# PlayOnline.py w 6200 np
import argparse
import sys
import subprocess

parser = argparse.ArgumentParser(description='Play a game of chess online!')
parser.add_argument('-o', '--offer', action="store_true")
parser.add_argument('-a', '--accept', metavar='id')
parser.add_argument('color', choices=['w', 'b'])
parser.add_argument('our_player', help='command line arguments to our player')
args = parser.parse_args()

BASE_URL = "imcs://MiniCheese:cheese@svcs.cs.pdx.edu:3589"
ACCEPT = "/accept?id={id}"
OFFER = "/offer"

## Skirmish command line arguments
# Players white and black can be one of the following options:

#   "-"                       (communicate with standard in/out)

#   "run COMMAND"             (use standard in/out of the specified shell command)

#   "imcs://user:pass@host:port/PATH", where path is one of:
#       /offer                (offer a game of the player's color)
#       /accept?arg=val[&..]  (accept game with the following allowed parameters)
#         id=N                  (game has id number N)
#         name=STR              (player has name STR)
#         rating=N              (player has rating N)
# """

commandline = ["python2", "skirmish/skirmish.py", "-v"]

# commandline for our player
our_player_cmd = ["run", "python3", "Game.py"]
if args.color == 'w':
    our_player_cmd += [args.our_player, 'skirmish']
else:
    our_player_cmd += ['skirmish', args.our_player]
our_player_cmd = " ".join(our_player_cmd)

# commandline for the server player
imcs_player_cmd = BASE_URL
if args.offer:
    imcs_player_cmd += OFFER
elif args.accept:
    imcs_player_cmd += ACCEPT.format(id=args.accept)
else:
    print("you have to either specifie accept or offer")
    sys.exit(0)

# final commandline for skirmish
if args.color == 'w':
    commandline.append(our_player_cmd)
    commandline.append(imcs_player_cmd)
else:
    commandline.append(imcs_player_cmd)
    commandline.append(our_player_cmd)

subprocess.call(commandline)<|endoftext|>


<commit_before>#!/usr/bin/env python
"""
basic plotting of radar data
"""
from pathlib import Path
import numpy as np
import scipy.signal as signal
from matplotlib.pyplot import figure,draw,show
#
from piradar import loadbin, playaudio
from radioutils import am_demod

fsaudio = 16e3 # [Hz]

def simple(fn,fs, tlim, fx=None):
    fn = Path(fn).expanduser()

    decim = int(fs/fsaudio)

    dat,t = loadbin(fn, fs, tlim, fx, decim)

    if fx is not None:
        fs /= decim

    return dat,t

def plots(dat,t,fs,zeropad):

    Nfft = int(dat.size*zeropad)

    f,Sp = signal.welch(dat, fs,
                        nperseg=Nfft,
                        window = 'hann',
    #                    noverlap=Nol,
                        nfft=Nfft,
                        return_onesided=False
                        )

    ax = figure().gca()
    ax.plot(f,10*np.log10(Sp))

    draw() # so that plots show while audio is playing

if __name__ == '__main__':
    from argparse import ArgumentParser
    p = ArgumentParser()
    p.add_argument('fn')
    p.add_argument('fs',type=float)
    p.add_argument('-t','--tlim',type=float,nargs=2,default=(0,None))
    p.add_argument('-z','--zeropad',type=float,default=1)
    p.add_argument('-a','--amplitude',type=float,help='gain factor for demodulated audio. real radios use an AGC.',default=1.)
    p = p.parse_args()

    fs = int(p.fs)

    dat,t = simple(p.fn, fs, p.tlim)

    plots(dat, t, fs, p.zeropad)

    aud = am_demod(p.amplitude*dat, fs, fsaudio, fc=3.5e3)

    playaudio(aud, fsaudio)

    show()<commit_msg>plot label<commit_after>#!/usr/bin/env python
"""
basic plotting of radar data
"""
from pathlib import Path
import numpy as np
import scipy.signal as signal
from matplotlib.pyplot import figure,draw,show
#
from piradar import loadbin, playaudio
from radioutils import am_demod

fsaudio = 16e3 # [Hz]

def simple(fn,fs, tlim, fx=None):
    fn = Path(fn).expanduser()

    decim = int(fs/fsaudio)

    dat,t = loadbin(fn, fs, tlim, fx, decim)

    if fx is not None:
        fs /= decim

    return dat,t

def plots(dat,t,fs,zeropad,audiobw,plotmin=None,fn=''):

    Nfft = int(dat.size*zeropad)

    f,Sp = signal.welch(dat, fs,
                        nperseg=Nfft,
                        window = 'hann',
    #                    noverlap=Nol,
                        nfft=Nfft,
                        return_onesided=False
                        )

    ax = figure().gca()

    ax.plot(f/1e3, 10*np.log10(Sp))
    ax.axvline(-audiobw/1e3,linestyle='--',color='red')
    ax.axvline(audiobw/1e3,linestyle='--',color='red')

    ax.set_ylim((plotmin,None))
    ax.grid(True)
    ax.set_xlabel('baseband freq. [kHz]')
    ax.set_ylabel('relative ampl. [dB]')
    ax.set_title(str(fn))

    draw() # so that plots show while audio is playing

if __name__ == '__main__':
    from argparse import ArgumentParser
    p = ArgumentParser()
    p.add_argument('fn')
    p.add_argument('fs',type=float)
    p.add_argument('-t','--tlim',type=float,nargs=2,default=(0,None))
    p.add_argument('-z','--zeropad',type=float,default=1)
    p.add_argument('-a','--amplitude',type=float,help='gain factor for demodulated audio. real radios use an AGC.',default=1.)
    p.add_argument('--plotmin',help='lower limit of spectrum display',type=float,default=-130)
    p.add_argument('--audiobw',help='desired audio bandwidth [Hz] for demodulated AM',type=float,default=3.5e3)
    p = p.parse_args()

    fs = int(p.fs)

    dat,t = simple(p.fn, fs, p.tlim)

    plots(dat, t, fs, p.zeropad,p.audiobw, p.plotmin, p.fn)

    aud = am_demod(p.amplitude*dat, fs, fsaudio, fc=p.audiobw)

    playaudio(aud, fsaudio)

    show()<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
According to data from official site [1], VxStream Sandbox Public API allows you to analyze:

- hash
- filename
- host / ip (some problems on API side for now)
- domain / fqdn (some problems on API side for now)

[1] https://www.hybrid-analysis.com/apikeys/info
"""

import hashlib
import requests
import time

from requests.auth import HTTPBasicAuth
from cortexutils.analyzer import Analyzer

class VxStreamSandboxAnalyzer(Analyzer):
    def __init__(self):
        Analyzer.__init__(self)
        self.basic_url = 'https://www.hybrid-analysis.com/api/'
        self.headers = {'User-Agent': 'VxStream'}

        self.secret = self.get_param('config.secret', None, 'VxStream Sandbox secret key is missing')
        self.api_key = self.get_param('config.key', None, 'VxStream Sandbox API key is missing')

    def summary(self, raw_report):
        taxonomies = []

        # default values
        level = "info"
        namespace = "HybridAnalysis"
        predicate = "Threat level"
        value = "\"No verdict\""

        # define json keys to loop
        if self.data_type in ['hash', 'file']:
            minireports = raw_report.get('results').get('response')
        elif self.data_type in ['filename']:
            minireports = raw_report.get('results').get('response').get('result')

        if len(minireports) != 0:
            # get first report with not Null verdict
            for minireport in minireports:
                if minireport.get('verdict') is not None:
                    report_verdict = minireport.get('verdict')
                    break

            # create shield badge for short.html
            if report_verdict == 'malicious':
                level = 'malicious'
                value = "\"Malicious\""
            elif report_verdict == 'suspicious':
                level = 'suspicious'
                value = "\"Suspicious\""
            elif report_verdict == 'whitelisted':
                level = 'safe'
                value = "\"Whitelisted\""
            elif report_verdict == 'no specific threat':
                level = 'info'
                value = "\"No Specific Threat\""
        else:
            level = 'info'
            value = "\"No threat found\""

        taxonomies.append(self.build_taxonomy(level, namespace, predicate, value))
        return {"taxonomies": taxonomies}

    def run(self):

        try:
            if self.data_type == 'hash':
                query_url = 'scan/'
                query_data = self.get_param('data', None, 'Hash is missing')

            elif self.data_type == 'file':
                query_url = 'scan/'
                hashes = self.get_param('attachment.hashes', None)

                if hashes is None:
                    filepath = self.get_param('file', None, 'File is missing')
                    query_data = hashlib.sha256(open(filepath, 'r').read()).hexdigest()
                else:
                    # find SHA256 hash
                    query_data = next(h for h in hashes if len(h) == 64)

            elif self.data_type == 'filename':
                query_url = 'search?query=filename:'
                query_data = self.get_param('data', None, 'Filename is missing')
            else:
                self.notSupported()

            url = str(self.basic_url) + str(query_url) + str(query_data)

            error = True
            while error:
                r = requests.get(url, headers=self.headers, auth=HTTPBasicAuth(self.api_key, self.secret), verify=False)
                if "error" in r.json().get('response'):
                    if "Exceeded maximum API requests per minute(5)" in r.json().get('response').get('error'):
                        time.sleep(60)
                    else:
                        self.error(r.json().get('response').get('error'))
                else:
                    error = False

            self.report({'results': r.json()})

        except ValueError as e:
            self.unexpectedError(e)

if __name__ == '__main__':
    VxStreamSandboxAnalyzer().run()
<commit_msg>#267 update wording<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
According to data from official site [1], VxStream Sandbox Public API allows you to analyze:

- hash
- filename
- host / ip (some problems on API side for now)
- domain / fqdn (some problems on API side for now)

[1] https://www.hybrid-analysis.com/apikeys/info
"""

import hashlib
import requests
import time

from requests.auth import HTTPBasicAuth
from cortexutils.analyzer import Analyzer

class VxStreamSandboxAnalyzer(Analyzer):
    def __init__(self):
        Analyzer.__init__(self)
        self.basic_url = 'https://www.hybrid-analysis.com/api/'
        self.headers = {'User-Agent': 'VxStream'}

        self.secret = self.get_param('config.secret', None, 'VxStream Sandbox secret key is missing')
        self.api_key = self.get_param('config.key', None, 'VxStream Sandbox API key is missing')

    def summary(self, raw_report):
        taxonomies = []

        # default values
        level = "info"
        namespace = "HybridAnalysis"
        predicate = "Threat level"
        value = "\"No verdict\""

        # define json keys to loop
        if self.data_type in ['hash', 'file']:
            minireports = raw_report.get('results').get('response')
        elif self.data_type in ['filename']:
            minireports = raw_report.get('results').get('response').get('result')

        if len(minireports) != 0:
            # get first report with not Null verdict
            for minireport in minireports:
                if minireport.get('verdict') is not None:
                    report_verdict = minireport.get('verdict')
                    break

            # create shield badge for short.html
            if report_verdict == 'malicious':
                level = 'malicious'
                value = "\"Malicious\""
            elif report_verdict == 'suspicious':
                level = 'suspicious'
                value = "\"Suspicious\""
            elif report_verdict == 'whitelisted':
                level = 'safe'
                value = "\"Whitelisted\""
            elif report_verdict == 'no specific threat':
                level = 'info'
                value = "\"No Specific Threat\""
        else:
            level = 'info'
            value = "\"None\""

        taxonomies.append(self.build_taxonomy(level, namespace, predicate, value))
        return {"taxonomies": taxonomies}

    def run(self):

        try:
            if self.data_type == 'hash':
                query_url = 'scan/'
                query_data = self.get_param('data', None, 'Hash is missing')

            elif self.data_type == 'file':
                query_url = 'scan/'
                hashes = self.get_param('attachment.hashes', None)

                if hashes is None:
                    filepath = self.get_param('file', None, 'File is missing')
                    query_data = hashlib.sha256(open(filepath, 'r').read()).hexdigest()
                else:
                    # find SHA256 hash
                    query_data = next(h for h in hashes if len(h) == 64)

            elif self.data_type == 'filename':
                query_url = 'search?query=filename:'
                query_data = self.get_param('data', None, 'Filename is missing')
            else:
                self.notSupported()

            url = str(self.basic_url) + str(query_url) + str(query_data)

            error = True
            while error:
                r = requests.get(url, headers=self.headers, auth=HTTPBasicAuth(self.api_key, self.secret), verify=False)
                if "error" in r.json().get('response'):
                    if "Exceeded maximum API requests per minute(5)" in r.json().get('response').get('error'):
                        time.sleep(60)
                    else:
                        self.error(r.json().get('response').get('error'))
                else:
                    error = False

            self.report({'results': r.json()})

        except ValueError as e:
            self.unexpectedError(e)

if __name__ == '__main__':
    VxStreamSandboxAnalyzer().run()
<|endoftext|>