from __future__ import absolute_import
from typing import Any, List, Dict, Optional, Text

from django.conf import settings
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect, HttpResponse, HttpRequest
from django.shortcuts import redirect
from django.utils import translation
from django.utils.cache import patch_cache_control
from six.moves import zip_longest, zip, range

from zerver.decorator import zulip_login_required, process_client
from zerver.forms import ToSForm
from zerver.lib.realm_icon import realm_icon_url
from zerver.models import Message, UserProfile, Stream, Subscription, Huddle, \
    Recipient, Realm, UserMessage, DefaultStream, RealmEmoji, RealmAlias, \
    RealmFilter, PreregistrationUser, UserActivity, \
    UserPresence, get_recipient, name_changes_disabled, email_to_username, \
    list_of_domains_for_realm
from zerver.lib.events import do_events_register
from zerver.lib.actions import update_user_presence, do_change_tos_version, \
    do_update_pointer, get_cross_realm_dicts, realm_user_count
from zerver.lib.avatar import avatar_url
from zerver.lib.i18n import get_language_list, get_language_name, \
    get_language_list_for_templates
from zerver.lib.push_notifications import num_push_devices_for_user
from zerver.lib.streams import access_stream_by_name
from zerver.lib.utils import statsd, get_subdomain
from zproject.backends import password_auth_enabled
from zproject.jinja2 import render_to_response

import calendar
import datetime
import logging
import os
import re
import simplejson
import time

@zulip_login_required
def accounts_accept_terms(request):
    # type: (HttpRequest) -> HttpResponse
    if request.method == "POST":
        form = ToSForm(request.POST)
        if form.is_valid():
            do_change_tos_version(request.user, settings.TOS_VERSION)
            return redirect(home)
    else:
        form = ToSForm()

    email = request.user.email
    special_message_template = None
    if request.user.tos_version is None and settings.FIRST_TIME_TOS_TEMPLATE is not None:
        special_message_template = 'zerver/' + settings.FIRST_TIME_TOS_TEMPLATE
    return render_to_response(
        'zerver/accounts_accept_terms.html',
        {'form': form,
         'email': email,
         'special_message_template': special_message_template},
        request=request)

def approximate_unread_count(user_profile):
    # type: (UserProfile) -> int
    not_in_home_view_recipients = [sub.recipient.id for sub in
                                   Subscription.objects.filter(
                                       user_profile=user_profile, in_home_view=False)]

    # TODO: We may want to exclude muted messages from this count.
    #       It was attempted in the past, but the original attempt
    #       was broken.  When we re-architect muting, we may
    #       want to to revisit this (see git issue #1019).
    return UserMessage.objects.filter(
        user_profile=user_profile, message_id__gt=user_profile.pointer).exclude(
        message__recipient__type=Recipient.STREAM,
        message__recipient__id__in=not_in_home_view_recipients).exclude(
        flags=UserMessage.flags.read).count()

def sent_time_in_epoch_seconds(user_message):
    # type: (UserMessage) -> Optional[float]
    # user_message is a UserMessage object.
    if not user_message:
        return None
    # We have USE_TZ = True, so our datetime objects are timezone-aware.
    # Return the epoch seconds in UTC.
    return calendar.timegm(user_message.message.pub_date.utctimetuple())

def home(request):
    # type: (HttpRequest) -> HttpResponse
    if settings.DEVELOPMENT and os.path.exists('var/handlebars-templates/compile.error'):
        response = render_to_response('zerver/handlebars_compilation_failed.html',
                                      request=request)
        response.status_code = 500
        return response
    if not settings.SUBDOMAINS_HOMEPAGE:
        return home_real(request)

    # If settings.SUBDOMAINS_HOMEPAGE, sends the user the landing
    # page, not the login form, on the root domain

    subdomain = get_subdomain(request)
    if subdomain != "":
        return home_real(request)

    return render_to_response('zerver/hello.html',
                              request=request)

@zulip_login_required
def home_real(request):
    # type: (HttpRequest) -> HttpResponse
    # We need to modify the session object every two weeks or it will expire.
    # This line makes reloading the page a sufficient action to keep the
    # session alive.
    request.session.modified = True

    user_profile = request.user

    # If a user hasn't signed the current Terms of Service, send them there
    if settings.TERMS_OF_SERVICE is not None and settings.TOS_VERSION is not None and \
       int(settings.TOS_VERSION.split('.')[0]) > user_profile.major_tos_version():
        return accounts_accept_terms(request)

    narrow = [] # type: List[List[Text]]
    narrow_stream = None
    narrow_topic = request.GET.get("topic")
    if request.GET.get("stream"):
        try:
            narrow_stream_name = request.GET.get("stream")
            (narrow_stream, ignored_rec, ignored_sub) = access_stream_by_name(
                user_profile, narrow_stream_name)
            narrow = [["stream", narrow_stream.name]]
        except Exception:
            logging.exception("Narrow parsing")
        if narrow_stream is not None and narrow_topic is not None:
            narrow.append(["topic", narrow_topic])

    register_ret = do_events_register(user_profile, request.client,
                                      apply_markdown=True, narrow=narrow)
    user_has_messages = (register_ret['max_message_id'] != -1)

    # Reset our don't-spam-users-with-email counter since the
    # user has since logged in
    if user_profile.last_reminder is not None:
        user_profile.last_reminder = None
        user_profile.save(update_fields=["last_reminder"])

    # Brand new users get the tutorial
    needs_tutorial = settings.TUTORIAL_ENABLED and \
        user_profile.tutorial_status != UserProfile.TUTORIAL_FINISHED

    first_in_realm = realm_user_count(user_profile.realm) == 1
    # If you are the only person in the realm and you didn't invite
    # anyone, we'll continue to encourage you to do so on the frontend.
    prompt_for_invites = first_in_realm and \
        not PreregistrationUser.objects.filter(referred_by=user_profile).count()

    if user_profile.pointer == -1 and user_has_messages:
        # Put the new user's pointer at the bottom
        #
        # This improves performance, because we limit backfilling of messages
        # before the pointer.  It's also likely that someone joining an
        # organization is interested in recent messages more than the very
        # first messages on the system.

        register_ret['pointer'] = register_ret['max_message_id']
        user_profile.last_pointer_updater = request.session.session_key

    if user_profile.pointer == -1:
        latest_read = None
    else:
        try:
            latest_read = UserMessage.objects.get(user_profile=user_profile,
                                                  message__id=user_profile.pointer)
        except UserMessage.DoesNotExist:
            # Don't completely fail if your saved pointer ID is invalid
            logging.warning("%s has invalid pointer %s" % (user_profile.email, user_profile.pointer))
            latest_read = None

    desktop_notifications_enabled = user_profile.enable_desktop_notifications
    if narrow_stream is not None:
        desktop_notifications_enabled = False

    if user_profile.realm.notifications_stream:
        notifications_stream = user_profile.realm.notifications_stream.name
    else:
        notifications_stream = ""

    # Set default language and make it persist
    default_language = register_ret['default_language']
    url_lang = '/{}'.format(request.LANGUAGE_CODE)
    if not request.path.startswith(url_lang):
        translation.activate(default_language)

    request.session[translation.LANGUAGE_SESSION_KEY] = default_language

    # Pass parameters to the client-side JavaScript code.
    # These end up in a global JavaScript Object named 'page_params'.
    page_params = dict(
        # Server settings.
        share_the_love        = settings.SHARE_THE_LOVE,
        development_environment = settings.DEVELOPMENT,
        debug_mode            = settings.DEBUG,
        test_suite            = settings.TEST_SUITE,
        poll_timeout          = settings.POLL_TIMEOUT,
        login_page            = settings.HOME_NOT_LOGGED_IN,
        server_uri            = settings.SERVER_URI,
        maxfilesize           = settings.MAX_FILE_UPLOAD_SIZE,
        max_avatar_file_size  = settings.MAX_AVATAR_FILE_SIZE,
        server_generation     = settings.SERVER_GENERATION,
        use_websockets        = settings.USE_WEBSOCKETS,
        save_stacktraces      = settings.SAVE_FRONTEND_STACKTRACES,

        # realm data.
        # TODO: Move all of these data to register_ret and pull from there
        realm_uri             = user_profile.realm.uri,
        password_auth_enabled = password_auth_enabled(user_profile.realm),
        domains               = list_of_domains_for_realm(user_profile.realm),
        name_changes_disabled = name_changes_disabled(user_profile.realm),
        mandatory_topics      = user_profile.realm.mandatory_topics,
        show_digest_email     = user_profile.realm.show_digest_email,
        realm_presence_disabled = user_profile.realm.presence_disabled,
        is_zephyr_mirror_realm = user_profile.realm.is_zephyr_mirror_realm,

        # user_profile data.
        # TODO: Move all of these data to register_ret and pull from there
        fullname              = user_profile.full_name,
        email                 = user_profile.email,
        enter_sends           = user_profile.enter_sends,
        user_id               = user_profile.id,
        is_admin              = user_profile.is_realm_admin,
        can_create_streams    = user_profile.can_create_streams(),
        autoscroll_forever = user_profile.autoscroll_forever,
        default_desktop_notifications = user_profile.default_desktop_notifications,
        avatar_url            = avatar_url(user_profile),
        avatar_url_medium     = avatar_url(user_profile, medium=True),
        avatar_source         = user_profile.avatar_source,
        timezone              = user_profile.timezone,

        # Stream message notification settings:
        stream_desktop_notifications_enabled = user_profile.enable_stream_desktop_notifications,
        stream_sounds_enabled = user_profile.enable_stream_sounds,

        # Private message and @-mention notification settings:
        desktop_notifications_enabled = desktop_notifications_enabled,
        sounds_enabled = user_profile.enable_sounds,
        enable_offline_email_notifications = user_profile.enable_offline_email_notifications,
        pm_content_in_desktop_notifications = user_profile.pm_content_in_desktop_notifications,
        enable_offline_push_notifications = user_profile.enable_offline_push_notifications,
        enable_online_push_notifications = user_profile.enable_online_push_notifications,
        enable_digest_emails  = user_profile.enable_digest_emails,

        # Realm foreign key data from register_ret.
        # TODO: Rename these to match register_ret values.
        subbed_info           = register_ret['subscriptions'],
        unsubbed_info         = register_ret['unsubscribed'],
        neversubbed_info      = register_ret['never_subscribed'],
        people_list           = register_ret['realm_users'],
        bot_list              = register_ret['realm_bots'],
        initial_pointer       = register_ret['pointer'],
        initial_presences     = register_ret['presences'],
        event_queue_id        = register_ret['queue_id'],

        # Misc. extra data.
        have_initial_messages = user_has_messages,
        initial_servertime    = time.time(), # Used for calculating relative presence age
        default_language_name = get_language_name(register_ret['default_language']),
        language_list_dbl_col = get_language_list_for_templates(register_ret['default_language']),
        language_list         = get_language_list(),
        needs_tutorial        = needs_tutorial,
        first_in_realm        = first_in_realm,
        prompt_for_invites    = prompt_for_invites,
        notifications_stream  = notifications_stream,
        cross_realm_bots      = list(get_cross_realm_dicts()),
        unread_count          = approximate_unread_count(user_profile),
        furthest_read_time    = sent_time_in_epoch_seconds(latest_read),
        has_mobile_devices    = num_push_devices_for_user(user_profile) > 0,
    )

    # These fields will be automatically copied from register_ret into
    # page_params.  It is a goal to move more of the page_params list
    # into this sort of cleaner structure.
    page_params_core_fields = [
        'alert_words',
        'attachments',
        'default_language',
        'emoji_alt_code',
        'last_event_id',
        'left_side_userlist',
        'max_icon_file_size',
        'max_message_id',
        'muted_topics',
        'realm_add_emoji_by_admins_only',
        'realm_allow_message_editing',
        'realm_authentication_methods',
        'realm_bot_domain',
        'realm_create_stream_by_admins_only',
        'realm_default_language',
        'realm_default_streams',
        'realm_email_changes_disabled',
        'realm_emoji',
        'realm_filters',
        'realm_icon_source',
        'realm_icon_url',
        'realm_invite_by_admins_only',
        'realm_invite_required',
        'realm_message_content_edit_limit_seconds',
        'realm_name',
        'realm_name_changes_disabled',
        'realm_restricted_to_domain',
        'realm_waiting_period_threshold',
        'referrals',
        'twenty_four_hour_time',
        'zulip_version',
    ]

    for field_name in page_params_core_fields:
        page_params[field_name] = register_ret[field_name]

    if narrow_stream is not None:
        # In narrow_stream context, initial pointer is just latest message
        recipient = get_recipient(Recipient.STREAM, narrow_stream.id)
        try:
            initial_pointer = Message.objects.filter(recipient=recipient).order_by('id').reverse()[0].id
        except IndexError:
            initial_pointer = -1
        page_params["narrow_stream"] = narrow_stream.name
        if narrow_topic is not None:
            page_params["narrow_topic"] = narrow_topic
        page_params["narrow"] = [dict(operator=term[0], operand=term[1]) for term in narrow]
        page_params["max_message_id"] = initial_pointer
        page_params["initial_pointer"] = initial_pointer
        page_params["have_initial_messages"] = (initial_pointer != -1)

    statsd.incr('views.home')
    show_invites = True

    # Some realms only allow admins to invite users
    if user_profile.realm.invite_by_admins_only and not user_profile.is_realm_admin:
        show_invites = False

    request._log_data['extra'] = "[%s]" % (register_ret["queue_id"],)
    response = render_to_response('zerver/index.html',
                                  {'user_profile': user_profile,
                                   'page_params': simplejson.encoder.JSONEncoderForHTML().encode(page_params),
                                   'nofontface': is_buggy_ua(request.META.get("HTTP_USER_AGENT", "Unspecified")),
                                   'avatar_url': avatar_url(user_profile),
                                   'show_debug':
                                       settings.DEBUG and ('show_debug' in request.GET),
                                   'pipeline': settings.PIPELINE_ENABLED,
                                   'show_invites': show_invites,
                                   'is_admin': user_profile.is_realm_admin,
                                   'show_webathena': user_profile.realm.webathena_enabled,
                                   'enable_feedback': settings.ENABLE_FEEDBACK,
                                   'embedded': narrow_stream is not None,
                                   },
                                  request=request)
    patch_cache_control(response, no_cache=True, no_store=True, must_revalidate=True)
    return response

@zulip_login_required
def desktop_home(request):
    # type: (HttpRequest) -> HttpResponse
    return HttpResponseRedirect(reverse('zerver.views.home.home'))

def is_buggy_ua(agent):
    # type: (str) -> bool
    """Discrimiate CSS served to clients based on User Agent

    Due to QTBUG-3467, @font-face is not supported in QtWebKit.
    This may get fixed in the future, but for right now we can
    just serve the more conservative CSS to all our desktop apps.
    """
    return ("Humbug Desktop/" in agent or "Zulip Desktop/" in agent or "ZulipDesktop/" in agent) and \
        "Mac" not in agent


from zeit.cms.i18n import MessageFactory as _
from zope.cachedescriptors.property import Lazy as cachedproperty
import os.path
import zeit.cms.browser.view
import zeit.cms.content.interfaces
import zeit.cms.interfaces
import zeit.content.image.interfaces
import zeit.content.video.interfaces
import zeit.edit.browser.form
import zeit.edit.browser.landing
import zeit.edit.browser.view
import zeit.newsletter.interfaces
import zope.formlib.form

class LandingZoneBase(zeit.edit.browser.landing.LandingZone):

    uniqueId = zeit.edit.browser.view.Form('uniqueId')
    block_type = 'teaser'

    def initialize_block(self):
        content = zeit.cms.interfaces.ICMSContent(self.uniqueId)
        self.block.reference = content

class GroupLandingZone(LandingZoneBase):
    """Handler to drop objects to the body's landing zone."""

    order = 0

class TeaserLandingZone(LandingZoneBase):
    """Handler to drop objects after other objects."""

    order = 'after-context'

class Teaser(zeit.cms.browser.view.Base):

    @cachedproperty
    def metadata(self):
        return zeit.cms.content.interfaces.ICommonMetadata(
            self.context.reference, None)

    @cachedproperty
    def image(self):
        # XXX copy&paste&tweak of zeit.content.cp.browser.blocks.teaser.Display
        content = self.context.reference
        if content is None:
            return
        if zeit.content.video.interfaces.IVideoContent.providedBy(content):
            return content.thumbnail
        images = zeit.content.image.interfaces.IImages(content, None)
        if images is None:
            preview = zope.component.queryMultiAdapter(
                (content, self.request), name='preview')
            if preview:
                return self.url(preview)
            return
        if not images.image:
            return
        group = images.image
        for name in group:
            basename, ext = os.path.splitext(name)
            if basename.endswith('148x84'):
                image = group[name]
                return self.url(image, '@@raw')

class Advertisement(zeit.cms.browser.view.Base):

    @cachedproperty
    def image(self):
        if not self.context.image:
            return
        return self.url(self.context.image, '@@raw')

class GroupTitle(zeit.edit.browser.form.InlineForm):

    legend = None
    prefix = 'group'
    undo_description = _('edit group title')

    form_fields = zope.formlib.form.FormFields(
        zeit.newsletter.interfaces.IGroup).select('title')

class Empty(object):

    def render(self):
        return u''


# Waitrose web scraper

__author__ = 'robdobsn'

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import selenium.webdriver.support.ui as webdriverui
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.common.exceptions import NoSuchElementException, WebDriverException, TimeoutException
from selenium.webdriver.support import expected_conditions as EC
from bs4 import BeautifulSoup
import logging
import json
import re

class WaitroseScraper():

    def __init__(self):
        logging.info("Waitrose scraper starting")
        self.isInitalized = False
        self.isLoggedIn = False
        self.webDriverType = "PhantomJS"
        self.execUsingJS = False

    def clickButtonByClassName(self, className):
        if self.execUsingJS:
            self.webDriver.execute_script("document.getElementsByClassName('" + className + "')[0].click()")
        else:
            btn = self.webDriver.find_element_by_class_name(className)
            btn.click()

    def clickButtonByXPath(self, xpath):
        if self.execUsingJS:
            self.webDriver.execute_script("return document.evaluate('" + xpath + "', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue.click()")
        else:
            btn = self.webDriver.find_element_by_xpath(xpath)
            btn.click()

    def clickButtonByCSSSelector(self, cssSelector):
        btn = self.webDriver.find_element_by_css_selector(cssSelector)
        btn.click()

    def checkButtonEnabledByCSSSelector(self, cssSelector):
        btn = self.webDriver.find_element_by_css_selector(cssSelector)
        return btn.is_enabled() and btn.is_displayed()

    def sendKeysToFieldById(self, elemId, strToSend, pressEnterAfter, clearFirst):
#       if self.execUsingJS:
#            self.webDriver.execute_script("document.getElementsByClassName('" + elemId + "').value = '" + strToSend)
#        else:
        print("Sending keys to elemId " + elemId + " keys = " + strToSend)
        field = self.webDriver.find_element_by_id(elemId)
        print(field)
        if (clearFirst):
            field.send_keys(Keys.CONTROL + "a")
            field.send_keys(Keys.DELETE)
        field.send_keys(strToSend + (Keys.RETURN if pressEnterAfter else ""))

    def debugDumpPageSource(self, filenameExtra=""):
        with open("debugPageSource" + filenameExtra + ".html", "w") as debugDumpFile:
           debugDumpFile.write(self.webDriver.page_source)
        self.webDriver.save_screenshot('debugPageImage.png')

    # Start the web driver (runs the browser)
    def startWebDriver(self):

        # Clear current session file info
        with open('browserSession.json', 'w') as outfile:
            json.dump({}, outfile)

        # Create WebDriver
        if self.webDriverType == "Chrome":
            try:
                self.webDriver = webdriver.Chrome()
            except WebDriverException:
                logging.error("startWebDriver() Chrome Failed to start")
                return False
        elif self.webDriverType == "Firefox":
            try:
                self.webDriver = webdriver.Firefox()
            except WebDriverException:
                logging.error("startWebDriver() Firefox Failed to start")
                return False
        elif self.webDriverType == "PhantomJS":
            try:
                self.webDriver = webdriver.PhantomJS()  # or add to your PATH
            except:
                try:
                    self.webDriver = webdriver.PhantomJS(
                        executable_path='C:\ProgramData\PhantomJS\bin')
                except:
                    try:
                        self.webDriver = webdriver.PhantomJS(
                            executable_path='/usr/local/lib/node_modules/phantomjs/lib/phantom/bin/phantomjs')
                    except:
                        try:
                            self.webDriver = webdriver.PhantomJS(
                                executable_path=r'C:\Users\rob_2\AppData\Roaming\npm\node_modules\phantomjs\lib\phantom\bin\phantomjs.exe')
                        except:
                            logging.error("Failed to load the PhantomJS webdriver")
                            return False

        # Set the window size (seems to be needed in phantomJS particularly
        # This is probably because the website responds in mobile mode?
        self.webDriver.set_window_size(1280,1024)

        # Save session info
        url = self.webDriver.command_executor._url
        session_id = self.webDriver.session_id
        with open('browserSession.json', 'w') as outfile:
            json.dump({"url": url, "session_id": session_id}, outfile)

        return True

    def websiteLogin(self, username, password, attemptIdx):
        try:
            self.webDriver.save_screenshot('debug1_'+str(attemptIdx)+'.png')
            logging.info("Waiting for signInRegister button")
            wait = WebDriverWait(self.webDriver, 30)
            wait.until(EC.visibility_of_element_located((By.CLASS_NAME, "js-sign-in-register")))
            logging.info("waitroseLogin() pressing signInRegister button")
            self.clickButtonByClassName('js-sign-in-register')
            self.webDriver.save_screenshot('debug2_'+str(attemptIdx)+'.png')

            try:
                print("Starting to wait for logon-email")
                wait = WebDriverWait(self.webDriver, 30)
                wait.until(EC.visibility_of_element_located((By.ID, "logon-email")))
                print("Finished waiting for logon-email")
                self.webDriver.save_screenshot('debug3_' + str(attemptIdx) + '.png')

                try:
                    logging.info("waitroseLogin() entering username")
                    self.debugDumpPageSource("contbutton")
                    self.sendKeysToFieldById('logon-email', username, False, True)
                    self.webDriver.save_screenshot('debug4_' + str(attemptIdx) + '.png')
                    # self.clickButtonByXPath("//input[@type='button' and @value='Continue']")
                    if (self.checkButtonEnabledByCSSSelector("input[value='Continue'][type='button']")):
                        self.clickButtonByCSSSelector("input[value='Continue'][type='button']")

                    try:
                        logging.info("waitroseLogin() waiting for logon-password visible")
                        wait = WebDriverWait(self.webDriver, 60)
                        wait.until(EC.visibility_of_element_located((By.ID, "logon-password")))
                        self.webDriver.save_screenshot('debug5_' + str(attemptIdx) + '.png')

                        try:
                            logging.info("waitroseLogin() entering password")
                            self.sendKeysToFieldById('logon-password', password, False, True)
                            #self.clickButtonById('logon-button-sign-in')
                            self.clickButtonByCSSSelector("input[value='Sign in'][type='button']")
                            self.webDriver.save_screenshot('debug6_' + str(attemptIdx) + '.png')
                            logging.info("waitroseLogin() waiting for trolley-total to be visible")
                            wait = WebDriverWait(self.webDriver, 60)
                            wait.until(EC.visibility_of_element_located((By.CLASS_NAME, "trolley-total")))
                            self.webDriver.save_screenshot('debug7_' + str(attemptIdx) + '.png')
                            elem2 = self.webDriver.find_element_by_class_name('trolley-total')
                            if elem2:
                                logging.info("waitroseLogin() basket found")
                            else:
                                logging.info("waitroseLogin() basket not found")

                            return True

                        except WebDriverException as err:
                            logging.error("waitroseLogin() Cannot find logon-password after wait " + err.msg)
                            self.debugDumpPageSource()

                    except WebDriverException as err:
                        logging.error("waitroseLogin() Cannot find logon-password field" + err.msg)
                        self.debugDumpPageSource()

                except WebDriverException as err:
                    logging.error("waitroseLogin() Error entering logon-email" + err.msg)
                    self.debugDumpPageSource()

            except WebDriverException as err:
                logging.error("waitroseLogin() Cannot find logon-email field" + err.msg)
                self.debugDumpPageSource()

        except WebDriverException as err:
            logging.error("waitroseLogin() Cannot find sign-in-register button" + err.msg)
            self.debugDumpPageSource()

        return False

    def getBasketSummary(self):

        basketSummary = {}

        # Ensure we wait until the trolley-total is visible
        try:
            wait = WebDriverWait(self.webDriver, 20)
            wait.until(EC.visibility_of_element_located((By.CLASS_NAME, "trolley-total")))
        except TimeoutException:
            logging.error("Get basket summary timeout exception")
            self.debugDumpPageSource()
            return None
        except WebDriverException:
            logging.error("Get basket summary webdriver element exception")
            self.debugDumpPageSource()
            return None

        # Get basket total price
        try:
            totalElem = self.webDriver.find_element_by_class_name('trolley-total')
            if totalElem:
                reTotalElem = re.search("([0-9]{1,4}\.[0-9]{2})", totalElem.text)
                if reTotalElem:
                    basketSummary["totalPrice"] = reTotalElem.group(1)
                    logging.info("waitrose: Basket: total=" + str(basketSummary["totalPrice"]))

            # Get number of basket items
            summaryElem = self.webDriver.find_element_by_class_name('trolley-summary')
            if summaryElem:
                reSummaryElem = re.search("([0-9]{1,4}) items", summaryElem.text)
                if reSummaryElem:
                    basketSummary["numItems"] = reSummaryElem.group(1)
                    logging.info("waitrose: Basket: num items=" + str(basketSummary["numItems"]))
        except WebDriverException:
            logging.error("waitrose: Get basket summary webdriver element exception")
            self.debugDumpPageSource()
            return None

        # Return info found
        return basketSummary

    def getElemAttrIfPresent(self, soup, elemName, className, subElem, attrName, regexReplace, destDict=None, dictName=None):
        rslt = ""
        try:
            el = soup.find(elemName, class_=className)
            if subElem is not "":
                el = el.find(subElem)
            if attrName == "text":
                rslt = el.get_text()
            else:
                rslt = el[attrName]
            if regexReplace is not "":
                rslt = re.sub(regexReplace, "", rslt)
            if destDict is not None:
                destDict[dictName] = rslt
        except WebDriverException:
            logging.error("waitrose: Error extracting element " + elemName + " " + className)
            self.debugDumpPageSource()
        except:
            logging.error("waitrose: Error (not webdriver) extracting element " + elemName + " " + className)
            self.debugDumpPageSource()
        return rslt

    def getShoppingItems(self, isTrolleyPage):

        # Make sure all items on the page are loaded - lazy loader
        try:
            self.debugDumpPageSource("m-product")
            webdriverui.WebDriverWait(self.webDriver, 10)\
                .until(EC.visibility_of_element_located((By.CLASS_NAME, "m-product")))
        except WebDriverException:
            logging.error("Wait for m-product webdriver element exception")
            return []

        productsFound = self.webDriver.find_elements_by_class_name("m-product")
        print("waitrose: Lazy loading products - currently " + str(len(productsFound)) + " found")
        numRepeats = 0
        if len(productsFound) > 10:
            while True:
                prevFound = len(productsFound)
                self.webDriver.execute_script("window.scrollBy(0,window.innerHeight)")
                productsFound = self.webDriver.find_elements_by_class_name("m-product")
                print("Loading products - currently " + str(len(productsFound)) + " found")
                if len(productsFound) <= prevFound:
                    numRepeats += 1
                    if numRepeats > 20:
                        break
                else:
                    numRepeats = 0

        print("Done lazy loading products " + str(len(productsFound)) + " found")

        # Go through items in the list on the current page
        shoppingItems = []
        for product in productsFound:

            # Get HTML for this product
            basketIt = {}
            el = product.get_attribute("innerHTML")
            productSoup = BeautifulSoup(el, "html.parser")

            # Extract some common details
            self.getElemAttrIfPresent(productSoup, "a", "m-product-open-details", "", "href", "", basketIt, "detailsHref")
            self.getElemAttrIfPresent(productSoup, "a", "m-product-open-details", "img", "src", "", basketIt, "imageSrc")
            self.getElemAttrIfPresent(productSoup, "div", "m-product-volume", "", "text", r"\W", basketIt, "productVolume")

            # Check if we are doing the trolley page - which has extra info like number of items ordered
            if isTrolleyPage:
                self.getElemAttrIfPresent(productSoup, "div", "m-product-title", "a", "text", "", basketIt, "productTitle")
                if not "productTitle" in basketIt or basketIt["productTitle"] == "":
                    self.getElemAttrIfPresent(productSoup, "a", "m-product-open-details", "img", "title", "", basketIt,
                                         "productTitle")
                self.getElemAttrIfPresent(productSoup, "div", "quantity-append", "input", "value", "", basketIt,
                                     "trolleyQuantity")
                self.getElemAttrIfPresent(productSoup, "p", "m-product-details", "span", "text", "", basketIt,
                                     "trolleyPrice")
                self.getElemAttrIfPresent(productSoup, "div", "m-product-details-container", "div", "data-price", "",
                                     basketIt,
                                     "price")
                self.getElemAttrIfPresent(productSoup, "div", "m-product-details-container", "div", "data-priceperkg",
                                     "", basketIt, "pricePerKg")
                self.getElemAttrIfPresent(productSoup, "div", "m-product-details-container", "div", "data-orderitemid",
                                     "", basketIt, "orderItemId")
                self.getElemAttrIfPresent(productSoup, "div", "m-product-details-container", "div", "data-producttype",
                                     "", basketIt, "productType")
                self.getElemAttrIfPresent(productSoup, "div", "m-product-details-container", "div", "data-productid",
                                     "", basketIt, "productId")
                self.getElemAttrIfPresent(productSoup, "div", "m-product-details-container", "div", "data-uom", "", basketIt,
                                     "UOM")
                self.getElemAttrIfPresent(productSoup, "div", "m-product-details-container", "div", "data-weighttype",
                                     "", basketIt, "weightType")
                self.getElemAttrIfPresent(productSoup, "div", "m-product-details-container", "div", "data-substitute",
                                     "", basketIt, "substitute")
            else:
                self.getElemAttrIfPresent(productSoup, "div", "m-product-price-container", "span", "text", "\W", basketIt,
                                     "price")
                self.getElemAttrIfPresent(productSoup, "a", "m-product-open-details", "", "text", "", basketIt,
                                     "productTitle")
                if not "productTitle" in basketIt or basketIt["productTitle"] == "":
                    self.getElemAttrIfPresent(productSoup, "a", "m-product-open-details", "img", "title", "", basketIt,
                                         "productTitle")

            # Check if the product at least has a title and only add to list if it does
            if not "productTitle" in basketIt or basketIt["productTitle"] == "":
                logging.error("Extract Shopping List: Failed to extract product name")
            else:
                shoppingItems.append(basketIt)

        return shoppingItems

    def getTrolleyContents(self):

        # Ensure we wait until the trolley-total is visible
        try:
            wait = WebDriverWait(self.webDriver, 20)
            wait.until(EC.visibility_of_element_located((By.CLASS_NAME, "trolley-total")))
        except WebDriverException:
            logging.error("Wait for Trolley-Total webdriver element exception")
            self.debugDumpPageSource()
            return None

        # Navigate to the basket contents
        try:
            self.clickButtonByXPath('//div[@class="mini-trolley"]//a')
            wait = WebDriverWait(self.webDriver, 30)
            wait.until(EC.visibility_of_element_located((By.ID, "my-trolley")))
        except NoSuchElementException:
            logging.error("Press view trolley button no such element")
            self.debugDumpPageSource()
            return None
        except WebDriverException:
            logging.error("Press view trolley button webdriver element exception")
            self.debugDumpPageSource()
            return None

        # Get the shopping items on the current page
        return self.getShoppingItems(True)

    def getFavourites(self):

        # Ensure we wait until the favourites is visible
        try:
            wait = WebDriverWait(self.webDriver, 20)
            wait.until(EC.visibility_of_element_located((By.CLASS_NAME, "js-navbar-favourites")))
        except WebDriverException:
            logging.error("Wait for favourites button webdriver element exception")
            self.debugDumpPageSource()
            return None

        # Navigate to the favourites
        try:
            FAVOURITES_BUTTON_XPATH = '//a[@class="js-navbar-favourites"]'
            elemBasketBtn = self.webDriver.find_element_by_xpath(FAVOURITES_BUTTON_XPATH)
            print(elemBasketBtn)
            elemBasketBtn.click()
            wait = WebDriverWait(self.webDriver, 60)
            wait.until(EC.visibility_of_element_located((By.CLASS_NAME, "products-grid")))
        except NoSuchElementException:
            logging.error("Press view favourites button no such element")
            self.debugDumpPageSource()
            return None
        except WebDriverException:
            logging.error("Press view favourites button webdriver element exception")
            self.debugDumpPageSource()
            return None

        # Get the shopping items on the current page
        return self.getShoppingItems(False)

    # Handle site login
    def siteLogin(self, siteUrl, username, password, titleMustContainStr):

        # Start webDriver
        if not self.startWebDriver():
            logging.error("Unable to start webdriver")
            return False
        self.isInitalized = True

        # Go to URL
        logging.info("Webdriver going to " + siteUrl)
        self.webDriver.get(siteUrl)
        logging.info("Webdriver site title = " + self.webDriver.title)
        if not titleMustContainStr in self.webDriver.title:
            logging.error("Site " + siteUrl + " title doesn't contain " + titleMustContainStr)
            self.debugDumpPageSource()
            return False

        # Handle login
        self.isLoggedIn = self.websiteLogin(username, password, 1)

        # Succeeded so far
        return self.isLoggedIn

    # Ensure that we are logged in
    def ensureLoggedIn(self, username, password):
        # Ensure we are initialised
        if not self.isInitalized:
            self.siteLogin("http://www.waitrose.com", username, password, "Waitrose")

        # Try to login again if not currently logged in
        if self.isInitalized:
            if not self.isLoggedIn:
                self.isLoggedIn = self.websiteLogin(username, password, 2)

        return self.isLoggedIn


# Pygame Template
# Use this to start a new Pygame project
# KidsCanCode 2015
import pygame
import random

# define some colors (R, G, B)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
BLACK = (0, 0, 0)
FUCHSIA = (255, 0, 255)
GRAY = (128, 128, 128)
LIME = (0, 128, 0)
MAROON = (128, 0, 0)
NAVYBLUE = (0, 0, 128)
OLIVE = (128, 128, 0)
PURPLE = (128, 0, 128)
RED = (255, 0, 0)
SILVER = (192, 192, 192)
TEAL = (0, 128, 128)
YELLOW = (255, 255, 0)
ORANGE = (255, 128, 0)
CYAN = (0, 255, 255)

# basic constants to set up your game
WIDTH = 360
HEIGHT = 480
FPS = 30
BGCOLOR = BLACK

# initialize pygame
pygame.init()
# initialize sound - uncomment if you're using sound
# pygame.mixer.init()
# create the game window and set the title
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("My Game")
# start the clock
clock = pygame.time.Clock()

# set the 'running' variable to False to end the game
running = True
# start the game loop
while running:
    # keep the loop running at the right speed
    clock.tick(FPS)
    # Game loop part 1: Events #####
    for event in pygame.event.get():
        # this one checks for the window being closed
        if event.type == pygame.QUIT:
            pygame.quit()
        # add any other events here (keys, mouse, etc.)

    # Game loop part 2: Updates #####

    # Game loop part 3: Draw #####
    screen.fill(BGCOLOR)
    # after drawing, flip the display
    pygame.display.flip()

# close the window
pygame.quit()


import argparse
import collections
import re
import subprocess

NOTES_REF = 'refs/notes/votes'

Vote = collections.namedtuple('Vote', ['commit', 'user'])

def vote(args):
	assert args.user, 'TODO: determine user automatically'
	vote = 'vote:%s' % args.user
	subprocess.check_call([
		'git', 'notes', '--ref', NOTES_REF, 'append', '--allow-empty', '-m', vote, args.COMMIT],
		cwd=args.repo_dir)
	# TODO: prevent voting twice as same user

def get_all_votes(repo_dir):
	output_bytes = subprocess.check_output([
		'git', 'notes', '--ref', NOTES_REF, 'list'],
		cwd=repo_dir)
	output = output_bytes.decode('utf-8')
	for line in output.splitlines():
		if not line:
			continue
		votenote_ref, commit_id = line.split()
		# TODO use dulwich or something more efficient here
		votenote_bytes = subprocess.check_output(
			['git', 'show', votenote_ref],
			cwd=repo_dir)

		votenote_content = votenote_bytes.decode('utf-8') # TODO ignore invalid votes
		for voteline in votenote_content.splitlines():
			if not voteline:
				continue
			m = re.match(r'^vote:(?P<user>[a-z0-9@._]+)$', voteline.strip()) # TODO check re for user spec
			if not m:
				print('Skipping crap %r' % voteline)
				continue
			user = m.group('user')

			yield Vote(commit=commit_id, user=user)

def print_list(args):
	all_votes = get_all_votes(args.repo_dir)
	all_votes_sorted = sorted(all_votes, key=lambda v: (v.commit, v.user))
	for v in all_votes_sorted:
		print('%s: +1 from %s' % (v.commit, v.user))

def tally(all_votes):
	""" Returns a dict commit id => set of users """
	res = collections.defaultdict(set)
	for v in all_votes:
		res[v.commit].add(v.user)
	return res

def print_tally(args):
	all_votes = get_all_votes(args.repo_dir)
	for commit, votes in sorted(tally(all_votes).items(), key=lambda kv: (kv[1], kv[0])):
		print('%s: %d votes' % (commit, len(votes)))

def print_elect(args):
	all_votes = get_all_votes(args.repo_dir)
	winner_vcount, winner_commit = max((len(votes), commit) for commit, votes in tally(all_votes).items())
	# TODO more algorithms
	print('%s won the election with %d votes' % (winner_commit, winner_vcount))

def main():
	parser = argparse.ArgumentParser('Vote on git commands')
	parser.add_argument('-r', '--repo-dir', metavar='DIR', help='root directory of the repository to modify')
	subparsers = parser.add_subparsers(dest='cmd')
	vote_parser = subparsers.add_parser('vote', help='Vote for commit')
	vote_parser.add_argument('--user', metavar='USER_ID', help='ID of the user to vote as')
	vote_parser.add_argument('COMMIT', help='reference to the commit to vote for')
	subparsers.add_parser('list', help='List all votes')
	subparsers.add_parser('tally', help='Tally all votes')
	subparsers.add_parser('elect', help='Elect a commit')

	args = parser.parse_args()
	if args.cmd == 'vote':
		vote(args)
	elif args.cmd == 'list':
		print_list(args)
	elif args.cmd == 'tally':
		print_tally(args)
	elif args.cmd == 'elect':
		print_elect(args)
	else:
		parser.print_help()

if __name__ == '__main__':
	main()


# Copyright (c) 2014-2016 Cedric Bellegarde <cedric.bellegarde@adishatz.org>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

from gi.repository import GObject, GLib

from threading import Thread
from time import time

from lollypop.sqlcursor import SqlCursor
from lollypop.tagreader import TagReader
from lollypop.web_youtube import WebYouTube
from lollypop.web_jgm90 import WebJmg90
from lollypop.define import Lp, DbPersistent, Type
from lollypop.lio import Lio

class Web(GObject.Object):
    """
        Web helper
    """

    __gsignals__ = {
        'saved': (GObject.SignalFlags.RUN_FIRST, None, (int,)),
        'progress': (GObject.SignalFlags.RUN_FIRST, None, (float,))
    }

    def play_track(track, play, callback):
        """
            Play track
            @param track as Track
            @param play as bool
            @param callback as func(uri: str, track: Track, play: bool)
        """
        if track.is_jgm:
            uri = WebJmg90.get_uri_content(track.uri)
        elif track.is_youtube:
            uri = WebYouTube.get_uri_content(track.uri)
        else:
            return
        GLib.idle_add(callback, uri, track, play)

    def __init__(self):
        """
            Init helper
        """
        GObject.Object.__init__(self)
        self.__helpers = [WebJmg90(), WebYouTube()]

    def save_track(self, item, persistent):
        """
            Save item into collection as track
            @param item as SearchItem
            @param persistent as DbPersistent
        """
        t = Thread(target=self.__save_track_thread, args=(item, persistent))
        t.daemon = True
        t.start()

    def save_album(self, item, persistent):
        """
            Save item into collection as album
            @param item as SearchItem
            @param persistent as DbPersistent
        """
        t = Thread(target=self.__save_album_thread,
                   args=(item, persistent))
        t.daemon = True
        t.start()

#######################
# PRIVATE             #
#######################
    def __save_album_thread(self, item, persistent):
        """
            Save item into collection as album
            @param item as SearchItem
            @param persistent as DbPersistent
        """
        nb_items = len(item.subitems)
        # Should not happen but happen :-/
        if nb_items == 0:
            return
        start = 0
        album_artist = item.subitems[0].artists[0]
        album_id = None
        for track_item in item.subitems:
            (album_id, track_id) = self.__save_track(track_item, persistent,
                                                     album_artist)
            if track_id is None:
                continue
            # Download cover
            if start == 0:
                t = Thread(target=self.__save_cover, args=(item, album_id))
                t.daemon = True
                t.start()
            start += 1
            GLib.idle_add(self.emit, "progress", start / nb_items)
        GLib.idle_add(self.emit, "progress", 1)
        if Lp().settings.get_value('artist-artwork'):
            Lp().art.cache_artists_info()
        if album_id is not None:
            GLib.idle_add(self.emit, "saved", album_id)

    def __save_track_thread(self, item, persistent):
        """
            Save item into collection as track
            @param item as SearchItem
            @param persistent as DbPersistent
        """
        album_artist = item.artists[0]
        (album_id, track_id) = self.__save_track(item, persistent,
                                                 album_artist)
        if track_id is None:
            return
        self.__save_cover(item, album_id)
        if Lp().settings.get_value('artist-artwork'):
            Lp().art.cache_artists_info()
        GLib.idle_add(self.emit, "saved", track_id)

    def __save_track(self, item, persistent, album_artist):
        """
            Save item into collection as track
            @param item as SearchItem
            @param persistent as DbPersistent
            @param album artist as str
            @return (album id as int, track id as int)
        """
        # Get uri from helpers
        for helper in self.__helpers:
            uri = helper.get_uri(item)
            if uri:
                break
        # Don't found anything
        if not uri:
            return (None, None)
        track_id = Lp().tracks.get_id_by_uri(uri)
        # Check if track needs to be updated
        if track_id is not None:
            if Lp().tracks.get_persistent(track_id) == DbPersistent.NONE\
                    and persistent == DbPersistent.EXTERNAL:
                Lp().tracks.set_persistent(track_id, DbPersistent.EXTERNAL)
                return (None, None)
        t = TagReader()
        with SqlCursor(Lp().db) as sql:
            # Happen often with Itunes/Spotify
            if album_artist not in item.artists:
                item.artists.append(album_artist)
            artists = "; ".join(item.artists)
            artist_ids = t.add_artists(artists, album_artist, "")
            album_artist_ids = t.add_album_artists(album_artist, "")
            (album_id, new_album) = t.add_album(item.album,
                                                album_artist_ids, "",
                                                False, 0, 0, int(time()), True)
            # FIXME: Check this, could move this in add_album()
            if new_album:
                Lp().albums.set_synced(album_id, Type.NONE)

            if persistent == DbPersistent.CHARTS:
                genre_ids = [Type.CHARTS]
                new_artist_ids = []
            else:
                new_artist_ids = list(set(artist_ids) | set(album_artist_ids))
                genre_ids = t.add_genres("Web", album_id)

            # Add track to db
            track_id = Lp().tracks.add(item.name, uri, item.duration,
                                       0, item.discnumber, "", album_id,
                                       item.year, 0, 0, 0, persistent)
            t.update_track(track_id, artist_ids, genre_ids)
            t.update_album(album_id, album_artist_ids, genre_ids, None)
            sql.commit()

        for genre_id in genre_ids:
            GLib.idle_add(Lp().scanner.emit, 'genre-updated', genre_id, True)
        for artist_id in new_artist_ids:
            GLib.idle_add(Lp().scanner.emit, 'artist-updated', artist_id, True)
        return (album_id, track_id)

    def __save_cover(self, item, album_id):
        """
            Save cover to store
            @param item as SearchItem
            @param album id as int
        """
        f = Lio.File.new_for_uri(item.cover)
        (status, data, tag) = f.load_contents(None)
        if status:
            Lp().art.save_album_artwork(data, album_id)


Question: army:order

Choices:
A. band:band leader
B. tourist:guide
C. volunteer:summon
D. students:instruction

Answer: A

Explanation: the "army" follows "order", and "army" is a collective concept.

Explanation: the "band" obeys the "band leader", and the "band" belongs to the concept of collection.

Explanation: the "tourist" follows the "guide" instead of obeying, and the "tourist" can be an individual or a whole, which does not belong to the concept of collection.

Explanation: "volunteers" respond to "summon" instead of obeying. "volunteers" can be individuals or a whole, and do not belong to the concept of collection.

Explanation: "student" obeys "instruction", "student" can be an individual or a whole, and does not belong to the concept of collection.


Question: expedition:drum:morale

Choices:
A. competition:scream:confidence
B. production:supervision:efficiency
C. drinking:negotiate:atmosphere
D. propaganda:publish in newspapers:fame

Answer: A

Explanation: "drumming" when going on an "expedition" can boost "morale".

Explanation: "screaming" during a "race" can increase "confidence".

Explanation: "supervision" in "production" can ensure quality, not "efficiency".

Explanation: "drinking" in "negotiating" can soften the "atmosphere", but the word order is inconsistent.

Explanation: "publish in newspapers" is a way of "propaganda", and it does not necessarily increase "fame".


Question: temple:buddha statue:tourist

Choices:
A. store:commodity:customer
B. gallery:exhibits:viewer
C. city:park:citizen
D. school:blackboard:student

Answer: B

Explanation: "buddha statues" are placed in "temples" for "tourists" to visit, and "buddha statues" are objects for sightseeing.

Explanation: "commodities" are placed in "stores" for "customers" to purchase, but "commodities" are not items for sightseeing.

Explanation: "exhibits" are placed in the "gallery" for the "viewer" to enjoy, and "exhibits" are items for sightseeing.

Explanation: "parks" are built in "cities" for "citizens" to play with, but "parks" are not items for sightseeing.

Explanation: the "blackboard" helps "student" to learn, but the "blackboard" is not an item for sightseeing.


Question: experimenter:test tube:utensils

Choices:
A. driver:bus:transportation
B. farmer:rice:crop
C. employee:computer:technology
D. sculptor:sculpture:artwork

Answer: A

Explanation: a "test tube" is the experimental tool of an "experimenter", and the "test tube" is a kind of "utensils".

Explanation: "bus" is the work tool of a "driver", and "bus" is a kind of "transportation".

Explanation: "crop" is the labor object of "farmers", and "crop" is not the labor tool of "farmers".

Explanation: "computer" is the work tool of the "employee", but "computer" is a "technical" product, not a "technology".

Explanation: "sculpture" is the work of a "sculptor", "sculpture" is not the tool of a "sculptor".


Question: customs:habit

Choices:
A. boy:girl
B. youth:man
C. New York:America
D. jump:action

Answer: D

Explanation: "habits" include "customs".

Explanation: people include "boys" and "girls".

Explanation: some "youths" are "men", some "men" are "youths", and "men" does not include "youth".

Explanation: "New York" is an integral part of "America".

Explanation: "jump" belongs to "action".


Question: research:symposium

Choices:
A. transformation:innovation
B. monopoly:franchise
C. invention:experimentation
D. order:smoothness

Answer: A

Explanation: "symposium" is a way of "research"

Explanation: "transformation" is a way of "innovation"

Explanation: "monopoly" generally refers to control and monopoly, "franchise" refers to specialized operation, and there is no obvious logical relationship between "monopoly" and "franchise".

Explanation: "invention" refers to a trial operation to understand its performance or results when something is known. "experimentation" is the process of creating new things, and there is no obvious logical relationship between "invention" and "testing".

Explanation: "order" refers to unobstructed, smooth and fluent passage, "smoothness" means the orderly and organized arrangement of various components in order to achieve normal operation or a state of good appearance, "order" and "smoothness" have no obvious logical relationship .


Question: USB drive:CD

Choices:
A. stairs:elevator
B. plug:socket
C. chinese painting:brush
D. water cup:cup lid

Answer: A

Explanation: "USB drive" and "CD" are all data storage, except for "USB drive" and "CD" hard disk are also data storage.

Explanation: "stairs" and "elevator" are tools that can reach different floors

Explanation: "plug" and "socket" need to be used together, and "plug" and "socket" do not belong to the same category.

Explanation: to draw a "chinese painting", you need to use a tool like a "brush"

Explanation: "water cup" is a component of "cup lid", and "water cup" and "cup lid" do not belong to the same category.


Question: people:adults:minors

Choices:
A. door:open:close
B. hand:left hand:right hand
C. weather:sunny:cloudy
D. car accident:survivor:victim

Answer: B

Explanation: "adults" and "minors" are both "human", and "adults" and "minors" are the same kind but have opposite meanings.

Explanation: "open the door" and "close the door" are both states of "door", and "open the door" and "close the door" have opposite meanings.

Explanation: "left-hand" and "right-hand" are both "hands", and "left-hand" and "right-hand" are of the same kind but have opposite meanings, which are consistent with the logical relationship of the query.

Explanation: "sunny" and "cloudy" are both "weather". "sunny" and "cloudy" are of the same kind, and there are other things besides "weather" and "sunny".

Explanation: both "survivors" and "victims" may be the result of a "car accident", and "survivors" and "victims" are the same but have opposite meanings.


Question: Chang'e-2:lunar exploration

Choices:
A. cosmetic:beauty
B. instant noodle:keep warm
C. coffee:sleep
D. key:door lock

Answer: A

Explanation: "Chang'e-2" can be used for "lunar exploration".

Explanation: "cosmetics" can be used for "beauty".

Explanation: "instant noodles" cannot be used to "keep warm".

Explanation: "coffee" can be used to refresh, not for "sleep".

Explanation: the "door lock" is opened with a "key", and the "key" cannot be used for the "door lock".


translate English to German: Bayer AG is a German chemicals and pharmaceuticals company founded in 1863.

Die Bayer-AG ist ein Unternehmen der Pharmaindustrie mit Hauptsitz in Leverkusen .


translate English to French: Source: www.pharmacopoeia.org.uk Committee on Food Chemicals Codex.

Source : www.pharmacopoeia.org.uk Committee on Food Chemicals Codex.


A Practical Approach towards Reducing the HVAC Flow Noise

Automotive heating ventilating and air conditioning (HVAC) noise is becoming a big concern area as the demand for acoustic comfort increases day by day. Vehicles are manufactured in recent years with quieter powertrain, reduced body leakage, better suspension. The other quieter technologies like electrification, hybridization of vehicle further complicate the whole subject of vehicle cabin noise issue. The HVAC noise is the major noise source inside the cabin. Hence designing a HVAC with very low sound pressure level is quite challenging and poses many difficulties in meeting other basic performances due to certain trade-off while meeting the noise requirement. However in recent years engineers have done extensive research and come up with various feasible and non-feasible solutions in order to reduce the HVAC noise significantly. Most commonly used tools and techniques are numerical simulation and experimental investigation or combined numerical simulation followed by experimental investigation. The present paper describes the way an existing HVAC noise is reduced by extensive experimental investigations. First the HVAC was dismantled and the flow path inside the HVAC was examined in details along with special features. Areas with chances of flow separations, vortices and high turbulent kinetic energy (TKE) were identified. Smoke tracing was also used in order to actually understand that phenomenon. After having deep investigation into those areas, existing HVAC was modified and series of experiments were carried out on this modified HVAC in a semi-anechoic chamber and noise data was captured at different voltages. In all these changes it is always aimed at keeping the airflow same or better than existing HVAC. It is observed that a significant improvement upto 3-4 dB(A) is achieved in overall noise level both at bench level and vehicle level. So this study provides a deeper insight into how HVAC overall noise level is reduced and hence further it can be very well applied at initial stage of design to make the noise level within desired limit.


Development of Tearing Pattern Prediction Model of Laser Scored Region on Invisible Passenger Side Airbag Door

The tear seam of invisible passenger side airbag door is made on the back of an instrument panel by laser scoring method and it is not shown outside. One of the requirements for the invisible passenger side airbag door is that the airbag module should deploy with no fragmentation at hot, room and cold temperature conditions. In this paper, a section model was developed by detail inspection of tearing phenomena at the laser-scored region. To validate the model, the finite elements of continuous and dot type laser-scored tear seam were built and analyzed in room and cold temperature conditions. Finally, a three-dimensional equivalent shell model was developed and it was proved that the section model and the equivalent shell model could represent well the tearing phenomena of the airbag door. It is expected that the tearing pattern prediction models developed in this study can be used to design the types of laser scoring and the airbag door with the minimum of real deployment tests.


Airflow Simulation Relative to Door-Closing Operability

Easiness in closing a vehicle door has been often evaluated on a physical vehicle body, and in most cases, has not been fully studied by computer-aided engineering (CAE) in an earlier developing stage. The authors have developed a numerical method for reproducing the behavior of a closing door with a high fidelity. Characteristics of this method are that moving grid is used to reproduce the unsteady air motion caused by closing the door, and that external reaction forces including cabin pressure are coupled with the equation of the door motion to achieve a high fidelity. This method has made it possible to quantitatively evaluate cabin pressure rise and determine minimum door closing velocity, and the method has turned out to be effective.


The Use of in Vehicle STL Testing to Correlate Subsystem Level SEA Models

For the assessment of vehicle acoustics in the early design stages of a vehicle program, the use of full vehicle SEA models is becoming the standard analysis method in the US automotive industry. One benefit is that OEM's and Tier 1 suppliers are able to cascade lower level acoustic performance targets for NVH systems and components. Detailed SEA system level models can be used to assess the performance of systems such as dash panels, floors and doors, however, the results will be questionable until test data Is available. Correlation can be accomplished with buck testing, which is a common practice in the automotive industry for assessing the STL (sound transmission loss) of vehicle level components. The opportunity to conduct buck testing can be limited by the availability of representative bodies to be cut into bucks and the availability of a transmission loss suite with a suitably large opening. In addition, the temporary fixture used to mount the test structure does not typically provide representative boundary conditions. Boundary conditions are particularly important when the in-vehicle performance is dependent on point connections at hinges / locking mechanisms and flexible seals at the perimeter of the system such as found in doors or lift-gate. In this paper the use of in-vehicle testing on prototype vehicles to assess the STL for the vehicle systems and the SEA models are discussed. Results are presented for a dash panel, floor system and door systems. The measurements are compared with predictions from system level SEA (Statistical Energy Analysis) models of the test systems. It is concluded that subsystem level SEA models can be used to assess the design and correlate well with STL measurements from in-vehicle tests.


Modular door system for side impact safety of motor vehicles

Side impact collision is one of the toughest safety challenges facing the Auto Industry today. Over thirteen thousand deaths, due to side impact, occurred during 1998 in the United States alone. The main difficulty in designing for side impact collisions is the limited crumple zone between the impacting vehicle and the impacted occupant. This paper presents a proprietary side impact protective door system within the space between the outer skin of a car door and the occupant, which will be as efficient as those already standard in frontal impact. The main objective for introducing the side impact structural system is to maximize energy absorption and minimize injury to the occupant. The developed structural side impact door system acts as a Primary Structure, to be assembled as a truly modular entity. This primary structure is also packaging modular in the sense that it acts as a carrier for the door latch, window regulator and hinges. A variation in safety and structural performance of the developed door system can be achieved by integrating the structural modular door with the vehicle body, using a patented integration system known as Door And Chassis-frame Integration Technology (DACIT). Unlike the traditional doors, that are just suspended weights, the modular door is truly structural and therefore adds strength to the vehicle body. When DACIT is used with the door system the vehicle door becomes part of the overall vehicle structure. The design and development of the side impact modular door system for different size vehicles with and without DACIT will be discussed. In addition, the five stars rating achieved during several side impact crash tests simulating Sport Utility Vehicles hitting mid-size vehicles, equipped with the developed modular door system, will be presented.


Simulation of Warm Forming Assisted Hemming to Study the Effect of Process Parameters on Product Quality

Current trends in the auto industry requiring tighter dimensional specifications combined with the use of lightweight materials, such as aluminum, are a challenge for the traditional manufacturing processes. The hemming process, a sheet metal bending operation used in the manufacturing of car doors and hoods, poses problems meeting tighter dimensional tolerances. Hemming is the final operation that is used to fasten the outer panel with the inner panel by folding the outer panel over the inner panel. Roll in/out is one of the main quality concerns with hemming, and keeping it under tolerance is a high priority issue for the auto manufacturers. Current hemming process technology, given the mechanical properties of current materials, has reached its saturation limit to deliver consistent dimensional quality to satisfy customers and at the same time meet government standards. Combining warm forming techniques with the traditional hemming process represents a new approach with the potential to overcome the current hemming limitation and to provide a satisfactory solution to all the requirements. The main objective of this research is to understand the effect of localized heating on the final quality in the hemming process by quantifying the influence of key geometrical and process parameters. To achieve this goal, a hemming finite element model, taking into consideration the mechanical properties as function of temperature is developed, and statistical methods to quantify the effect of key variables are employed. As an outcome to this study, the effectiveness of using warm forming techniques to improve hemming quality is assessed for A5182O aluminum, one of the most common used materials for this application.


Comparative Dimensional Quality of Doors: A Benchmarking Study

A comparative benchmarking study of the dimensional door quality 14 vehicles from Ford, General Motors, Daimler-Chrysler, Toyota, Nissan, BMW, Volvo, and Renault was conducted. Various aspects of the door design, manufacturing, assembly and hanging system were studied. This paper focuses on the dimensional quality of the doors and relates it to the final vehicle quality in terms of gaps and flush as well as customer satisfaction as established by J. D. Power Initial Quality Survey (IQS). For confidentiality reasons, all vehicles in the study are referred to by a coded designation.


Yangliuqing

Yangliuqing () is a market town in Xiqing District, in the western suburbs of Tianjin, People's Republic of China. Despite its relatively small size, it has been named since 2006 in the "famous historical and cultural market towns in China". It is best known in China for creating nianhua or Yangliuqing nianhua. For more than 400 years, Yangliuqing has in effect specialised in the creation of these woodcuts for the New Year. wood block prints using vivid colourschemes to portray traditional scenes of children's games often interwoven with auspiciouse objects. , it had 27 residential communities () and 25 villages


Yangliuqing

1,200 square meters, incorporates the elegance of imperial garden and delicacy of south garden. Now the courtyard of Shi family covers about 10,000 square meters, which is called the first mansion in North China. Now it serves as the folk custom museum in Yangliuqing, which has a large collection of folk custom museum in Yanliuqing, which has a large collection of folk art pieces like Yanliuqing New Year pictures, brick sculpture. Shi's ancestor came from Dong'e County in Shandong Province, engaged in water transport of grain. As the wealth gradually accumulated, the Shi Family moved to Yangliuqing and bought large


Yangliuqing

tracts of land and set up their residence. Shi Yuanshi came from the fourth generation of the family, who was a successful businessman and a good household manager, and the residence was thus enlarged for several times until it acquired the present scale. It is believed to be the first mansion in the west of Tianjin. The residence is symmetric based on the axis formed by a passageway in the middle, on which there are four archways. On the east side of the courtyard, there are traditional single-story houses with rows of rooms around the four sides, which was once


Yangliuqing

the living area for the Shi Family. The rooms on north side were the accountants' office. On the west are the major constructions including the family hall for worshipping Buddha, theater and the south reception room. On both sides of the residence are side yard rooms for maids and servants. Today, the Shi mansion, located in the township of Yangliuqing to the west of central Tianjin, stands as a surprisingly well-preserved monument to China's pre-revolution mercantile spirit. It also serves as an on-location shoot for many of China's popular historical dramas. Many of the rooms feature period furniture, paintings and


She co-starred in film The Birth of a Nation -LRB- 2016 -RRB- , and next appeared in Almost Christmas -LRB- 2016 -RRB- and Sleepless -LRB- 2017 -RRB- .


eleveneleven is a record label founded in 2010 by Mike Hamlin , Ellen DeGeneres and her production company , A Very Good Production , in association with longtime affiliate Warner Bros. .


Cosmos: A Spacetime Odyssey secured studio support thanks to Seth MacFarlane.

MacFarlane served as executive producer of Cosmos : A Spacetime Odyssey , an update of the 1980s Carl Sagan -- hosted Cosmos series , hosted by Neil deGrasse Tyson .


The World According to Paris starred Hilton's then-girlfriend.

It was filmed from November 2010 , with Hilton 's court-ordered community service stemming from her arrest in Las Vegas , Nevada for cocaine possession , to February 2011 , with her birthday party , the series co-starred Brooke Mueller , Lexi Dreyfus , Jennifer Rovero , Allison Melnick , Brooke Brinson -LRB- daughter of Kim Richards -RRB- , Hilton 's then-boyfriend Cy Waits , and Kathy Hilton .


The Germanic peoples are also called Gothic.

The Germanic peoples -LRB- also called Teutonic , Suebian , or Gothic in older literature -RRB- are an Indo-European ethno-linguistic group of Northern European origin .


In 2005 , Kidder became a naturalized U.S. citizen .


Chokher Bali was nominated for a Golden Leopard in 2003.

Chokher Bali won the National Film Award for Best Feature Film in Bengali and was nominated for the Golden Leopard -LRB- Best Film -RRB- award at the Locarno International Film Festival in 2003 .


Bolt is the only sprinter to win Olympic 100 m and 200 m titles at three consecutive olympics -LRB- 2008 , 2012 and 2016 -RRB- , a feat referred to as the `` triple double . ''


The industry that the company The New York Times is part of is declining.

The New York Times -LRB- sometimes abbreviated NYT and The Times -RRB- is an American daily newspaper , founded and continuously published in New York City since September 18 , 1851 , by The New York Times Company .

The late 2000s -- early 2010s global recession , combined with the rapid growth of free web-based alternatives , has helped cause a decline in advertising and circulation , as many papers had to retrench operations to stanch the losses .


# Copyright 2013 NEC Corporation.
# 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.

from oslo_serialization import jsonutils as json

from tempest.lib.api_schema.response.compute.v2_1 import aggregates as schema
from tempest.lib.common import rest_client
from tempest.lib import exceptions as lib_exc
from tempest.lib.services.compute import base_compute_client

class AggregatesClient(base_compute_client.BaseComputeClient):

    def list_aggregates(self):
        """Get aggregate list."""
        resp, body = self.get("os-aggregates")
        body = json.loads(body)
        self.validate_response(schema.list_aggregates, resp, body)
        return rest_client.ResponseBody(resp, body)

    def show_aggregate(self, aggregate_id):
        """Get details of the given aggregate."""
        resp, body = self.get("os-aggregates/%s" % aggregate_id)
        body = json.loads(body)
        self.validate_response(schema.get_aggregate, resp, body)
        return rest_client.ResponseBody(resp, body)

    def create_aggregate(self, **kwargs):
        """Create a new aggregate.

        Available params: see http://developer.openstack.org/
                              api-ref-compute-v2.1.html#createAggregate
        """
        post_body = json.dumps({'aggregate': kwargs})
        resp, body = self.post('os-aggregates', post_body)

        body = json.loads(body)
        self.validate_response(schema.create_aggregate, resp, body)
        return rest_client.ResponseBody(resp, body)

    def update_aggregate(self, aggregate_id, **kwargs):
        """Update an aggregate.

        Available params: see http://developer.openstack.org/
                              api-ref-compute-v2.1.html#updateAggregate
        """
        put_body = json.dumps({'aggregate': kwargs})
        resp, body = self.put('os-aggregates/%s' % aggregate_id, put_body)

        body = json.loads(body)
        self.validate_response(schema.update_aggregate, resp, body)
        return rest_client.ResponseBody(resp, body)

    def delete_aggregate(self, aggregate_id):
        """Delete the given aggregate."""
        resp, body = self.delete("os-aggregates/%s" % aggregate_id)
        self.validate_response(schema.delete_aggregate, resp, body)
        return rest_client.ResponseBody(resp, body)

    def is_resource_deleted(self, id):
        try:
            self.show_aggregate(id)
        except lib_exc.NotFound:
            return True
        return False

    @property
    def resource_type(self):
        """Return the primary type of resource this client works with."""
        return 'aggregate'

    def add_host(self, aggregate_id, **kwargs):
        """Add a host to the given aggregate.

        Available params: see http://developer.openstack.org/
                              api-ref-compute-v2.1.html#addHost
        """
        post_body = json.dumps({'add_host': kwargs})
        resp, body = self.post('os-aggregates/%s/action' % aggregate_id,
                               post_body)
        body = json.loads(body)
        self.validate_response(schema.aggregate_add_remove_host, resp, body)
        return rest_client.ResponseBody(resp, body)

    def remove_host(self, aggregate_id, **kwargs):
        """Remove a host from the given aggregate.

        Available params: see http://developer.openstack.org/
                              api-ref-compute-v2.1.html#removeAggregateHost
        """
        post_body = json.dumps({'remove_host': kwargs})
        resp, body = self.post('os-aggregates/%s/action' % aggregate_id,
                               post_body)
        body = json.loads(body)
        self.validate_response(schema.aggregate_add_remove_host, resp, body)
        return rest_client.ResponseBody(resp, body)

    def set_metadata(self, aggregate_id, **kwargs):
        """Replace the aggregate's existing metadata with new metadata.

        Available params: see http://developer.openstack.org/
                              api-ref-compute-v2.1.html#addAggregateMetadata
        """
        post_body = json.dumps({'set_metadata': kwargs})
        resp, body = self.post('os-aggregates/%s/action' % aggregate_id,
                               post_body)
        body = json.loads(body)
        self.validate_response(schema.aggregate_set_metadata, resp, body)
        return rest_client.ResponseBody(resp, body)


"""Create coordinate transforms."""

# Author: Eric Larson <larson.eric.d<gmail.com>
#
# License: BSD (3-clause)

import numpy as np
from scipy import linalg

from ...transforms import combine_transforms, invert_transform, Transform
from ...utils import logger
from ..constants import FIFF
from .constants import CTF

def _make_transform_card(fro, to, r_lpa, r_nasion, r_rpa):
    """Make a transform from cardinal landmarks."""
    # XXX de-duplicate this with code from Montage somewhere?
    diff_1 = r_nasion - r_lpa
    ex = r_rpa - r_lpa
    alpha = np.dot(diff_1, ex) / np.dot(ex, ex)
    ex /= np.sqrt(np.sum(ex * ex))
    trans = np.eye(4)
    move = (1. - alpha) * r_lpa + alpha * r_rpa
    trans[:3, 3] = move
    trans[:3, 0] = ex
    ey = r_nasion - move
    ey /= np.sqrt(np.sum(ey * ey))
    trans[:3, 1] = ey
    trans[:3, 2] = np.cross(ex, ey)  # ez
    return Transform(fro, to, trans)

def _quaternion_align(from_frame, to_frame, from_pts, to_pts):
    """Perform an alignment using the unit quaternions (modifies points)."""
    assert from_pts.shape[1] == to_pts.shape[1] == 3

    # Calculate the centroids and subtract
    from_c, to_c = from_pts.mean(axis=0), to_pts.mean(axis=0)
    from_ = from_pts - from_c
    to_ = to_pts - to_c

    # Compute the dot products
    S = np.dot(from_.T, to_)

    # Compute the magical N matrix
    N = np.array([[S[0, 0] + S[1, 1] + S[2, 2], 0., 0., 0.],
                  [S[1, 2] - S[2, 1], S[0, 0] - S[1, 1] - S[2, 2], 0., 0.],
                  [S[2, 0] - S[0, 2], S[0, 1] + S[1, 0],
                   -S[0, 0] + S[1, 1] - S[2, 2], 0.],
                  [S[0, 1] - S[1, 0], S[2, 0] + S[0, 2],
                   S[1, 2] + S[2, 1], -S[0, 0] - S[1, 1] + S[2, 2]]])

    # Compute the eigenvalues and eigenvectors
    # Use the eigenvector corresponding to the largest eigenvalue as the
    # unit quaternion defining the rotation
    eig_vals, eig_vecs = linalg.eigh(N, overwrite_a=True)
    which = np.argmax(eig_vals)
    if eig_vals[which] < 0:
        raise RuntimeError('No positive eigenvalues. Cannot do the alignment.')
    q = eig_vecs[:, which]

    # Write out the rotation
    trans = np.eye(4)
    trans[0, 0] = q[0] * q[0] + q[1] * q[1] - q[2] * q[2] - q[3] * q[3]
    trans[0, 1] = 2.0 * (q[1] * q[2] - q[0] * q[3])
    trans[0, 2] = 2.0 * (q[1] * q[3] + q[0] * q[2])
    trans[1, 0] = 2.0 * (q[2] * q[1] + q[0] * q[3])
    trans[1, 1] = q[0] * q[0] - q[1] * q[1] + q[2] * q[2] - q[3] * q[3]
    trans[1, 2] = 2.0 * (q[2] * q[3] - q[0] * q[1])
    trans[2, 0] = 2.0 * (q[3] * q[1] - q[0] * q[2])
    trans[2, 1] = 2.0 * (q[3] * q[2] + q[0] * q[1])
    trans[2, 2] = q[0] * q[0] - q[1] * q[1] - q[2] * q[2] + q[3] * q[3]

    # Now we need to generate a transformed translation vector
    trans[:3, 3] = to_c - np.dot(trans[:3, :3], from_c)
    del to_c, from_c

    # Test the transformation and print the results
    logger.info('    Quaternion matching (desired vs. transformed):')
    for fro, to in zip(from_pts, to_pts):
        rr = np.dot(trans[:3, :3], fro) + trans[:3, 3]
        diff = np.sqrt(np.sum((to - rr) ** 2))
        logger.info('    %7.2f %7.2f %7.2f mm <-> %7.2f %7.2f %7.2f mm '
                    '(orig : %7.2f %7.2f %7.2f mm) diff = %8.3f mm'
                    % (tuple(1000 * to) + tuple(1000 * rr) +
                       tuple(1000 * fro) + (1000 * diff,)))
        if diff > 1e-4:
            raise RuntimeError('Something is wrong: quaternion matching did '
                               'not work (see above)')
    return Transform(from_frame, to_frame, trans)

def _make_ctf_coord_trans_set(res4, coils):
    """Figure out the necessary coordinate transforms."""
    # CTF head > Neuromag head
    lpa = rpa = nas = T1 = T2 = T3 = T5 = None
    if coils is not None:
        for p in coils:
            if p['valid'] and (p['coord_frame'] ==
                               FIFF.FIFFV_MNE_COORD_CTF_HEAD):
                if lpa is None and p['kind'] == CTF.CTFV_COIL_LPA:
                    lpa = p
                elif rpa is None and p['kind'] == CTF.CTFV_COIL_RPA:
                    rpa = p
                elif nas is None and p['kind'] == CTF.CTFV_COIL_NAS:
                    nas = p
        if lpa is None or rpa is None or nas is None:
            raise RuntimeError('Some of the mandatory HPI device-coordinate '
                               'info was not there.')
        t = _make_transform_card(FIFF.FIFFV_COORD_HEAD,
                                 FIFF.FIFFV_MNE_COORD_CTF_HEAD,
                                 lpa['r'], nas['r'], rpa['r'])
        T3 = invert_transform(t)

    # CTF device -> Neuromag device
    #
    # Rotate the CTF coordinate frame by 45 degrees and shift by 190 mm
    # in z direction to get a coordinate system comparable to the Neuromag one
    #
    R = np.eye(4)
    R[:3, 3] = [0., 0., 0.19]
    val = 0.5 * np.sqrt(2.)
    R[0, 0] = val
    R[0, 1] = -val
    R[1, 0] = val
    R[1, 1] = val
    T4 = Transform(FIFF.FIFFV_MNE_COORD_CTF_DEVICE,
                   FIFF.FIFFV_COORD_DEVICE, R)

    # CTF device -> CTF head
    # We need to make the implicit transform explicit!
    h_pts = dict()
    d_pts = dict()
    kinds = (CTF.CTFV_COIL_LPA, CTF.CTFV_COIL_RPA, CTF.CTFV_COIL_NAS,
             CTF.CTFV_COIL_SPARE)
    if coils is not None:
        for p in coils:
            if p['valid']:
                if p['coord_frame'] == FIFF.FIFFV_MNE_COORD_CTF_HEAD:
                    for kind in kinds:
                        if kind not in h_pts and p['kind'] == kind:
                            h_pts[kind] = p['r']
                elif p['coord_frame'] == FIFF.FIFFV_MNE_COORD_CTF_DEVICE:
                    for kind in kinds:
                        if kind not in d_pts and p['kind'] == kind:
                            d_pts[kind] = p['r']
        if any(kind not in h_pts for kind in kinds[:-1]):
            raise RuntimeError('Some of the mandatory HPI device-coordinate '
                               'info was not there.')
        if any(kind not in d_pts for kind in kinds[:-1]):
            raise RuntimeError('Some of the mandatory HPI head-coordinate '
                               'info was not there.')
        use_kinds = [kind for kind in kinds
                     if (kind in h_pts and kind in d_pts)]
        r_head = np.array([h_pts[kind] for kind in use_kinds])
        r_dev = np.array([d_pts[kind] for kind in use_kinds])
        T2 = _quaternion_align(FIFF.FIFFV_MNE_COORD_CTF_DEVICE,
                               FIFF.FIFFV_MNE_COORD_CTF_HEAD, r_dev, r_head)

    # The final missing transform
    if T3 is not None and T2 is not None:
        T5 = combine_transforms(T2, T3, FIFF.FIFFV_MNE_COORD_CTF_DEVICE,
                                FIFF.FIFFV_COORD_HEAD)
        T1 = combine_transforms(invert_transform(T4), T5,
                                FIFF.FIFFV_COORD_DEVICE, FIFF.FIFFV_COORD_HEAD)
    s = dict(t_dev_head=T1, t_ctf_dev_ctf_head=T2, t_ctf_head_head=T3,
             t_ctf_dev_dev=T4, t_ctf_dev_head=T5)
    logger.info('    Coordinate transformations established.')
    return s


#!/usr/bin/python
#
# Copyright (c) .NET Foundation and contributors. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for full license information.
#

# Extract Json Value
#
# Very simple tool to ease extracting json values from the cmd line.
import os
import sys
import json

def print_usage():
	print """
		Usage: extract_json_value.py [json file path] [key of value to extract]
		For nested keys, use . separator
	"""

def help_and_exit(msg=None):
	print msg
	print_usage()
	sys.exit(1)

def parse_and_validate_args():

	if len(sys.argv) < 3:
		help_and_exit(msg="Error: Invalid Args")

	json_path = sys.argv[1]
	json_key = sys.argv[2]

	if not os.path.isfile(json_path):
		help_and_exit("Error: Invalid json file path")

	return json_path, json_key

def extract_key(json_path, json_key):
	json_data = None

	with open(json_path, 'r') as json_file:
		json_data = json.load(json_file)

	nested_keys = json_key.split('.')
	json_context = json_data

	for key in nested_keys:
		json_context = json_context.get(key, None)

		if json_context is None:
			help_and_exit("Error: Invalid json key")

	return str(json_context)

def execute():
	json_path, json_key = parse_and_validate_args()

	value = extract_key(json_path, json_key)

	return value

if __name__ == "__main__":
	print execute()


#################################################################
# Program: Toolib
"""
Known issues:
	! GetTable call after Destroy leads to crush
	  Careful with delegating to table

	  Example (how to avoid crush):

		def __getattr__(self, name):
			if name != '__del__':
				return getattr(self.GetTable(), name)
			else:
				raise AttributeError, name

"""
__author__  = "Oleg Noga"
__date__	= "$Date: 2007/09/17 13:19:12 $"
__version__ = "$Revision: 1.3 $"
# $Source: D:/HOME/cvs/toolib/wx/grid/wxGrid.py,v $
#
#################################################################

import wx.grid

FIX_SETTABLE = 1

if FIX_SETTABLE:

	from table.MTableMessaging import MTableMessaging

	class NoneTable(wx.grid.PyGridTableBase):

		def GetNumberRows(self):
			return 0

		def GetNumberCols(self):
			return 0

		def __nonzero__(self):
			return False

	USE_SETWXTABLE = 0

	class DelegatingTable(wx.grid.PyGridTableBase, MTableMessaging):
		"""
		Since wxGrid SetTable is buggy
		using TableDelegator and pythonic tables
		"""

		def __init__(self, table=None):
			wx.grid.PyGridTableBase.__init__(self)
			MTableMessaging.__init__(self)

			self.__table = table or NoneTable()
			if USE_SETWXTABLE:
				self.__table._setWxTable(self)

		def _setTable(self, table):
			self.fireTableStructureChanging()

			if USE_SETWXTABLE:
				if self.__table is not None:
					self.__table._setWxTable(None)

			self.__table = table

			if USE_SETWXTABLE:
				self.__table._setWxTable(self)

			self.fireTableStructureChanged()

		def _getTable(self):
			return self.__table

		#######################################################
		# BEGIN_AUTO_GENERATED_CODE
		def AppendCols(self, *args):
			return self.__table.AppendCols(*args)

		def AppendRows(self, *args):
			return self.__table.AppendRows(*args)

		def AttrProvider(self, *args):
			return self.__table.AttrProvider(*args)

		def CanGetValueAs(self, *args):
			return self.__table.CanGetValueAs(*args)

		def CanHaveAttributes(self, *args):
			return self.__table.CanHaveAttributes(*args)

		def CanSetValueAs(self, *args):
			return self.__table.CanSetValueAs(*args)

		def ClassName(self, *args):
			return self.__table.ClassName(*args)

		def Clear(self, *args):
			return self.__table.Clear(*args)

		def DeleteCols(self, *args):
			return self.__table.DeleteCols(*args)

		def DeleteRows(self, *args):
			return self.__table.DeleteRows(*args)

		def Destroy(self, *args):
			return self.__table.Destroy(*args)

		def GetAttr(self, *args):
			return self.__table.GetAttr(*args)

		def GetAttrProvider(self, *args):
			return self.__table.GetAttrProvider(*args)

		def GetClassName(self, *args):
			return self.__table.GetClassName(*args)

		def GetColLabelValue(self, *args):
			return self.__table.GetColLabelValue(*args)

		def GetNumberCols(self, *args):
			return self.__table.GetNumberCols(*args)

		def GetNumberRows(self, *args):
			return self.__table.GetNumberRows(*args)

		def GetRowLabelValue(self, *args):
			return self.__table.GetRowLabelValue(*args)

		def GetTypeName(self, *args):
			return self.__table.GetTypeName(*args)

		def GetValue(self, *args):
			return self.__table.GetValue(*args)

		def GetValueAsBool(self, *args):
			return self.__table.GetValueAsBool(*args)

		def GetValueAsDouble(self, *args):
			return self.__table.GetValueAsDouble(*args)

		def GetValueAsLong(self, *args):
			return self.__table.GetValueAsLong(*args)

		def GetView(self, *args):
			return self.__table.GetView(*args)

		def InsertCols(self, *args):
			return self.__table.InsertCols(*args)

		def InsertRows(self, *args):
			return self.__table.InsertRows(*args)

		def IsEmptyCell(self, *args):
			return self.__table.IsEmptyCell(*args)

		def IsSameAs(self, *args):
			return self.__table.IsSameAs(*args)

		def NumberCols(self, *args):
			return self.__table.NumberCols(*args)

		def NumberRows(self, *args):
			return self.__table.NumberRows(*args)

		def SetAttr(self, *args):
			return self.__table.SetAttr(*args)

		def SetAttrProvider(self, *args):
			return self.__table.SetAttrProvider(*args)

		def SetColAttr(self, *args):
			return self.__table.SetColAttr(*args)

		def SetColLabelValue(self, *args):
			return self.__table.SetColLabelValue(*args)

		def SetRowAttr(self, *args):
			return self.__table.SetRowAttr(*args)

		def SetRowLabelValue(self, *args):
			return self.__table.SetRowLabelValue(*args)

		def SetValue(self, *args):
			return self.__table.SetValue(*args)

		def SetValueAsBool(self, *args):
			return self.__table.SetValueAsBool(*args)

		def SetValueAsDouble(self, *args):
			return self.__table.SetValueAsDouble(*args)

		def SetValueAsLong(self, *args):
			return self.__table.SetValueAsLong(*args)

		def SetView(self, *args):
			return self.__table.SetView(*args)

		def View(self, *args):
			return self.__table.View(*args)

		# END_AUTO_GENERATED_CODE
		#######################################################

	__super__ = wx.grid.Grid
	class wxGrid(__super__):

		def __init__(self, *args, **kwargs):
			__super__.__init__(self, *args, **kwargs)
			table = DelegatingTable()
			__super__.SetTable(self, table, True)
			table.addGridTableListener(self)

		def GetTable(self):
			return __super__.GetTable(self)._getTable()

		def SetTable(self, table, ignored_takeOwnership=False):
			__super__.GetTable(self)._setTable(table)

else:
	wxGrid = wx.grid.Grid

if __name__ == '__main__':

	def inject(f):
		d = filter(lambda name: name[0].isupper(), dir(wx.grid.PyGridTableBase))
		d.sort()

		for i in d:
		#if VERBOSE: print "%s", args
			print >>f, """\
		def %s(self, *args, **kwargs):
			return self.__table.%s(*args, **kwargs)
		""".replace("%s", i)

	f = open(__file__, 'rt')
	code = f.readlines()
	f.close()

	state = "begin"
	f = open(__file__, 'wt')
	for i in code:
		if state == 'begin':
			f.write(i)
			if i.find('BEGIN_AUTO_GENERATED_CODE') != -1:
				inject(f)
				state = 'injected'
		elif state == 'injected':
			if i.find('END_AUTO_GENERATED_CODE') != -1:
				f.write(i)
				state = 'end'
		elif state == 'end':
			f.write(i)

	f.close()


#
# Copyright (C) 2013-2015 Red Hat, Inc.
#
# 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 for project."""

import logging

from . import util

@util.export
class Base(object):
    """Base class for all objects."""

    _LOG_PREFIX = 'ovirt.engine.'

    @property
    def logger(self):
        """Logger."""
        return self._logger

    def __init__(self):
        """Contructor."""

        prefix = ''
        if not self.__module__.startswith(self._LOG_PREFIX):
            prefix = self._LOG_PREFIX

        self._logger = logging.getLogger(prefix + self.__module__)

# vim: expandtab tabstop=4 shiftwidth=4


#!/usr/bin/env python

try:
	import pacman
except ImportError:
	import alpm
	pacman = alpm
import os, tempfile, shutil, sys

def pacman_pkg_getgroups(pkg):
	i = pacman.void_to_PM_LIST(pacman.pkg_getinfo(pkg, pacman.PKG_GROUPS))
	ret = []
	while i:
		ret.append(pacman.void_to_char(pacman.list_getdata(i)))
		i = pacman.list_next(i)
	return ret

def any_in(needle, haystack):
	"""return true if any of the needle list is found in haystack"""
	for i in needle:
		if i in haystack:
			return True
	return False

if len(sys.argv) > 1 and sys.argv[1] == "--help":
	print "COREPKGS (core, chroot-core, devel-core) packages which depend on packages outsite COREPKGS (->COREPKGS is needed)"
	sys.exit(0)

basecats = ['core', 'chroot-core', 'devel-core']

root = tempfile.mkdtemp()
pacman.initialize(root)
if os.getcwd().split('/')[-2] == "frugalware-current":
	treename = "frugalware-current"
else:
	treename = "frugalware"
db = pacman.db_register(treename)
pacman.db_setserver(db, "file://" + os.getcwd() + "/../frugalware-%s" % sys.argv[1])
pacman.db_update(1, db)

i = pacman.db_getpkgcache(db)
while i:
	pkg = pacman.void_to_PM_PKG(pacman.list_getdata(i))
	pkgname = pacman.void_to_char(pacman.pkg_getinfo(pkg, pacman.PKG_NAME))
	groups = pacman_pkg_getgroups(pkg)

	if not any_in(basecats, groups):
		i = pacman.list_next(i)
		continue
	j = pacman.void_to_PM_LIST(pacman.pkg_getinfo(pkg, pacman.PKG_DEPENDS))
	while j:
		found = False
		dep = pacman.void_to_char(pacman.list_getdata(j)).split("<")[0].split(">")[0].split("=")[0]
		k = pacman.db_getpkgcache(db)
		while not found and k:
			p = pacman.void_to_PM_PKG(pacman.list_getdata(k))
			if pacman.void_to_char(pacman.pkg_getinfo(p, pacman.PKG_NAME)) == dep:
				if any_in(basecats, pacman_pkg_getgroups(p)):
					found = True
			else:
				l = pacman.void_to_PM_LIST(pacman.pkg_getinfo(p, pacman.PKG_PROVIDES))
				while not found and l:
					pr = pacman.void_to_PM_PKG(pacman.list_getdata(l))
					if pacman.void_to_char(pacman.pkg_getinfo(pr, pacman.PKG_NAME)) == dep:
						found = True
					l = pacman.list_next(l)
			k = pacman.list_next(k)
		if not found:
			try:
				socket = open("../source/%s/%s/FrugalBuild" % (groups[0], pkgname))
				while True:
					line = socket.readline()
					if not line:
						break
					if line[:14] != "# Maintainer: ":
						continue
					# FIXME: we here hardcore the encoding of the FBs
					maintainer = line[14:].strip().decode('latin1')
					break
				socket.close()
			except IOError:
				maintainer = "Unknown"
			print "%s should be moved out from COREPKGS (%s is not in COREPKGS; %s)" % (pkgname, pacman.void_to_char(pacman.list_getdata(j)), maintainer)
		j = pacman.list_next(j)
	i = pacman.list_next(i)
shutil.rmtree(root)