text:
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/views/frame/opaque_browser_frame_view.h"

#include <algorithm>
#include <string>

#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/prefs/pref_service.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/themes/theme_properties.h"
#include "chrome/browser/ui/views/avatar_menu_button.h"
#include "chrome/browser/ui/views/frame/browser_frame.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/tab_icon_view.h"
#include "chrome/browser/ui/views/tabs/tab_strip.h"
#include "chrome/browser/ui/views/toolbar_view.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/web_contents.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "grit/ui_resources.h"
#include "ui/base/accessibility/accessible_view_state.h"
#include "ui/base/hit_test.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/theme_provider.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/font.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/path.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/widget/root_view.h"
#include "ui/views/window/frame_background.h"
#include "ui/views/window/window_shape.h"

#if defined(OS_WIN)
#include "win8/util/win8_util.h"
#endif  // OS_WIN

using content::WebContents;

namespace {

// The frame border is only visible in restored mode and is hardcoded to 4 px on
// each side regardless of the system window border size.
const int kFrameBorderThickness = 4;
// Besides the frame border, there's another 9 px of empty space atop the
// window in restored mode, to use to drag the window around.
const int kNonClientRestoredExtraThickness = 9;
// While resize areas on Windows are normally the same size as the window
// borders, our top area is shrunk by 1 px to make it easier to move the window
// around with our thinner top grabbable strip.  (Incidentally, our side and
// bottom resize areas don't match the frame border thickness either -- they
// span the whole nonclient area, so there's no "dead zone" for the mouse.)
const int kTopResizeAdjust = 1;
// In the window corners, the resize areas don't actually expand bigger, but the
// 16 px at the end of each edge triggers diagonal resizing.
const int kResizeAreaCornerSize = 16;
// The titlebar never shrinks too short to show the caption button plus some
// padding below it.
const int kCaptionButtonHeightWithPadding = 19;
// The content left/right images have a shadow built into them.
const int kContentEdgeShadowThickness = 2;
// The titlebar has a 2 px 3D edge along the top and bottom.
const int kTitlebarTopAndBottomEdgeThickness = 2;
// The icon is inset 2 px from the left frame border.
const int kIconLeftSpacing = 2;
// The icon never shrinks below 16 px on a side.
const int kIconMinimumSize = 16;
// There is a 4 px gap between the icon and the title text.
const int kIconTitleSpacing = 4;
// There is a 5 px gap between the title text and the caption buttons.
const int kTitleLogoSpacing = 5;
// The avatar ends 2 px above the bottom of the tabstrip (which, given the
// way the tabstrip draws its bottom edge, will appear like a 1 px gap to the
// user).
const int kAvatarBottomSpacing = 2;
// Space between the frame border and the left edge of the avatar.
const int kAvatarLeftSpacing = 2;
// Space between the right edge of the avatar and the tabstrip.
const int kAvatarRightSpacing = -2;
// The top 3 px of the tabstrip is shadow; in maximized mode we push this off
// the top of the screen so the tabs appear flush against the screen edge.
const int kTabstripTopShadowThickness = 3;
// In restored mode, the New Tab button isn't at the same height as the caption
// buttons, but the space will look cluttered if it actually slides under them,
// so we stop it when the gap between the two is down to 5 px.
const int kNewTabCaptionRestoredSpacing = 5;
// In maximized mode, where the New Tab button and the caption buttons are at
// similar vertical coordinates, we need to reserve a larger, 16 px gap to avoid
// looking too cluttered.
const int kNewTabCaptionMaximizedSpacing = 16;
// How far to indent the tabstrip from the left side of the screen when there
// is no avatar icon.
const int kTabStripIndent = -6;

// Converts |bounds| from |src|'s coordinate system to |dst|, and checks if
// |pt| is contained within.
bool ConvertedContainsCheck(gfx::Rect bounds, const views::View* src,
                            const views::View* dst, const gfx::Point& pt) {
  DCHECK(src);
  DCHECK(dst);
  gfx::Point origin(bounds.origin());
  views::View::ConvertPointToTarget(src, dst, &origin);
  bounds.set_origin(origin);
  return bounds.Contains(pt);
}

bool ShouldAddDefaultCaptionButtons() {
#if defined(OS_WIN)
  return !win8::IsSingleWindowMetroMode();
#endif  // OS_WIN
  return true;
}

}  // namespace

///////////////////////////////////////////////////////////////////////////////
// OpaqueBrowserFrameView, public:

OpaqueBrowserFrameView::OpaqueBrowserFrameView(BrowserFrame* frame,
                                               BrowserView* browser_view)
    : BrowserNonClientFrameView(frame, browser_view),
      minimize_button_(NULL),
      maximize_button_(NULL),
      restore_button_(NULL),
      close_button_(NULL),
      window_icon_(NULL),
      window_title_(NULL),
      frame_background_(new views::FrameBackground()) {
  if (ShouldAddDefaultCaptionButtons()) {
    minimize_button_ = InitWindowCaptionButton(IDR_MINIMIZE,
                                               IDR_MINIMIZE_H,
                                               IDR_MINIMIZE_P,
                                               IDR_MINIMIZE_BUTTON_MASK,
                                               IDS_ACCNAME_MINIMIZE);
    maximize_button_ = InitWindowCaptionButton(IDR_MAXIMIZE,
                                               IDR_MAXIMIZE_H,
                                               IDR_MAXIMIZE_P,
                                               IDR_MAXIMIZE_BUTTON_MASK,
                                               IDS_ACCNAME_MAXIMIZE);
    restore_button_ = InitWindowCaptionButton(IDR_RESTORE,
                                              IDR_RESTORE_H,
                                              IDR_RESTORE_P,
                                              IDR_RESTORE_BUTTON_MASK,
                                              IDS_ACCNAME_RESTORE);
    close_button_ = InitWindowCaptionButton(IDR_CLOSE,
                                            IDR_CLOSE_H,
                                            IDR_CLOSE_P,
                                            IDR_CLOSE_BUTTON_MASK,
                                            IDS_ACCNAME_CLOSE);
  }

  // Initializing the TabIconView is expensive, so only do it if we need to.
  if (browser_view->ShouldShowWindowIcon()) {
    window_icon_ = new TabIconView(this);
    window_icon_->set_is_light(true);
    AddChildView(window_icon_);
    window_icon_->Update();
  }

  window_title_ = new views::Label(browser_view->GetWindowTitle(),
                                   BrowserFrame::GetTitleFont());
  window_title_->SetVisible(browser_view->ShouldShowWindowTitle());
  window_title_->SetEnabledColor(SK_ColorWHITE);
  // TODO(msw): Use a transparent background color as a workaround to use the
  // gfx::Canvas::NO_SUBPIXEL_RENDERING flag and avoid some visual artifacts.
  window_title_->SetBackgroundColor(0x00000000);
  window_title_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
  window_title_->SetElideBehavior(views::Label::ELIDE_AT_END);
  AddChildView(window_title_);

  UpdateAvatarInfo();
  if (!browser_view->IsOffTheRecord()) {
    registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED,
                   content::NotificationService::AllSources());
  }
}

OpaqueBrowserFrameView::~OpaqueBrowserFrameView() {
}

///////////////////////////////////////////////////////////////////////////////
// OpaqueBrowserFrameView, protected:

int OpaqueBrowserFrameView::GetReservedHeight() const {
  return 0;
}

gfx::Rect OpaqueBrowserFrameView::GetBoundsForReservedArea() const {
  gfx::Rect client_view_bounds = CalculateClientAreaBounds(width(), height());
  return gfx::Rect(
      client_view_bounds.x(),
      client_view_bounds.y() + client_view_bounds.height(),
      client_view_bounds.width(),
      GetReservedHeight());
}

int OpaqueBrowserFrameView::NonClientTopBorderHeight(
    bool restored) const {
  views::WidgetDelegate* delegate = frame()->widget_delegate();
  // |delegate| may be NULL if called from callback of InputMethodChanged while
  // a window is being destroyed.
  // See more discussion at http://crosbug.com/8958
  if (delegate && delegate->ShouldShowWindowTitle()) {
    return std::max(FrameBorderThickness(restored) + IconSize(),
        CaptionButtonY(restored) + kCaptionButtonHeightWithPadding) +
        TitlebarBottomThickness(restored);
  }

  return FrameBorderThickness(restored) -
      ((browser_view()->IsTabStripVisible() &&
          !restored && !frame()->ShouldLeaveOffsetNearTopBorder())
              ? kTabstripTopShadowThickness : 0);
}

///////////////////////////////////////////////////////////////////////////////
// OpaqueBrowserFrameView, BrowserNonClientFrameView implementation:

gfx::Rect OpaqueBrowserFrameView::GetBoundsForTabStrip(
    views::View* tabstrip) const {
  if (!tabstrip)
    return gfx::Rect();

  gfx::Rect bounds = GetBoundsForTabStripAndAvatarArea(tabstrip);
  const int space_left_of_tabstrip = browser_view()->ShouldShowAvatar() ?
      (kAvatarLeftSpacing + avatar_bounds_.width() + kAvatarRightSpacing) :
      kTabStripIndent;
  bounds.Inset(space_left_of_tabstrip, 0, 0, 0);
  return bounds;
}

BrowserNonClientFrameView::TabStripInsets
OpaqueBrowserFrameView::GetTabStripInsets(bool restored) const {
  int top = NonClientTopBorderHeight(restored) + ((!restored &&
      (!frame()->ShouldLeaveOffsetNearTopBorder() ||
      frame()->IsFullscreen())) ?
      0 : kNonClientRestoredExtraThickness);
  // TODO: include OTR and caption.
  return TabStripInsets(top, 0, 0);
}

int OpaqueBrowserFrameView::GetThemeBackgroundXInset() const {
  return 0;
}

void OpaqueBrowserFrameView::UpdateThrobber(bool running) {
  if (window_icon_)
    window_icon_->Update();
}

gfx::Size OpaqueBrowserFrameView::GetMinimumSize() {
  gfx::Size min_size(browser_view()->GetMinimumSize());
  int border_thickness = NonClientBorderThickness();
  min_size.Enlarge(2 * border_thickness,
                   NonClientTopBorderHeight(false) + border_thickness);

  views::WidgetDelegate* delegate = frame()->widget_delegate();
  int min_titlebar_width = (2 * FrameBorderThickness(false)) +
      kIconLeftSpacing +
      (delegate && delegate->ShouldShowWindowIcon() ?
       (IconSize() + kTitleLogoSpacing) : 0);
#if !defined(OS_CHROMEOS)
  if (ShouldAddDefaultCaptionButtons()) {
    min_titlebar_width +=
        minimize_button_->GetMinimumSize().width() +
        restore_button_->GetMinimumSize().width() +
        close_button_->GetMinimumSize().width();
  }
#endif
  min_size.set_width(std::max(min_size.width(), min_titlebar_width));

  // Ensure that the minimum width is enough to hold a minimum width tab strip
  // and avatar icon at their usual insets.
  if (browser_view()->IsTabStripVisible()) {
    TabStrip* tabstrip = browser_view()->tabstrip();
    const int min_tabstrip_width = tabstrip->GetMinimumSize().width();
    const int min_tabstrip_area_width =
        width() - GetBoundsForTabStripAndAvatarArea(tabstrip).width() +
        min_tabstrip_width + browser_view()->GetOTRAvatarIcon().width() +
        kAvatarLeftSpacing + kAvatarRightSpacing;
    min_size.set_width(std::max(min_size.width(), min_tabstrip_area_width));
  }

  return min_size;
}

///////////////////////////////////////////////////////////////////////////////
// OpaqueBrowserFrameView, views::NonClientFrameView implementation:

gfx::Rect OpaqueBrowserFrameView::GetBoundsForClientView() const {
  return client_view_bounds_;
}

gfx::Rect OpaqueBrowserFrameView::GetWindowBoundsForClientBounds(
    const gfx::Rect& client_bounds) const {
  int top_height = NonClientTopBorderHeight(false);
  int border_thickness = NonClientBorderThickness();
  return gfx::Rect(std::max(0, client_bounds.x() - border_thickness),
                   std::max(0, client_bounds.y() - top_height),
                   client_bounds.width() + (2 * border_thickness),
                   client_bounds.height() + top_height + border_thickness);
}

int OpaqueBrowserFrameView::NonClientHitTest(const gfx::Point& point) {
  if (!bounds().Contains(point))
    return HTNOWHERE;

  // See if the point is within the avatar menu button.
  if (avatar_button() &&
      avatar_button()->GetMirroredBounds().Contains(point))
    return HTCLIENT;

  int frame_component = frame()->client_view()->NonClientHitTest(point);

  // See if we're in the sysmenu region.  We still have to check the tabstrip
  // first so that clicks in a tab don't get treated as sysmenu clicks.
  gfx::Rect sysmenu_rect(IconBounds());
  // In maximized mode we extend the rect to the screen corner to take advantage
  // of Fitts' Law.
  if (frame()->IsMaximized())
    sysmenu_rect.SetRect(0, 0, sysmenu_rect.right(), sysmenu_rect.bottom());
  sysmenu_rect.set_x(GetMirroredXForRect(sysmenu_rect));
  if (sysmenu_rect.Contains(point))
    return (frame_component == HTCLIENT) ? HTCLIENT : HTSYSMENU;

  if (frame_component != HTNOWHERE)
    return frame_component;

  // Then see if the point is within any of the window controls.
  if (close_button_ && close_button_->visible() &&
      close_button_->GetMirroredBounds().Contains(point))
    return HTCLOSE;
  if (restore_button_ && restore_button_->visible() &&
      restore_button_->GetMirroredBounds().Contains(point))
    return HTMAXBUTTON;
  if (maximize_button_ && maximize_button_->visible() &&
      maximize_button_->GetMirroredBounds().Contains(point))
    return HTMAXBUTTON;
  if (minimize_button_ && minimize_button_->visible() &&
      minimize_button_->GetMirroredBounds().Contains(point))
    return HTMINBUTTON;

  views::WidgetDelegate* delegate = frame()->widget_delegate();
  if (!delegate) {
    LOG(WARNING) << "delegate is NULL, returning safe default.";
    return HTCAPTION;
  }
  int window_component = GetHTComponentForFrame(point, TopResizeHeight(),
      NonClientBorderThickness(), kResizeAreaCornerSize, kResizeAreaCornerSize,
      delegate->CanResize());
  // Fall back to the caption if no other component matches.
  return (window_component == HTNOWHERE) ? HTCAPTION : window_component;
}

void OpaqueBrowserFrameView::GetWindowMask(const gfx::Size& size,
                                           gfx::Path* window_mask) {
  DCHECK(window_mask);

  if (frame()->IsMaximized() || frame()->IsFullscreen())
    return;

  views::GetDefaultWindowMask(size, window_mask);
}

void OpaqueBrowserFrameView::ResetWindowControls() {
  if (!ShouldAddDefaultCaptionButtons())
    return;
  restore_button_->SetState(views::CustomButton::STATE_NORMAL);
  minimize_button_->SetState(views::CustomButton::STATE_NORMAL);
  maximize_button_->SetState(views::CustomButton::STATE_NORMAL);
  // The close button isn't affected by this constraint.
}

void OpaqueBrowserFrameView::UpdateWindowIcon() {
  window_icon_->SchedulePaint();
}

void OpaqueBrowserFrameView::UpdateWindowTitle() {
  if (!frame()->IsFullscreen())
    window_title_->SchedulePaint();
}

///////////////////////////////////////////////////////////////////////////////
// OpaqueBrowserFrameView, views::View overrides:

void OpaqueBrowserFrameView::OnPaint(gfx::Canvas* canvas) {
  if (frame()->IsFullscreen())
    return;  // Nothing is visible, so don't bother to paint.

  if (frame()->IsMaximized())
    PaintMaximizedFrameBorder(canvas);
  else
    PaintRestoredFrameBorder(canvas);

  // The window icon and title are painted by their respective views.
  /* TODO(pkasting):  If this window is active, we should also draw a drop
   * shadow on the title.  This is tricky, because we don't want to hardcode a
   * shadow color (since we want to work with various themes), but we can't
   * alpha-blend either (since the Windows text APIs don't really do this).
   * So we'd need to sample the background color at the right location and
   * synthesize a good shadow color. */

  if (browser_view()->IsToolbarVisible())
    PaintToolbarBackground(canvas);
  if (!frame()->IsMaximized())
    PaintRestoredClientEdge(canvas);
}

void OpaqueBrowserFrameView::Layout() {
  LayoutWindowControls();
  LayoutTitleBar();
  LayoutAvatar();
  client_view_bounds_ = CalculateClientAreaBounds(width(), height());
}

bool OpaqueBrowserFrameView::HitTestRect(const gfx::Rect& rect) const {
  // If |rect| does not intersect the bounds of the client area, claim it.
  bool in_nonclient = NonClientFrameView::HitTestRect(rect);
  if (in_nonclient)
    return in_nonclient;

  // Otherwise claim it only if it's in a non-tab portion of the tabstrip.
  if (!browser_view()->tabstrip())
    return false;
  gfx::Rect tabstrip_bounds(browser_view()->tabstrip()->bounds());
  gfx::Point tabstrip_origin(tabstrip_bounds.origin());
  View::ConvertPointToTarget(frame()->client_view(), this, &tabstrip_origin);
  tabstrip_bounds.set_origin(tabstrip_origin);
  if (rect.bottom() > tabstrip_bounds.bottom())
    return false;

  // We convert from our parent's coordinates since we assume we fill its bounds
  // completely. We need to do this since we're not a parent of the tabstrip,
  // meaning ConvertPointToTarget would otherwise return something bogus.
  // TODO(tdanderson): Initialize |browser_view_point| using |rect| instead of
  // its center point once GetEventHandlerForRect() is implemented.
  gfx::Point browser_view_point(rect.CenterPoint());
  View::ConvertPointToTarget(parent(), browser_view(), &browser_view_point);
  return browser_view()->IsPositionInWindowCaption(browser_view_point);
}

void OpaqueBrowserFrameView::GetAccessibleState(
    ui::AccessibleViewState* state) {
  state->role = ui::AccessibilityTypes::ROLE_TITLEBAR;
}

///////////////////////////////////////////////////////////////////////////////
// OpaqueBrowserFrameView, views::ButtonListener implementation:

void OpaqueBrowserFrameView::ButtonPressed(views::Button* sender,
                                           const ui::Event& event) {
  if (sender == minimize_button_)
    frame()->Minimize();
  else if (sender == maximize_button_)
    frame()->Maximize();
  else if (sender == restore_button_)
    frame()->Restore();
  else if (sender == close_button_)
    frame()->Close();
}

///////////////////////////////////////////////////////////////////////////////
// OpaqueBrowserFrameView, TabIconView::TabContentsProvider implementation:

bool OpaqueBrowserFrameView::ShouldTabIconViewAnimate() const {
  // This function is queried during the creation of the window as the
  // TabIconView we host is initialized, so we need to NULL check the selected
  // WebContents because in this condition there is not yet a selected tab.
  WebContents* current_tab = browser_view()->GetActiveWebContents();
  return current_tab ? current_tab->IsLoading() : false;
}

gfx::ImageSkia OpaqueBrowserFrameView::GetFaviconForTabIconView() {
  views::WidgetDelegate* delegate = frame()->widget_delegate();
  if (!delegate) {
    LOG(WARNING) << "delegate is NULL, returning safe default.";
    return gfx::ImageSkia();
  }
  return delegate->GetWindowIcon();
}

///////////////////////////////////////////////////////////////////////////////
// OpaqueBrowserFrameView, protected:

void OpaqueBrowserFrameView::Observe(
    int type,
    const content::NotificationSource& source,
    const content::NotificationDetails& details) {
  switch (type) {
    case chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED:
      UpdateAvatarInfo();
      break;
    default:
      NOTREACHED() << "Got a notification we didn't register for!";
      break;
  }
}

///////////////////////////////////////////////////////////////////////////////
// OpaqueBrowserFrameView, private:

views::ImageButton* OpaqueBrowserFrameView::InitWindowCaptionButton(
    int normal_image_id,
    int hot_image_id,
    int pushed_image_id,
    int mask_image_id,
    int accessibility_string_id) {
  views::ImageButton* button = new views::ImageButton(this);
  ui::ThemeProvider* tp = frame()->GetThemeProvider();
  button->SetImage(views::CustomButton::STATE_NORMAL,
                   tp->GetImageSkiaNamed(normal_image_id));
  button->SetImage(views::CustomButton::STATE_HOVERED,
                   tp->GetImageSkiaNamed(hot_image_id));
  button->SetImage(views::CustomButton::STATE_PRESSED,
                   tp->GetImageSkiaNamed(pushed_image_id));
  if (browser_view()->IsBrowserTypeNormal()) {
    button->SetBackground(
        tp->GetColor(ThemeProperties::COLOR_BUTTON_BACKGROUND),
        tp->GetImageSkiaNamed(IDR_THEME_WINDOW_CONTROL_BACKGROUND),
        tp->GetImageSkiaNamed(mask_image_id));
  }
  button->SetAccessibleName(
      l10n_util::GetStringUTF16(accessibility_string_id));
  AddChildView(button);
  return button;
}

int OpaqueBrowserFrameView::FrameBorderThickness(bool restored) const {
  return (!restored && (frame()->IsMaximized() || frame()->IsFullscreen())) ?
      0 : kFrameBorderThickness;
}

int OpaqueBrowserFrameView::TopResizeHeight() const {
  return FrameBorderThickness(false) - kTopResizeAdjust;
}

int OpaqueBrowserFrameView::NonClientBorderThickness() const {
  // When we fill the screen, we don't show a client edge.
  return FrameBorderThickness(false) +
      ((frame()->IsMaximized() || frame()->IsFullscreen()) ?
       0 : kClientEdgeThickness);
}

int OpaqueBrowserFrameView::CaptionButtonY(bool restored) const {
  // Maximized buttons start at window top so that even if their images aren't
  // drawn flush with the screen edge, they still obey Fitts' Law.
  return (!restored && frame()->IsMaximized()) ?
      FrameBorderThickness(false) : kFrameShadowThickness;
}

int OpaqueBrowserFrameView::TitlebarBottomThickness(bool restored) const {
  return kTitlebarTopAndBottomEdgeThickness +
      ((!restored && frame()->IsMaximized()) ? 0 : kClientEdgeThickness);
}

int OpaqueBrowserFrameView::IconSize() const {
#if defined(OS_WIN)
  // This metric scales up if either the titlebar height or the titlebar font
  // size are increased.
  return GetSystemMetrics(SM_CYSMICON);
#else
  return std::max(BrowserFrame::GetTitleFont().GetHeight(), kIconMinimumSize);
#endif
}

gfx::Rect OpaqueBrowserFrameView::IconBounds() const {
  int size = IconSize();
  int frame_thickness = FrameBorderThickness(false);
  int y;
  views::WidgetDelegate* delegate = frame()->widget_delegate();
  if (delegate && (delegate->ShouldShowWindowIcon() ||
                   delegate->ShouldShowWindowTitle())) {
    // Our frame border has a different "3D look" than Windows'.  Theirs has a
    // more complex gradient on the top that they push their icon/title below;
    // then the maximized window cuts this off and the icon/title are centered
    // in the remaining space.  Because the apparent shape of our border is
    // simpler, using the same positioning makes things look slightly uncentered
    // with restored windows, so when the window is restored, instead of
    // calculating the remaining space from below the frame border, we calculate
    // from below the 3D edge.
    int unavailable_px_at_top = frame()->IsMaximized() ?
        frame_thickness : kTitlebarTopAndBottomEdgeThickness;
    // When the icon is shorter than the minimum space we reserve for the
    // caption button, we vertically center it.  We want to bias rounding to put
    // extra space above the icon, since the 3D edge (+ client edge, for
    // restored windows) below looks (to the eye) more like additional space
    // than does the 3D edge (or nothing at all, for maximized windows) above;
    // hence the +1.
    y = unavailable_px_at_top + (NonClientTopBorderHeight(false) -
        unavailable_px_at_top - size - TitlebarBottomThickness(false) + 1) / 2;
  } else {
    // For "browser mode" windows, we use the native positioning, which is just
    // below the top frame border.
    y = frame_thickness;
  }
  return gfx::Rect(frame_thickness + kIconLeftSpacing, y, size, size);
}

gfx::Rect OpaqueBrowserFrameView::GetBoundsForTabStripAndAvatarArea(
    views::View* tabstrip) const {
  int available_width = width();
  if (minimize_button_) {
    available_width = minimize_button_->x();
  } else if (browser_view()->window_switcher_button()) {
    // We don't have the sysmenu buttons in Windows 8 metro mode. However there
    // are buttons like the window switcher which are drawn in the non client
    // are in the BrowserView. We need to ensure that the tab strip does not
    // draw on the window switcher button.
    available_width -= browser_view()->window_switcher_button()->width();
  }
  const int caption_spacing = frame()->IsMaximized() ?
      kNewTabCaptionMaximizedSpacing : kNewTabCaptionRestoredSpacing;
  const int tabstrip_x = NonClientBorderThickness();
  const int tabstrip_width = available_width - tabstrip_x - caption_spacing;
  return gfx::Rect(tabstrip_x, GetTabStripInsets(false).top,
                   std::max(0, tabstrip_width),
                   tabstrip->GetPreferredSize().height());
}

void OpaqueBrowserFrameView::PaintRestoredFrameBorder(gfx::Canvas* canvas) {
  frame_background_->set_frame_color(GetFrameColor());
  frame_background_->set_theme_image(GetFrameImage());
  frame_background_->set_theme_overlay_image(GetFrameOverlayImage());
  frame_background_->set_top_area_height(GetTopAreaHeight());

  ui::ThemeProvider* tp = GetThemeProvider();
  frame_background_->SetSideImages(
      tp->GetImageSkiaNamed(IDR_WINDOW_LEFT_SIDE),
      tp->GetImageSkiaNamed(IDR_WINDOW_TOP_CENTER),
      tp->GetImageSkiaNamed(IDR_WINDOW_RIGHT_SIDE),
      tp->GetImageSkiaNamed(IDR_WINDOW_BOTTOM_CENTER));
  frame_background_->SetCornerImages(
      tp->GetImageSkiaNamed(IDR_WINDOW_TOP_LEFT_CORNER),
      tp->GetImageSkiaNamed(IDR_WINDOW_TOP_RIGHT_CORNER),
      tp->GetImageSkiaNamed(IDR_WINDOW_BOTTOM_LEFT_CORNER),
      tp->GetImageSkiaNamed(IDR_WINDOW_BOTTOM_RIGHT_CORNER));
  frame_background_->PaintRestored(canvas, this);

  // Note: When we don't have a toolbar, we need to draw some kind of bottom
  // edge here.  Because the App Window graphics we use for this have an
  // attached client edge and their sizing algorithm is a little involved, we do
  // all this in PaintRestoredClientEdge().
}

void OpaqueBrowserFrameView::PaintMaximizedFrameBorder(gfx::Canvas* canvas) {
  frame_background_->set_frame_color(GetFrameColor());
  frame_background_->set_theme_image(GetFrameImage());
  frame_background_->set_theme_overlay_image(GetFrameOverlayImage());
  frame_background_->set_top_area_height(GetTopAreaHeight());

  // Theme frame must be aligned with the tabstrip as if we were
  // in restored mode.  Note that the top of the tabstrip is
  // kTabstripTopShadowThickness px off the top of the screen.
  int theme_background_y = -(GetTabStripInsets(true).top +
      kTabstripTopShadowThickness);
  frame_background_->set_theme_background_y(theme_background_y);

  frame_background_->PaintMaximized(canvas, this);

  // TODO(jamescook): Migrate this into FrameBackground.
  if (!browser_view()->IsToolbarVisible()) {
    // There's no toolbar to edge the frame border, so we need to draw a bottom
    // edge.  The graphic we use for this has a built in client edge, so we clip
    // it off the bottom.
    gfx::ImageSkia* top_center =
        GetThemeProvider()->GetImageSkiaNamed(IDR_APP_TOP_CENTER);
    int edge_height = top_center->height() - kClientEdgeThickness;
    canvas->TileImageInt(*top_center, 0,
        frame()->client_view()->y() - edge_height, width(), edge_height);
  }
}

void OpaqueBrowserFrameView::PaintToolbarBackground(gfx::Canvas* canvas) {
  gfx::Rect toolbar_bounds(browser_view()->GetToolbarBounds());
  if (toolbar_bounds.IsEmpty())
    return;
  gfx::Point toolbar_origin(toolbar_bounds.origin());
  ConvertPointToTarget(browser_view(), this, &toolbar_origin);
  toolbar_bounds.set_origin(toolbar_origin);

  int x = toolbar_bounds.x();
  int w = toolbar_bounds.width();
  int y = toolbar_bounds.y();
  int h = toolbar_bounds.height();

  // Gross hack: We split the toolbar images into two pieces, since sometimes
  // (popup mode) the toolbar isn't tall enough to show the whole image.  The
  // split happens between the top shadow section and the bottom gradient
  // section so that we never break the gradient.
  int split_point = kFrameShadowThickness * 2;
  int bottom_y = y + split_point;
  ui::ThemeProvider* tp = GetThemeProvider();
  gfx::ImageSkia* toolbar_left = tp->GetImageSkiaNamed(
      IDR_CONTENT_TOP_LEFT_CORNER);
  int bottom_edge_height = std::min(toolbar_left->height(), h) - split_point;

  // Split our canvas out so we can mask out the corners of the toolbar
  // without masking out the frame.
  canvas->SaveLayerAlpha(
      255, gfx::Rect(x - kClientEdgeThickness, y, w + kClientEdgeThickness * 3,
                     h));

  // Paint the bottom rect.
  canvas->FillRect(gfx::Rect(x, bottom_y, w, bottom_edge_height),
                   tp->GetColor(ThemeProperties::COLOR_TOOLBAR));

  // Tile the toolbar image starting at the frame edge on the left and where the
  // horizontal tabstrip is (or would be) on the top.
  gfx::ImageSkia* theme_toolbar = tp->GetImageSkiaNamed(IDR_THEME_TOOLBAR);
  canvas->TileImageInt(*theme_toolbar,
                       x + GetThemeBackgroundXInset(),
                       bottom_y - GetTabStripInsets(false).top,
                       x, bottom_y, w, theme_toolbar->height());

  // Draw rounded corners for the tab.
  gfx::ImageSkia* toolbar_left_mask =
      tp->GetImageSkiaNamed(IDR_CONTENT_TOP_LEFT_CORNER_MASK);
  gfx::ImageSkia* toolbar_right_mask =
      tp->GetImageSkiaNamed(IDR_CONTENT_TOP_RIGHT_CORNER_MASK);

  // We mask out the corners by using the DestinationIn transfer mode,
  // which keeps the RGB pixels from the destination and the alpha from
  // the source.
  SkPaint paint;
  paint.setXfermodeMode(SkXfermode::kDstIn_Mode);

  // Mask the left edge.
  int left_x = x - kContentEdgeShadowThickness;
  canvas->DrawImageInt(*toolbar_left_mask, 0, 0, toolbar_left_mask->width(),
                       split_point, left_x, y, toolbar_left_mask->width(),
                       split_point, false, paint);
  canvas->DrawImageInt(*toolbar_left_mask, 0,
      toolbar_left_mask->height() - bottom_edge_height,
      toolbar_left_mask->width(), bottom_edge_height, left_x, bottom_y,
      toolbar_left_mask->width(), bottom_edge_height, false, paint);

  // Mask the right edge.
  int right_x =
      x + w - toolbar_right_mask->width() + kContentEdgeShadowThickness;
  canvas->DrawImageInt(*toolbar_right_mask, 0, 0, toolbar_right_mask->width(),
                       split_point, right_x, y, toolbar_right_mask->width(),
                       split_point, false, paint);
  canvas->DrawImageInt(*toolbar_right_mask, 0,
      toolbar_right_mask->height() - bottom_edge_height,
      toolbar_right_mask->width(), bottom_edge_height, right_x, bottom_y,
      toolbar_right_mask->width(), bottom_edge_height, false, paint);
  canvas->Restore();

  canvas->DrawImageInt(*toolbar_left, 0, 0, toolbar_left->width(), split_point,
                       left_x, y, toolbar_left->width(), split_point, false);
  canvas->DrawImageInt(*toolbar_left, 0,
      toolbar_left->height() - bottom_edge_height, toolbar_left->width(),
      bottom_edge_height, left_x, bottom_y, toolbar_left->width(),
      bottom_edge_height, false);

  gfx::ImageSkia* toolbar_center =
      tp->GetImageSkiaNamed(IDR_CONTENT_TOP_CENTER);
  canvas->TileImageInt(*toolbar_center, 0, 0, left_x + toolbar_left->width(),
      y, right_x - (left_x + toolbar_left->width()),
      split_point);

  gfx::ImageSkia* toolbar_right = tp->GetImageSkiaNamed(
      IDR_CONTENT_TOP_RIGHT_CORNER);
  canvas->DrawImageInt(*toolbar_right, 0, 0, toolbar_right->width(),
      split_point, right_x, y, toolbar_right->width(), split_point, false);
  canvas->DrawImageInt(*toolbar_right, 0,
      toolbar_right->height() - bottom_edge_height, toolbar_right->width(),
      bottom_edge_height, right_x, bottom_y, toolbar_right->width(),
      bottom_edge_height, false);

  // Draw the content/toolbar separator.
  canvas->FillRect(
      gfx::Rect(x + kClientEdgeThickness,
                toolbar_bounds.bottom() - kClientEdgeThickness,
                w - (2 * kClientEdgeThickness),
                kClientEdgeThickness),
      ThemeProperties::GetDefaultColor(
          ThemeProperties::COLOR_TOOLBAR_SEPARATOR));
}

void OpaqueBrowserFrameView::PaintRestoredClientEdge(gfx::Canvas* canvas) {
  ui::ThemeProvider* tp = GetThemeProvider();
  int client_area_top = frame()->client_view()->y();
  int image_top = client_area_top;

  gfx::Rect client_area_bounds = CalculateClientAreaBounds(width(), height());
  SkColor toolbar_color = tp->GetColor(ThemeProperties::COLOR_TOOLBAR);

  if (browser_view()->IsToolbarVisible()) {
    // The client edge images always start below the toolbar corner images.  The
    // client edge filled rects start there or at the bottom of the toolbar,
    // whichever is shorter.
    gfx::Rect toolbar_bounds(browser_view()->GetToolbarBounds());
    image_top += toolbar_bounds.y() +
        tp->GetImageSkiaNamed(IDR_CONTENT_TOP_LEFT_CORNER)->height();
    client_area_top = std::min(image_top,
        client_area_top + toolbar_bounds.bottom() - kClientEdgeThickness);
  } else if (!browser_view()->IsTabStripVisible()) {
    // The toolbar isn't going to draw a client edge for us, so draw one
    // ourselves.
    gfx::ImageSkia* top_left = tp->GetImageSkiaNamed(IDR_APP_TOP_LEFT);
    gfx::ImageSkia* top_center = tp->GetImageSkiaNamed(IDR_APP_TOP_CENTER);
    gfx::ImageSkia* top_right = tp->GetImageSkiaNamed(IDR_APP_TOP_RIGHT);
    int top_edge_y = client_area_top - top_center->height();
    int height = client_area_top - top_edge_y;

    canvas->DrawImageInt(*top_left, 0, 0, top_left->width(), height,
        client_area_bounds.x() - top_left->width(), top_edge_y,
        top_left->width(), height, false);
    canvas->TileImageInt(*top_center, 0, 0, client_area_bounds.x(), top_edge_y,
      client_area_bounds.width(), std::min(height, top_center->height()));
    canvas->DrawImageInt(*top_right, 0, 0, top_right->width(), height,
        client_area_bounds.right(), top_edge_y,
        top_right->width(), height, false);

    // Draw the toolbar color across the top edge.
    canvas->FillRect(gfx::Rect(client_area_bounds.x() - kClientEdgeThickness,
        client_area_top - kClientEdgeThickness,
        client_area_bounds.width() + (2 * kClientEdgeThickness),
        kClientEdgeThickness), toolbar_color);
  }

  int client_area_bottom =
      std::max(client_area_top, height() - NonClientBorderThickness());
  int image_height = client_area_bottom - image_top;

  // Draw the client edge images.
  // Draw the client edge images.
  gfx::ImageSkia* right = tp->GetImageSkiaNamed(IDR_CONTENT_RIGHT_SIDE);
  canvas->TileImageInt(*right, client_area_bounds.right(), image_top,
                       right->width(), image_height);
  canvas->DrawImageInt(
      *tp->GetImageSkiaNamed(IDR_CONTENT_BOTTOM_RIGHT_CORNER),
      client_area_bounds.right(), client_area_bottom);
  gfx::ImageSkia* bottom = tp->GetImageSkiaNamed(IDR_CONTENT_BOTTOM_CENTER);
  canvas->TileImageInt(*bottom, client_area_bounds.x(),
      client_area_bottom, client_area_bounds.width(),
      bottom->height());
  gfx::ImageSkia* bottom_left =
      tp->GetImageSkiaNamed(IDR_CONTENT_BOTTOM_LEFT_CORNER);
  canvas->DrawImageInt(*bottom_left,
      client_area_bounds.x() - bottom_left->width(), client_area_bottom);
  gfx::ImageSkia* left = tp->GetImageSkiaNamed(IDR_CONTENT_LEFT_SIDE);
  canvas->TileImageInt(*left, client_area_bounds.x() - left->width(),
                       image_top, left->width(), image_height);

  // Draw the toolbar color so that the client edges show the right color even
  // where not covered by the toolbar image.  NOTE: We do this after drawing the
  // images because the images are meant to alpha-blend atop the frame whereas
  // these rects are meant to be fully opaque, without anything overlaid.
  canvas->FillRect(gfx::Rect(client_area_bounds.x() - kClientEdgeThickness,
      client_area_top, kClientEdgeThickness,
      client_area_bottom + kClientEdgeThickness - client_area_top),
       toolbar_color);
  canvas->FillRect(gfx::Rect(client_area_bounds.x(), client_area_bottom,
                             client_area_bounds.width(), kClientEdgeThickness),
                   toolbar_color);
  canvas->FillRect(gfx::Rect(client_area_bounds.right(), client_area_top,
      kClientEdgeThickness,
      client_area_bottom + kClientEdgeThickness - client_area_top),
      toolbar_color);
}

SkColor OpaqueBrowserFrameView::GetFrameColor() const {
  bool is_incognito = browser_view()->IsOffTheRecord();
  if (browser_view()->IsBrowserTypeNormal()) {
    if (ShouldPaintAsActive()) {
      return GetThemeProvider()->GetColor(is_incognito ?
          ThemeProperties::COLOR_FRAME_INCOGNITO :
          ThemeProperties::COLOR_FRAME);
    }
    return GetThemeProvider()->GetColor(is_incognito ?
        ThemeProperties::COLOR_FRAME_INCOGNITO_INACTIVE :
        ThemeProperties::COLOR_FRAME_INACTIVE);
  }
  // Never theme app and popup windows.
  if (ShouldPaintAsActive()) {
    return ThemeProperties::GetDefaultColor(is_incognito ?
        ThemeProperties::COLOR_FRAME_INCOGNITO : ThemeProperties::COLOR_FRAME);
  }
  return ThemeProperties::GetDefaultColor(is_incognito ?
      ThemeProperties::COLOR_FRAME_INCOGNITO_INACTIVE :
      ThemeProperties::COLOR_FRAME_INACTIVE);
}

gfx::ImageSkia* OpaqueBrowserFrameView::GetFrameImage() const {
  bool is_incognito = browser_view()->IsOffTheRecord();
  int resource_id;
  if (browser_view()->IsBrowserTypeNormal()) {
    if (ShouldPaintAsActive()) {
      resource_id = is_incognito ?
          IDR_THEME_FRAME_INCOGNITO : IDR_THEME_FRAME;
    } else {
      resource_id = is_incognito ?
          IDR_THEME_FRAME_INCOGNITO_INACTIVE : IDR_THEME_FRAME_INACTIVE;
    }
    return GetThemeProvider()->GetImageSkiaNamed(resource_id);
  }
  // Never theme app and popup windows.
  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
  if (ShouldPaintAsActive()) {
    resource_id = is_incognito ?
        IDR_THEME_FRAME_INCOGNITO : IDR_FRAME;
  } else {
    resource_id = is_incognito ?
        IDR_THEME_FRAME_INCOGNITO_INACTIVE : IDR_THEME_FRAME_INACTIVE;
  }
  return rb.GetImageSkiaNamed(resource_id);
}

gfx::ImageSkia* OpaqueBrowserFrameView::GetFrameOverlayImage() const {
  ui::ThemeProvider* tp = GetThemeProvider();
  if (tp->HasCustomImage(IDR_THEME_FRAME_OVERLAY) &&
      browser_view()->IsBrowserTypeNormal() &&
      !browser_view()->IsOffTheRecord()) {
    return tp->GetImageSkiaNamed(ShouldPaintAsActive() ?
        IDR_THEME_FRAME_OVERLAY : IDR_THEME_FRAME_OVERLAY_INACTIVE);
  }
  return NULL;
}

int OpaqueBrowserFrameView::GetTopAreaHeight() const {
  gfx::ImageSkia* frame_image = GetFrameImage();
  int top_area_height = frame_image->height();
  if (browser_view()->IsTabStripVisible()) {
    top_area_height = std::max(top_area_height,
      GetBoundsForTabStrip(browser_view()->tabstrip()).bottom());
  }
  return top_area_height;
}

void OpaqueBrowserFrameView::LayoutWindowControls() {
  if (!ShouldAddDefaultCaptionButtons())
    return;
  bool is_maximized = frame()->IsMaximized();
  close_button_->SetImageAlignment(views::ImageButton::ALIGN_LEFT,
                                   views::ImageButton::ALIGN_BOTTOM);
  int caption_y = CaptionButtonY(false);
  // There should always be the same number of non-shadow pixels visible to the
  // side of the caption buttons.  In maximized mode we extend the rightmost
  // button to the screen corner to obey Fitts' Law.
  int right_extra_width = is_maximized ?
      (kFrameBorderThickness - kFrameShadowThickness) : 0;
  gfx::Size close_button_size = close_button_->GetPreferredSize();
  close_button_->SetBounds(width() - FrameBorderThickness(false) -
      right_extra_width - close_button_size.width(), caption_y,
      close_button_size.width() + right_extra_width,
      close_button_size.height());

  // When the window is restored, we show a maximized button; otherwise, we show
  // a restore button.
  bool is_restored = !is_maximized && !frame()->IsMinimized();
  views::ImageButton* invisible_button = is_restored ?
      restore_button_ : maximize_button_;
  invisible_button->SetVisible(false);

  views::ImageButton* visible_button = is_restored ?
      maximize_button_ : restore_button_;
  visible_button->SetVisible(true);
  visible_button->SetImageAlignment(views::ImageButton::ALIGN_LEFT,
                                    views::ImageButton::ALIGN_BOTTOM);
  gfx::Size visible_button_size = visible_button->GetPreferredSize();
  visible_button->SetBounds(close_button_->x() - visible_button_size.width(),
                            caption_y, visible_button_size.width(),
                            visible_button_size.height());

  minimize_button_->SetVisible(true);
  minimize_button_->SetImageAlignment(views::ImageButton::ALIGN_LEFT,
                                      views::ImageButton::ALIGN_BOTTOM);
  gfx::Size minimize_button_size = minimize_button_->GetPreferredSize();
  minimize_button_->SetBounds(
      visible_button->x() - minimize_button_size.width(), caption_y,
      minimize_button_size.width(),
      minimize_button_size.height());
}

void OpaqueBrowserFrameView::LayoutTitleBar() {
  const views::WidgetDelegate* delegate = frame()->widget_delegate();
  if (delegate) {
    gfx::Rect icon_bounds(IconBounds());
    if (delegate->ShouldShowWindowIcon())
      window_icon_->SetBoundsRect(icon_bounds);

    window_title_->SetVisible(delegate->ShouldShowWindowTitle());
    if (delegate->ShouldShowWindowTitle()) {
      window_title_->SetText(delegate->GetWindowTitle());
      const int title_x = delegate->ShouldShowWindowIcon() ?
          icon_bounds.right() + kIconTitleSpacing : icon_bounds.x();
      window_title_->SetBounds(title_x, icon_bounds.y(),
          std::max(0, minimize_button_->x() - kTitleLogoSpacing - title_x),
          icon_bounds.height());
    }
  }
}

void OpaqueBrowserFrameView::LayoutAvatar() {
  // Even though the avatar is used for both incognito and profiles we always
  // use the incognito icon to layout the avatar button. The profile icon
  // can be customized so we can't depend on its size to perform layout.
  gfx::ImageSkia incognito_icon = browser_view()->GetOTRAvatarIcon();

  int avatar_bottom = GetTabStripInsets(false).top +
      browser_view()->GetTabStripHeight() - kAvatarBottomSpacing;
  int avatar_restored_y = avatar_bottom - incognito_icon.height();
  int avatar_y = frame()->IsMaximized() ?
      (NonClientTopBorderHeight(false) + kTabstripTopShadowThickness) :
      avatar_restored_y;
  avatar_bounds_.SetRect(NonClientBorderThickness() + kAvatarLeftSpacing,
      avatar_y, incognito_icon.width(),
      browser_view()->ShouldShowAvatar() ? (avatar_bottom - avatar_y) : 0);

  if (avatar_button())
    avatar_button()->SetBoundsRect(avatar_bounds_);
}

gfx::Rect OpaqueBrowserFrameView::CalculateClientAreaBounds(int width,
                                                            int height) const {
  int top_height = NonClientTopBorderHeight(false);
  int border_thickness = NonClientBorderThickness();
  return gfx::Rect(border_thickness, top_height,
                   std::max(0, width - (2 * border_thickness)),
                   std::max(0, height - GetReservedHeight() -
                       top_height - border_thickness));
}


text:
using Discord;
using Discord.Commands;
using NadekoBot.Attributes;
using NadekoBot.Extensions;
using System;
using System.Threading.Tasks;
using System.Collections.Concurrent;
using System.Linq;
using Discord.WebSocket;

namespace NadekoBot.Modules.Searches
{
    public partial class Searches
    {
        public struct UserChannelPair
        {
            public ulong UserId { get; set; }
            public ulong ChannelId { get; set; }
        }

        [Group]
        public class TranslateCommands : ModuleBase
        {
            private static ConcurrentDictionary<ulong, bool> TranslatedChannels { get; } = new ConcurrentDictionary<ulong, bool>();
            private static ConcurrentDictionary<UserChannelPair, string> UserLanguages { get; } = new ConcurrentDictionary<UserChannelPair, string>();

            static TranslateCommands()
            {
                NadekoBot.Client.MessageReceived += async (msg) =>
                {
                    try
                    {
                        var umsg = msg as SocketUserMessage;
                        if (umsg == null)
                            return;

                        bool autoDelete;
                        if (!TranslatedChannels.TryGetValue(umsg.Channel.Id, out autoDelete))
                            return;
                        var key = new UserChannelPair()
                        {
                            UserId = umsg.Author.Id,
                            ChannelId = umsg.Channel.Id,
                        };

                        string langs;
                        if (!UserLanguages.TryGetValue(key, out langs))
                            return;

                        var text = await TranslateInternal(langs, umsg.Resolve(TagHandling.Ignore), true)
                                            .ConfigureAwait(false);
                        if (autoDelete)
                            try { await umsg.DeleteAsync().ConfigureAwait(false); } catch { }
                        await umsg.Channel.SendConfirmAsync($"{umsg.Author.Mention} `:` " + text.Replace("<@ ", "<@").Replace("<@! ", "<@!")).ConfigureAwait(false);
                    }
                    catch { }
                };
            }

            [NadekoCommand, Usage, Description, Aliases]
            public async Task Translate(string langs, [Remainder] string text = null)
            {
                try
                {
                    await Context.Channel.TriggerTypingAsync().ConfigureAwait(false);
                    var translation = await TranslateInternal(langs, text);
                    await Context.Channel.SendConfirmAsync("Translation " + langs, translation).ConfigureAwait(false);
                }
                catch
                {
                    await Context.Channel.SendErrorAsync("Bad input format, or something went wrong...").ConfigureAwait(false);
                }
            }

            private static async Task<string> TranslateInternal(string langs, [Remainder] string text = null, bool silent = false)
            {
                var langarr = langs.ToLowerInvariant().Split('>');
                if (langarr.Length != 2)
                    throw new ArgumentException();
                string from = langarr[0];
                string to = langarr[1];
                text = text?.Trim();
                if (string.IsNullOrWhiteSpace(text))
                    throw new ArgumentException();
                return (await GoogleTranslator.Instance.Translate(text, from, to).ConfigureAwait(false)).SanitizeMentions();
            }

            public enum AutoDeleteAutoTranslate
            {
                Del,
                Nodel
            }

            [NadekoCommand, Usage, Description, Aliases]
            [RequireContext(ContextType.Guild)]
            [RequireUserPermission(GuildPermission.Administrator)]
            [OwnerOnly]
            public async Task AutoTranslate(AutoDeleteAutoTranslate autoDelete = AutoDeleteAutoTranslate.Nodel)
            {
                var channel = (ITextChannel)Context.Channel;

                if (autoDelete == AutoDeleteAutoTranslate.Del)
                {
                    TranslatedChannels.AddOrUpdate(channel.Id, true, (key, val) => true);
                    try { await channel.SendConfirmAsync("Started automatic translation of messages on this channel. User messages will be auto-deleted.").ConfigureAwait(false); } catch { }
                    return;
                }

                bool throwaway;
                if (TranslatedChannels.TryRemove(channel.Id, out throwaway))
                {
                    try { await channel.SendConfirmAsync("Stopped automatic translation of messages on this channel.").ConfigureAwait(false); } catch { }
                    return;
                }
                else if (TranslatedChannels.TryAdd(channel.Id, autoDelete == AutoDeleteAutoTranslate.Del))
                {
                    try { await channel.SendConfirmAsync("Started automatic translation of messages on this channel.").ConfigureAwait(false); } catch { }
                }
            }

            [NadekoCommand, Usage, Description, Aliases]
            [RequireContext(ContextType.Guild)]
            public async Task AutoTransLang([Remainder] string langs = null)
            {
                var ucp = new UserChannelPair
                {
                    UserId = Context.User.Id,
                    ChannelId = Context.Channel.Id,
                };

                if (string.IsNullOrWhiteSpace(langs))
                {
                    if (UserLanguages.TryRemove(ucp, out langs))
                        await Context.Channel.SendConfirmAsync($"{Context.User.Mention}'s auto-translate language has been removed.").ConfigureAwait(false);
                    return;
                }

                var langarr = langs.ToLowerInvariant().Split('>');
                if (langarr.Length != 2)
                    return;
                var from = langarr[0];
                var to = langarr[1];

                if (!GoogleTranslator.Instance.Languages.Contains(from) || !GoogleTranslator.Instance.Languages.Contains(to))
                {
                    try { await Context.Channel.SendErrorAsync("Invalid source and/or target language.").ConfigureAwait(false); } catch { }
                    return;
                }

                UserLanguages.AddOrUpdate(ucp, langs, (key, val) => langs);

                await Context.Channel.SendConfirmAsync($"Your auto-translate language has been set to {from}>{to}").ConfigureAwait(false);
            }

            [NadekoCommand, Usage, Description, Aliases]
            [RequireContext(ContextType.Guild)]
            public async Task Translangs()
            {
                await Context.Channel.SendTableAsync(GoogleTranslator.Instance.Languages, str => $"{str,-15}", columns: 3);
            }

        }
    }
}

redpajama_set_name: RedPajamaGithub


text:
CKEDITOR.plugins.setLang( 'image', 'ca', {
	alertUrl: 'Si us plau, escriviu la URL de la imatge',
	alt: 'Text alternatiu',
	border: 'Vora',
	btnUpload: 'Envia-la al servidor',
	button2Img: 'Voleu transformar el botó d\'imatge seleccionat en una simple imatge?',
	hSpace: 'Espaiat horit.',
	img2Button: 'Voleu transformar la imatge seleccionada en un botó d\'imatge?',
	infoTab: 'Informació de la imatge',
	linkTab: 'Enllaç',
	lockRatio: 'Bloqueja les proporcions',
	menu: 'Propietats de la imatge',
	resetSize: 'Restaura la mida',
	title: 'Propietats de la imatge',
	titleButton: 'Propietats del botó d\'imatge',
	upload: 'Puja',
	urlMissing: 'Falta la URL de la imatge.',
	vSpace: 'Espaiat vert.',
	validateBorder: 'La vora ha de ser un nombre enter.',
	validateHSpace: 'HSpace ha de ser un nombre enter.',
	validateVSpace: 'VSpace ha de ser un nombre enter.'
});


text:
module Feldspar.Run.Concurrent
  ( ThreadId
  , Chan, Closeable, Uncloseable
  , Transferable (..), BulkTransferable (..)
  , fork
  , forkWithId
  , asyncKillThread
  , killThread
  , waitThread
  , delayThread
  , closeChan
  , lastChanReadOK
  ) where

import Prelude hiding ((&&))
import Data.Proxy
import Data.TypedStruct

import qualified Language.Embedded.Concurrent as Imp
import Language.Embedded.Concurrent (ThreadId, Chan, Closeable, Uncloseable)

import Feldspar
import Feldspar.Representation
import Feldspar.Run.Representation

-- | Fork off a computation as a new thread.
fork :: Run () -> Run ThreadId
fork = Run . Imp.fork . unRun

-- | Fork off a computation as a new thread, with access to its own thread ID.
forkWithId :: (ThreadId -> Run ()) -> Run ThreadId
forkWithId f = Run $ Imp.forkWithId (unRun . f)

-- | Forcibly terminate a thread, then continue execution immediately.
asyncKillThread :: ThreadId -> Run ()
asyncKillThread = Run . Imp.asyncKillThread

-- | Forcibly terminate a thread. Blocks until the thread is actually dead.
killThread :: ThreadId -> Run ()
killThread = Run . Imp.killThread

-- | Wait for a thread to terminate.
waitThread :: ThreadId -> Run ()
waitThread = Run . Imp.waitThread

-- | Sleep for a given amount of microseconds. Implemented with `usleep`.
--   A C compiler might require a feature test macro to be defined,
--   otherwise it emits a warning about an implicitly declared function.
--   For more details, see: http://man7.org/linux/man-pages/man3/usleep.3.html
delayThread :: Integral i => Data i -> Run ()
delayThread = Run . Imp.delayThread

--------------------------------------------------------------------------------
-- * 'Transferable' classes
--------------------------------------------------------------------------------

class Transferable a
  where
    -- | Size specification of a channel. In most of the cases, it is a natural
    --   number representing how many elements could be stored at the same time
    --   in the channel.
    type SizeSpec a :: *

    -- | Maps a size specification to an internal channel size representation,
    --   that is a map from primitive types to quantities. The byte size of the
    --   channel will be calculated as the sum of multiplying the byte size of
    --   each type with its quantity.
    calcChanSize :: proxy a -> SizeSpec a -> Imp.ChanSize Data PrimType' Length

    -- | Create a new channel. Writing a reference type to a channel will copy
    --   contents into the channel, so modifying it post-write is completely
    --   safe.
    newChan :: SizeSpec a -> Run (Chan Uncloseable a)
    newChan = Run . Imp.newChan' . calcChanSize (Proxy :: Proxy a)

    newCloseableChan :: SizeSpec a -> Run (Chan Closeable a)
    newCloseableChan = Run . Imp.newCloseableChan' . calcChanSize (Proxy :: Proxy a)

    -- | Read an element from a channel. If channel is empty, blocks until there
    --   is an item available.
    --   If 'closeChan' has been called on the channel *and* if the channel is
    --   empty, @readChan@ returns an undefined value immediately.
    readChan :: Chan t a -> Run a
    readChan = untypedReadChan

    -- | Reads a value from any kind of channel. Instances should define this,
    --   but the user should never call it.
    untypedReadChan :: Chan t c -> Run a

    -- | Write a data element to a channel.
    --   If 'closeChan' has been called on the channel, all calls to @writeChan@
    --   become non-blocking no-ops and return @False@, otherwise returns @True@.
    --   If the channel is full, this function blocks until there's space in the
    --   queue.
    writeChan :: Chan t a -> a -> Run (Data Bool)
    writeChan = untypedWriteChan

    -- | Writes a value to any kind of channel. Instances should define this,
    --   but the user should never call it.
    untypedWriteChan :: Chan t c -> a -> Run (Data Bool)

class Transferable a => BulkTransferable a
  where
    type ContainerType a :: *

    -- | Read an arbitrary number of elements from a channel into an array.
    --   The semantics are the same as for 'readChan', where "channel is empty"
    --   is defined as "channel contains less data than requested".
    --   Returns @False@ without reading any data if the channel is closed.
    readChanBuf :: Chan t a
                -> Data Index -- ^ Offset in array to start writing
                -> Data Index -- ^ Elements to read
                -> (ContainerType a)
                -> Run (Data Bool)
    readChanBuf = untypedReadChanBuf (Proxy :: Proxy a)

    -- | Read an arbitrary number of elements from any channel into an array.
    --   Instances should define this, but the user should never call it.
    untypedReadChanBuf :: proxy a
                       -> Chan t c
                       -> Data Index -- ^ Offset in array to start writing
                       -> Data Index -- ^ Elements to read
                       -> (ContainerType a)
                       -> Run (Data Bool)

    -- | Write an arbitrary number of elements from an array into an channel.
    --   The semantics are the same as for 'writeChan', where "channel is full"
    --   is defined as "channel has insufficient free space to store all written
    --   data".
    writeChanBuf :: Chan t a
                 -> Data Index -- ^ Offset in array to start reading
                 -> Data Index -- ^ Elements to write
                 -> (ContainerType a)
                 -> Run (Data Bool)
    writeChanBuf = untypedWriteChanBuf (Proxy :: Proxy a)

    -- | Write an arbitrary number of elements from an array into any channel.
    --   Instances should define this, but the user should never call it.
    untypedWriteChanBuf :: proxy a
                        -> Chan t c
                        -> Data Index -- ^ Offset in array to start reading
                        -> Data Index -- ^ Elements to write
                        -> (ContainerType a)
                        -> Run (Data Bool)

-- | When 'readChan' was last called on the given channel, did the read
--   succeed?
--   Always returns @True@ unless 'closeChan' has been called on the channel.
--   Always returns @True@ if the channel has never been read.
lastChanReadOK :: Chan Closeable a -> Run (Data Bool)
lastChanReadOK = Run . Imp.lastChanReadOK

-- | Close a channel. All subsequent write operations will be no-ops.
--   After the channel is drained, all subsequent read operations will be
--   no-ops as well.
closeChan :: Chan Closeable a -> Run ()
closeChan = Run . Imp.closeChan

--------------------------------------------------------------------------------
-- * 'Transferable' instances
--------------------------------------------------------------------------------

instance PrimType' a => Transferable (Data a)
  where
    type SizeSpec (Data a) = Data Length
    calcChanSize _ sz = sz `Imp.timesSizeOf` (Proxy :: Proxy a)
    untypedReadChan    = Run . Imp.readChan'
    untypedWriteChan c = Run . Imp.writeChan' c

instance PrimType' a => BulkTransferable (Data a)
  where
    type ContainerType (Data a) = DArr a
    untypedReadChanBuf  _ c off len arr = do
      r <- sequence $ listStruct (Run . Imp.readChanBuf' c off len) (unArr arr)
      return $ foldl1 (&&) r
    untypedWriteChanBuf _ c off len arr = do
      r <- sequence $ listStruct (Run . Imp.writeChanBuf' c off len) (unArr arr)
      return $ foldl1 (&&) r

instance ( Transferable a, Transferable b
         , SizeSpec a ~ SizeSpec b
         ) => Transferable (a, b)
  where
    type SizeSpec (a, b) = SizeSpec a
    calcChanSize _ sz =
      let asz = calcChanSize (Proxy :: Proxy a) sz
          bsz = calcChanSize (Proxy :: Proxy b) sz
      in  asz `Imp.plusSize` bsz
    untypedReadChan ch = (,) <$> untypedReadChan ch <*> untypedReadChan ch
    untypedWriteChan ch (a, b) = do
      sa <- untypedWriteChan ch a
      ifE sa (untypedWriteChan ch b) (return false)

instance ( Transferable a, Transferable b, Transferable c
         , SizeSpec a ~ SizeSpec b, SizeSpec b ~ SizeSpec c
         ) => Transferable (a, b, c)
  where
    type SizeSpec (a, b, c) = SizeSpec a
    calcChanSize _ sz =
      let asz = calcChanSize (Proxy :: Proxy a) sz
          bsz = calcChanSize (Proxy :: Proxy b) sz
          csz = calcChanSize (Proxy :: Proxy c) sz
      in  asz `Imp.plusSize` bsz `Imp.plusSize` csz
    untypedReadChan ch = (,,)
                     <$> untypedReadChan ch
                     <*> untypedReadChan ch
                     <*> untypedReadChan ch
    untypedWriteChan ch (a, b, c) = do
      sa <- untypedWriteChan ch a
      ifE sa
        (do sb <- untypedWriteChan ch b
            ifE sb (untypedWriteChan ch c) (return false))
        (return false)

instance ( Transferable a, Transferable b, Transferable c, Transferable d
         , SizeSpec a ~ SizeSpec b, SizeSpec b ~ SizeSpec c, SizeSpec c ~ SizeSpec d
         ) => Transferable (a, b, c, d)
  where
    type SizeSpec (a, b, c, d) = SizeSpec a
    calcChanSize _ sz =
      let asz = calcChanSize (Proxy :: Proxy a) sz
          bsz = calcChanSize (Proxy :: Proxy b) sz
          csz = calcChanSize (Proxy :: Proxy c) sz
          dsz = calcChanSize (Proxy :: Proxy d) sz
      in  asz `Imp.plusSize` bsz `Imp.plusSize` csz `Imp.plusSize` dsz
    untypedReadChan ch = (,,,)
                     <$> untypedReadChan ch
                     <*> untypedReadChan ch
                     <*> untypedReadChan ch
                     <*> untypedReadChan ch
    untypedWriteChan ch (a, b, c, d) = do
      sa <- untypedWriteChan ch a
      ifE sa
        (do sb <- untypedWriteChan ch b
            ifE sb
              (do sc <- untypedWriteChan ch c
                  ifE sc
                    (untypedWriteChan ch d)
                    (return false))
              (return false))
        (return false)


text:
package fig.basic;

import java.io.*;
import java.lang.reflect.Method;
import java.util.*;

/**
 * The logging output has a tree structure, where each node is a
 * line of output, and the depth of a node is its indent level.
 * A run is the sequence of children of some node.
 * A subset of the lines in the run will get printed.
 */
public class LogInfo {
  public static void track(String format, Object... args) {
    track(String.format(format, args), false);
  }
  public static void track(Object o) {
    track(o, false);
  }

  public synchronized static void track_methods(Object o, String[] methodNames) throws Exception {
	  for (String methodName: methodNames) {
		  track_method(o, methodName);
	  }
  }
  /**
   * Invokes a method and wraps it's invocation in a track. The method must be public and
   * not take any arguments.
   * @param o	Object to call method on
   * @param methodName name of method to invoke
   * @throws Exception
   */
  public synchronized static void track_method(Object o, String methodName, Object...args) throws Exception {
	  Class<? extends Object> c = o.getClass();
      Method[] methods = c.getDeclaredMethods();
      Method targetMethod = null;
      for (Method m: methods) {
      	if (m.getName().equals(methodName)) {
      		targetMethod = m; break;
      	}
      }
      if (targetMethod == null) {
      	String msg = String.format("Couldn't find method %d in class %s",methodName,c.getName());
      	throw new IllegalArgumentException(msg);
      }
		LogInfo.track(methodName);
		targetMethod.invoke(o, args);
		LogInfo.end_track();
  }
  public synchronized static void track_method(Object o, String methodName) throws Exception {
	  track_method(o, methodName, new Object[0]);
  }

  public synchronized static void track(Object o, boolean printAllLines) {
    track(o, printAllLines, false);
  }
  public synchronized static void track(Object o,
      boolean printAllChildLines, boolean printIfParentPrinted) {
    if(indWithin()) {
      if(printIfParentPrinted && parentPrinted()) thisRun().forcePrint();
      if(thisRun().shouldPrint()) {
        print(o);
        buf.append(" {\n"); // Open the block.

        childRun().init();
        childRun().printAllLines = printAllChildLines;
      }
      else {
        stoppedIndLevel = indLevel;
        maxIndLevel = -maxIndLevel; // Prevent children from outputting.
      }
    }

    indLevel++;
  }

  // Convenient way to end and return a value
  public static <T> T end_track(T x) { end_track(); return x; }

  public synchronized static void end_track() {
    indLevel--;

    if(stoppedIndLevel == indLevel) {
      stoppedIndLevel = -1;
      maxIndLevel = -maxIndLevel; // Restore indent level.
    }

    if(indWithin()) {
      if(thisRun().newLine()) { // Note that we pay for the line only at the end
        // Finish up child level.
        indLevel++;
        int n = thisRun().numOmitted();
        if(n > 0)
          print("... " + n + " lines omitted ...\n");
        indLevel--;
        childRun().finish();

        if(buf.length() > 0) // Nothing was printed, because buf hasn't been emptied.
          buf.delete(0, buf.length()); // Just pretend we didn't open the block.
        else // Something indented was printed.
          print("}"); // Close the block.

        // Print time
        StopWatch ct = childRun().watch;
        if(ct.ms > 1000) {
          rawPrint(" [" + ct);
          if(indLevel > 0) {
            StopWatch tt = thisRun().watch;
            tt.stop();
            rawPrint(", cum. " + tt);
          }
          rawPrint("]");
        }
        rawPrint("\n");
      }
    }
  }

  // Normal printing
  public static void logs(String format, Object... args) {
    logs(String.format(format, args));
  }
  public synchronized static void logs(Object o) {
    if(forcePrint || (indWithin() && thisRun().newLine()))
      printLines(o);
  }

  // Always print
  public synchronized static void logsForce(String format, Object...args) {
    printLines(String.format(format, args));
  }
  public synchronized static void logsForce(Object o) {
    thisRun().newLine();
    printLines(o);
  }

  // Print if parent printed
  public static void logss(String format, Object... args) {
    logss(String.format(format, args));
  }
  public synchronized static void logss(Object o) {
    if(parentPrinted()) thisRun().forcePrint();
    logs(o);
  }
  private static boolean parentPrinted() {
    // Parent must have been a track, so its run information has not been
    // updated yet.  Therefore, shouldPrint() is valid.
    return indLevel == 0 ||
      (indLevel <= maxIndLevel && parentIndWithin() && parentRun().shouldPrint());
  }

  // Log different types of information
  public static void dbgs(String format, Object... args) {
    dbg(String.format(format, args));
  }
  public static void dbg(Object o) {
    logss("DBG: " + o);
  }
  public static void rants(String format, Object... args) {
    rant(String.format(format, args));
  }
  public static void rant(Object o) {
    logss("RANT: " + o);
  }
  public static void errors(String format, Object... args) {
    error(String.format(format, args));
  }
  public static void error(Object o) {
    if(numErrors < maxPrintErrors)
      print("ERROR: " + o + "\n");
    numErrors++;
  }
  public static void warnings(String format, Object... args) {
    warning(String.format(format, args));
  }
  public static void warning(Object o) {
    print("WARNING: " + o + "\n");
    numWarnings++;
  }

  public static void fails(String format, Object... args) {
    fail(String.format(format, args));
  }
  public static void fail(Object o) {
    throw Exceptions.bad(o);
  }

  // Print random things
  public static void printProgStatus() {
    logs("PROG_STATUS: time = " + watch.stop() + ", memory = " + SysInfoUtils.getUsedMemoryStr());
  }
  public static <T> void printList(String s, String lines) {
    printList(s, Arrays.asList(lines.split("\n")));
  }
  public static <T> void printList(String s, List<T> items) {
    track(s, true);
    for(T x : items) logs(x);
    end_track();
  }

  ////////////////////////////////////////////////////////////

  // Options
  @Option(gloss="Maximum indent level.")
    public static int maxIndLevel = 10;
  @Option(gloss="Maximum number of milliseconds between consecutive lines of output.")
    public static int msPerLine = 1000;
  @Option(gloss="File to write log.")
    public static String file = "";
  @Option(gloss="Whether to output to the console.", name="stdout")
    public static boolean writeToStdout = true;
  @Option(gloss="Dummy placeholder for a comment")
    static public String note = "";
  @Option(gloss="Force printing from logs*")
  	static public boolean forcePrint;
  @Option(gloss="Maximum number of errors (via error()) to print")
  	static public int maxPrintErrors = 10000;

  static { updateStdStreams(); }
  public static void updateStdStreams() {
    try {
      stdin  = CharEncUtils.getReader(System.in);
      stdout = CharEncUtils.getWriter(System.out);
      stderr = CharEncUtils.getWriter(System.err);
    } catch(IOException e) {
      throw new RuntimeException(e);
    }
  }

  public static void init() {
    // Write to file, stdout?
    if(!file.equals("")) {
      fout = IOUtils.openOutHard(file);
    }
    if(writeToStdout) out = stdout;
  }

  private static LogRun parentRun() { return runs.get(indLevel-1); }
  private static LogRun thisRun()   { return runs.get(indLevel); }
  private static LogRun childRun()  { return runs.get(indLevel+1); }

  // If we were to print a new line, should we print?
  private static boolean indWithin()       { return indLevel   <= maxIndLevel; }
  private static boolean parentIndWithin() { return indLevel-1 <= maxIndLevel; }

  // Internal: don't use these functions directly

  private static void rawPrint(Object o) {
    if(out != null) { out.print(o); out.flush(); }
    if(fout != null) { fout.print(o); fout.flush(); }
  }

  // Print with indent; flush the buffer as necessary
  private static void print(Object o) {
    rawPrint(buf);
    buf.delete(0, buf.length());
    for(int i = 0; i < indLevel; i++) rawPrint("  ");
    rawPrint(o);
  }
  // If there are new lines, put indents before them
  private static void printLines(Object o) {
    if(o == null) o = "null";
    String s = StrUtils.toString(o);
    if(s.indexOf('\n') == -1)
      print(s+"\n");
    else
      for(String t : StrUtils.split(s, "\n")) print(t+"\n");
  }

  public static StopWatch getWatch() { return watch; }
  public static int getNumErrors() { return numErrors; }
  public static int getNumWarnings() { return numWarnings; }

  public static BufferedReader stdin;
  public static PrintWriter stdout, stderr;

  // Private state.
  static PrintWriter out, fout;
  static int indLevel;           // Current indent level.
  static int stoppedIndLevel;    // At what level did we stop printing
  static StringBuilder buf;      // The buffer to be flushed out the next time _logs is called.
  static ArrayList<LogRun> runs; // Indent level -> state
  static StopWatch watch;        // StopWatch that starts at the beginning of the program
  static int numErrors;          // Number of errors made
  static int numWarnings;        // Number of warnings

  // Default setup
  static {
    buf = new StringBuilder();
    indLevel = 0;
    stoppedIndLevel = -1;

    runs = new ArrayList<LogRun>(128);
    for(int i = 0; i < 128; i++)
      runs.add(new LogRun());
    watch = new StopWatch();
    watch.start();

    out = stdout;
  }
}

/**
 * A run is a sequence of lines of text, some of which are printed.
 * Stores the state associated with a run.
 */
class LogRun {
  public LogRun() {
    watch = new StopWatch();
    init();
  }
  void init() {
    numLines = 0;
    numLinesPrinted = 0;
    nextLineToPrint = 0;
    printAllLines = false;
    watch.start();
  }
  void finish() {
    // Make it clear that this run is not printed.
    // Otherwise, logss might think its
    // parent was printed when it really wasn't.
    nextLineToPrint = -1;
    watch.stop();
  }

  void forcePrint() { forcePrint = true; }
  boolean shouldPrint() { return forcePrint || nextLineToPrint == numLines; }
  int numOmitted() { return numLines - numLinesPrinted; }

  /**
   * Decide whether to print the next line.  If yes,
   * then you must print it.
   * @return Whether the next line should be printed.
   */
  boolean newLine() {
    boolean p = shouldPrint();
    numLines++;
    if(!p) return false; // Assume forcePrint == false

    // Ok, we're going to print this line.
    numLinesPrinted++;

    // Decide next line to print.
    int msPerLine = LogInfo.msPerLine;
    if(numLines <= 2  || // Print first few lines anyway.
       msPerLine == 0 || // Print everything.
       printAllLines  || // Print every line in this run (by fiat).
       forcePrint)       // Force-printed things shouldn't affect timing.
      nextLineToPrint++;
    else {
      watch.stop();
      if(watch.ms == 0) { // No time has elapsed.
        // This usually applies in the beginning of a run when we have
        // no idea how long things are going to take
        nextLineToPrint *= 2; // Exponentially increase time between lines.
      }
      else // Try to maintain the number of lines per second.
        nextLineToPrint += (int)Math.max((double)numLines * msPerLine / watch.ms, 1);
    }
    forcePrint = false;

    return true;
  }

  int numLines;           // Number of lines that we've gone through so far in this run.
  int numLinesPrinted;    // Number of lines actually printed.
  int nextLineToPrint;    // Next line to be printed (lines are 0-based).
  StopWatch watch;        // Keeps track of time spent on this run.
  boolean printAllLines;  // Whether or not to force the printing of each line.
  boolean forcePrint;     // Whether to print out the next item (is reset afterwards).
}


text:
package org.jclouds.cloudstack.predicates;

import static com.google.common.base.Preconditions.checkNotNull;

import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Singleton;

import org.jclouds.cloudstack.CloudStackApi;
import org.jclouds.cloudstack.domain.LoadBalancerRule;
import org.jclouds.cloudstack.domain.LoadBalancerRule.State;
import org.jclouds.logging.Logger;

import com.google.common.base.Predicate;

/**
 *
 * Tests to see if a LoadBalancerRule is active
 */
@Singleton
public class LoadBalancerRuleActive implements Predicate<LoadBalancerRule> {

   private final CloudStackApi client;

   @Resource
   protected Logger logger = Logger.NULL;

   @Inject
   public LoadBalancerRuleActive(CloudStackApi client) {
      this.client = client;
   }

   public boolean apply(LoadBalancerRule rule) {
      logger.trace("looking for state on rule %s", checkNotNull(rule, "rule"));
      rule = refresh(rule);
      if (rule == null)
         return false;
      logger.trace("%s: looking for rule state %s: currently: %s", rule.getId(), State.ACTIVE, rule.getState());
      return rule.getState() == State.ACTIVE;
   }

   private LoadBalancerRule refresh(LoadBalancerRule rule) {
      return client.getLoadBalancerApi().getLoadBalancerRule(rule.getId());
   }
}


text:
require 'rails_helper'

describe User do
  let(:user) {User.create(username: "Jack", email: "boop@bop.com", password: "1234")}

  it "🍌🍌🍌🍌🍌" do
    expect(true).to be(true)
  end

  it "is not null" do
    expect(user).to_not eq(nil)
  end

  it "can have many articles" do
    user.articles << Article.create(title: "test1", content: "Testing")
    user.articles << Article.create(title: "test1", content: "Testing")
    expect(user.articles.length).to eq(2)
  end

  it "can have many revisions" do
    user.revisions << Revision.create()
    user.revisions << Revision.create()
    expect(user.revisions.length).to eq(2)
  end

  it "can make revisions on others articles" do
    User.create(username: "Bob", email: "bob@bob")
    Article.create(title: "test1", content: "Testing", creator_id: 2)
    user.revisions << Revision.create(article_id: 1)
    expect(user.revisions.length).to eq(1)
  end

end

describe Article do
  let(:user) {User.create(username: "Jack", email: "boop@bop.com", password: "1234")}
  let(:article) {Article.create(title: "Test", content: "Potato Yarn Batman")}

  it "has many revisions" do
    article.revisions << Revision.create()
    article.revisions << Revision.create()
    expect(article.revisions.length).to eq(2)
  end

  it "can reference its revisors" do
    user.revisions << Revision.create(article: article)
    expect(article.revisors.first).to eq(user)
  end

  it "can search for articles that contain a word in title or content" do
    Article.create(title: "Test2", content: "Batman is cool")
    Article.create(title: "Test2", content: "fuck yeah Batman is cool")
    expect(Article.search("Batman").length).to eq(2)
  end

end

describe Revision do

end


text:
<%if $interactiveType != ""%>

<%/if%>

<%**%>

<%**%>

<%**%>

<%**%>

<%**%>

<%**%>

<%**%>

<%**%>
<%if $storyImage != ""%>
<meta property="thumbnail" content="<%$storyImage%>" />
<meta property="og:title" content="<%$pageHeadline%>" />
<meta property="og:url" content="/<%$itemType%>/<%$id|default:$story.id%>" />
<meta property="og:description" content="<%$shareLead%>" />
<meta property="og:image" content="<%$storyImage%>" />
<meta property="og:type" content="article" />
<meta property="og:site_name" content="FT中文网" />
<meta property="twitter:card" content="summary_large_image" />
<meta property="twitter:site" content="@FT中文网" />
<meta property="twitter:title" content="<%$pageHeadline%>" />
<meta property="twitter:description" content="<%$shareLead%>" />
<meta property="twitter:image" content="<%$storyImage%>" />
<%else%>
<meta property="thumbnail" content="https://d2785ji6wtdqx8.cloudfront.net/img/friend-share-icon.jpg" />
<%/if%>
<%**%>

<%if $debug_model == 1%>

<%/if%>

<%include file="next/partials/head-db.html"%>


text:
package common

import (
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/asn1"
	"encoding/pem"
	"fmt"
	"hash"
	"io/ioutil"
	mrand "math/rand"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"

	"github.com/rolandshoemaker/stapled/log"
)

func HumanDuration(d time.Duration) string {
	maybePluralize := func(input string, num int) string {
		if num == 1 {
			return input
		}
		return input + "s"
	}
	nanos := time.Duration(d.Nanoseconds())
	if nanos == 0 {
		return "instantly"
	}
	days := int(nanos / (time.Hour * 24))
	nanos %= time.Hour * 24
	hours := int(nanos / (time.Hour))
	nanos %= time.Hour
	minutes := int(nanos / time.Minute)
	nanos %= time.Minute
	seconds := int(nanos / time.Second)
	s := ""
	if days > 0 {
		s += fmt.Sprintf("%d %s ", days, maybePluralize("day", days))
	}
	if hours > 0 {
		s += fmt.Sprintf("%d %s ", hours, maybePluralize("hour", hours))
	}
	if minutes > 0 {
		s += fmt.Sprintf("%d %s ", minutes, maybePluralize("minute", minutes))
	}
	if seconds > 0 {
		s += fmt.Sprintf("%d %s ", seconds, maybePluralize("second", seconds))
	}
	return strings.TrimRight(s, " ")
}

type Failer interface {
	Fail(*log.Logger, string)
}

type BasicFailer struct{}

func (bf *BasicFailer) Fail(logger *log.Logger, msg string) {
	logger.Err(msg)
	fmt.Fprintln(os.Stderr, msg)
	os.Exit(1)
}

func randomURL(urls []*url.URL) *url.URL {
	return urls[mrand.Intn(len(urls))]
}

func ProxyFunc(proxies []string) (func(*http.Request) (*url.URL, error), error) {
	proxyURLs := []*url.URL{}
	for _, p := range proxies {
		u, err := url.Parse(p)
		if err != nil {
			return nil, err
		}
		proxyURLs = append(proxyURLs, u)
	}
	return func(*http.Request) (*url.URL, error) {
		return randomURL(proxyURLs), nil
	}, nil
}

// ParseCertificate parses a certificate from either it's PEM
// or DER form
func ParseCertificate(contents []byte) (*x509.Certificate, error) {
	certBytes := []byte{}
	block, _ := pem.Decode(contents)
	if block == nil {
		certBytes = contents
	} else {
		if block.Type != "CERTIFICATE" {
			return nil, fmt.Errorf("Invalid PEM type '%s'", block.Type)
		}
		certBytes = block.Bytes
	}
	return x509.ParseCertificate(certBytes)
}

func ReadCertificate(filename string) (*x509.Certificate, error) {
	contents, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	return ParseCertificate(contents)
}

func HashNameAndPKI(h hash.Hash, name, pki []byte) ([]byte, []byte, error) {
	h.Write(name)
	nameHash := h.Sum(nil)
	h.Reset()
	var publicKeyInfo struct {
		Algorithm pkix.AlgorithmIdentifier
		PublicKey asn1.BitString
	}
	if _, err := asn1.Unmarshal(pki, &publicKeyInfo); err != nil {
		return nil, nil, err
	}
	h.Write(publicKeyInfo.PublicKey.RightAlign())
	pkiHash := h.Sum(nil)
	return nameHash[:], pkiHash[:], nil
}


text:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace RichoM.Data
{
    /// <summary>
    /// Specific type of <c>DatabaseCommand</c> that is responsible for executing inserts, deletes, updates,
    /// and any "non-query" command.
    /// </summary>
    /// <typeparam name="TConnection"></typeparam>
    public class DatabaseNonQuery<TConnection> : DatabaseCommand where TConnection : DbConnection, new()
    {
        private DatabaseContext<TConnection> context;

        internal DatabaseNonQuery(DatabaseContext<TConnection> context, string commandText, bool storedProcedure)
            : base(commandText, storedProcedure)
        {
            this.context = context;
        }

        /// <summary>
        /// Use this method to specify values for your command's parameters.
        /// </summary>
        /// <param name="name">Parameter name.</param>
        /// <param name="value">Parameter value.</param>
        /// <param name="type">Optional. Parameter type.</param>
        /// <returns>The current instance so you can keep chaining method calls.</returns>
        public DatabaseNonQuery<TConnection> WithParameter(string name, object value, DbType? type = null)
        {
            AddParameter(name, value, type);
            return this;
        }

        /// <summary>
        /// Executes the command and returns the number of affected rows.
        /// </summary>
        /// <returns>The number of affected rows.</returns>
        public int Execute()
        {
            return context.ExecuteNonQuery(this);
        }
    }
}


text:
package com.intellij.diff.tools.fragmented;

import com.intellij.diff.comparison.ComparisonManager;
import com.intellij.diff.comparison.ComparisonManagerImpl;
import com.intellij.diff.comparison.ComparisonPolicy;
import com.intellij.diff.fragments.LineFragment;
import com.intellij.diff.util.LineRange;
import com.intellij.diff.util.Side;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.impl.DocumentImpl;
import com.intellij.openapi.progress.DumbProgressIndicator;
import com.intellij.testFramework.UsefulTestCase;

import java.util.Collections;
import java.util.List;

public class UnifiedFragmentBuilderTest extends UsefulTestCase {
  private static ComparisonManager myComparisonManager = new ComparisonManagerImpl();

  public void testEquals() {
    Document document1 = new DocumentImpl("A\nB\nC");
    Document document2 = new DocumentImpl("A\nB\nC");

    List<LineFragment> fragments = myComparisonManager.compareLinesInner(document1.getCharsSequence(), document2.getCharsSequence(),
                                                                         ComparisonPolicy.DEFAULT, DumbProgressIndicator.INSTANCE);

    UnifiedFragmentBuilder builder = new UnifiedFragmentBuilder(fragments, document1, document2, Side.LEFT);
    builder.exec();

    assertTrue(builder.isEqual());
    assertEquals(builder.getText().toString(), "A\nB\nC\n");
    assertEmpty(builder.getChangedLines());
    assertEmpty(builder.getBlocks());
  }

  public void testWrongEndLineTypoBug() {
    Document document1 = new DocumentImpl("A\nB\nC\nD");
    Document document2 = new DocumentImpl("A\nD");

    List<LineFragment> fragments = myComparisonManager.compareLinesInner(document1.getCharsSequence(), document2.getCharsSequence(),
                                                                         ComparisonPolicy.DEFAULT, DumbProgressIndicator.INSTANCE);

    UnifiedFragmentBuilder builder = new UnifiedFragmentBuilder(fragments, document1, document2, Side.RIGHT);
    builder.exec();

    assertFalse(builder.isEqual());
    assertEquals(builder.getText().toString(), "A\nB\nC\nD\n");
    assertEquals(builder.getChangedLines(), Collections.singletonList(new LineRange(1, 3)));

    assertEquals(builder.getBlocks().size(), 1);
    ChangedBlock block = builder.getBlocks().get(0);
    assertEquals(block.getLine1(), 1);
    assertEquals(block.getLine2(), 3);
    assertEquals(block.getStartOffset1(), 2);
    assertEquals(block.getEndOffset1(), 6);
    assertEquals(block.getStartOffset2(), 6);
    assertEquals(block.getEndOffset2(), 6);
  }
}


text:
blocChat = angular
.module('blocChat',  [
  'ui.router',
  'firebase',
  'ngCookies'
  ])

.config(function ($stateProvider, $urlRouterProvider) {
  $urlRouterProvider.otherwise('/home');

  $stateProvider
  .state('home', {
    url: "/home",
    controller: 'roomsList',
    templateUrl: "templates/home.html"
  });

})

.run(['$cookies', function($cookies) {
    if (!$cookies.blocChatCurrentUser || $cookies.blocChatCurrentUser === '' ) {
      angular.element('#myModal2').modal({backdrop:'static'});
      angular.element('#myModal2').modal('show');
    }

  }]);

// RoomsList Controller

blocChat.controller('roomsList', ['$firebaseArray', '$scope', '$cookies', '$window', 'Room', 'Message', function ($firebaseArray, $scope, $cookies, $window, Room, Message) {
  $scope.rooms = Room.all;

  $scope.deleteRoom = function (room) {
      Room.remove(room);
    };

     $scope.addMessage = function (room) {
      var message = {
        text: $scope.messageText,
        time: $window.moment().format('h:mm a'),
        name: $cookies.blocChatCurrentUser
      };

      Message.add(room, message);
      $scope.messageText = '';
    };

        $scope.getMessagesForRoom = function (room) {
      $scope.currentRoom = room;
      $scope.currentRoomName = room.name;

      var currentRoomMessagesRef = new $window.Firebase($scope.rooms.$ref() + '/' + room.$id + '/messages/');
      $scope.roomMessages = $firebaseArray(currentRoomMessagesRef);
    };

  $scope.addRoom = function (newRoomName) {
      Room.add({name: newRoomName});

      $scope.newRoomName = '';
    };

  //USERS
    $scope.addUser = function (nickname) {
      console.log(nickname);
      if (nickname === null) {
        angular.element('#myModal2').modal({backdrop:'static'});
        angular.element('#myModal2').modal('show');
      }

      else {
        $cookies.blocChatCurrentUser = nickname;
        $scope.newNickname = '';
        angular.element('#myModal2').modal('hide');
      }
    };

}]);

// Firebase

 blocChat.factory( 'Room' , function($firebaseArray, $window) {

 var ref = new $window.Firebase('https://blazing-torch-5544.firebaseio.com/rooms/');
   // create an AngularFire reference to the data
   var rooms = $firebaseArray(ref);

   return {
     all: rooms,
     add: function (room) {
       this.all.$add(room);
     },
     remove: function (room) {
       this.all.$remove(room);
     }
   };

 });

 blocChat.factory( 'Message' , function($firebaseArray, $window) {
    return {
      all: function (roomId) {
       var ref = new $window.Firebase('https://blazing-torch-5544.firebaseio.com/rooms/'+roomId+'/messages/');
       return $firebaseArray(ref);
      },
      add: function (room, message) {
        this.all(room.$id).$add(message);
      },
      remove: function (room, message) {
        this.all(room.$id).$remove(message);
      }
    };

 });


text:
.sc-prose-editor {}
.sc-prose-editor .sc-container-editor {
  padding:  var(--default-padding);
}
/* Add padding to each child except last one */
.sc-prose-editor .sc-container-editor > * + * {
  padding-top:  var(--default-padding);
}
.sc-prose-editor .sc-toolbar {
  border-bottom: 1px solid  var(--border-color);
}


text:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using Sriracha.Deploy.Data.Impl;

namespace Sriracha.Deploy.Data.Tests
{
	public interface TestInterface
	{
		string Test(int input);
	}

	public class TestImplementationClass : TestInterface
	{
		public string Test(int input)
		{
 			return input.ToString();
		}
	}

	public class ModuleInspectorTests
	{
		public class FindTypesImplementingInterfaces
		{
			[Test, Explicit]
			public void CanFindTypesImplementingInterfaces()
			{
				IModuleInspector sut = new ModuleInspector();
				var result = sut.FindTypesImplementingInterfaces(typeof(TestInterface));
				Assert.IsNotNull(result);
				Assert.AreEqual(1, result.Count);
				Assert.AreEqual(typeof(TestImplementationClass), result[0]);
			}
		}
	}
}


text:
var Promise = require('bluebird');
var factory = require('./factory.js');
var _ = require('../util.js');

function Remote(address, options) {

    this.getConfig = function() {
        throw new Error('Implement this in sub class.');
    };

    // maybe already installed in /components.
    this.resolve = function() {
        if (this.location) {
            return Promise.resolve(this.location);
        }

        var self = this;

        return Promise

            // try local
            .try(function() {
                var componentsDir = factory.settings.componentsDir;
                var path = require('path');
                var exists = require('fs').existsSync;
                var filepath =  path.join(componentsDir, self.name, 'component.json');

                if (exists(filepath)) {
                    var getConfig = Promise.promisify(require('../config'));

                    return getConfig(filepath)

                        // 查看本地版本是否符合版本要求。
                        .then(function(json) {
                            var semver = require('semver');
                            var version = self._version;
                            var resolved;

                            if (!/\d+(\.\d+)*$/.test(version)) {
                                resolved = json.version;
                            } else if (semver.satisfies(json.version, version)) {
                                resolved = json.version;
                            }

                            if (resolved) {
                                self.version = resolved;
                                self.config = json;
                                return 'local';
                            } else {
                                return 'remote';
                            }
                        });

                }

                return 'remote';
            })

            .then(function(location) {
                self.location = location;
                return location;
            });
    };

    this.getDependencies = function() {
        if (this.dependencies) {
            return Promise.resolve(this.dependencies);
        }

        var self = this;

        return this

            .resolve()

            .then(this.getConfig.bind(this))

            .then(function(config) {
                return config.dependencies || [];
            })

            .then(function(components) {
                var factory = require('./factory.js');
                var logger = require('../logger.js');

                var origin = factory.getSettings();
                var config = self.config;
                var settings = {};

                config.protocol && (settings.protocol = config.protocol);
                config.github && _.mixin(settings, {github: config.github});
                config.gitlab && _.mixin(settings, {gitlab: config.github});
                config.lights && _.mixin(settings, {lights: config.github});

                factory.setSettings(settings);

                // validate and filter invalid dependencies.
                components = components
                    .map(function(component) {
                        var type = factory.detect(component);
                        if (!type) {
                            logger.warn('`%s` is not a valid dependency.', component);
                            return null;
                        }

                        return factory(component);
                    })
                    .filter(function(item) {
                        return item != null;
                    });

                var collector = require('../collector.js');
                return collector(components)

                    // 还原 factory.settings
                    .then(function(components) {
                        factory.setSettings(origin);
                        return components;
                    });
            });
    };

    this.resolveVersion = function(versions) {
        if (!this.version) {
            var version = this._version;
            var resolved;

            if (version === '*') {
                resolved = versions[0];
            } else {
                var semver = require('semver');

                versions.every(function(current) {
                    var normalized = current.replace(/^v\s*/i, '');

                    if (!/^\d+(\.\d+)*$/.test(normalized) && normalized === version) {
                        resolved = current;
                        return false;
                    } else if (/\d/.test(normalized) && semver.satisfies(normalized, version)) {
                        resolved = current;
                        return false;
                    }

                    return true;
                });
            }

            if (!resolved && ~versions.indexOf('master')) {
                resolved = 'master';
            }

            if (!resolved) {
                throw new Error('cannot find matched version of `'+this.address+'@'+version+'`');
            }

            this.version = resolved;
        }

        return Promise.resolve(this.version);
    }

    this.noramlizeConfig = function(config) {
        if (config.dependencies && !Array.isArray(config.dependencies)) {
            var dependencies = [];

            Object.keys(config.dependencies).forEach(function(key) {
                var val = config.dependencies[key];

                dependencies.push(key + '@' + val);
            });

            config.dependencies = dependencies;
        }

        if (!config.mapping) {
            var mapping = [];
            ['scripts', 'styles', 'json', 'images', 'fonts', 'files', 'templates'].forEach(function(key) {
                if (config[key] && Array.isArray(config[key])) {
                    config[key].forEach(function(file) {
                        mapping.push({
                            reg: '/' + file,
                            release: file
                        })
                    });
                }
            });

            if (mapping.length) {
                mapping.push({
                    reg: /^\/README\.md$/i,
                    release: '$&'
                });

                mapping.push({
                    reg: /^\/component\.json$/i,
                    release: '$&'
                });

                mapping.push({
                    reg: '**',
                    release: false
                });
            }

            config.mapping = mapping;
        }

        return config;
    };
}

module.exports = Remote;


text:
{{title}}

<form name='comForm' class='form-horizontal' novalidate ng-submit='save()'>

    	Firma

			<input name='name' type='text' ng-model='name' required class='form-control'></input>

		Hinweis

			<textarea name='description' type='text' ng-model='description' class='form-control' rows='3' placehoder='Hinweis eintragen' ></textarea>

		RechnungsNr

			<input name='rnumber' type='text' ng-model='rnumber' class='form-control'></input>

		Datum

			<ng-datepicker ng-model='date' view-format="DD.MM.YYYY" locale='de'></ng-datepicker>

		Woche

				<select name='activityId' class='sel-base form-control' ng-model='activityId'>
					<option ng-repeat='activity in activities' value='{{activity._id}}'>{{activity.name}}</option>
				</select>

		Typ

			<select name='type' class='sel-base form-control' ng-model='type' required>
				<option value='business'>Sachkosten</option>
				<option value='food'>Verpflegung/Essen</option>
			</select>

		Betrag

				<input type="number" text-align='right' ng-model='amount' value="0" min="0.1" step="0.01" required aria-describedby="basic-addon-euro"></input>
				€

				<input type='checkbox' name='payment' ng-model='isPaymentDone' />selbst bezahlt
				<input type='checkbox' name='payment' ng-model='isPaymentJDDone' />bezahlt mit JD Bankomat
				<input type='checkbox' name='payment' ng-model='isInvoice' />Rechnung an JD

		</div

				<input type='checkbox' ng-model='isCleared' />abgerechnet

		<input class='btn btn-success bnt-lg btn-block' type='submit' value='Speichern' ng-disabled='comForm.$invalid'>

</form>


text:
class Marathon::Base

  include Marathon::Error

  attr_reader :info

  # Create the object
  # ++hash++: object returned from API. May be Hash or Array.
  # ++attr_accessors++: List of attribute accessors.
  def initialize(hash, attr_accessors = [])
    raise ArgumentError, 'hash must be a Hash' if attr_accessors and attr_accessors.size > 0 and not hash.is_a?(Hash)
    raise ArgumentError, 'hash must be Hash or Array' unless hash.is_a?(Hash) or hash.is_a?(Array)
    raise ArgumentError, 'attr_accessors must be an Array' unless attr_accessors.is_a?(Array)
    @info = Marathon::Util.keywordize_hash!(hash)
    attr_accessors.each { |e| add_attr_accessor(e) }
  end

  # Return application as JSON formatted string.
  def to_json(opts = {})
    info.to_json(opts)
  end

  private

  # Create attr_accessor for @info[key].
  # ++key++: key in @info
  def add_attr_accessor(key)
    sym = key.to_sym
    self.class.send(:define_method, sym.id2name) { info[sym] }
    self.class.send(:define_method, "#{sym.id2name}=") { |v| info[sym] = v }
  end
end