text:
using content::DomOperationNotificationDetails;
using content::NavigationController;
using content::RenderViewHost;

namespace {

const char kTestingPage[] = "files/keyevents_test.html";
const char kSuppressEventJS[] =
    "window.domAutomationController.send(setDefaultAction('%ls', %ls));";
const char kGetResultJS[] =
    "window.domAutomationController.send(keyEventResult[%d]);";
const char kGetResultLengthJS[] =
    "window.domAutomationController.send(keyEventResult.length);";
const char kGetFocusedElementJS[] =
    "window.domAutomationController.send(focusedElement);";
const char kSetFocusedElementJS[] =
    "window.domAutomationController.send(setFocusedElement('%ls'));";
const char kGetTextBoxValueJS[] =
    "window.domAutomationController.send("
    "    document.getElementById('%ls').value);";
const char kSetTextBoxValueJS[] =
    "window.domAutomationController.send("
    "    document.getElementById('%ls').value = '%ls');";
const char kStartTestJS[] =
    "window.domAutomationController.send(startTest(%d));";

// Maximum lenght of the result array in KeyEventTestData structure.
const size_t kMaxResultLength = 10;

// A structure holding test data of a keyboard event.
// Each keyboard event may generate multiple result strings representing
// the result of keydown, keypress, keyup and textInput events.
// For keydown, keypress and keyup events, the format of the result string is:
// <type> <keyCode> <charCode> <ctrlKey> <shiftKey> <altKey> <commandKey>
// where <type> may be 'D' (keydown), 'P' (keypress) or 'U' (keyup).
// <ctrlKey>, <shiftKey> <altKey> and <commandKey> are boolean value indicating
// the state of corresponding modifier key.
// For textInput event, the format is: T <text>, where <text> is the text to be
// input.
// Please refer to chrome/test/data/keyevents_test.html for details.
struct KeyEventTestData {
  ui::KeyboardCode key;
  bool ctrl;
  bool shift;
  bool alt;
  bool command;

  bool suppress_keydown;
  bool suppress_keypress;
  bool suppress_keyup;
  bool suppress_textinput;

  int result_length;
  const char* const result[kMaxResultLength];
};

const wchar_t* GetBoolString(bool value) {
  return value ? L"true" : L"false";
}

// A class to help wait for the finish of a key event test.
class TestFinishObserver : public content::NotificationObserver {
 public:
  explicit TestFinishObserver(RenderViewHost* render_view_host)
      : finished_(false), waiting_(false) {
    registrar_.Add(this, content::NOTIFICATION_DOM_OPERATION_RESPONSE,
                   content::Source<RenderViewHost>(render_view_host));
  }

  bool WaitForFinish() {
    if (!finished_) {
      waiting_ = true;
      content::RunMessageLoop();
      waiting_ = false;
    }
    return finished_;
  }

  virtual void Observe(int type,
                       const content::NotificationSource& source,
                       const content::NotificationDetails& details) {
    DCHECK(type == content::NOTIFICATION_DOM_OPERATION_RESPONSE);
    content::Details<DomOperationNotificationDetails> dom_op_details(details);
    // We might receive responses for other script execution, but we only
    // care about the test finished message.
    if (dom_op_details->json == "\"FINISHED\"") {
      finished_ = true;
      if (waiting_)
        MessageLoopForUI::current()->Quit();
    }
  }

 private:
  bool finished_;
  bool waiting_;
  content::NotificationRegistrar registrar_;

  DISALLOW_COPY_AND_ASSIGN(TestFinishObserver);
};

class BrowserKeyEventsTest : public InProcessBrowserTest {
 public:
  BrowserKeyEventsTest() {}

  bool IsViewFocused(ViewID vid) {
    return ui_test_utils::IsViewFocused(browser(), vid);
  }

  void ClickOnView(ViewID vid) {
    ui_test_utils::ClickOnView(browser(), vid);
  }

  // Set the suppress flag of an event specified by |type|. If |suppress| is
  // true then the web page will suppress all events with |type|. Following
  // event types are supported: keydown, keypress, keyup and textInput.
  void SuppressEventByType(int tab_index, const wchar_t* type, bool suppress) {
    ASSERT_LT(tab_index, browser()->tab_strip_model()->count());
    bool actual;
    ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
        browser()->tab_strip_model()->GetWebContentsAt(tab_index),
        base::StringPrintf(kSuppressEventJS, type, GetBoolString(!suppress)),
        &actual));
    ASSERT_EQ(!suppress, actual);
  }

  void SuppressEvents(int tab_index, bool keydown, bool keypress,
                      bool keyup, bool textinput) {
    ASSERT_NO_FATAL_FAILURE(
        SuppressEventByType(tab_index, L"keydown", keydown));
    ASSERT_NO_FATAL_FAILURE(
        SuppressEventByType(tab_index, L"keypress", keypress));
    ASSERT_NO_FATAL_FAILURE(
        SuppressEventByType(tab_index, L"keyup", keyup));
    ASSERT_NO_FATAL_FAILURE(
        SuppressEventByType(tab_index, L"textInput", textinput));
  }

  void SuppressAllEvents(int tab_index, bool suppress) {
    SuppressEvents(tab_index, suppress, suppress, suppress, suppress);
  }

  void GetResultLength(int tab_index, int* length) {
    ASSERT_LT(tab_index, browser()->tab_strip_model()->count());
    ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
        browser()->tab_strip_model()->GetWebContentsAt(tab_index),
        kGetResultLengthJS,
        length));
  }

  void CheckResult(int tab_index, int length, const char* const result[]) {
    ASSERT_LT(tab_index, browser()->tab_strip_model()->count());
    int actual_length;
    ASSERT_NO_FATAL_FAILURE(GetResultLength(tab_index, &actual_length));
    ASSERT_GE(actual_length, length);
    for (int i = 0; i < actual_length; ++i) {
      std::string actual;
      ASSERT_TRUE(content::ExecuteScriptAndExtractString(
          browser()->tab_strip_model()->GetWebContentsAt(tab_index),
          base::StringPrintf(kGetResultJS, i),
          &actual));

      // If more events were received than expected, then the additional events
      // must be keyup events.
      if (i < length)
        ASSERT_STREQ(result[i], actual.c_str());
      else
        ASSERT_EQ('U', actual[0]);
    }
  }

  void CheckFocusedElement(int tab_index, const wchar_t* focused) {
    ASSERT_LT(tab_index, browser()->tab_strip_model()->count());
    std::string actual;
    ASSERT_TRUE(content::ExecuteScriptAndExtractString(
        browser()->tab_strip_model()->GetWebContentsAt(tab_index),
        kGetFocusedElementJS,
        &actual));
    ASSERT_EQ(WideToUTF8(focused), actual);
  }

  void SetFocusedElement(int tab_index, const wchar_t* focused) {
    ASSERT_LT(tab_index, browser()->tab_strip_model()->count());
    bool actual;
    ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
        browser()->tab_strip_model()->GetWebContentsAt(tab_index),
        base::StringPrintf(kSetFocusedElementJS, focused),
        &actual));
    ASSERT_TRUE(actual);
  }

  void CheckTextBoxValue(int tab_index, const wchar_t* id,
                         const wchar_t* value) {
    ASSERT_LT(tab_index, browser()->tab_strip_model()->count());
    std::string actual;
    ASSERT_TRUE(content::ExecuteScriptAndExtractString(
        browser()->tab_strip_model()->GetWebContentsAt(tab_index),
        base::StringPrintf(kGetTextBoxValueJS, id),
        &actual));
    ASSERT_EQ(WideToUTF8(value), actual);
  }

  void SetTextBoxValue(int tab_index, const wchar_t* id,
                       const wchar_t* value) {
    ASSERT_LT(tab_index, browser()->tab_strip_model()->count());
    std::string actual;
    ASSERT_TRUE(content::ExecuteScriptAndExtractString(
        browser()->tab_strip_model()->GetWebContentsAt(tab_index),
        base::StringPrintf(kSetTextBoxValueJS, id, value),
        &actual));
    ASSERT_EQ(WideToUTF8(value), actual);
  }

  void StartTest(int tab_index, int result_length) {
    ASSERT_LT(tab_index, browser()->tab_strip_model()->count());
    bool actual;
    ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
        browser()->tab_strip_model()->GetWebContentsAt(tab_index),
        base::StringPrintf(kStartTestJS, result_length),
        &actual));
    ASSERT_TRUE(actual);
  }

  void TestKeyEvent(int tab_index, const KeyEventTestData& test) {
    ASSERT_LT(tab_index, browser()->tab_strip_model()->count());
    ASSERT_EQ(tab_index, browser()->tab_strip_model()->active_index());

    // Inform our testing web page that we are about to start testing a key
    // event.
    ASSERT_NO_FATAL_FAILURE(StartTest(tab_index, test.result_length));
    ASSERT_NO_FATAL_FAILURE(SuppressEvents(
        tab_index, test.suppress_keydown, test.suppress_keypress,
        test.suppress_keyup, test.suppress_textinput));

    // We need to create a finish observer before sending the key event,
    // because the test finished message might be arrived before returning
    // from the SendKeyPressSync() method.
    TestFinishObserver finish_observer(
        browser()->tab_strip_model()->GetWebContentsAt(tab_index)->
            GetRenderViewHost());

    ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
        browser(), test.key, test.ctrl, test.shift, test.alt, test.command));
    ASSERT_TRUE(finish_observer.WaitForFinish());
    ASSERT_NO_FATAL_FAILURE(CheckResult(
        tab_index, test.result_length, test.result));
  }

  std::string GetTestDataDescription(const KeyEventTestData& data) {
    std::string desc = base::StringPrintf(
        " VKEY:0x%02x, ctrl:%d, shift:%d, alt:%d, command:%d\n"
        " Suppress: keydown:%d, keypress:%d, keyup:%d, textInput:%d\n"
        " Expected results(%d):\n",
        data.key, data.ctrl, data.shift, data.alt, data.command,
        data.suppress_keydown, data.suppress_keypress, data.suppress_keyup,
        data.suppress_textinput, data.result_length);
    for (int i = 0; i < data.result_length; ++i) {
      desc.append("  ");
      desc.append(data.result[i]);
      desc.append("\n");
    }
    return desc;
  }
};

#if defined(OS_MACOSX)
// http://crbug.com/81451
#define MAYBE_NormalKeyEvents DISABLED_NormalKeyEvents
#elif defined(OS_LINUX)
// http://crbug.com/129235
#define MAYBE_NormalKeyEvents DISABLED_NormalKeyEvents
#else
#define MAYBE_NormalKeyEvents NormalKeyEvents
#endif

IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, MAYBE_NormalKeyEvents) {
  static const KeyEventTestData kTestNoInput[] = {
    // a
    { ui::VKEY_A, false, false, false, false,
      false, false, false, false, 3,
      { "D 65 0 false false false false",
        "P 97 97 false false false false",
        "U 65 0 false false false false" } },
    // shift-a
    { ui::VKEY_A, false, true, false, false,
      false, false, false, false, 5,
      { "D 16 0 false true false false",
        "D 65 0 false true false false",
        "P 65 65 false true false false",
        "U 65 0 false true false false",
        "U 16 0 false true false false" } },
    // a, suppress keydown
    { ui::VKEY_A, false, false, false, false,
      true, false, false, false, 2,
      { "D 65 0 false false false false",
        "U 65 0 false false false false" } },
  };

  static const KeyEventTestData kTestWithInput[] = {
    // a
    { ui::VKEY_A, false, false, false, false,
      false, false, false, false, 4,
      { "D 65 0 false false false false",
        "P 97 97 false false false false",
        "T a",
        "U 65 0 false false false false" } },
    // shift-a
    { ui::VKEY_A, false, true, false, false,
      false, false, false, false, 6,
      { "D 16 0 false true false false",
        "D 65 0 false true false false",
        "P 65 65 false true false false",
        "T A",
        "U 65 0 false true false false",
        "U 16 0 false true false false" } },
    // a, suppress keydown
    { ui::VKEY_A, false, false, false, false,
      true, false, false, false, 2,
      { "D 65 0 false false false false",
        "U 65 0 false false false false" } },
    // a, suppress keypress
    { ui::VKEY_A, false, false, false, false,
      false, true, false, false, 3,
      { "D 65 0 false false false false",
        "P 97 97 false false false false",
        "U 65 0 false false false false" } },
    // a, suppress textInput
    { ui::VKEY_A, false, false, false, false,
      false, false, false, true, 4,
      { "D 65 0 false false false false",
        "P 97 97 false false false false",
        "T a",
        "U 65 0 false false false false" } },
  };

  ASSERT_TRUE(test_server()->Start());

  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
  GURL url = test_server()->GetURL(kTestingPage);
  ui_test_utils::NavigateToURL(browser(), url);

  ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));

  int tab_index = browser()->tab_strip_model()->active_index();
  for (size_t i = 0; i < arraysize(kTestNoInput); ++i) {
    EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestNoInput[i]))
        << "kTestNoInput[" << i << "] failed:\n"
        << GetTestDataDescription(kTestNoInput[i]);
  }

  // Input in normal text box.
  ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L"A"));
  for (size_t i = 0; i < arraysize(kTestWithInput); ++i) {
    EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestWithInput[i]))
        << "kTestWithInput[" << i << "] in text box failed:\n"
        << GetTestDataDescription(kTestWithInput[i]);
  }
  EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index, L"A", L"aA"));

  // Input in password box.
  ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L"B"));
  for (size_t i = 0; i < arraysize(kTestWithInput); ++i) {
    EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestWithInput[i]))
        << "kTestWithInput[" << i << "] in password box failed:\n"
        << GetTestDataDescription(kTestWithInput[i]);
  }
  EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index, L"B", L"aA"));
}

#if defined(OS_WIN) || defined(OS_LINUX)

#if defined(OS_LINUX)
// http://crbug.com/129235
#define MAYBE_CtrlKeyEvents DISABLED_CtrlKeyEvents
#else
#define MAYBE_CtrlKeyEvents CtrlKeyEvents
#endif

IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, MAYBE_CtrlKeyEvents) {
  static const KeyEventTestData kTestCtrlF = {
    ui::VKEY_F, true, false, false, false,
    false, false, false, false, 2,
    { "D 17 0 true false false false",
      "D 70 0 true false false false" }
  };

  static const KeyEventTestData kTestCtrlFSuppressKeyDown = {
    ui::VKEY_F, true, false, false, false,
    true, false, false, false, 4,
    { "D 17 0 true false false false",
      "D 70 0 true false false false",
      "U 70 0 true false false false",
      "U 17 0 true false false false" }
  };

  // Ctrl+Z doesn't bind to any accelerators, which then should generate a
  // keypress event with charCode=26.
  static const KeyEventTestData kTestCtrlZ = {
    ui::VKEY_Z, true, false, false, false,
    false, false, false, false, 5,
    { "D 17 0 true false false false",
      "D 90 0 true false false false",
      "P 26 26 true false false false",
      "U 90 0 true false false false",
      "U 17 0 true false false false" }
  };

  static const KeyEventTestData kTestCtrlZSuppressKeyDown = {
    ui::VKEY_Z, true, false, false, false,
    true, false, false, false, 4,
    { "D 17 0 true false false false",
      "D 90 0 true false false false",
      "U 90 0 true false false false",
      "U 17 0 true false false false" }
  };

  // Ctrl+Enter shall generate a keypress event with charCode=10 (LF).
  static const KeyEventTestData kTestCtrlEnter = {
    ui::VKEY_RETURN, true, false, false, false,
    false, false, false, false, 5,
    { "D 17 0 true false false false",
      "D 13 0 true false false false",
      "P 10 10 true false false false",
      "U 13 0 true false false false",
      "U 17 0 true false false false" }
  };

  ASSERT_TRUE(test_server()->Start());

  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
  GURL url = test_server()->GetURL(kTestingPage);
  ui_test_utils::NavigateToURL(browser(), url);

  ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));

  int tab_index = browser()->tab_strip_model()->active_index();
  // Press Ctrl+F, which will make the Find box open and request focus.
  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlF));
  EXPECT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));

  // Press Escape to close the Find box and move the focus back to the web page.
  ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
      browser(), ui::VKEY_ESCAPE, false, false, false, false));
  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));

  // Press Ctrl+F with keydown suppressed shall not open the find box.
  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlFSuppressKeyDown));
  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));

  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlZ));
  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlZSuppressKeyDown));
  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlEnter));
}
#elif defined(OS_MACOSX)
// http://crbug.com/81451
IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, DISABLED_CommandKeyEvents) {
  static const KeyEventTestData kTestCmdF = {
    ui::VKEY_F, false, false, false, true,
    false, false, false, false, 2,
    { "D 91 0 false false false true",
      "D 70 0 false false false true" }
  };

  // On Mac we don't send key up events when command modifier is down.
  static const KeyEventTestData kTestCmdFSuppressKeyDown = {
    ui::VKEY_F, false, false, false, true,
    true, false, false, false, 3,
    { "D 91 0 false false false true",
      "D 70 0 false false false true",
      "U 91 0 false false false true" }
  };

  ASSERT_TRUE(test_server()->Start());

  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
  GURL url = test_server()->GetURL(kTestingPage);
  ui_test_utils::NavigateToURL(browser(), url);

  ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));

  int tab_index = browser()->tab_strip_model()->active_index();
  // Press Cmd+F, which will make the Find box open and request focus.
  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCmdF));
  EXPECT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));

  // Press Escape to close the Find box and move the focus back to the web page.
  ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
      browser(), ui::VKEY_ESCAPE, false, false, false, false));
  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));

  // Press Cmd+F with keydown suppressed shall not open the find box.
  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCmdFSuppressKeyDown));
  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
}
#endif

#if defined(OS_MACOSX)
// http://crbug.com/81451 for mac
#define MAYBE_AccessKeys DISABLED_AccessKeys
#elif defined(OS_LINUX)
// http://crbug.com/129235
#define MAYBE_AccessKeys DISABLED_AccessKeys
#else
#define MAYBE_AccessKeys AccessKeys
#endif

IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, MAYBE_AccessKeys) {
#if defined(OS_MACOSX)
  // On Mac, access keys use ctrl+alt modifiers.
  static const KeyEventTestData kTestAccessA = {
    ui::VKEY_A, true, false, true, false,
    false, false, false, false, 6,
    { "D 17 0 true false false false",
      "D 18 0 true false true false",
      "D 65 0 true false true false",
      "U 65 0 true false true false",
      "U 18 0 true false true false",
      "U 17 0 true false false false" }
  };

  static const KeyEventTestData kTestAccessDSuppress = {
    ui::VKEY_D, true, false, true, false,
    true, true, true, false, 6,
    { "D 17 0 true false false false",
      "D 18 0 true false true false",
      "D 68 0 true false true false",
      "U 68 0 true false true false",
      "U 18 0 true false true false",
      "U 17 0 true false false false" }
  };

  static const KeyEventTestData kTestAccess1 = {
    ui::VKEY_1, true, false, true, false,
    false, false, false, false, 6,
    { "D 17 0 true false false false",
      "D 18 0 true false true false",
      "D 49 0 true false true false",
      "U 49 0 true false true false",
      "U 18 0 true false true false",
      "U 17 0 true false false false" }
  };
#else
  static const KeyEventTestData kTestAccessA = {
    ui::VKEY_A, false, false, true, false,
    false, false, false, false, 4,
    { "D 18 0 false false true false",
      "D 65 0 false false true false",
      "U 65 0 false false true false",
      "U 18 0 false false true false" }
  };

  static const KeyEventTestData kTestAccessD = {
    ui::VKEY_D, false, false, true, false,
    false, false, false, false, 2,
    { "D 18 0 false false true false",
      "D 68 0 false false true false" }
  };

  static const KeyEventTestData kTestAccessDSuppress = {
    ui::VKEY_D, false, false, true, false,
    true, true, true, false, 4,
    { "D 18 0 false false true false",
      "D 68 0 false false true false",
      "U 68 0 false false true false",
      "U 18 0 false false true false" }
  };

#if !defined(USE_ASH)
  static const KeyEventTestData kTestAccess1 = {
    ui::VKEY_1, false, false, true, false,
    false, false, false, false, 4,
    { "D 18 0 false false true false",
      "D 49 0 false false true false",
      "U 49 0 false false true false",
      "U 18 0 false false true false" }
  };
#endif
#endif

  ASSERT_TRUE(test_server()->Start());

  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
  GURL url = test_server()->GetURL(kTestingPage);
  ui_test_utils::NavigateToURL(browser(), url);

  content::RunAllPendingInMessageLoop();
  ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));

  int tab_index = browser()->tab_strip_model()->active_index();
  // Make sure no element is focused.
  EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));
  // Alt+A should focus the element with accesskey = "A".
  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAccessA));
  EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L"A"));

  // Blur the focused element.
  EXPECT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L""));
  // Make sure no element is focused.
  EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));

#if !defined(OS_MACOSX)
  // Alt+D should move the focus to the location entry.
  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAccessD));

  // TODO(isherman): This is an experimental change to help diagnose
  // http://crbug.com/55713
  content::RunAllPendingInMessageLoop();
#if defined(USE_AURA)
  EXPECT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
#else
  EXPECT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR));
#endif
  // No element should be focused, as Alt+D was handled by the browser.
  EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));

  // Move the focus back to the web page.
  ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));

  // Make sure no element is focused.
  EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));
#endif

  // If the keydown event is suppressed, then Alt+D should be handled as an
  // accesskey rather than an accelerator key. Activation of an accesskey is not
  // a part of the default action of the key event, so it should not be
  // suppressed at all.
  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAccessDSuppress));
  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
  EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L"D"));

  // Blur the focused element.
  EXPECT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L""));
  // Make sure no element is focused.
  EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));
#if !defined(USE_ASH)
  // On Ash, alt-1..9 are assigned as window selection global accelerators, so
  // they can not be used as accesskeys.
  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAccess1));
#if defined(TOOLKIT_GTK)
  // On GTK, alt-0..9 are assigned as tab selection accelerators, so they can
  // not be used as accesskeys.
  EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));
#else
  EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L"1"));
#endif
#endif
}

// Flaky, http://crbug.com/69475.
#if defined(OS_LINUX)
#define MAYBE_ReservedAccelerators DISABLED_ReservedAccelerators
#else
#define MAYBE_ReservedAccelerators ReservedAccelerators
#endif
IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, MAYBE_ReservedAccelerators) {
  ASSERT_TRUE(test_server()->Start());

  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
  GURL url = test_server()->GetURL(kTestingPage);
  ui_test_utils::NavigateToURL(browser(), url);

  ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));

  ASSERT_EQ(1, browser()->tab_strip_model()->count());

  static const KeyEventTestData kTestCtrlOrCmdT = {
#if defined(OS_MACOSX)
    ui::VKEY_T, false, false, false, true,
    true, false, false, false, 1,
    { "D 91 0 false false false true" }
#else
    ui::VKEY_T, true, false, false, false,
    true, false, false, false, 1,
    { "D 17 0 true false false false" }
#endif
  };

  content::WindowedNotificationObserver wait_for_new_tab(
      chrome::NOTIFICATION_TAB_PARENTED,
      content::NotificationService::AllSources());

  // Press Ctrl/Cmd+T, which will open a new tab. It cannot be suppressed.
  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(0, kTestCtrlOrCmdT));
  wait_for_new_tab.Wait();

  int result_length;
  ASSERT_NO_FATAL_FAILURE(GetResultLength(0, &result_length));
  EXPECT_EQ(1, result_length);

  EXPECT_EQ(2, browser()->tab_strip_model()->count());
  ASSERT_EQ(1, browser()->tab_strip_model()->active_index());

  // Because of issue <http://crbug.com/65375>, switching back to the first tab
  // may cause the focus to be grabbed by omnibox. So instead, we load our
  // testing page in the newly created tab and try Cmd-W here.
  ui_test_utils::NavigateToURL(browser(), url);

  // Make sure the focus is in the testing page.
  ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));

  // Reserved accelerators can't be suppressed.
  ASSERT_NO_FATAL_FAILURE(SuppressAllEvents(1, true));

  content::WindowedNotificationObserver wait_for_tab_closed(
      content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
      content::Source<content::WebContents>(
          browser()->tab_strip_model()->GetWebContentsAt(1)));

  // Press Ctrl/Cmd+W, which will close the tab.
#if defined(OS_MACOSX)
  ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
      browser(), ui::VKEY_W, false, false, false, true));
#else
  ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
      browser(), ui::VKEY_W, true, false, false, false));
#endif

  ASSERT_NO_FATAL_FAILURE(wait_for_tab_closed.Wait());

  EXPECT_EQ(1, browser()->tab_strip_model()->count());
}

#if defined(OS_MACOSX)
IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, EditorKeyBindings) {
  static const KeyEventTestData kTestCtrlA = {
    ui::VKEY_A, true, false, false, false,
    false, false, false, false, 4,
    { "D 17 0 true false false false",
      "D 65 0 true false false false",
      "U 65 0 true false false false",
      "U 17 0 true false false false" }
  };

  static const KeyEventTestData kTestCtrlF = {
    ui::VKEY_F, true, false, false, false,
    false, false, false, false, 4,
    { "D 17 0 true false false false",
      "D 70 0 true false false false",
      "U 70 0 true false false false",
      "U 17 0 true false false false" }
  };

  static const KeyEventTestData kTestCtrlK = {
    ui::VKEY_K, true, false, false, false,
    false, false, false, false, 4,
    { "D 17 0 true false false false",
      "D 75 0 true false false false",
      "U 75 0 true false false false",
      "U 17 0 true false false false" }
  };

  ASSERT_TRUE(test_server()->Start());

  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
  GURL url = test_server()->GetURL(kTestingPage);
  ui_test_utils::NavigateToURL(browser(), url);

  ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));

  int tab_index = browser()->tab_strip_model()->active_index();
  ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L"A"));
  ASSERT_NO_FATAL_FAILURE(SetTextBoxValue(tab_index, L"A", L"Hello"));
  // Move the caret to the beginning of the line.
  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlA));
  // Forward one character
  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlF));
  // Delete to the end of the line.
  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlK));
  EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index, L"A", L"H"));
}
#endif

// See http://crbug.com/147579
IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, DISABLED_PageUpDownKeys) {
  static const KeyEventTestData kTestPageUp = {
    ui::VKEY_PRIOR, false, false, false, false,
    false, false, false, false, 2,
    { "D 33 0 false false false false",
      "U 33 0 false false false false" }
  };

  static const KeyEventTestData kTestPageDown = {
    ui::VKEY_NEXT, false, false, false, false,
    false, false, false, false, 2,
    { "D 34 0 false false false false",
      "U 34 0 false false false false" }
  };

  ASSERT_TRUE(test_server()->Start());

  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
  GURL url = test_server()->GetURL(kTestingPage);
  ui_test_utils::NavigateToURL(browser(), url);

  ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));

  int tab_index = browser()->tab_strip_model()->active_index();
  ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L"A"));
  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestPageUp));
  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestPageDown));
  EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index, L"A", L""));
}

#if defined(OS_WIN)
// AltKey is enabled only on Windows. See crbug.com/114537.
IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, FocusMenuBarByAltKey) {
  static const KeyEventTestData kTestAltKey = {
    ui::VKEY_MENU, false, false, false, false,
    false, false, false, false, 2,
    { "D 18 0 false false true false",
      "U 18 0 false false true false" }
  };

  static const KeyEventTestData kTestAltKeySuppress = {
    ui::VKEY_MENU, false, false, false, false,
    true, false, false, false, 2,
    { "D 18 0 false false true false",
      "U 18 0 false false true false" }
  };

  static const KeyEventTestData kTestCtrlAltKey = {
    ui::VKEY_MENU, true, false, false, false,
    false, false, false, false, 4,
    { "D 17 0 true false false false",
      "D 18 0 true false true false",
      "U 18 0 true false true false",
      "U 17 0 true false false false" }
  };

  ASSERT_TRUE(test_server()->Start());

  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
  GURL url = test_server()->GetURL(kTestingPage);
  ui_test_utils::NavigateToURL(browser(), url);

  ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));

  int tab_index = browser()->tab_strip_model()->active_index();
  // Press and release Alt key to focus wrench menu button.
  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAltKey));
  EXPECT_TRUE(IsViewFocused(VIEW_ID_APP_MENU));

  ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));

  // Alt key can be suppressed.
  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAltKeySuppress));
  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));

  // Ctrl+Alt should have no effect.
  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlAltKey));
  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
}
#endif

}  // namespace


text:
layout: post
date: 2017-08-23
title: Caption
description: The caption that goes below an image.
category: litmus-content
subcategory: Content
trigger: caption
order: 6
---

The caption that goes below an image.

![image caption]({{site.image_path}}/{{page.category}}/caption.jpg)

~~~

{caption}

~~~
{: .language-html.toggle}

redpajama_set_name: RedPajamaGithub


text:
\section{Modeling}

In the following we describe how you can create PCM-Models using the Workbench and how you can publish them to the server.

\subsection{Creating a new Model}

We assume that you have started the Workbench and the server. There are two ways to create a new model.
You can either use the File\textgreater\textgreater New menu or the New Icon.
Nevertheless, you always have to choose the type of the model to be created.

\subsection{Publish a Model}

If you create your diagrams in the Workbench and if you have a Processeditor Server running you can publish a model to the centralized repository (the server).
Therefore you have to do either, click on the Publish icon or use the menu item inside the file Menu.
Then you have to select a server and a name for the model.
In addition you can choose if you want to save the model as a new version of an existing one or as a new model.

\subsection{Fetch a Model}

If you work inside your Workbench you have to fetch Models from the server, in order to alter or view them.
To do so click on the Fetch icon or use the menu item inside the File menu.
You can now connect to a server.
After that you will see a tree with all diagrams and folders on the server model repository.
Choose the one you want to open.

\subsection{Modeling PCM-Fragments}

You can model a PCM Fragment by choosing the PCM Fragment type from the context menu. Now you can add nodes by clicking right on the canvas. You can choose from Start Events, Activities, Gateways, End Events and Data Objects.

If you want to use the created model for the execution in the engine you have to be aware of the following constraints:

\begin{itemize}
\item Every fragment must contain exactly one start and end event
\item All Events must be blank
\item The activities must be either blank, Sending Mail Task or Service Task
\item The Gateways must be exclusive or parallel ones
\end{itemize}

\noindent
\textbf{Referring an Activity From Another Fragment}

\noindent
If you want to refer an activity from another Fragment you have to do the following steps.
\begin{enumerate}
\item The task in the other fragment has to be marked as global (right click on activity, properties, global).
\item This fragment has to be published on a server.
\item Make a right click choose Copy and Refer Task. Select the Fragment and the Task to be copied.
\end{enumerate}
The task will be added to the current model.
\noindent
You can add edges either by dragging a new node from the context menu of the previous node or by pressing and holding the right button.

\subsection{Modeling a Data Model}

If you want to create a Data Model for the Data Objects in your PCM Process you have to create a new Domain Model. Again, if you want to use this model from within the JEngine you have to publish it and you should at most create one Root Class.
Right click "Edit Attributes" Allows you to add and remove attributes for each class.
You can create relations between data classes using an Aggregation by pressing and holding the right mouse button.

\subsection{Modeling a PCM Scenario}

A PCM Scenario holds the whole Process, therefore it needs information about all fragments, the data objects and their relation to data classes. Hence, a couple of steps are necessary.
\begin{enumerate}
\item \textbf{Adding Fragments}.
First of all you have to add new Fragments. You can do this by using the plugin "Add Fragments" from within the process's contexts menu. Now you can connect to a server and select a number of Fragments from the right side, which should be added to the scenario.
\item \textbf{Define a Domain-Model}.
Every Scenario needs an Domain Model, therefore go to the properties of the model and paste the URL of the domain model into the domainModelURL Property. The server address must be the same as specified in the configuration class of the JEngine. This means the default URL would be \url{http://localhost:1205/models/<domainModelId>.pm}.
\item \textbf{Map Data Objects to Data Classes}.
Every Data Object needs one Data Class.
Hence, you must assign one.
You can do this by editing the properties (figure \ref{pic:propdo}). If you want to execute the scenario you have to make sure, that the selected data class is in the model assigned to the PCM Scenario.
\item \textbf{Define a Termination Condition}.
A Scenario needs a clear termination condition. You can define it inside the properties menu (figure \ref{pic:propscen}) of the process. There type the name of exactly one data object int the field and the state surrounded by [ ] in the state field.
\end{enumerate}
\begin{figure}[h!]
\includegraphics[height=0.4\textheight]{graphics/dataNodeProperties.png}
\caption{Properties of a Data Object Node}
\label{pic:propdo}
\end{figure}

\begin{figure}[h!]
\includegraphics[height=0.4\textheight]{graphics/scenarioProperties.png}
\caption{Properties of a PCM Scenario}
\label{pic:propscen}
\end{figure}
\noindent
Make sure to publish the scenario, the domain model and all fragments to the process repository.


text:
ACCEPTED

#### According to
The Catalogue of Life, 3rd January 2011

#### Published in
Schr. naturf. Ges. Leipzig 1: 74 (1822)

#### Original name
Gymnosporangium juniperi-virginianae Schwein., 1822

### Remarks
null


text:
using dom_distiller::ArticleEntry;
using dom_distiller::test::FakeDistiller;
using dom_distiller::test::util::CreateStoreWithFakeDB;
using dom_distiller::DomDistillerContextKeyedService;
using dom_distiller::DomDistillerService;
using dom_distiller::DistillerFactory;
using dom_distiller::DistillerPageFactory;
using dom_distiller::DomDistillerStoreInterface;
using dom_distiller::test::MockDistillerFactory;
using dom_distiller::test::MockDistillerPage;
using dom_distiller::test::MockDistillerPageFactory;
using leveldb_proto::test::FakeDB;

class ReadingListPrivateApiTest : public ExtensionApiTest {
 public:
  static scoped_ptr<KeyedService> Build(content::BrowserContext* context) {
    FakeDB<ArticleEntry>* fake_db =
        new FakeDB<ArticleEntry>(new FakeDB<ArticleEntry>::EntryMap);
    FakeDistiller* distiller = new FakeDistiller(true);
    MockDistillerPage* distiller_page = new MockDistillerPage();
    MockDistillerFactory* distiller_factory = new MockDistillerFactory();
    MockDistillerPageFactory* distiller_page_factory =
        new MockDistillerPageFactory();

    // Setting up pref service for DistilledPagePrefs.
    user_prefs::TestingPrefServiceSyncable* pref_service =
        new user_prefs::TestingPrefServiceSyncable();
    dom_distiller::DistilledPagePrefs::RegisterProfilePrefs(
        pref_service->registry());

    scoped_ptr<DomDistillerContextKeyedService> service(
        new DomDistillerContextKeyedService(
            scoped_ptr<DomDistillerStoreInterface>(CreateStoreWithFakeDB(
                fake_db, FakeDB<ArticleEntry>::EntryMap())),
            scoped_ptr<DistillerFactory>(distiller_factory),
            scoped_ptr<DistillerPageFactory>(distiller_page_factory),
            scoped_ptr<dom_distiller::DistilledPagePrefs>(
                new dom_distiller::DistilledPagePrefs(pref_service))));
    fake_db->InitCallback(true);
    fake_db->LoadCallback(true);
    EXPECT_CALL(*distiller_factory, CreateDistillerImpl())
        .WillOnce(testing::Return(distiller));
    EXPECT_CALL(*distiller_page_factory, CreateDistillerPageImpl())
        .WillOnce(testing::Return(distiller_page));
    return service.Pass();
  }
};

IN_PROC_BROWSER_TEST_F(ReadingListPrivateApiTest, ReadingListPrivate) {
  dom_distiller::DomDistillerServiceFactory::GetInstance()->SetTestingFactory(
      profile(), &ReadingListPrivateApiTest::Build);
  ASSERT_TRUE(RunComponentExtensionTest("reading_list_private")) << message_;
}


text:
package org.jtwig.spring.boot;

import org.jtwig.spring.boot.availability.IsClassPresent;
import org.junit.Test;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;

import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class JtwigTemplateAvailabilityProviderTest {
    private final IsClassPresent isClassPresent = mock(IsClassPresent.class);
    private JtwigTemplateAvailabilityProvider underTest = new JtwigTemplateAvailabilityProvider(isClassPresent);

    @Test
    public void isTemplateAvailableNoJtwigViewResolver() throws Exception {
        ClassLoader classLoader = mock(ClassLoader.class);
        ResourceLoader resourceLoader = mock(ResourceLoader.class);
        Environment environment = mock(Environment.class);
        String view = "boop";

        when(isClassPresent.isPresent(classLoader, "org.jtwig.spring.JtwigViewResolver")).thenReturn(false);

        boolean result = underTest.isTemplateAvailable(view, environment, classLoader, resourceLoader);

        assertThat(result, is(false));
    }

    @Test
    public void isTemplateAvailableNoJtwigTempalte() throws Exception {
        ClassLoader classLoader = mock(ClassLoader.class);
        ResourceLoader resourceLoader = mock(ResourceLoader.class);
        Environment environment = mock(Environment.class);
        String view = "boop";

        when(isClassPresent.isPresent(classLoader, "org.jtwig.spring.JtwigViewResolver")).thenReturn(true);
        when(isClassPresent.isPresent(classLoader, "org.jtwig.JtwigTemplate")).thenReturn(false);

        boolean result = underTest.isTemplateAvailable(view, environment, classLoader, resourceLoader);

        assertThat(result, is(false));
    }
}


text:
package net.kuujo.vertigo.network.builder;

/**
 * Input port builder.
 *
 * @author Jordan Halterman
 */
public interface InputPortBuilder extends PortBuilder<InputPortBuilder>, InputBuilder {
}


text:
i18n.hu = {
  fullName: 'Magyar',
  ok: 'Rendben',
  main: {
    legend: 'Legenda',
    diagram: 'Diagram',
    mapView: 'Térkép nézet',
    favoriteView: 'Kedvencek',
    settings: 'Beállítások',
    stationSelection: 'Válasszon ki egy állomást',
    chartView: 'Diagram nézet',
    allPhenomena: 'Minden jelenség',
    phenomenon: 'Jelenség',
    favoritesList: 'Kedvencek',
    importFavorites: 'Import',
    exportFavorites: 'Export',
    importExportHelp: 'Fájl importálásához, válasszon egy exportált fájlt előtt.',
    noFileSelected: 'Nincs fájl kiválasztva'
  },
  chart: {
    noTimeseriesSelected: 'Nem választott ki előre definiált, a kiválasztott előre definiált nincs értékeket az adott időben tartomány vagy a előre definiált rejtett.',
    outsideOfDataRange: 'Kívül adatok körét!',
    annotation: 'Az adatok garancia nélkül!',
    monthNames: [ 'Január', 'Február', 'Elront', 'Április', 'Május', 'Június', 'Július', 'Augusztus', 'Szeptember', 'Október', 'November', 'December' ]
  },
  table: {
    time: 'Idő'
  },
  map: {
    userLocation: 'Itt az aktuális tartózkodási helyét',
    stationSelection: {
      station: 'Állomás',
      selectAllTimeseries: 'jelölje ki az összes előre definiált'
    },
    stationLocation: {
      station: 'Állomás',
      timeseries: 'Előre definiált',
      provider: 'Ellátó',
      jumpBackToChart: 'Vissza a chart'
    },
    providerList: {
      provider: 'Ellátó',
      stations: 'Állomások',
      timeseries: 'Előre definiált',
      phenomena: 'Jelenségek'
    },
    search: {
      label: 'címkereséshez ...',
      noResult: 'Sajnáljuk, hogy címet nem található.'
    }
  },
  listSelection: {
    header: 'Válassza ki az előre definiált tömbök által lista',
    headers: {
      category: 'Kategória',
      station: 'Állomás',
      phenomenon: 'Jelenség',
      procedure: 'Érzékelő'
    },
    warning: {
      moreThanOneTimeseries: 'találtak több mint egy előre definiált'
    }
  },
  legend: {
    entry: {
      noData: 'nincs adat',
      jumpToLastValue: 'utolsó értéket',
      firstValueAt: 'Első érték',
      lastValueAt: 'Utolsó érték'
    }
  },
  export: {
    label: 'Az adatok CSV (Zip archívum)'
  },
  timeSelection: {
    header: 'Idő Tartomány',
    presetsHeader: 'előre beállított',
    presets: {
      lastHour: 'az elmúlt órában',
      today: 'ma',
      yesterday: 'tegnap',
      todayYesterday: 'Ma & tegnap',
      thisWeek: 'ezen a héten',
      lastWeek: 'a múlt héten',
      thisMonth: 'ebben a hónapban',
      lastMonth: 'az utolsó hónapban',
      thisYear: 'ebben az évben',
      lastYear: 'tavaly'
    },
    custom: {
      header: 'szokás',
      start: 'Kezdési időpont',
      end: 'A befejezés dátuma'
    },
    warning: {
      startBeforeEnd: 'A kezdő dátum nem lehet nagyobb, mint a befejezés dátumát',
      maxTimeRange: 'Az idő tartomány nem lehet nagyobb, mint egy év'
    }
  },
  styleChange: {
    header: 'Stílus',
    currentColor: 'Jelenlegi színe',
    selectColor: 'Válasszon egy új színt',
    selectBarInterval: 'Válassza ki a vonalat intervallum',
    barChartInterval: {
      hour: 'Óra',
      day: 'Nap',
      week: 'Hét',
      month: 'Hónap'
    },
    zeroScaled: 'zéró pikkelyes Y-tengely',
    groupedAxis: 'csoportosítva tengely'
  },
  settings: {
    header: 'Beállítások',
    chooseLanguage: 'Switch nyelven',
    requiresRestart: 'Újra kell indítani!',
    permalink: {
      create: 'Hozzon létre egy permalink mint',
      inWindow: 'Link új ablakban',
      inMail: 'linkre egy e-mailt',
      inClipboard: 'Hivatkoznak a vágólapra',
      clipboardInfo: 'Másolás a vágólapra:',
      inQrCode: 'mint QR-kód',
      favorite: 'Mentsd munkakörnyezet kedvencként bejegyzés'
    },
    clusterMarker: 'cluster marker',
    markerWithLastInfo: {
      header: 'marker utolsó értéket információk',
      label: 'Figyelem - néhány adatszolgáltató nagyon lassúak'
    },
    saveStatus: {
      header: 'Save környezet',
      label: 'Minden előre definiált, a kiválasztott időtávot és a beállítások mentése folyamatos.'
    },
    resetStatus: 'Reset környezet',
    generalizeData: 'általánosítani adatok',
    imprint: {
      header: 'Impresszum',
      github: 'Keresd meg ezt a projektet GitHub',
      text: '
 52 ° North GmbH felelős ezen a weboldalon.

 52 ° North Initiative for térinformatikai nyílt forráskódú szoftver GmbH
 Martin-Luther-King-Weg 24
 48155 Münster, Németország
'
    }
  },
  permalink: {
    noMatchingTimeseriesFound: 'Nem illő előre definiált található.'
  },
  guide: {
    start: {
      request: 'Amikor elindítja ezt az útmutatót, az a jelenlegi állapot visszaáll.'
    },
    step1: {
      header: 'JavaScript Client - Tárlatvezetés',
      text: 'Ez a túra ad néhány lépésben áttekintést, hogyan kell használni ezt a kliens. Először adjunk hozzá egy előre definiált a térképről.'
    },
    step2: {
      header: 'Menj a térképen',
      text: 'Itt váltani a nézetet, hogy a térképet.'
    },
    step3: {
      header: 'Térkép nézet',
      text: 'Ez a térkép nézet. A térképen látható markerek vagy markergroups.'
    },
    step4: {
      header: 'Change Provider',
      text: 'Itt választhatunk más előre definiált szolgáltatót.'
    },
    step5: {
      header: 'Show location',
      text: 'És itt keresse meg a készülék a térképen.'
    },
    step6: {
      header: 'Lista kiválasztása',
      text: 'Itt lehet kiválasztani a előre definiált ki rendezett listák.'
    },
    step7: {
      header: 'Válasszon ki egy állomást',
      text: 'Kérjük, válasszon most egy állomás a térképen.'
    },
    step8: {
      header: 'Válassza ki az előre definiált tömbök',
      text: 'Válassza ki ezt a jelölőnégyzetet. Ha csak egy előre definiált ennek az állomásnak, a négyzetet bejelölve. Most lehet menni az "OK" gombot betölteni az előre definiált.'
    },
    step9: {
      header: 'Legend bejegyzés',
      text: 'Itt láthatja a hozzá idősorok. Törölheti, vagy keresse az idősor, vagy változtatni a színét.'
    },
    step10: {
      header: 'Táblázat',
      text: 'Ez az ábra a kiválasztott idősorok.'
    },
    step11: {
      header: 'Váltási idő',
      text: 'Itt lehet megváltoztatni az időt mértékben az Ön által választott idősorok.'
    },
    step12: {
      header: 'Táblázat megtekintése',
      text: 'Most itt van egy táblázat a nyers adatok értékeket a kiválasztott idősorok.'
    },
    step13: {
      header: 'Kedvenc menedzsment',
      text: 'A legenda bejegyzések / előre definiált meg lehetne menteni a kedvencek. Ebben a nézetben az összes kedvenc vannak felsorolva, és fenn lehet tartani.'
    },
    step14: {
      header: 'Kész',
      text: 'Szép munka!
 Ez a kliens egy olyan termék a 52 ° North GmbH . Megtalálható a forráskódot GitHub .'
    }
  },
  favorite: {
    firstValueAt: 'Első érték',
    lastValueAt: 'Utolsó érték',
    label: 'kedvenc',
    edit: {
      header: 'Kedvenc szerkesztése'
    },
    group: {
      add: 'A status '{0}' hozzáadódik a kedvenceid közé.',
      exists: 'Ez az állapot továbbra is fennáll.',
      noTimeseries: 'Jelenleg nincs előre definiált kerülnek kiválasztásra.',
      notSupported: 'A szolgáltató a bejegyzést a status '{0}' nem támogatott és nem lehet betölteni.'
    },
    single: {
      add: 'Egy új kedvenc "{0}" hozzáadódik a listához.',
      remove: 'A kedvenc '{0}' eltávolítása.',
      exists: 'Ez a kedvenc még mindig létezik.',
      notSupported: 'A szolgáltató a kedvenc '{0}' nem támogatott és nem lehet betölteni.'
    },
    import: {
      override: 'Szeretné, hogy felülbírálja az aktuális kedvencek?',
      wrongFile: 'Nem sikerült beolvasni a fájlt',
      noValidJson: 'A JSON fájl nem érvényes!',
      header: 'Import kedvencekhez',
      text: 'Itt lehet importálni az exportált kedvenceket. Csak illessze be a JSON ezen a beviteli mezőbe:'
    },
    export: {
      header: 'Export kedvencekhez',
      text: 'Itt tudja exportálni a kedvenceit. Csak másolja a JSON ki ezt a szövegdobozba, és mentse el egy fájlba importálni később:'
    },
    error: {
      fileApiNotSupported: 'A File API-k nem támogatják maradéktalanul ezt a böngészőt.'
    }
  },
  inform: {
    error: 'Hiba történt:',
    warn: 'Kérjük, ne feledje, hogy:'
  }
};


text:
/*!
 * \file dcxlistview.h
 * \brief blah
 *
 * blah
 *
 * \author David Legault ( clickhere at scriptsdb dot org )
 * \version 1.0
 *
 * \b Revisions
 *
 * © ScriptsDB.org - 2006
 */

#ifndef _DCXLISTVIEW_H_
#define _DCXLISTVIEW_H_

#include "defines.h"
#include "Classes/dcxcontrol.h"
#include "Classes/dcxprogressbar.h"
#include "Classes/tinyxml/tinyxml.h"

class DcxDialog;

#define LVIS_BOLD       0x00100 //!< ListView Caption Bold Style
#define LVIS_UNDERLINE  0x00200 //!< ListView Caption Underline Style
#define LVIS_COLOR      0x00400 //!< ListView Caption Color Style
#define LVIS_BGCOLOR    0x00800 //!< ListView Caption Background Color Style
#define LVIS_PBAR       0x01000 //!< ListView ProgressBar Style
#define LVIS_ITALIC     0x02000 //!< ListView Caption Italic Style
#define LVIS_HASHITEM	0x04000 //!< ListView Item takes it's text from a hashtable. (text is `table item`) (to be replaced by LVIS_HASHTABLE)
#define LVIS_HASHNUMBER	0x08000 //!< ListView Item takes it's text from a hashtable. (text is `table N`) (to be replaced by LVIS_HASHTABLE)
#define LVIS_XML		0x10000 //!< ListView Item takes it's text from a xml file. (text is `dataset_name filename`) (adds all items in dataset_name)
#define LVIS_HASHTABLE	0x20000	//!< ListView Item takes it's text from a hashtable. (text is `+flags hashtable (N|N1,N2|item)`) (can add multiple items)
#define LVIS_WINDOW		0x40000	//!< ListView Item takes it's text from a custom window. (text is `+flags window (N|N1,N2)`) (can add multiple items)
#define LVIS_CONTROL	0x80000	//!< ListView Item takes it's text from another DCX control. (text is `+flags dialog id (N|N1,N2)`) (can add multiple items)
// +flags mentioned above tell the parser extra details about how the items are added.
// +	:	single item is added as text only (N)
// +a	:	items added include all info for the item not just it's text.
// +n	:	Numeric range supplied N1,N2
// +i	:	item name supplied (for hashtable)
// +A	:	adds ALL items starting at N
#define LVIMF_ALLINFO	0x01
#define LVIMF_NUMERIC	0x02
#define LVIMF_NAMED		0x04
#define LVIMF_ADDALL	0x08

#define LVSS_ASC        0x01   //!< ListView Sort Ascending Style
#define LVSS_DESC       0x02   //!< ListView Sort Descending Style
#define LVSS_NUMERIC    0x04   //!< ListView Sort Numeric Style
#define LVSS_ALPHA      0x08   //!< ListView Sort Alpha-Numeric Style
#define LVSS_CUSTOM     0x10   //!< ListView Sort Custom Style
#define LVSS_CASE       0x20   //!< ListView Sort Case-sensitive Style

#define LVCS_TEXT       0x01   //!< ListView Text Color Style
#define LVCS_BKGTEXT    0x02   //!< ListView Background Text Color Style
#define LVCS_BKG        0x04   //!< ListView Background Color Style
#define LVCS_OUTLINE    0x08   //!< ListView Selection Outline Color Style

#define LVSEARCH_W 0x01 //!< ListView WildCard Search
#define LVSEARCH_R 0x02 //!< ListView Regex Search
#define LVSEARCH_E 0x04 //!< ListView Exact Match

#define LVSCW_AUTOSIZE_MAX	-3	// Max of LVSCW_AUTOSIZE & LVSCW_AUTOSIZE_USEHEADER

/*!
 * \brief blah
 *
 * blah
 */

typedef struct tagDCXLVSORT {

  TString tsCustomAlias;  //!< Custom Sorting Alias
  UINT iSortFlags;        //!< Sorting Flags
  HWND m_Hwnd;            //!< ListView Handle
  int nColumn;            //!< Sorting Column

} DCXLVSORT,*LPDCXLVSORT;

typedef struct tagDCXLVRENDERINFO {
	DWORD		m_dFlags;	//!< Render flags (bold etc..)
	COLORREF	m_cText;	//!< Text Colour
	COLORREF	m_cBg;		//!< Background Colour.
} DCXLVRENDERINFO, *LPDCXLVRENDERINFO;

typedef std::vector<LPDCXLVRENDERINFO> VectorOfRenderInfo;

/*!
 * \brief blah
 *
 * blah
 */

typedef struct tagDCXLVITEM {
	TString tsTipText;	//!< Tooltip text
	TString tsMark;		// Marked text
	DcxControl *pbar;
	int iPbarCol;
	VectorOfRenderInfo	vInfo;	//!< Render Info for each colum
} DCXLVITEM,*LPDCXLVITEM;

/*!
 * \brief blah
 *
 * blah
 */

class DcxListView : public DcxControl {

public:

	DcxListView( UINT ID, DcxDialog * p_Dialog, HWND mParentHwnd, RECT * rc, TString & styles );
	virtual ~DcxListView( );

	LRESULT PostMessage( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & bParsed );
	LRESULT ParentMessage( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & bParsed );

	void parseInfoRequest( TString & input, char * szReturnValue );
	void parseCommandRequest( TString & input );
	void parseControlStyles( TString & styles, LONG * Styles, LONG * ExStyles, BOOL * bNoTheme );
	static void parseListviewExStyles( const TString & styles, LONG * ExStyles );

	HIMAGELIST getImageList( const int iImageList );
	void setImageList( HIMAGELIST himl, const int iImageList );
	static HIMAGELIST createImageList( const BOOL bIcons );

	BOOL isListViewStyle( const long dwView ) const;

	int getColumnCount( ) const;

	static LRESULT CALLBACK EditLabelProc( HWND mHwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );

	static int CALLBACK sortItemsEx( LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort );

	inline TString getType( ) { return TString( "listview" ); };

	int getTopIndex( ) const;
	int getBottomIndex( ) const;
	TString getStyles(void);

protected:

	WNDPROC m_OrigEditProc; //!< Label Edit Control Orignal Procedure

	static UINT parseIconFlagOptions( const TString & flags );
	static UINT parseItemFlags( const TString & flags );
	static UINT parseHeaderFlags( const TString & flags );
	static INT parseHeaderFlags2( const TString & flags );
	static INT parseHeaderFlags2( const XSwitchFlags & xflags );
	static UINT parseSortFlags( const TString & flags );
	static UINT parseColorFlags( const TString & flags );
	static UINT parseImageFlags( const TString & flags );
	static UINT parseGroupFlags( const TString & flags );
	static UINT parseGroupState( const TString & flags );

	BOOL matchItemText( const int nItem, const int nSubItem, const TString * search, const UINT SearchType );

	void autoSize(const int nColumn, const TString &flags);
	void autoSize(const int nColumn, const int iFlags );

	BOOL m_bDrag; //!< Dragging Items ?

private:
	DcxControl* CreatePbar(LPLVITEM lvi, const TString &style);
	void ScrollPbars(const int row);
	void UpdateScrollPbars(void);
	HIMAGELIST initImageList(const int iImageList);
	bool xmlLoadListview(const int nPos, const TString &dataset, TString &filename);
	void xmlSetItem(const int nItem, const int nSubItem, const TiXmlElement *xNode, LPLVITEM lvi, LPDCXLVITEM lpmylvi);
	bool ctrlLoadListview(const int nPos, const TString &tsData);
	bool xLoadListview(const int nPos, const TString &tsData, const char *sTest, const char *sCount, const char *sGet, const char *sGetNamed);
	void massSetItem(const int nPos, const TString &input);
	static UINT parseMassItemFlags( const TString & flags );
	static void parseText2Item(const TString & tsTxt, TString & tsItem, const TString &tsData);
	//
	HFONT m_hItemFont; // Font used for specific item changes.
	HFONT m_hOldItemFont; // Font used for specific item changes.
	int m_iSelectedItem;
	int m_iSelectedSubItem;
};

#endif // _DCXLISTVIEW_H_


text:
angular.module('fleetonrails.controllers.group_car_fuel_edit-controller', [])

    .controller('groupFuelEditCtrl', ['$scope', 'FuelService', 'GroupsCarsService','$location', '$routeParams','GroupsService', '$timeout',
        function ($scope, FuelService,GroupsCarsService, $location, $routeParams,GroupsService,$timeout) {

            $scope.options = [{ name: "True", id: 1 }, { name: "False", id: 2 }];
            $scope.selectedOption = $scope.options[1];

            $scope.optionsFuel = [{ name: "Petrol", id: 1 }, { name: "Diesel", id: 2 }];
            $scope.selectedOptionFuel = $scope.optionsFuel[1];

            $scope.alerts = [];

            getCar = function (id) {
                GroupsCarsService.show(id, $routeParams.car_id,function (data) {
                    $scope.car = data['car'];
                });
            };

            $scope.closeAlert = function(index) {
                $scope.alerts.splice(index, 1);
            };

            getFuelEntry = function(id) {
                FuelService.show(id,$routeParams.fuel_id,function (data) {
                    console.log('Got the fuel entry ', data)
                    $scope.fuel = data;
                });

            };

            $scope.getGroup = function(id){
                GroupsService.show(id,function(data){
                    console.log(data)
                    $scope.group = data['group'];
                })
            };

            $scope.updateFuel = function() {
                var attributes = {
                    fuel_entry: {
                        odometer: $scope.fuel.fuel_entry.odometer,
                        liters: $scope.fuel.fuel_entry.liters,
                        price: $scope.fuel.fuel_entry.price,
                        fuel_type: $scope.selectedOptionFuel.name.toLocaleUpperCase(),
                        filling_station: $scope.fuel.fuel_entry.filling_station,
                        date: $scope.fuel.fuel_entry.date,
                        filled_tank: $scope.selectedOption.name.toLocaleUpperCase(),
                        location_attributes:{
                            address: $scope.fuel.fuel_entry.location.address
                        }
                    }
                };
                FuelService.update($routeParams.car_id,$routeParams.fuel_id,attributes,function(data){
                    $location.path('/group/' + $routeParams.id + '/car/' + $routeParams.car_id +'/fuel');
                },function(data){
                    $scope.alerts.push({msg: 'Missing values', type: 'danger'});
                })
            }

            $scope.today = function() {
                $scope.dt = new Date();
            };
            $scope.today();

            $scope.showWeeks = true;
            $scope.toggleWeeks = function () {
                $scope.showWeeks = ! $scope.showWeeks;
            };

            $scope.clear = function () {
                $scope.dt = null;
            };

            $scope.open = function($event) {
                $event.preventDefault();
                $event.stopPropagation();

                $scope.opened = true;
            };

            $scope.dateOptions = {
                'year-format': "'yy'",
                'starting-day': 1
            };

            $scope.formats = ['dd-MMMM-yyyy', 'yyyy/MM/dd', 'shortDate'];
            $scope.format = $scope.formats[0];

            $scope.fuel_options = {thickness: 5, mode: "gauge", total: 100};

            if ($routeParams && $routeParams.id) {
                getFuelEntry($routeParams.car_id);
                getCar($routeParams.id);
                $scope.getGroup($routeParams.id)
            }

        }]);/**

/**
 * Created by krystian on 23/05/2014.
 */


text:
<?php

namespace AppBundle\Controller;

use AppBundle\Entity\User;
use DateTime;
use Exception;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class SecurityController extends Controller
{
    /**
     * @Route("/login", name="security_login_form")
     */
    public function loginAction(Request $request)
    {

        // Getting message from session (if successfully registered)
        $session = $this->getRequest()->getSession();
        $message_text = $session->get('regsuccess');
        $registered_email = $session->get('regemail');
        $session->remove('regsuccess');
        $session->remove('regemail');

        $hideRegistrationButton = 0;
        if ($this->container->hasParameter('hide_registration_button')) {
            $hideRegistrationButton = ($this->container->getParameter('hide_registration_button')==1)?1:0;
        }

        $helper = $this->get('security.authentication_utils');

        return $this->render('security/login.html.twig', array(
            // last username entered by the user (if any)
            'last_username' => $helper->getLastUsername(),
            // last authentication error (if any)
            'error' => $helper->getLastAuthenticationError(),
            'message_text' => $message_text,
            'registered_email' => $registered_email,
            'hide_registration_button' => $hideRegistrationButton,
        ));

    }

    /**
     * @Route("/sign-up", name="security_sign_up_form")
     */
    public function signUpAction($error = array())
    {
        $request = $this->getRequest();
        $err = array();
        $error_text = "";

        $hideRegistrationButton = 0;
        if ($this->container->hasParameter('hide_registration_button')) {
            $hideRegistrationButton = ($this->container->getParameter('hide_registration_button')==1)?1:0;
        }

        $phash=null;
        $pemail = null;

        if ($hideRegistrationButton == 1) {
            $phash = $request ->get("i");
            $pemail = rawurldecode( $request ->get("email"));

            $iKeyService = $this->get("i_key_service");

            $iKey = $iKeyService ->findIKey( $pemail, $phash );

            $securityService = $this->get("security_service");

            $foundUser = $securityService->findUserByEmail( $pemail );

            if ( !$iKey || is_object($foundUser) ) {

                return $this->render('security/sign_up_wrong_url.html.twig', array(
                    'message' => 'Устаревшая или не существующая ссылка!',
                ));
            }

        }

        if (!empty($error)) {
            $error_text = "Have some errors!";
        }

        return $this->render('security/sign_up.html.twig', array(
            'last_request' => $request->request,
            'error_text' => $error_text,
            'errors' => $error,
            'hash' => $phash,
            'email' => $pemail,
        ));

    }

    /**
     * @Route("/sign-up-check", name="security_sign_up_check")
     */
    public function signUpCheckAction()
    {
        $request = $this->getRequest();
        $validator = $this->get('validator');

        $password = $request->request->get("_password");
        $retype_password = $request->request->get("_retype_password");
        $email = $request->request->get("_email");
        $username = $email;

        $errors = array();
        $securityService = $this->get("security_service");
        $user = $securityService->findUsername($username);
        if ( isset($user) ) {
            $errors["username"] = "Username already used!";
        }

        if ( $retype_password !== $password ) {
            $errors["retype_password"] = "The passwords does not match!";
        }

        $user = new User();
        $user -> setFirstname($request->request->get("_firstname"));
        $user -> setLastname($request->request->get("_lastname"));
        //$user -> setUsername($request->request->get("_username"));
        $user -> setPassword($password);
        $user -> setEmail($email);
        $user -> setUsername($email);
        $user -> setRoles(array());

        $error = $validator->validate($user);
        foreach ($error as $val) {
            $errors[$val->getPropertyPath()] = $val->getMessage();
        }

        if ( (count($errors)>0) ) {
            return $this->forward("AppBundle:Security:signUp", array('error' => $errors) );

        } else {
            // encoding password
            $factory = $this->get('security.encoder_factory');
            $encoder = $factory->getEncoder($user);
            $password = $encoder->encodePassword($request->request->get("_password"), $user->getSalt());
            $user->setPassword($password);

            $em = $this->getDoctrine()->getEntityManager();
            $em->persist($user);
            $em->flush();

            //sending message throug session
            $message_text = "You have successfully registered ".$email.". Now sign in and start analyzing influencers!";
            $session = $this->getRequest()->getSession();
            $session->set('regsuccess', $message_text);
            $session->set('regemail', $email);

            return $this->redirect($this->generateUrl('security_login_form'));
        }
    }

    /**
     * This is the route the login form submits to.
     *
     * But, this will never be executed. Symfony will intercept this first
     * and handle the login automatically. See form_login in app/config/security.yml
     *
     * @Route("/login_check", name="security_login_check")
     */
    public function loginCheckAction()
    {
        throw new Exception('This should never be reached!');
    }

    /**
     * This is the route the user can use to logout.
     *
     * But, this will never be executed. Symfony will intercept this first
     * and handle the logout automatically. See logout in app/config/security.yml
     *
     * @Route("/logout", name="security_logout")
     */
    public function logoutAction()
    {
        throw new Exception('This should never be reached!');
    }

    /*
     * Checking if email registered
     *
     * @Route("/sign-up/check-email", name="check_email")
     */
    public function checkEmailAction(Request $request) {

        $username = $request ->get("email");

        if (isset($username)) {
            $securityService = $this->get("security_service");
            $user = $securityService->findUsername($username);
        } else {
            $user = null;
        }

        $result = array( "email" => $username, "result" => isset($user) );

        //return new Response(json_encode($result), 200, array('Content-Type', 'application/json'));

        $response = new Response();
        $response->setContent( json_encode($result) );
        $response->headers->set('Content-Type', 'application/json');

        return $response;
    }

    /*
     * Forgot password
     *
     * @Route("/forgot-password", name="forgot_password")
     */
    public function forgotPasswordAction(Request $request) {

        $username = $request ->get("_email");
        $email = '';

        if ( ($request->getMethod('post') == 'POST') && isset($username) ) {
            $securityService = $this->get("security_service");
            $user = $securityService->findUsername($username);
        } else {
            $user = null;
        }

        if (is_object($user)) {
            $email = trim($user->getEmail());
        }

        $success_message_text = null;
        $error_message_text = null;

        if ( filter_var($email, FILTER_VALIDATE_EMAIL) ) {

            $securityService = $this->get("security_service");
            $hash = $securityService ->getForgotPasswordHash($user, $this->container->getParameter('secret'));

            $forgot_link = $this->generateUrl('change_password',array(),true) .
                    '?email=' . rawurlencode($email) .
                    '&h=' . $hash ;

            $email_from_name = $this->container->getParameter('support_email_from_name');
            $email_from = $this->container->getParameter('support_email_from');
            $email_replay_to = $this->container->getParameter('support_email_replay_to');
            $email_footer_message = $this->container->getParameter('support_email_footer_message');
            $base_url = $this->container->getParameter('base_url');
            $base_url_name = $this->container->getParameter('base_url_name');

            $mail_params = array(
                'fullname' => $user->getFirstName().' '.$user->getLastName(),
                'forgot_link' => $forgot_link,
                'email_footer_message' => $email_footer_message,
                'base_url' => $base_url,
                'base_url_name' => $base_url_name,
            );

            $message = $this->get('mail_manager');
            $message->sendEmail('emails/forgot_password_email.html.twig', $mail_params, $email, $email_from, $email_from_name, $email_replay_to);

            $success_message_text = 'На указанную почту было отправлено письмо для изменения пароля.';
        } else if (isset($username)) {

            $error_message_text = 'User not found!';
        }

        return $this->render('security/forgot_password.html.twig', array(
            'success_message_text' => $success_message_text,
            'error_message_text' => $error_message_text,
            'username' => $username,
        ));
    }

    /*
     * Change password
     *
     * @Route("/change-password", name="change_password")
     */
    public function changePasswordAction(Request $request) {

        $em = $this->getDoctrine()->getEntityManager();
        $email = rawurldecode($request ->get("email"));
        $hash = $request ->get("h");

        $newPassword = $request ->get("_new_password");
        $retypePassword = $request ->get("_retype_password");

        $resetGranted = false;
        $resetSuccess = false;

        $success_message_text = '';
        $error_message_text = '';
        $username = '';

        $securityService = $this->get("security_service");

        if ( isset($email) && isset($hash) ) {
            $user = $securityService->findUserByEmail($email);
        } else {
            $user = null;
        }

        $now = new DateTime();

        if (is_object($user)) {
            $forgotPasswordHash = $user->getForgotPasswordHash();
            $forgotPasswordExpireDatetime = $user->getForgotPasswordExpireDatetime();
            $username = $user->getFirstname() . " " . $user->getLastname();

            if ( ($forgotPasswordHash == $hash) && isset($forgotPasswordExpireDatetime) && ($forgotPasswordExpireDatetime >= $now) ) {
                $resetGranted = true;
            }
        }

        if ($resetGranted && isset($newPassword) && (strlen($newPassword)>0) && ($newPassword == $retypePassword)) {

            $factory = $this->get('security.encoder_factory');
            $encoder = $factory->getEncoder($user);
            $password = $encoder->encodePassword($newPassword, $user->getSalt());
            $user->setPassword($password);
            $user->setForgotPasswordHash(null);
            $user->setForgotPasswordExpireDatetime(null);

            $em ->persist($user);
            $em ->flush();

            $resetSuccess = true;
        }

        if ($resetSuccess) {
            $success_message_text = 'The password is successfully changed!';
        } else if (!$resetGranted) {
            $error_message_text = 'This link is wrong or expired!';
        }

        return $this->render('security/forgot_password_reset.html.twig', array(
            'success_message_text' => $success_message_text,
            'error_message_text' => $error_message_text,
            'username' => $username,
        ));
    }
}


text:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<TITLE
>Here Documents</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.7"><LINK
REL="HOME"
TITLE="Advanced Bash-Scripting Guide"
HREF="index.html"><LINK
REL="UP"
TITLE="Advanced Topics"
HREF="part5.html"><LINK
REL="PREVIOUS"
TITLE="Globbing"
HREF="globbingref.html"><LINK
REL="NEXT"
TITLE="Here Strings"
HREF="x17837.html">

Advanced Bash-Scripting Guide:

Prev		Next

Chapter 19. Here Documents

Here and now, boys.

--Aldous Huxley, Island

A here document is a special-purpose
	code block. It uses a form of I/O
	redirection to feed a command list to
	an interactive program or a command, such as ftp, cat,
	or the ex text editor.

COMMAND <<InputComesFromHERE
...
...
...
InputComesFromHERE

A limit string delineates (frames)
	the command list.  The special symbol << precedes
	the limit string.  This has the effect of redirecting the output
	of a command block into the <TT
CLASS="FILENAME"
>stdin</TT
> of the program
	or command. It is similar to <TT
CLASS="USERINPUT"
>interactive-program <
	command-file</TT
>, where <TT
CLASS="FILENAME"
>command-file</TT
>
	contains

command #1
command #2
...

The here document equivalent looks
        like this:

interactive-program <<LimitString
command #1
command #2
...
LimitString

Choose a limit string sufficiently
	unusual that it will not occur anywhere in the command list and
	confuse matters.

Note that here documents may sometimes
	be used to good effect with non-interactive utilities and commands,
	such as, for example, wall.

Example 19-1. broadcast: Sends message to everyone
	logged in

#!/bin/bash

wall <<zzz23EndOfMessagezzz23
E-mail your noontime orders for pizza to the system administrator.
    (Add an extra dollar for anchovy or mushroom topping.)
# Additional message text goes here.
# Note: 'wall' prints comment lines.
zzz23EndOfMessagezzz23

# Could have been done more efficiently by
#         wall <message-file
#  However, embedding the message template in a script
#+ is a quick-and-dirty one-off solution.

exit

Even such unlikely candidates as the vi
        text editor lend themselves to here
        documents.

Example 19-2. dummyfile: Creates a 2-line dummy
	file

#!/bin/bash

# Noninteractive use of 'vi' to edit a file.
# Emulates 'sed'.

E_BADARGS=85

if [ -z "$1" ]
then
  echo "Usage: `basename $0` filename"
  exit $E_BADARGS
fi

TARGETFILE=$1

# Insert 2 lines in file, then save.
#--------Begin here document-----------#
vi $TARGETFILE <<x23LimitStringx23
i
This is line 1 of the example file.
This is line 2 of the example file.
^[
ZZ
x23LimitStringx23
#----------End here document-----------#

#  Note that ^[ above is a literal escape
#+ typed by Control-V <Esc>.

#  Bram Moolenaar points out that this may not work with 'vim'
#+ because of possible problems with terminal interaction.

exit

        The above script could just as effectively have been implemented with
	ex, rather than
	vi. Here
	documents containing a list of ex
	commands are common enough to form their own category, known as
	ex scripts.

#!/bin/bash
#  Replace all instances of "Smith" with "Jones"
#+ in files with a ".txt" filename suffix.

ORIGINAL=Smith
REPLACEMENT=Jones

for word in $(fgrep -l $ORIGINAL *.txt)
do
  # -------------------------------------
  ex $word <<EOF
  :%s/$ORIGINAL/$REPLACEMENT/g
  :wq
EOF
  # :%s is the "ex" substitution command.
  # :wq is write-and-quit.
  # -------------------------------------
done

Analogous to "ex scripts" are cat
        scripts.

Example 19-3. Multi-line message using cat

#!/bin/bash

#  'echo' is fine for printing single line messages,
#+  but somewhat problematic for for message blocks.
#   A 'cat' here document overcomes this limitation.

cat <<End-of-message
-------------------------------------
This is line 1 of the message.
This is line 2 of the message.
This is line 3 of the message.
This is line 4 of the message.
This is the last line of the message.
-------------------------------------
End-of-message

#  Replacing line 7, above, with
#+   cat > $Newfile <<End-of-message
#+       ^^^^^^^^^^
#+ writes the output to the file $Newfile, rather than to stdout.

exit 0

#--------------------------------------------
# Code below disabled, due to "exit 0" above.

# S.C. points out that the following also works.
echo "-------------------------------------
This is line 1 of the message.
This is line 2 of the message.
This is line 3 of the message.
This is line 4 of the message.
This is the last line of the message.
-------------------------------------"
# However, text may not include double quotes unless they are escaped.

The <TT
CLASS="OPTION"
>-</TT
> option to mark a here document limit string
	(<TT
CLASS="USERINPUT"
><<-LimitString</TT
>) suppresses leading
	tabs (but not spaces) in the output. This may be useful in making
	a script more readable.

Example 19-4. Multi-line message, with tabs suppressed

#!/bin/bash
# Same as previous example, but...

#  The - option to a here document <<-
#+ suppresses leading tabs in the body of the document,
#+ but *not* spaces.

cat <<-ENDOFMESSAGE
	This is line 1 of the message.
	This is line 2 of the message.
	This is line 3 of the message.
	This is line 4 of the message.
	This is the last line of the message.
ENDOFMESSAGE
# The output of the script will be flush left.
# Leading tab in each line will not show.

# Above 5 lines of "message" prefaced by a tab, not spaces.
# Spaces not affected by   <<-  .

# Note that this option has no effect on *embedded* tabs.

exit 0

A here document supports parameter and
	command substitution.  It is therefore possible to pass different
	parameters to the body of the here document, changing its output
	accordingly.

Example 19-5. Here document with replaceable parameters

#!/bin/bash
# Another 'cat' here document, using parameter substitution.

# Try it with no command-line parameters,   ./scriptname
# Try it with one command-line parameter,   ./scriptname Mortimer
# Try it with one two-word quoted command-line parameter,
#                           ./scriptname "Mortimer Jones"

CMDLINEPARAM=1     #  Expect at least command-line parameter.

if [ $# -ge $CMDLINEPARAM ]
then
  NAME=$1          #  If more than one command-line param,
                   #+ then just take the first.
else
  NAME="John Doe"  #  Default, if no command-line parameter.
fi

RESPONDENT="the author of this fine script"

cat <<Endofmessage

Hello, there, $NAME.
Greetings to you, $NAME, from $RESPONDENT.

# This comment shows up in the output (why?).

Endofmessage

# Note that the blank lines show up in the output.
# So does the comment.

exit

This is a useful script containing a here
        document with parameter substitution.

Example 19-6. Upload a file pair to Sunsite incoming
	  directory

#!/bin/bash
# upload.sh

#  Upload file pair (Filename.lsm, Filename.tar.gz)
#+ to incoming directory at Sunsite/UNC (ibiblio.org).
#  Filename.tar.gz is the tarball itself.
#  Filename.lsm is the descriptor file.
#  Sunsite requires "lsm" file, otherwise will bounce contributions.

E_ARGERROR=85

if [ -z "$1" ]
then
  echo "Usage: `basename $0` Filename-to-upload"
  exit $E_ARGERROR
fi

Filename=`basename $1`           # Strips pathname out of file name.

Server="ibiblio.org"
Directory="/incoming/Linux"
#  These need not be hard-coded into script,
#+ but may instead be changed to command-line argument.

Password="your.e-mail.address"   # Change above to suit.

ftp -n $Server <<End-Of-Session
# -n option disables auto-logon

user anonymous "$Password"       #  If this doesn't work, then try:
                                 #  quote user anonymous "$Password"
binary
bell                             # Ring 'bell' after each file transfer.
cd $Directory
put "$Filename.lsm"
put "$Filename.tar.gz"
bye
End-Of-Session

exit 0

Quoting or escaping the "limit string" at the
        head of a here document disables parameter substitution within its
	body. The reason for this is that quoting/escaping the
	limit string effectively escapes the $,
	`, and \ special characters, and causes them to
	be interpreted literally. (Thank you, Allen Halsey, for pointing
	this out.)

Example 19-7. Parameter substitution turned off

#!/bin/bash
#  A 'cat' here-document, but with parameter substitution disabled.

NAME="John Doe"
RESPONDENT="the author of this fine script"

cat <<'Endofmessage'

Hello, there, $NAME.
Greetings to you, $NAME, from $RESPONDENT.

Endofmessage

#   No parameter substitution when the "limit string" is quoted or escaped.
#   Either of the following at the head of the here document would have
#+  the same effect.
#   cat <<"Endofmessage"
#   cat <<\Endofmessage

#   And, likewise:

cat <<"SpecialCharTest"

Directory listing would follow
if limit string were not quoted.
`ls -l`

Arithmetic expansion would take place
if limit string were not quoted.
$((5 + 3))

A a single backslash would echo
if limit string were not quoted.
\\

SpecialCharTest

exit

Disabling parameter substitution permits outputting literal text.
        Generating scripts or even program code is one use for this.

Example 19-8. A script that generates another script

#!/bin/bash
# generate-script.sh
# Based on an idea by Albert Reiner.

OUTFILE=generated.sh         # Name of the file to generate.

# -----------------------------------------------------------
# 'Here document containing the body of the generated script.
(
cat <<'EOF'
#!/bin/bash

echo "This is a generated shell script."
#  Note that since we are inside a subshell,
#+ we can't access variables in the "outside" script.

echo "Generated file will be named: $OUTFILE"
#  Above line will not work as normally expected
#+ because parameter expansion has been disabled.
#  Instead, the result is literal output.

a=7
b=3

let "c = $a * $b"
echo "c = $c"

exit 0
EOF
) > $OUTFILE
# -----------------------------------------------------------

#  Quoting the 'limit string' prevents variable expansion
#+ within the body of the above 'here document.'
#  This permits outputting literal strings in the output file.

if [ -f "$OUTFILE" ]
then
  chmod 755 $OUTFILE
  # Make the generated file executable.
else
  echo "Problem in creating file: \"$OUTFILE\""
fi

#  This method also works for generating
#+ C programs, Perl programs, Python programs, Makefiles,
#+ and the like.

exit 0

        It is possible to set a variable from the output of a here document.
	This is actually a devious form of command substitution.

variable=$(cat <<SETVAR
This variable
runs over multiple lines.
SETVAR
)

echo "$variable"

A here document can supply input to a function in the same
        script.

Example 19-9. Here documents and functions

#!/bin/bash
# here-function.sh

GetPersonalData ()
{
  read firstname
  read lastname
  read address
  read city
  read state
  read zipcode
} # This certainly appears to be an interactive function, but . . .

# Supply input to the above function.
GetPersonalData <<RECORD001
Bozo
Bozeman
2726 Nondescript Dr.
Bozeman
MT
21226
RECORD001

echo
echo "$firstname $lastname"
echo "$address"
echo "$city, $state $zipcode"
echo

exit 0

It is possible to use : as a dummy command
        accepting output from a here document. This, in effect, creates an
	"anonymous" here document.

Example 19-10. "Anonymous" Here Document

#!/bin/bash

: <<TESTVARIABLES
${HOSTNAME?}${USER?}${MAIL?}  # Print error message if one of the variables not set.
TESTVARIABLES

exit $?

A variation of the above technique permits "commenting
        out" blocks of code.

Example 19-11. Commenting out a block of code

#!/bin/bash
# commentblock.sh

: <<COMMENTBLOCK
echo "This line will not echo."
This is a comment line missing the "#" prefix.
This is another comment line missing the "#" prefix.

&*@!!++=
The above line will cause no error message,
because the Bash interpreter will ignore it.
COMMENTBLOCK

echo "Exit value of above \"COMMENTBLOCK\" is $?."   # 0
# No error shown.
echo

#  The above technique also comes in useful for commenting out
#+ a block of working code for debugging purposes.
#  This saves having to put a "#" at the beginning of each line,
#+ then having to go back and delete each "#" later.
#  Note that the use of of colon, above, is optional.

echo "Just before commented-out code block."
#  The lines of code between the double-dashed lines will not execute.
#  ===================================================================
: <<DEBUGXXX
for file in *
do
 cat "$file"
done
DEBUGXXX
#  ===================================================================
echo "Just after commented-out code block."

exit 0

######################################################################
#  Note, however, that if a bracketed variable is contained within
#+ the commented-out code block,
#+ then this could cause problems.
#  for example:

#/!/bin/bash

  : <<COMMENTBLOCK
  echo "This line will not echo."
  &*@!!++=
  ${foo_bar_bazz?}
  $(rm -rf /tmp/foobar/)
  $(touch my_build_directory/cups/Makefile)
COMMENTBLOCK

$ sh commented-bad.sh
commented-bad.sh: line 3: foo_bar_bazz: parameter null or not set

# The remedy for this is to strong-quote the 'COMMENTBLOCK' in line 49, above.

  : <<'COMMENTBLOCK'

# Thank you, Kurt Pfeifle, for pointing this out.

Yet another twist of this nifty trick makes
        "self-documenting" scripts possible.

Example 19-12. A self-documenting script

#!/bin/bash
# self-document.sh: self-documenting script
# Modification of "colm.sh".

DOC_REQUEST=70

if [ "$1" = "-h"  -o "$1" = "--help" ]     # Request help.
then
  echo; echo "Usage: $0 [directory-name]"; echo
  sed --silent -e '/DOCUMENTATIONXX$/,/^DOCUMENTATIONXX$/p' "$0" |
  sed -e '/DOCUMENTATIONXX$/d'; exit $DOC_REQUEST; fi

: <<DOCUMENTATIONXX
List the statistics of a specified directory in tabular format.
---------------------------------------------------------------
The command-line parameter gives the directory to be listed.
If no directory specified or directory specified cannot be read,
then list the current working directory.

DOCUMENTATIONXX

if [ -z "$1" -o ! -r "$1" ]
then
  directory=.
else
  directory="$1"
fi

echo "Listing of "$directory":"; echo
(printf "PERMISSIONS LINKS OWNER GROUP SIZE MONTH DAY HH:MM PROG-NAME\n" \
; ls -l "$directory" | sed 1d) | column -t

exit 0

Using a cat script is an
        alternate way of accomplishing this.

DOC_REQUEST=70

if [ "$1" = "-h"  -o "$1" = "--help" ]     # Request help.
then                                       # Use a "cat script" . . .
  cat <<DOCUMENTATIONXX
List the statistics of a specified directory in tabular format.
---------------------------------------------------------------
The command-line parameter gives the directory to be listed.
If no directory specified or directory specified cannot be read,
then list the current working directory.

DOCUMENTATIONXX
exit $DOC_REQUEST
fi

See also Example A-28, Example A-40,
        Example A-41, and Example A-42 for more examples
        of self-documenting scripts.

Here documents create temporary files, but these
	    files are deleted after opening and are not accessible to
	    any other process.

<TT
CLASS="PROMPT"
>bash$ </TT
><TT
CLASS="USERINPUT"
>bash -c 'lsof -a -p $$ -d0' << EOF</TT
>
<TT
CLASS="PROMPT"
>> </TT
><TT
CLASS="USERINPUT"
>EOF</TT
>
<TT
CLASS="COMPUTEROUTPUT"
>lsof    1213 bozo    0r   REG    3,5    0 30386 /tmp/t1213-0-sh (deleted)</TT
>

Some utilities will not work inside a
	  here document.

The closing limit string,
	  on the final line of a here document, must start in the
	  first character position. There can
	  be no leading whitespace. Trailing
	  whitespace after the limit string likewise causes unexpected
	  behavior. The whitespace prevents the limit string from being
	  recognized.

          [1]

#!/bin/bash

echo "----------------------------------------------------------------------"

cat <<LimitString
echo "This is line 1 of the message inside the here document."
echo "This is line 2 of the message inside the here document."
echo "This is the final line of the message inside the here document."
     LimitString
#^^^^Indented limit string. Error! This script will not behave as expected.

echo "----------------------------------------------------------------------"

#  These comments are outside the 'here document',
#+ and should not echo.

echo "Outside the here document."

exit 0

echo "This line had better not echo."  # Follows an 'exit' command.

Some people very cleverly use a
          single ! as a limit string. But, that's not
          necessarily a good idea.

# This works.
cat <<!
Hello!
! Three more exclamations !!!
!

# But . . .
cat <<!
Hello!
Single exclamation point follows!
!
!
# Crashes with an error message.

# However, the following will work.
cat <<EOF
Hello!
Single exclamation point follows!
!
EOF
# It's safer to use a multi-character limit string.

For those tasks too complex for a here
	  document, consider using the
	  <TT
CLASS="REPLACEABLE"
>expect</TT
> scripting language, which
	  was specifically designed for feeding input into interactive
	  programs.

Notes

[1]
Except, as Dennis Benzinger points out,
          if using
          <<- to suppress
          tabs.

Prev	Home	Next

Globbing	Up	Here Strings


text:
<?php
declare(strict_types=1);

namespace Cake\Datasource;

use Cake\ORM\TableRegistry;
use InvalidArgumentException;

/**
 * Class FactoryLocator
 */
class FactoryLocator
{
    /**
     * A list of model factory functions.
     *
     * @var callable[]
     */
    protected static $_modelFactories = [];

    /**
     * Register a callable to generate repositories of a given type.
     *
     * @param string $type The name of the repository type the factory function is for.
     * @param callable $factory The factory function used to create instances.
     * @return void
     */
    public static function add(string $type, callable $factory): void
    {
        static::$_modelFactories[$type] = $factory;
    }

    /**
     * Drop a model factory.
     *
     * @param string $type The name of the repository type to drop the factory for.
     * @return void
     */
    public static function drop(string $type): void
    {
        unset(static::$_modelFactories[$type]);
    }

    /**
     * Get the factory for the specified repository type.
     *
     * @param string $type The repository type to get the factory for.
     * @throws \InvalidArgumentException If the specified repository type has no factory.
     * @return callable The factory for the repository type.
     */
    public static function get(string $type): callable
    {
        if (!isset(static::$_modelFactories['Table'])) {
            static::$_modelFactories['Table'] = [TableRegistry::getTableLocator(), 'get'];
        }

        if (!isset(static::$_modelFactories[$type])) {
            throw new InvalidArgumentException(sprintf(
                'Unknown repository type "%s". Make sure you register a type before trying to use it.',
                $type
            ));
        }

        return static::$_modelFactories[$type];
    }
}