@classmethod
  @gen.coroutine
  def _FormatConversationEmail(cls, client, recipient_id, viewpoint, activity):
    from viewfinder.backend.db.identity import Identity
    from viewfinder.backend.db.photo import Photo
    from viewfinder.backend.db.user import User

    # Get email address of recipient.
    recipient_user = yield gen.Task(User.Query, client, recipient_id, None)
    if recipient_user.email is None:
      # No email address associated with user, so can't send email.
      raise gen.Return(None)

    identity_key = 'Email:%s' % recipient_user.email

    # Create ShortURL that sets prospective user cookie and then redirects to the conversation.
    viewpoint_url = yield AlertManager._CreateViewpointURL(client, recipient_user, identity_key, viewpoint)

    sharer = yield gen.Task(User.Query, client, activity.user_id, None)
    sharer_name = AlertManager._GetNameFromUser(sharer, prefer_given_name=False)

    # Create the cover photo ShortURL by appending a "next" query parameter to the viewpoint ShortURL.
    cover_photo_url = None
    cover_photo_height = None
    cover_photo_width = None
    if viewpoint.cover_photo != None:
      next_url = '/episodes/%s/photos/%s.f' % (viewpoint.cover_photo['episode_id'], viewpoint.cover_photo['photo_id'])
      cover_photo_url = "%s?%s" % (viewpoint_url, urlencode(dict(next=next_url)))

      photo = yield gen.Task(Photo.Query, client, viewpoint.cover_photo['photo_id'], None)

      if photo.aspect_ratio < 1:
        cover_photo_height = AlertManager._MAX_COVER_PHOTO_DIM
        cover_photo_width = int(AlertManager._MAX_COVER_PHOTO_DIM * photo.aspect_ratio)
      else:
        cover_photo_width = AlertManager._MAX_COVER_PHOTO_DIM
        cover_photo_height = int(AlertManager._MAX_COVER_PHOTO_DIM / photo.aspect_ratio)

    email_args = {'from': EmailManager.Instance().GetInfoAddress(),
                  'to': recipient_user.email,
                  'subject': '%s added you to a conversation' % sharer_name}
    util.SetIfNotEmpty(email_args, 'toname', recipient_user.name)
    if sharer_name:
      email_args['fromname'] = '%s via Viewfinder' % sharer_name

    # Create the unsubscribe URL.
    unsubscribe_cookie = User.CreateUnsubscribeCookie(recipient_id, AccountSettings.EMAIL_ALERTS)
    unsubscribe_url = 'https://%s/unsubscribe?%s' % (options.options.domain,
                                                     urlencode(dict(cookie=unsubscribe_cookie)))

    # Set viewpoint title.
    viewpoint_title = viewpoint.title if viewpoint is not None else None

    fmt_args = {'cover_photo_url': cover_photo_url,
                'cover_photo_height': cover_photo_height,
                'cover_photo_width': cover_photo_width,
                'viewpoint_url': viewpoint_url,
                'unsubscribe_url': unsubscribe_url,
                'sharer_name': sharer_name,
                'viewpoint_title': viewpoint_title,
                'toname': recipient_user.name}

    resources_mgr = ResourcesManager.Instance()

    email_args['html'] = escape.squeeze(resources_mgr.GenerateTemplate('alert_conv_base.email',
                                                                       is_html=True,
                                                                       **fmt_args))
    email_args['text'] = resources_mgr.GenerateTemplate('alert_conv_base.email',
                                                        is_html=False,
                                                        **fmt_args)

    raise gen.Return(email_args)
Return (a,b)-sinh/sinh pseudo-derivative of a periodic sequence x.
dataset/ETHPy150Open viewfinderco/viewfinder/backend/op/alert_manager.py/AlertManager._FormatConversationEmail--crossover with--dataset/ETHPy150Open scipy/scipy/scipy/fftpack/pseudo_diffs.py/ss_diff