<commit_before>// Copyright (c) 2010 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 "base/command_line.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/debugger/devtools_client_host.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/debugger/devtools_window.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "net/test/test_server.h"

namespace {

// Used to block until a dev tools client window's browser is closed.
class BrowserClosedObserver : public NotificationObserver {
 public:
  explicit BrowserClosedObserver(Browser* browser) {
    registrar_.Add(this, NotificationType::BROWSER_CLOSED,
                   Source<Browser>(browser));
    ui_test_utils::RunMessageLoop();
  }

  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    MessageLoopForUI::current()->Quit();
  }

 private:
  NotificationRegistrar registrar_;
  DISALLOW_COPY_AND_ASSIGN(BrowserClosedObserver);
};

// The delay waited in some cases where we don't have a notifications for an
// action we take.
const int kActionDelayMs = 500;

const char kConsoleTestPage[] = "files/devtools/console_test_page.html";
const char kDebuggerTestPage[] = "files/devtools/debugger_test_page.html";
const char kJsPage[] = "files/devtools/js_page.html";
const char kHeapProfilerPage[] = "files/devtools/heap_profiler.html";
const char kPauseWhenLoadingDevTools[] =
    "files/devtools/pause_when_loading_devtools.html";
const char kPauseWhenScriptIsRunning[] =
    "files/devtools/pause_when_script_is_running.html";
const char kResourceContentLengthTestPage[] = "files/devtools/image.html";
const char kResourceTestPage[] = "files/devtools/resource_test_page.html";
const char kSimplePage[] = "files/devtools/simple_page.html";
const char kCompletionOnPause[] =
    "files/devtools/completion_on_pause.html";
const char kPageWithContentScript[] =
    "files/devtools/page_with_content_script.html";

class DevToolsSanityTest : public InProcessBrowserTest {
 public:
  DevToolsSanityTest() {
    set_show_window(true);
    EnableDOMAutomation();
  }

 protected:
  void RunTest(const std::string& test_name, const std::string& test_page) {
    OpenDevToolsWindow(test_page);
    std::string result;

    // At first check that JavaScript part of the front-end is loaded by
    // checking that global variable uiTests exists(it's created after all js
    // files have been loaded) and has runTest method.
    ASSERT_TRUE(
        ui_test_utils::ExecuteJavaScriptAndExtractString(
            client_contents_->render_view_host(),
            L"",
            L"window.domAutomationController.send("
            L"'' + (window.uiTests && (typeof uiTests.runTest)));",
            &result));

    if (result == "function") {
      ASSERT_TRUE(
          ui_test_utils::ExecuteJavaScriptAndExtractString(
              client_contents_->render_view_host(),
              L"",
              UTF8ToWide(StringPrintf("uiTests.runTest('%s')",
                                      test_name.c_str())),
              &result));
      EXPECT_EQ("[OK]", result);
    } else {
      FAIL() << "DevTools front-end is broken.";
    }
    CloseDevToolsWindow();
  }

  void OpenDevToolsWindow(const std::string& test_page) {
    ASSERT_TRUE(test_server()->Start());
    GURL url = test_server()->GetURL(test_page);
    ui_test_utils::NavigateToURL(browser(), url);

    inspected_rvh_ = GetInspectedTab()->render_view_host();
    DevToolsManager* devtools_manager = DevToolsManager::GetInstance();
    devtools_manager->OpenDevToolsWindow(inspected_rvh_);

    DevToolsClientHost* client_host =
        devtools_manager->GetDevToolsClientHostFor(inspected_rvh_);
    window_ = client_host->AsDevToolsWindow();
    RenderViewHost* client_rvh = window_->GetRenderViewHost();
    client_contents_ = client_rvh->delegate()->GetAsTabContents();
    ui_test_utils::WaitForNavigation(&client_contents_->controller());
  }

  TabContents* GetInspectedTab() {
    return browser()->GetTabContentsAt(0);
  }

  void CloseDevToolsWindow() {
    DevToolsManager* devtools_manager = DevToolsManager::GetInstance();
    // UnregisterDevToolsClientHostFor may destroy window_ so store the browser
    // first.
    Browser* browser = window_->browser();
    devtools_manager->UnregisterDevToolsClientHostFor(inspected_rvh_);

    // Wait only when DevToolsWindow has a browser. For docked DevTools, this
    // is NULL and we skip the wait.
    if (browser)
      BrowserClosedObserver close_observer(browser);
  }

  TabContents* client_contents_;
  DevToolsWindow* window_;
  RenderViewHost* inspected_rvh_;
};

class CancelableQuitTask : public Task {
 public:
  explicit CancelableQuitTask(const std::string& timeout_message)
      : timeout_message_(timeout_message),
        cancelled_(false) {
  }

  void cancel() {
    cancelled_ = true;
  }

  virtual void Run() {
    if (cancelled_) {
      return;
    }
    FAIL() << timeout_message_;
    MessageLoop::current()->Quit();
  }

 private:
  std::string timeout_message_;
  bool cancelled_;
};

// Base class for DevTools tests that test devtools functionality for
// extensions and content scripts.
class DevToolsExtensionDebugTest : public DevToolsSanityTest,
                                   public NotificationObserver {
 public:
  DevToolsExtensionDebugTest() : DevToolsSanityTest() {
    PathService::Get(chrome::DIR_TEST_DATA, &test_extensions_dir_);
    test_extensions_dir_ = test_extensions_dir_.AppendASCII("devtools");
    test_extensions_dir_ = test_extensions_dir_.AppendASCII("extensions");
  }

 protected:
  // Load an extention from test\data\devtools\extensions\<extension_name>
  void LoadExtension(const char* extension_name) {
    FilePath path = test_extensions_dir_.AppendASCII(extension_name);
    ASSERT_TRUE(LoadExtensionFromPath(path)) << "Failed to load extension.";
  }

 private:
  bool LoadExtensionFromPath(const FilePath& path) {
    ExtensionsService* service = browser()->profile()->GetExtensionsService();
    size_t num_before = service->extensions()->size();
    {
      NotificationRegistrar registrar;
      registrar.Add(this, NotificationType::EXTENSION_LOADED,
                    NotificationService::AllSources());
      CancelableQuitTask* delayed_quit =
          new CancelableQuitTask("Extension load timed out.");
      MessageLoop::current()->PostDelayedTask(FROM_HERE, delayed_quit,
          4*1000);
      service->LoadExtension(path);
      ui_test_utils::RunMessageLoop();
      delayed_quit->cancel();
    }
    size_t num_after = service->extensions()->size();
    if (num_after != (num_before + 1))
      return false;

    return WaitForExtensionHostsToLoad();
  }

  bool WaitForExtensionHostsToLoad() {
    // Wait for all the extension hosts that exist to finish loading.
    // NOTE: This assumes that the extension host list is not changing while
    // this method is running.

    NotificationRegistrar registrar;
    registrar.Add(this, NotificationType::EXTENSION_HOST_DID_STOP_LOADING,
                  NotificationService::AllSources());
    CancelableQuitTask* delayed_quit =
        new CancelableQuitTask("Extension host load timed out.");
    MessageLoop::current()->PostDelayedTask(FROM_HERE, delayed_quit,
        4*1000);

    ExtensionProcessManager* manager =
          browser()->profile()->GetExtensionProcessManager();
    for (ExtensionProcessManager::const_iterator iter = manager->begin();
         iter != manager->end();) {
      if ((*iter)->did_stop_loading())
        ++iter;
      else
        ui_test_utils::RunMessageLoop();
    }

    delayed_quit->cancel();
    return true;
  }

  void Observe(NotificationType type,
               const NotificationSource& source,
               const NotificationDetails& details) {
    switch (type.value) {
      case NotificationType::EXTENSION_LOADED:
      case NotificationType::EXTENSION_HOST_DID_STOP_LOADING:
        MessageLoopForUI::current()->Quit();
        break;
      default:
        NOTREACHED();
        break;
    }
  }

  FilePath test_extensions_dir_;
};

// Fails after WebKit roll 69808:70011, http://crbug.com/59727.
#if defined(OS_LINUX) || defined(OS_WIN)
#define MAYBE_TestEnableResourcesTab DISABLED_TestEnableResourcesTab
#else
#define MAYBE_TestEnableResourcesTab TestEnableResourcesTab
#endif  // defined(OS_LINUX) || defined(OS_WIN)

// Tests resources panel enabling.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, MAYBE_TestEnableResourcesTab) {
  RunTest("testEnableResourcesTab", kSimplePage);
}

// Fails after WebKit roll 59365:59477, http://crbug.com/44202.
#if defined(OS_LINUX)
#define MAYBE_TestResourceContentLength FLAKY_TestResourceContentLength
#else
#define MAYBE_TestResourceContentLength TestResourceContentLength
#endif  // defined(OS_LINUX)

// Tests resources have correct sizes.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, MAYBE_TestResourceContentLength) {
  RunTest("testResourceContentLength", kResourceContentLengthTestPage);
}

// Tests resource headers.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestResourceHeaders) {
  RunTest("testResourceHeaders", kResourceTestPage);
}

// Tests cached resource mime type.
// @see http://crbug.com/27364
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestCachedResourceMimeType) {
  RunTest("testCachedResourceMimeType", kResourceTestPage);
}

// Tests profiler panel.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, FLAKY_TestProfilerTab) {
  RunTest("testProfilerTab", kJsPage);
}

// Tests heap profiler.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestHeapProfiler) {
  RunTest("testHeapProfiler", kHeapProfilerPage);
}

// Tests scripts panel showing.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestShowScriptsTab) {
  RunTest("testShowScriptsTab", kDebuggerTestPage);
}

// Tests that scripts tab is populated with inspected scripts even if it
// hadn't been shown by the moment inspected paged refreshed.
// @see http://crbug.com/26312
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,
                       TestScriptsTabIsPopulatedOnInspectedPageRefresh) {
  // Clear inspector settings to ensure that Elements will be
  // current panel when DevTools window is open.
  GetInspectedTab()->render_view_host()->delegate()->ClearInspectorSettings();
  RunTest("testScriptsTabIsPopulatedOnInspectedPageRefresh",
          kDebuggerTestPage);
}

// Tests that a content script is in the scripts list.
// This test is disabled, see bug 28961.
IN_PROC_BROWSER_TEST_F(DevToolsExtensionDebugTest,
                       TestContentScriptIsPresent) {
  LoadExtension("simple_content_script");
  RunTest("testContentScriptIsPresent", kPageWithContentScript);
}

// Tests that scripts are not duplicated after Scripts Panel switch.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,
                       TestNoScriptDuplicatesOnPanelSwitch) {
  RunTest("testNoScriptDuplicatesOnPanelSwitch", kDebuggerTestPage);
}

// Tests that debugger works correctly if pause event occurs when DevTools
// frontend is being loaded.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestPauseWhenLoadingDevTools) {
  RunTest("testPauseWhenLoadingDevTools", kPauseWhenLoadingDevTools);
}

// Tests that pressing 'Pause' will pause script execution if the script
// is already running.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestPauseWhenScriptIsRunning) {
  RunTest("testPauseWhenScriptIsRunning", kPauseWhenScriptIsRunning);
}

// Fails after WebKit roll 66724:66804, http://crbug.com/54592
#if defined(OS_LINUX) || defined(OS_WIN)
#define MAYBE_TestCompletionOnPause FAILS_TestCompletionOnPause
#else
#define MAYBE_TestCompletionOnPause TestCompletionOnPause
#endif  // defined(OS_LINUX) || defined(OS_WIN)
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, MAYBE_TestCompletionOnPause) {
  RunTest("testCompletionOnPause", kCompletionOnPause);
}

// Tests that 'Pause' button works for eval.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, DISABLED_TestPauseInEval) {
  RunTest("testPauseInEval", kDebuggerTestPage);
}

}  // namespace
<commit_msg>DevTools: remove resources panel tests since it is going aways upstream.<commit_after>// Copyright (c) 2010 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 "base/command_line.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/debugger/devtools_client_host.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/debugger/devtools_window.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "net/test/test_server.h"

namespace {

// Used to block until a dev tools client window's browser is closed.
class BrowserClosedObserver : public NotificationObserver {
 public:
  explicit BrowserClosedObserver(Browser* browser) {
    registrar_.Add(this, NotificationType::BROWSER_CLOSED,
                   Source<Browser>(browser));
    ui_test_utils::RunMessageLoop();
  }

  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    MessageLoopForUI::current()->Quit();
  }

 private:
  NotificationRegistrar registrar_;
  DISALLOW_COPY_AND_ASSIGN(BrowserClosedObserver);
};

// The delay waited in some cases where we don't have a notifications for an
// action we take.
const int kActionDelayMs = 500;

const char kConsoleTestPage[] = "files/devtools/console_test_page.html";
const char kDebuggerTestPage[] = "files/devtools/debugger_test_page.html";
const char kJsPage[] = "files/devtools/js_page.html";
const char kHeapProfilerPage[] = "files/devtools/heap_profiler.html";
const char kPauseWhenLoadingDevTools[] =
    "files/devtools/pause_when_loading_devtools.html";
const char kPauseWhenScriptIsRunning[] =
    "files/devtools/pause_when_script_is_running.html";
const char kResourceContentLengthTestPage[] = "files/devtools/image.html";
const char kResourceTestPage[] = "files/devtools/resource_test_page.html";
const char kSimplePage[] = "files/devtools/simple_page.html";
const char kCompletionOnPause[] =
    "files/devtools/completion_on_pause.html";
const char kPageWithContentScript[] =
    "files/devtools/page_with_content_script.html";

class DevToolsSanityTest : public InProcessBrowserTest {
 public:
  DevToolsSanityTest() {
    set_show_window(true);
    EnableDOMAutomation();
  }

 protected:
  void RunTest(const std::string& test_name, const std::string& test_page) {
    OpenDevToolsWindow(test_page);
    std::string result;

    // At first check that JavaScript part of the front-end is loaded by
    // checking that global variable uiTests exists(it's created after all js
    // files have been loaded) and has runTest method.
    ASSERT_TRUE(
        ui_test_utils::ExecuteJavaScriptAndExtractString(
            client_contents_->render_view_host(),
            L"",
            L"window.domAutomationController.send("
            L"'' + (window.uiTests && (typeof uiTests.runTest)));",
            &result));

    if (result == "function") {
      ASSERT_TRUE(
          ui_test_utils::ExecuteJavaScriptAndExtractString(
              client_contents_->render_view_host(),
              L"",
              UTF8ToWide(StringPrintf("uiTests.runTest('%s')",
                                      test_name.c_str())),
              &result));
      EXPECT_EQ("[OK]", result);
    } else {
      FAIL() << "DevTools front-end is broken.";
    }
    CloseDevToolsWindow();
  }

  void OpenDevToolsWindow(const std::string& test_page) {
    ASSERT_TRUE(test_server()->Start());
    GURL url = test_server()->GetURL(test_page);
    ui_test_utils::NavigateToURL(browser(), url);

    inspected_rvh_ = GetInspectedTab()->render_view_host();
    DevToolsManager* devtools_manager = DevToolsManager::GetInstance();
    devtools_manager->OpenDevToolsWindow(inspected_rvh_);

    DevToolsClientHost* client_host =
        devtools_manager->GetDevToolsClientHostFor(inspected_rvh_);
    window_ = client_host->AsDevToolsWindow();
    RenderViewHost* client_rvh = window_->GetRenderViewHost();
    client_contents_ = client_rvh->delegate()->GetAsTabContents();
    ui_test_utils::WaitForNavigation(&client_contents_->controller());
  }

  TabContents* GetInspectedTab() {
    return browser()->GetTabContentsAt(0);
  }

  void CloseDevToolsWindow() {
    DevToolsManager* devtools_manager = DevToolsManager::GetInstance();
    // UnregisterDevToolsClientHostFor may destroy window_ so store the browser
    // first.
    Browser* browser = window_->browser();
    devtools_manager->UnregisterDevToolsClientHostFor(inspected_rvh_);

    // Wait only when DevToolsWindow has a browser. For docked DevTools, this
    // is NULL and we skip the wait.
    if (browser)
      BrowserClosedObserver close_observer(browser);
  }

  TabContents* client_contents_;
  DevToolsWindow* window_;
  RenderViewHost* inspected_rvh_;
};

class CancelableQuitTask : public Task {
 public:
  explicit CancelableQuitTask(const std::string& timeout_message)
      : timeout_message_(timeout_message),
        cancelled_(false) {
  }

  void cancel() {
    cancelled_ = true;
  }

  virtual void Run() {
    if (cancelled_) {
      return;
    }
    FAIL() << timeout_message_;
    MessageLoop::current()->Quit();
  }

 private:
  std::string timeout_message_;
  bool cancelled_;
};

// Base class for DevTools tests that test devtools functionality for
// extensions and content scripts.
class DevToolsExtensionDebugTest : public DevToolsSanityTest,
                                   public NotificationObserver {
 public:
  DevToolsExtensionDebugTest() : DevToolsSanityTest() {
    PathService::Get(chrome::DIR_TEST_DATA, &test_extensions_dir_);
    test_extensions_dir_ = test_extensions_dir_.AppendASCII("devtools");
    test_extensions_dir_ = test_extensions_dir_.AppendASCII("extensions");
  }

 protected:
  // Load an extention from test\data\devtools\extensions\<extension_name>
  void LoadExtension(const char* extension_name) {
    FilePath path = test_extensions_dir_.AppendASCII(extension_name);
    ASSERT_TRUE(LoadExtensionFromPath(path)) << "Failed to load extension.";
  }

 private:
  bool LoadExtensionFromPath(const FilePath& path) {
    ExtensionsService* service = browser()->profile()->GetExtensionsService();
    size_t num_before = service->extensions()->size();
    {
      NotificationRegistrar registrar;
      registrar.Add(this, NotificationType::EXTENSION_LOADED,
                    NotificationService::AllSources());
      CancelableQuitTask* delayed_quit =
          new CancelableQuitTask("Extension load timed out.");
      MessageLoop::current()->PostDelayedTask(FROM_HERE, delayed_quit,
          4*1000);
      service->LoadExtension(path);
      ui_test_utils::RunMessageLoop();
      delayed_quit->cancel();
    }
    size_t num_after = service->extensions()->size();
    if (num_after != (num_before + 1))
      return false;

    return WaitForExtensionHostsToLoad();
  }

  bool WaitForExtensionHostsToLoad() {
    // Wait for all the extension hosts that exist to finish loading.
    // NOTE: This assumes that the extension host list is not changing while
    // this method is running.

    NotificationRegistrar registrar;
    registrar.Add(this, NotificationType::EXTENSION_HOST_DID_STOP_LOADING,
                  NotificationService::AllSources());
    CancelableQuitTask* delayed_quit =
        new CancelableQuitTask("Extension host load timed out.");
    MessageLoop::current()->PostDelayedTask(FROM_HERE, delayed_quit,
        4*1000);

    ExtensionProcessManager* manager =
          browser()->profile()->GetExtensionProcessManager();
    for (ExtensionProcessManager::const_iterator iter = manager->begin();
         iter != manager->end();) {
      if ((*iter)->did_stop_loading())
        ++iter;
      else
        ui_test_utils::RunMessageLoop();
    }

    delayed_quit->cancel();
    return true;
  }

  void Observe(NotificationType type,
               const NotificationSource& source,
               const NotificationDetails& details) {
    switch (type.value) {
      case NotificationType::EXTENSION_LOADED:
      case NotificationType::EXTENSION_HOST_DID_STOP_LOADING:
        MessageLoopForUI::current()->Quit();
        break;
      default:
        NOTREACHED();
        break;
    }
  }

  FilePath test_extensions_dir_;
};

// Fails after WebKit roll 69808:70011, http://crbug.com/59727.
#if defined(OS_LINUX) || defined(OS_WIN)
#define MAYBE_TestEnableResourcesTab DISABLED_TestEnableResourcesTab
#else
#define MAYBE_TestEnableResourcesTab TestEnableResourcesTab
#endif  // defined(OS_LINUX) || defined(OS_WIN)

// Tests resources panel enabling.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, MAYBE_TestEnableResourcesTab) {
  RunTest("testEnableResourcesTab", kSimplePage);
}

// Fails after WebKit roll 59365:59477, http://crbug.com/44202.
#if defined(OS_LINUX)
#define MAYBE_TestResourceContentLength FLAKY_TestResourceContentLength
#else
#define MAYBE_TestResourceContentLength TestResourceContentLength
#endif  // defined(OS_LINUX)

// Tests profiler panel.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, FLAKY_TestProfilerTab) {
  RunTest("testProfilerTab", kJsPage);
}

// Tests heap profiler.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestHeapProfiler) {
  RunTest("testHeapProfiler", kHeapProfilerPage);
}

// Tests scripts panel showing.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestShowScriptsTab) {
  RunTest("testShowScriptsTab", kDebuggerTestPage);
}

// Tests that scripts tab is populated with inspected scripts even if it
// hadn't been shown by the moment inspected paged refreshed.
// @see http://crbug.com/26312
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,
                       TestScriptsTabIsPopulatedOnInspectedPageRefresh) {
  // Clear inspector settings to ensure that Elements will be
  // current panel when DevTools window is open.
  GetInspectedTab()->render_view_host()->delegate()->ClearInspectorSettings();
  RunTest("testScriptsTabIsPopulatedOnInspectedPageRefresh",
          kDebuggerTestPage);
}

// Tests that a content script is in the scripts list.
// This test is disabled, see bug 28961.
IN_PROC_BROWSER_TEST_F(DevToolsExtensionDebugTest,
                       TestContentScriptIsPresent) {
  LoadExtension("simple_content_script");
  RunTest("testContentScriptIsPresent", kPageWithContentScript);
}

// Tests that scripts are not duplicated after Scripts Panel switch.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,
                       TestNoScriptDuplicatesOnPanelSwitch) {
  RunTest("testNoScriptDuplicatesOnPanelSwitch", kDebuggerTestPage);
}

// Tests that debugger works correctly if pause event occurs when DevTools
// frontend is being loaded.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestPauseWhenLoadingDevTools) {
  RunTest("testPauseWhenLoadingDevTools", kPauseWhenLoadingDevTools);
}

// Tests that pressing 'Pause' will pause script execution if the script
// is already running.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestPauseWhenScriptIsRunning) {
  RunTest("testPauseWhenScriptIsRunning", kPauseWhenScriptIsRunning);
}

// Fails after WebKit roll 66724:66804, http://crbug.com/54592
#if defined(OS_LINUX) || defined(OS_WIN)
#define MAYBE_TestCompletionOnPause FAILS_TestCompletionOnPause
#else
#define MAYBE_TestCompletionOnPause TestCompletionOnPause
#endif  // defined(OS_LINUX) || defined(OS_WIN)
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, MAYBE_TestCompletionOnPause) {
  RunTest("testCompletionOnPause", kCompletionOnPause);
}

// Tests that 'Pause' button works for eval.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, DISABLED_TestPauseInEval) {
  RunTest("testPauseInEval", kDebuggerTestPage);
}

}  // namespace
<|endoftext|>


<commit_before>///
/// @file   ParallelSieve.cpp
/// @brief  Multi-threaded prime sieve using std::async.
///
/// Copyright (C) 2022 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primesieve/config.hpp>
#include <primesieve/forward.hpp>
#include <primesieve/ParallelSieve.hpp>
#include <primesieve/PrimeSieve.hpp>
#include <primesieve/macros.hpp>
#include <primesieve/pmath.hpp>

#include <stdint.h>
#include <algorithm>
#include <atomic>
#include <chrono>
#include <future>
#include <mutex>
#include <vector>

using std::size_t;
using namespace primesieve;

namespace {

counts_t& operator+=(counts_t& v1, const counts_t& v2)
{
  for (size_t i = 0; i < v1.size(); i++)
    v1[i] += v2[i];
  return v1;
}

} // namespace

namespace primesieve {

ParallelSieve::ParallelSieve()
{
  int threads = get_num_threads();
  setNumThreads(threads);
}

int ParallelSieve::getMaxThreads()
{
  int maxThreads = std::thread::hardware_concurrency();
  return std::max(1, maxThreads);
}

int ParallelSieve::getNumThreads() const
{
  return numThreads_;
}

void ParallelSieve::setNumThreads(int threads)
{
  numThreads_ = inBetween(1, threads, getMaxThreads());
}

/// Get an ideal number of threads for
/// the start and stop numbers.
///
int ParallelSieve::idealNumThreads() const
{
  if (start_ > stop_)
    return 1;

  uint64_t threshold = isqrt(stop_) / 5;
  threshold = std::max(threshold, config::MIN_THREAD_DISTANCE);
  uint64_t threads = getDistance() / threshold;
  threads = inBetween(1, threads, numThreads_);

  return (int) threads;
}

uint64_t ParallelSieve::getThreadDistance(int threads) const
{
  ASSERT(threads > 0);
  ASSERT(getDistance() > 0);

  uint64_t dist = getDistance();
  uint64_t balanced = isqrt(stop_) * 1000;
  uint64_t unbalanced = dist / threads;
  uint64_t fastest = std::min(balanced, unbalanced);
  uint64_t iters = dist / fastest;

  // The number of iterations should always be
  // a multiple of threads in order to ensure
  // all threads finish nearly at the same time.
  iters = (iters / threads) * threads;
  iters = std::max(iters, (uint64_t) threads);

  uint64_t threadDist = ((dist - 1) / iters) + 1;
  threadDist = std::max(threadDist, config::MIN_THREAD_DISTANCE);
  threadDist += 30 - threadDist % 30;

  return threadDist;
}

/// (n % 30) == 2 ensures that prime k-tuplets
/// cannot be split at thread boundaries.
///
uint64_t ParallelSieve::align(uint64_t n) const
{
  uint64_t n32 = checkedAdd(n, 32);

  if (n32 >= stop_)
    return stop_;
  else
    return n32 - n % 30;
}

/// Print sieving status to stdout
bool ParallelSieve::tryUpdateStatus(uint64_t dist)
{
  std::unique_lock<std::mutex> lock(mutex_, std::try_to_lock);

  if (lock.owns_lock())
    updateStatus(dist);

  return lock.owns_lock();
}

/// Sieve the primes and prime k-tuplets in [start, stop]
/// in parallel using multi-threading.
///
void ParallelSieve::sieve()
{
  reset();

  if (start_ > stop_)
    return;

  int threads = idealNumThreads();

  if (threads == 1)
    PrimeSieve::sieve();
  else
  {
    setStatus(0);
    auto t1 = std::chrono::system_clock::now();
    uint64_t dist = getDistance();
    uint64_t threadDist = getThreadDistance(threads);
    uint64_t iters = ((dist - 1) / threadDist) + 1;
    threads = inBetween(1, threads, iters);
    std::atomic<uint64_t> a(0);

    // Each thread executes 1 task
    auto task = [&]()
    {
      PrimeSieve ps(this);

      // To improve load balancing each thread sieves many small
      // intervals. For small intervals only basic pre-sieving
      // is used by default to avoid initialization overhead.
      // However here we know that many intervals will be sieved
      // and hence there is no initialization overhead issue.
      // Therefore we manually initialize pre-sieving.
      PreSieve& preSieve = ps.getPreSieve();
      preSieve.init(0, dist / threads);

      uint64_t i;
      counts_t counts;
      counts.fill(0);

      while ((i = a.fetch_add(1, std::memory_order_relaxed)) < iters)
      {
        uint64_t start = start_ + threadDist * i;
        uint64_t stop = checkedAdd(start, threadDist);
        stop = align(stop);

        if (start > start_)
          start = align(start) + 1;

        // Sieve the primes inside [start, stop]
        ps.sieve(start, stop);
        counts += ps.getCounts();
      }

      return counts;
    };

    std::vector<std::future<counts_t>> futures;
    futures.reserve(threads);

    for (int t = 0; t < threads; t++)
      futures.emplace_back(std::async(std::launch::async, task));

    for (auto& f : futures)
      counts_ += f.get();

    auto t2 = std::chrono::system_clock::now();
    std::chrono::duration<double> seconds = t2 - t1;
    seconds_ = seconds.count();
    setStatus(100);
  }
}

} // namespace
<commit_msg>Use pod_vector instead of std::vector<commit_after>///
/// @file   ParallelSieve.cpp
/// @brief  Multi-threaded prime sieve using std::async.
///
/// Copyright (C) 2022 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primesieve/config.hpp>
#include <primesieve/forward.hpp>
#include <primesieve/ParallelSieve.hpp>
#include <primesieve/PrimeSieve.hpp>
#include <primesieve/macros.hpp>
#include <primesieve/pmath.hpp>
#include <primesieve/pod_vector.hpp>

#include <stdint.h>
#include <algorithm>
#include <atomic>
#include <chrono>
#include <future>
#include <mutex>

using std::size_t;
using namespace primesieve;

namespace {

counts_t& operator+=(counts_t& v1, const counts_t& v2)
{
  for (size_t i = 0; i < v1.size(); i++)
    v1[i] += v2[i];
  return v1;
}

} // namespace

namespace primesieve {

ParallelSieve::ParallelSieve()
{
  int threads = get_num_threads();
  setNumThreads(threads);
}

int ParallelSieve::getMaxThreads()
{
  int maxThreads = std::thread::hardware_concurrency();
  return std::max(1, maxThreads);
}

int ParallelSieve::getNumThreads() const
{
  return numThreads_;
}

void ParallelSieve::setNumThreads(int threads)
{
  numThreads_ = inBetween(1, threads, getMaxThreads());
}

/// Get an ideal number of threads for
/// the start and stop numbers.
///
int ParallelSieve::idealNumThreads() const
{
  if (start_ > stop_)
    return 1;

  uint64_t threshold = isqrt(stop_) / 5;
  threshold = std::max(threshold, config::MIN_THREAD_DISTANCE);
  uint64_t threads = getDistance() / threshold;
  threads = inBetween(1, threads, numThreads_);

  return (int) threads;
}

uint64_t ParallelSieve::getThreadDistance(int threads) const
{
  ASSERT(threads > 0);
  ASSERT(getDistance() > 0);

  uint64_t dist = getDistance();
  uint64_t balanced = isqrt(stop_) * 1000;
  uint64_t unbalanced = dist / threads;
  uint64_t fastest = std::min(balanced, unbalanced);
  uint64_t iters = dist / fastest;

  // The number of iterations should always be
  // a multiple of threads in order to ensure
  // all threads finish nearly at the same time.
  iters = (iters / threads) * threads;
  iters = std::max(iters, (uint64_t) threads);

  uint64_t threadDist = ((dist - 1) / iters) + 1;
  threadDist = std::max(threadDist, config::MIN_THREAD_DISTANCE);
  threadDist += 30 - threadDist % 30;

  return threadDist;
}

/// (n % 30) == 2 ensures that prime k-tuplets
/// cannot be split at thread boundaries.
///
uint64_t ParallelSieve::align(uint64_t n) const
{
  uint64_t n32 = checkedAdd(n, 32);

  if (n32 >= stop_)
    return stop_;
  else
    return n32 - n % 30;
}

/// Print sieving status to stdout
bool ParallelSieve::tryUpdateStatus(uint64_t dist)
{
  std::unique_lock<std::mutex> lock(mutex_, std::try_to_lock);

  if (lock.owns_lock())
    updateStatus(dist);

  return lock.owns_lock();
}

/// Sieve the primes and prime k-tuplets in [start, stop]
/// in parallel using multi-threading.
///
void ParallelSieve::sieve()
{
  reset();

  if (start_ > stop_)
    return;

  int threads = idealNumThreads();

  if (threads == 1)
    PrimeSieve::sieve();
  else
  {
    setStatus(0);
    auto t1 = std::chrono::system_clock::now();
    uint64_t dist = getDistance();
    uint64_t threadDist = getThreadDistance(threads);
    uint64_t iters = ((dist - 1) / threadDist) + 1;
    threads = inBetween(1, threads, iters);
    std::atomic<uint64_t> a(0);

    // Each thread executes 1 task
    auto task = [&]()
    {
      PrimeSieve ps(this);

      // To improve load balancing each thread sieves many small
      // intervals. For small intervals only basic pre-sieving
      // is used by default to avoid initialization overhead.
      // However here we know that many intervals will be sieved
      // and hence there is no initialization overhead issue.
      // Therefore we manually initialize pre-sieving.
      PreSieve& preSieve = ps.getPreSieve();
      preSieve.init(0, dist / threads);

      uint64_t i;
      counts_t counts;
      counts.fill(0);

      while ((i = a.fetch_add(1, std::memory_order_relaxed)) < iters)
      {
        uint64_t start = start_ + threadDist * i;
        uint64_t stop = checkedAdd(start, threadDist);
        stop = align(stop);

        if (start > start_)
          start = align(start) + 1;

        // Sieve the primes inside [start, stop]
        ps.sieve(start, stop);
        counts += ps.getCounts();
      }

      return counts;
    };

    pod_vector<std::future<counts_t>> futures;
    futures.reserve(threads);

    for (int t = 0; t < threads; t++)
      futures.emplace_back(std::async(std::launch::async, task));

    for (auto& f : futures)
      counts_ += f.get();

    auto t2 = std::chrono::system_clock::now();
    std::chrono::duration<double> seconds = t2 - t1;
    seconds_ = seconds.count();
    setStatus(100);
  }
}

} // namespace
<|endoftext|>


<commit_before>/*
    This file is part of kdepim.

    Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

#include "kabc_resourcegroupwiseconfig.h"

#include "kabc_resourcegroupwise.h"
#include "kabc_groupwiseprefs.h"

#include <kcombobox.h>
#include <kdebug.h>
#include <kdialog.h>
#include <klocale.h>
#include <klineedit.h>
#include <k3listview.h>
#include <kurlrequester.h>

#include <QLabel>
#include <QLayout>
//Added by qt3to4:
#include <QFrame>
#include <QGridLayout>

using namespace KABC;

class AddressBookItem : public Q3CheckListItem
{
  public:
    AddressBookItem( K3ListView *parent, GroupWise::AddressBook ab )
      : Q3CheckListItem( parent, "", CheckBox ),
        mId( ab.id )
    {
      setText( 0, ab.name );
      if ( ab.isPersonal ) setText( 1, i18n("Yes") );
      else setText( 1, i18n("No") );
      if ( ab.isFrequentContacts ) setText( 2, i18n("Yes") );
      else setText( 2, i18n("No") );
    }

    QString id() const { return mId; }

  private:
    QString mId;
};

ResourceGroupwiseConfig::ResourceGroupwiseConfig( QWidget* parent )
  : KRES::ConfigWidget( parent )
{
  QGridLayout *mainLayout = new QGridLayout( this );
  mainLayout->setSpacing( KDialog::spacingHint() );
  mainLayout->setMargin( 0 );

  QLabel *label = new QLabel( i18n( "URL:" ), this );
  mURL = new KUrlRequester( this );

  mainLayout->addWidget( label, 0, 0 );
  mainLayout->addWidget( mURL, 0, 1 );

  label = new QLabel( i18n( "User:" ), this );
  mUser = new KLineEdit( this );

  mainLayout->addWidget( label, 1, 0 );
  mainLayout->addWidget( mUser, 1, 1 );

  label = new QLabel( i18n( "Password:" ), this );
  mPassword = new KLineEdit( this );
  mPassword->setEchoMode( QLineEdit::Password );

  mainLayout->addWidget( label, 2, 0 );
  mainLayout->addWidget( mPassword, 2, 1 );

  QFrame *hline = new QFrame( this );
  hline->setFrameStyle( QFrame::HLine | QFrame::Sunken );

  mainLayout->addWidget( hline, 3, 0, 1, 2 );

  QPushButton *updateButton = new QPushButton( i18n( "Retrieve Address Book List From Server" ), this );
  mainLayout->addWidget( updateButton, 4, 0, 1, 2 );

  mAddressBookView = new K3ListView( this );
  mAddressBookView->addColumn( i18n( "Address Book" ) );
  mAddressBookView->addColumn( i18n( "Personal" ) );
  mAddressBookView->addColumn( i18n( "Frequent Contacts" ) );
  mAddressBookView->setFullWidth( true );

  mainLayout->addWidget( mAddressBookView, 5, 0, 1, 2 );

  label = new QLabel( i18n( "Address book for new contacts:" ), this );
  mAddressBookBox = new KComboBox( this );

  mainLayout->addWidget( label, 6, 0 );
  mainLayout->addWidget( mAddressBookBox, 6, 1 );

  connect( updateButton, SIGNAL( clicked() ), SLOT( updateAddressBookList() ) );
}

void ResourceGroupwiseConfig::loadSettings( KRES::Resource *res )
{
  mResource = dynamic_cast<ResourceGroupwise*>( res );

  if ( !mResource ) {
    kDebug(5700) <<"ResourceGroupwiseConfig::loadSettings(): cast failed";
    return;
  }

  mURL->setUrl( mResource->prefs()->url() );
  mUser->setText( mResource->prefs()->user() );
  mPassword->setText( mResource->prefs()->password() );
  mReadAddressBookIds = mResource->prefs()->readAddressBooks();
  updateAddressBookView();
}

void ResourceGroupwiseConfig::saveSettings( KRES::Resource *res )
{
  ResourceGroupwise *resource = dynamic_cast<ResourceGroupwise*>( res );

  if ( !resource ) {
    kDebug(5700) <<"ResourceGroupwiseConfig::saveSettings(): cast failed";
    return;
  }

  saveServerSettings( resource );

  saveAddressBookSettings();
}

void ResourceGroupwiseConfig::saveServerSettings( ResourceGroupwise *resource )
{
  resource->prefs()->setUrl( mURL->url().url() );
  resource->prefs()->setUser( mUser->text() );
  resource->prefs()->setPassword( mPassword->text() );
}

void ResourceGroupwiseConfig::updateAddressBookList()
{
  saveServerSettings( mResource );

  mResource->retrieveAddressBooks();

  updateAddressBookView();
}

void ResourceGroupwiseConfig::saveAddressBookSettings()
{
  QStringList selectedRead;
  QString selectedWrite;

  Q3ListViewItemIterator it2( mAddressBookView );
  while ( it2.current() ) {
    AddressBookItem *item = static_cast<AddressBookItem*>( it2.current() );
    if ( item->isOn() )
      selectedRead.append( item->id() );

    ++it2;
  }
  // check if the SAB was selected when the settings were loaded and is not selected now,
  // if so, clear the resource to clear the SAB data that is no longer required.
  // also, set the sequence numbers to 0 so that we know the SAB should be re-fetched in its entirety the next time we do load it
  QString sab = mResource->prefs()->systemAddressBook();
  if ( mReadAddressBookIds.contains( sab ) && !selectedRead.contains( sab ) )
  {
    mResource->clearCache();
    mResource->prefs()->setLastSequenceNumber( 0 );
    mResource->prefs()->setFirstSequenceNumber( 0 );
  }
  selectedWrite = mWriteAddressBookIds[ mAddressBookBox->currentIndex() ];

  mResource->prefs()->setReadAddressBooks( selectedRead );
  mResource->prefs()->setWriteAddressBook( selectedWrite );
}

void ResourceGroupwiseConfig::updateAddressBookView()
{
  if ( mAddressBookBox->count() != 0 ) // we loaded it already
    saveAddressBookSettings();

  mAddressBookView->clear();
  mAddressBookBox->clear();
  mWriteAddressBookIds.clear();

  QStringList selectedRead = mResource->prefs()->readAddressBooks();

  GroupWise::AddressBook::List addressBooks = mResource->addressBooks();
  GroupWise::AddressBook::List::ConstIterator abIt;
  for ( abIt = addressBooks.begin(); abIt != addressBooks.end(); ++abIt ) {
    AddressBookItem *item = new AddressBookItem( mAddressBookView, *abIt );
    if ( selectedRead.contains( (*abIt).id ) )
      item->setOn( true );

    mAddressBookBox->addItem( (*abIt).name );
    mWriteAddressBookIds.append( (*abIt).id );
  }

  int index = mWriteAddressBookIds.indexOf( mResource->prefs()->writeAddressBook() );
  mAddressBookBox->setCurrentIndex( index );
}
<commit_msg>Backport of fix in Rev 853019:<commit_after>/*
    This file is part of kdepim.

    Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

#include "kabc_resourcegroupwiseconfig.h"

#include "kabc_resourcegroupwise.h"
#include "kabc_groupwiseprefs.h"

#include <kcombobox.h>
#include <kdebug.h>
#include <kdialog.h>
#include <klocale.h>
#include <klineedit.h>
#include <k3listview.h>
#include <kurlrequester.h>

#include <QLabel>
#include <QLayout>
//Added by qt3to4:
#include <QFrame>
#include <QGridLayout>

using namespace KABC;

class AddressBookItem : public Q3CheckListItem
{
  public:
    AddressBookItem( K3ListView *parent, GroupWise::AddressBook ab )
      : Q3CheckListItem( parent, "", CheckBox ),
        mId( ab.id )
    {
      setText( 0, ab.name );
      if ( ab.isPersonal ) setText( 1, i18n("Yes") );
      else setText( 1, i18n("No") );
      if ( ab.isFrequentContacts ) setText( 2, i18n("Yes") );
      else setText( 2, i18n("No") );
    }

    QString id() const { return mId; }

  private:
    QString mId;
};

ResourceGroupwiseConfig::ResourceGroupwiseConfig( QWidget* parent )
  : KRES::ConfigWidget( parent )
{
  QGridLayout *mainLayout = new QGridLayout( this );
  mainLayout->setSpacing( KDialog::spacingHint() );
  mainLayout->setMargin( 0 );

  QLabel *label = new QLabel( i18n( "URL:" ), this );
  mURL = new KUrlRequester( this );

  mainLayout->addWidget( label, 0, 0 );
  mainLayout->addWidget( mURL, 0, 1 );

  label = new QLabel( i18n( "User:" ), this );
  mUser = new KLineEdit( this );

  mainLayout->addWidget( label, 1, 0 );
  mainLayout->addWidget( mUser, 1, 1 );

  label = new QLabel( i18n( "Password:" ), this );
  mPassword = new KLineEdit( this );
  mPassword->setEchoMode( QLineEdit::Password );

  mainLayout->addWidget( label, 2, 0 );
  mainLayout->addWidget( mPassword, 2, 1 );

  QFrame *hline = new QFrame( this );
  hline->setFrameStyle( QFrame::HLine | QFrame::Sunken );

  mainLayout->addWidget( hline, 3, 0, 1, 2 );

  QPushButton *updateButton = new QPushButton( i18n( "Retrieve Address Book List From Server" ), this );
  mainLayout->addWidget( updateButton, 4, 0, 1, 2 );

  mAddressBookView = new K3ListView( this );
  mAddressBookView->addColumn( i18n( "Address Book" ) );
  mAddressBookView->addColumn( i18n( "Personal" ) );
  mAddressBookView->addColumn( i18n( "Frequent Contacts" ) );
  mAddressBookView->setFullWidth( true );

  mainLayout->addWidget( mAddressBookView, 5, 0, 1, 2 );

  label = new QLabel( i18n( "Address book for new contacts:" ), this );
  mAddressBookBox = new KComboBox( this );

  mainLayout->addWidget( label, 6, 0 );
  mainLayout->addWidget( mAddressBookBox, 6, 1 );

  connect( updateButton, SIGNAL( clicked() ), SLOT( updateAddressBookList() ) );
}

void ResourceGroupwiseConfig::loadSettings( KRES::Resource *res )
{
  mResource = dynamic_cast<ResourceGroupwise*>( res );

  if ( !mResource ) {
    kDebug(5700) <<"ResourceGroupwiseConfig::loadSettings(): cast failed";
    return;
  }

  mURL->setUrl( mResource->prefs()->url() );
  mUser->setText( mResource->prefs()->user() );
  mPassword->setText( mResource->prefs()->password() );
  mReadAddressBookIds = mResource->prefs()->readAddressBooks();
  updateAddressBookView();
}

void ResourceGroupwiseConfig::saveSettings( KRES::Resource *res )
{
  ResourceGroupwise *resource = dynamic_cast<ResourceGroupwise*>( res );

  if ( !resource ) {
    kDebug(5700) <<"ResourceGroupwiseConfig::saveSettings(): cast failed";
    return;
  }

  saveServerSettings( resource );

  saveAddressBookSettings();
}

void ResourceGroupwiseConfig::saveServerSettings( ResourceGroupwise *resource )
{
  resource->prefs()->setUrl( mURL->url().url() );
  resource->prefs()->setUser( mUser->text() );
  resource->prefs()->setPassword( mPassword->text() );
}

void ResourceGroupwiseConfig::updateAddressBookList()
{
  saveServerSettings( mResource );

  mResource->retrieveAddressBooks();

  updateAddressBookView();
}

void ResourceGroupwiseConfig::saveAddressBookSettings()
{
  QStringList selectedRead;
  QString selectedWrite;

  Q3ListViewItemIterator it2( mAddressBookView );
  while ( it2.current() ) {
    AddressBookItem *item = static_cast<AddressBookItem*>( it2.current() );
    if ( item->isOn() )
      selectedRead.append( item->id() );

    ++it2;
  }
  // check if the SAB was selected when the settings were loaded and is not selected now,
  // if so, clear the resource to clear the SAB data that is no longer required.
  // also, set the sequence numbers to 0 so that we know the SAB should be re-fetched in its entirety the next time we do load it
  QString sab = mResource->prefs()->systemAddressBook();
  if ( mReadAddressBookIds.contains( sab ) && !selectedRead.contains( sab ) )
  {
    mResource->clearCache();
    mResource->prefs()->setLastSequenceNumber( 0 );
    mResource->prefs()->setFirstSequenceNumber( 0 );
  }
  selectedWrite = mWriteAddressBookIds.value( mAddressBookBox->currentIndex() );

  mResource->prefs()->setReadAddressBooks( selectedRead );
  mResource->prefs()->setWriteAddressBook( selectedWrite );
}

void ResourceGroupwiseConfig::updateAddressBookView()
{
  if ( mAddressBookBox->count() != 0 ) // we loaded it already
    saveAddressBookSettings();

  mAddressBookView->clear();
  mAddressBookBox->clear();
  mWriteAddressBookIds.clear();

  QStringList selectedRead = mResource->prefs()->readAddressBooks();

  GroupWise::AddressBook::List addressBooks = mResource->addressBooks();
  GroupWise::AddressBook::List::ConstIterator abIt;
  for ( abIt = addressBooks.begin(); abIt != addressBooks.end(); ++abIt ) {
    AddressBookItem *item = new AddressBookItem( mAddressBookView, *abIt );
    if ( selectedRead.contains( (*abIt).id ) )
      item->setOn( true );

    mAddressBookBox->addItem( (*abIt).name );
    mWriteAddressBookIds.append( (*abIt).id );
  }

  int index = mWriteAddressBookIds.indexOf( mResource->prefs()->writeAddressBook() );
  mAddressBookBox->setCurrentIndex( index );
}
<|endoftext|>


<commit_before>#include "../USB.h"
#include "../configuration.h"
#include "../deviceproxy.h"
#include "../usb-pad/config.h"
#include "../usb-pad/padproxy.h"
#include "../usb-mic/audiosourceproxy.h"

#include <sstream>
#include <map>
#include <vector>
#include <string>

#include "ini.h"
#include "config.h"

//libjoyrumble used as an example
//Hopefully PCSX2 has inited all the GTK stuff already
using namespace std;

static std::string usb_path;
std::string IniDir;
std::string LogDir;
const char* iniFile = "USBqemu-wheel.ini";

void SysMessage(const char *fmt, ...)
{
	va_list arglist;

	va_start(arglist, fmt);
	vfprintf(stderr, fmt, arglist);
	va_end(arglist);
}

void CALLBACK USBsetSettingsDir( const char* dir )
{
	fprintf(stderr, "USBsetSettingsDir: %s\n", dir);
	IniDir = dir;
}

void CALLBACK USBsetLogDir( const char* dir )
{
	printf("USBsetLogDir: %s\n", dir);
	LogDir = dir;
}

template<typename T>
bool LoadSettingValue(const std::string& ini, const std::string& section, const char* param, T& value);
template<typename T>
bool SaveSettingValue(const std::string& ini, const std::string& section, const char* param, T& value);

template<>
bool LoadSettingValue(const std::string& ini, const std::string& section, const char* param, std::string& value)
{
	char tmp[4096] = {0};
	INILoadString(ini.c_str(), section.c_str(), param, tmp);
	value = tmp;
	return true;
}

template<>
bool LoadSettingValue(const std::string& ini, const std::string& section, const char* param, int64_t& value)
{
	INILoadUInt(ini.c_str(), section.c_str(), param, (unsigned int *)value);
	return true;
}

template<>
bool SaveSettingValue(const std::string& ini, const std::string& section, const char* param, std::string& value)
{
	INISaveString(ini.c_str(), section.c_str(), param, value.c_str());
	return true;
}

template<>
bool SaveSettingValue(const std::string& ini, const std::string& section, const char* param, int64_t& value)
{
	INISaveUInt(ini.c_str(), section.c_str(), param, (unsigned int)value);
	return true;
}

bool LoadSetting(int port, const std::string& key, CONFIGVARIANT& var)
{
	fprintf(stderr, "USBqemu load \"%s\" from %s\n", var.name, key.c_str());

	std::stringstream section;
	section << key << " " << port;

	std::string ini(IniDir);
	ini.append(iniFile);

	switch(var.type)
	{
		case CONFIG_TYPE_INT:
			return LoadSettingValue(ini, section.str(), var.name, var.intValue);
		//case CONFIG_TYPE_DOUBLE:
		//	return LoadSettingValue(ini, section.str(), var.name, var.doubleValue);
		case CONFIG_TYPE_TCHAR:
			return LoadSettingValue(ini, section.str(), var.name, var.strValue);
		case CONFIG_TYPE_CHAR:
			return LoadSettingValue(ini, section.str(), var.name, var.strValue);
		//case CONFIG_TYPE_WCHAR:
		//	return LoadSettingValue(ini, section.str(), var.name, var.wstrValue);
		break;
		default:
			fprintf(stderr, "Invalid config type %d for %s\n", var.type, var.name);
			break;
	};
	return false;
}

/**
 *
 * [devices]
 * portX = pad
 *
 * [pad X]
 * api = joydev
 *
 * [joydev X]
 * button0 = 1
 * button1 = 2
 * ...
 *
 * */
bool SaveSetting(int port, const std::string& key, CONFIGVARIANT& var)
{
	fprintf(stderr, "USBqemu save \"%s\" to %s\n", var.name, key.c_str());

	std::stringstream section;
	section << key << " " << port;

	std::string ini(IniDir);
	ini.append(iniFile);

	switch(var.type)
	{
		case CONFIG_TYPE_INT:
			return SaveSettingValue(ini, section.str(), var.name, var.intValue);
		case CONFIG_TYPE_TCHAR:
			return LoadSettingValue(ini, section.str(), var.name, var.strValue);
		case CONFIG_TYPE_CHAR:
			return SaveSettingValue(ini, section.str(), var.name, var.strValue);
		break;
		default:
			fprintf(stderr, "Invalid config type %d for %s\n", var.type, var.name);
			break;
	};
	return false;
}

void SaveConfig() {
	fprintf(stderr, "USB save config\n");
	//char* envptr = getenv("HOME");
	//if(envptr == NULL)
	//	return;
	//char path[1024];
	//snprintf(path, sizeof(path), "%s/.config/PCSX2/inis/USBqemu-wheel.ini", envptr);
	std::string iniPath(IniDir);
	iniPath.append(iniFile);
	const char *path = iniPath.c_str();

	//fprintf(stderr, "%s\n", path);
	//snprintf(conf.usb_img, sizeof(conf.usb_img), "%s", usb_path.c_str());

	INISaveString(path, N_DEVICES, N_DEVICE_PORT0, conf.Port0.c_str());
	INISaveString(path, N_DEVICES, N_DEVICE_PORT1, conf.Port1.c_str());
	INISaveUInt(path, N_DEVICES, N_WHEEL_TYPE0, conf.WheelType[0]);
	INISaveUInt(path, N_DEVICES, N_WHEEL_TYPE1, conf.WheelType[1]);
	//INISaveString(path, N_DEVICES, "USB Image", conf.usb_img);
	//INISaveString(path, "Joystick", "Player1", player_joys[0].c_str());
	//INISaveString(path, "Joystick", "Player2", player_joys[1].c_str());
	for (auto& k : changedAPIs)
	{
		CONFIGVARIANT var(N_DEVICE_API, CONFIG_TYPE_CHAR);
		var.strValue = k.second;
		fprintf(stderr, "Save apis: %s %s\n", k.first.second.c_str(), k.second.c_str());
		SaveSetting(k.first.first, k.first.second, var);
	}
}

void LoadConfig() {
	char tmp[1024] = {0};
	fprintf(stderr, "USB load config\n");
	//char* envptr = getenv("HOME");
	//if(envptr == NULL)
	//	return;
	//char path[1024];
	//sprintf(path, "%s/.config/PCSX2/inis/USBqemu-wheel.ini", envptr);
	std::string iniPath(IniDir);
	iniPath.append(iniFile);
	const char *path = iniPath.c_str();

	INILoadString(path, N_DEVICES, N_DEVICE_PORT0, tmp);
	conf.Port0 = tmp;
	INILoadString(path, N_DEVICES, N_DEVICE_PORT1, tmp);
	conf.Port1 = tmp;
	INILoadUInt(path, N_DEVICES, N_WHEEL_TYPE0, (u32*)&conf.WheelType[0]);
	INILoadUInt(path, N_DEVICES, N_WHEEL_TYPE1, (u32*)&conf.WheelType[1]);

	{
		auto instance = RegisterDevice::instance();
		CONFIGVARIANT tmpVar(N_DEVICE_API, CONFIG_TYPE_CHAR);
		LoadSetting(0, conf.Port0, tmpVar);
		std::string api = tmpVar.strValue;
		auto dev = instance.Device(conf.Port0);

		if (dev && !dev->IsValidAPI(api))
			api = *instance.Device(conf.Port0)->APIs().begin();

		if(api.size())
			changedAPIs[std::make_pair(0, conf.Port0)] = api;

		LoadSetting(1, conf.Port1, tmpVar);
		api = tmpVar.strValue;

		dev = instance.Device(conf.Port1);
		if (dev && !dev->IsValidAPI(api))
			api = *instance.Device(conf.Port1)->APIs().begin();

		if(api.size())
			changedAPIs[std::make_pair(1, conf.Port1)] = api;
	}

	//INILoadString(path, N_DEVICES, "USB Image", conf.usb_img);
	//INILoadString(path, "Joystick", "Player1", tmp);
	//player_joys[0] = tmp;
	//INILoadString(path, "Joystick", "Player2", tmp);
	//player_joys[1] = tmp;
}
<commit_msg>linux: fix possible nullptr error with api names.<commit_after>#include "../USB.h"
#include "../configuration.h"
#include "../deviceproxy.h"
#include "../usb-pad/config.h"
#include "../usb-pad/padproxy.h"
#include "../usb-mic/audiosourceproxy.h"

#include <sstream>
#include <map>
#include <vector>
#include <string>

#include "ini.h"
#include "config.h"

//libjoyrumble used as an example
//Hopefully PCSX2 has inited all the GTK stuff already
using namespace std;

static std::string usb_path;
std::string IniDir;
std::string LogDir;
const char* iniFile = "USBqemu-wheel.ini";

void SysMessage(const char *fmt, ...)
{
	va_list arglist;

	va_start(arglist, fmt);
	vfprintf(stderr, fmt, arglist);
	va_end(arglist);
}

void CALLBACK USBsetSettingsDir( const char* dir )
{
	fprintf(stderr, "USBsetSettingsDir: %s\n", dir);
	IniDir = dir;
}

void CALLBACK USBsetLogDir( const char* dir )
{
	printf("USBsetLogDir: %s\n", dir);
	LogDir = dir;
}

template<typename T>
bool LoadSettingValue(const std::string& ini, const std::string& section, const char* param, T& value);
template<typename T>
bool SaveSettingValue(const std::string& ini, const std::string& section, const char* param, T& value);

template<>
bool LoadSettingValue(const std::string& ini, const std::string& section, const char* param, std::string& value)
{
	char tmp[4096] = {0};
	INILoadString(ini.c_str(), section.c_str(), param, tmp);
	value = tmp;
	return true;
}

template<>
bool LoadSettingValue(const std::string& ini, const std::string& section, const char* param, int64_t& value)
{
	INILoadUInt(ini.c_str(), section.c_str(), param, (unsigned int *)value);
	return true;
}

template<>
bool SaveSettingValue(const std::string& ini, const std::string& section, const char* param, std::string& value)
{
	INISaveString(ini.c_str(), section.c_str(), param, value.c_str());
	return true;
}

template<>
bool SaveSettingValue(const std::string& ini, const std::string& section, const char* param, int64_t& value)
{
	INISaveUInt(ini.c_str(), section.c_str(), param, (unsigned int)value);
	return true;
}

bool LoadSetting(int port, const std::string& key, CONFIGVARIANT& var)
{
	fprintf(stderr, "USBqemu load \"%s\" from %s\n", var.name, key.c_str());

	std::stringstream section;
	section << key << " " << port;

	std::string ini(IniDir);
	ini.append(iniFile);

	switch(var.type)
	{
		case CONFIG_TYPE_INT:
			return LoadSettingValue(ini, section.str(), var.name, var.intValue);
		//case CONFIG_TYPE_DOUBLE:
		//	return LoadSettingValue(ini, section.str(), var.name, var.doubleValue);
		case CONFIG_TYPE_TCHAR:
			return LoadSettingValue(ini, section.str(), var.name, var.strValue);
		case CONFIG_TYPE_CHAR:
			return LoadSettingValue(ini, section.str(), var.name, var.strValue);
		//case CONFIG_TYPE_WCHAR:
		//	return LoadSettingValue(ini, section.str(), var.name, var.wstrValue);
		break;
		default:
			fprintf(stderr, "Invalid config type %d for %s\n", var.type, var.name);
			break;
	};
	return false;
}

/**
 *
 * [devices]
 * portX = pad
 *
 * [pad X]
 * api = joydev
 *
 * [joydev X]
 * button0 = 1
 * button1 = 2
 * ...
 *
 * */
bool SaveSetting(int port, const std::string& key, CONFIGVARIANT& var)
{
	fprintf(stderr, "USBqemu save \"%s\" to %s\n", var.name, key.c_str());

	std::stringstream section;
	section << key << " " << port;

	std::string ini(IniDir);
	ini.append(iniFile);

	switch(var.type)
	{
		case CONFIG_TYPE_INT:
			return SaveSettingValue(ini, section.str(), var.name, var.intValue);
		case CONFIG_TYPE_TCHAR:
			return LoadSettingValue(ini, section.str(), var.name, var.strValue);
		case CONFIG_TYPE_CHAR:
			return SaveSettingValue(ini, section.str(), var.name, var.strValue);
		break;
		default:
			fprintf(stderr, "Invalid config type %d for %s\n", var.type, var.name);
			break;
	};
	return false;
}

void SaveConfig() {
	fprintf(stderr, "USB save config\n");
	//char* envptr = getenv("HOME");
	//if(envptr == NULL)
	//	return;
	//char path[1024];
	//snprintf(path, sizeof(path), "%s/.config/PCSX2/inis/USBqemu-wheel.ini", envptr);
	std::string iniPath(IniDir);
	iniPath.append(iniFile);
	const char *path = iniPath.c_str();

	//fprintf(stderr, "%s\n", path);
	//snprintf(conf.usb_img, sizeof(conf.usb_img), "%s", usb_path.c_str());

	INISaveString(path, N_DEVICES, N_DEVICE_PORT0, conf.Port0.c_str());
	INISaveString(path, N_DEVICES, N_DEVICE_PORT1, conf.Port1.c_str());
	INISaveUInt(path, N_DEVICES, N_WHEEL_TYPE0, conf.WheelType[0]);
	INISaveUInt(path, N_DEVICES, N_WHEEL_TYPE1, conf.WheelType[1]);
	//INISaveString(path, N_DEVICES, "USB Image", conf.usb_img);
	//INISaveString(path, "Joystick", "Player1", player_joys[0].c_str());
	//INISaveString(path, "Joystick", "Player2", player_joys[1].c_str());
	for (auto& k : changedAPIs)
	{
		CONFIGVARIANT var(N_DEVICE_API, CONFIG_TYPE_CHAR);
		var.strValue = k.second;
		fprintf(stderr, "Save apis: %s %s\n", k.first.second.c_str(), k.second.c_str());
		SaveSetting(k.first.first, k.first.second, var);
	}
}

void LoadConfig() {
	char tmp[1024] = {0};
	fprintf(stderr, "USB load config\n");
	//char* envptr = getenv("HOME");
	//if(envptr == NULL)
	//	return;
	//char path[1024];
	//sprintf(path, "%s/.config/PCSX2/inis/USBqemu-wheel.ini", envptr);
	std::string iniPath(IniDir);
	iniPath.append(iniFile);
	const char *path = iniPath.c_str();

	INILoadString(path, N_DEVICES, N_DEVICE_PORT0, tmp);
	conf.Port0 = tmp;
	INILoadString(path, N_DEVICES, N_DEVICE_PORT1, tmp);
	conf.Port1 = tmp;
	INILoadUInt(path, N_DEVICES, N_WHEEL_TYPE0, (u32*)&conf.WheelType[0]);
	INILoadUInt(path, N_DEVICES, N_WHEEL_TYPE1, (u32*)&conf.WheelType[1]);

	{
		auto instance = RegisterDevice::instance();
		CONFIGVARIANT tmpVar(N_DEVICE_API, CONFIG_TYPE_CHAR);
		LoadSetting(0, conf.Port0, tmpVar);
		std::string api = tmpVar.strValue;
		auto dev = instance.Device(conf.Port0);

		if (dev && !dev->IsValidAPI(api))
		{
			auto apis = dev->APIs();
			if (!apis.empty())
				api = *apis.begin();
		}

		if(api.size())
			changedAPIs[std::make_pair(0, conf.Port0)] = api;

		LoadSetting(1, conf.Port1, tmpVar);
		api = tmpVar.strValue;

		dev = instance.Device(conf.Port1);
		if (dev && !dev->IsValidAPI(api))
		{
			auto apis = dev->APIs();
			if (!apis.empty())
				api = *apis.begin();
		}

		if(api.size())
			changedAPIs[std::make_pair(1, conf.Port1)] = api;
	}

	//INILoadString(path, N_DEVICES, "USB Image", conf.usb_img);
	//INILoadString(path, "Joystick", "Player1", tmp);
	//player_joys[0] = tmp;
	//INILoadString(path, "Joystick", "Player2", tmp);
	//player_joys[1] = tmp;
}
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "World.h"
#include "usefull.h"

#pragma warning (disable: 4091)
#include <dbghelp.h>

LONG CALLBACK unhandled_handler(::EXCEPTION_POINTERS* e)
{
	auto hDbgHelp = ::LoadLibraryA("dbghelp");
	if (hDbgHelp == nullptr)
		return EXCEPTION_CONTINUE_SEARCH;
	auto pMiniDumpWriteDump = (decltype(&MiniDumpWriteDump))::GetProcAddress(hDbgHelp, "MiniDumpWriteDump");
	if (pMiniDumpWriteDump == nullptr)
		return EXCEPTION_CONTINUE_SEARCH;

	char name[MAX_PATH];
	{
		auto nameEnd = name + ::GetModuleFileNameA(::GetModuleHandleA(0), name, MAX_PATH);
		::SYSTEMTIME t;
		::GetLocalTime(&t);
		wsprintfA(nameEnd - strlen(".exe"),
			"_crashdump_%4d%02d%02d_%02d%02d%02d.dmp",
			t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond);
	}

	auto hFile = ::CreateFileA(name, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
	if (hFile == INVALID_HANDLE_VALUE)
		return EXCEPTION_CONTINUE_SEARCH;

	::MINIDUMP_EXCEPTION_INFORMATION exceptionInfo;
	exceptionInfo.ThreadId = ::GetCurrentThreadId();
	exceptionInfo.ExceptionPointers = e;
	exceptionInfo.ClientPointers = FALSE;

	auto dumped = pMiniDumpWriteDump(
		::GetCurrentProcess(),
		::GetCurrentProcessId(),
		hFile,
		::MINIDUMP_TYPE(::MiniDumpWithIndirectlyReferencedMemory | ::MiniDumpScanMemory),
		e ? &exceptionInfo : nullptr,
		nullptr,
		nullptr);

	::CloseHandle(hFile);

	return EXCEPTION_CONTINUE_SEARCH;
}

HWND Hwnd;
WNDPROC BaseWindowProc;
PCOPYDATASTRUCT pDane;
extern TWorld World;

LRESULT APIENTRY WndProc( HWND hWnd, // handle for this window
                         UINT uMsg, // message for this window
                         WPARAM wParam, // additional message information
                         LPARAM lParam) // additional message information
{
    switch( uMsg ) // check for windows messages
    {
        case WM_COPYDATA: {
            // obsługa danych przesłanych przez program sterujący
            pDane = (PCOPYDATASTRUCT)lParam;
            if( pDane->dwData == MAKE_ID4('E', 'U', '0', '7')) // sygnatura danych
                World.OnCommandGet( (DaneRozkaz *)( pDane->lpData ) );
            break;
        }
    }
    // pass all unhandled messages to DefWindowProc
    return CallWindowProc( BaseWindowProc, Hwnd, uMsg, wParam, lParam );
};<commit_msg>crazy hack for weird numpads on windows<commit_after>#include "stdafx.h"
#include "World.h"
#include "usefull.h"

#pragma warning (disable: 4091)
#include <dbghelp.h>

LONG CALLBACK unhandled_handler(::EXCEPTION_POINTERS* e)
{
	auto hDbgHelp = ::LoadLibraryA("dbghelp");
	if (hDbgHelp == nullptr)
		return EXCEPTION_CONTINUE_SEARCH;
	auto pMiniDumpWriteDump = (decltype(&MiniDumpWriteDump))::GetProcAddress(hDbgHelp, "MiniDumpWriteDump");
	if (pMiniDumpWriteDump == nullptr)
		return EXCEPTION_CONTINUE_SEARCH;

	char name[MAX_PATH];
	{
		auto nameEnd = name + ::GetModuleFileNameA(::GetModuleHandleA(0), name, MAX_PATH);
		::SYSTEMTIME t;
		::GetLocalTime(&t);
		wsprintfA(nameEnd - strlen(".exe"),
			"_crashdump_%4d%02d%02d_%02d%02d%02d.dmp",
			t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond);
	}

	auto hFile = ::CreateFileA(name, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
	if (hFile == INVALID_HANDLE_VALUE)
		return EXCEPTION_CONTINUE_SEARCH;

	::MINIDUMP_EXCEPTION_INFORMATION exceptionInfo;
	exceptionInfo.ThreadId = ::GetCurrentThreadId();
	exceptionInfo.ExceptionPointers = e;
	exceptionInfo.ClientPointers = FALSE;

	auto dumped = pMiniDumpWriteDump(
		::GetCurrentProcess(),
		::GetCurrentProcessId(),
		hFile,
		::MINIDUMP_TYPE(::MiniDumpWithIndirectlyReferencedMemory | ::MiniDumpScanMemory),
		e ? &exceptionInfo : nullptr,
		nullptr,
		nullptr);

	::CloseHandle(hFile);

	return EXCEPTION_CONTINUE_SEARCH;
}

HWND Hwnd;
WNDPROC BaseWindowProc;
PCOPYDATASTRUCT pDane;
extern TWorld World;

LRESULT APIENTRY WndProc( HWND hWnd, // handle for this window
                         UINT uMsg, // message for this window
                         WPARAM wParam, // additional message information
                         LPARAM lParam) // additional message information
{
    switch( uMsg ) // check for windows messages
    {
        case WM_COPYDATA: {
            // obsługa danych przesłanych przez program sterujący
            pDane = (PCOPYDATASTRUCT)lParam;
            if( pDane->dwData == MAKE_ID4('E', 'U', '0', '7')) // sygnatura danych
                World.OnCommandGet( (DaneRozkaz *)( pDane->lpData ) );
            break;
        }
		case WM_KEYDOWN:
		case WM_KEYUP: {
			lParam &= ~0x1ff0000;
			lParam |= MapVirtualKey(MAPVK_VK_TO_VSC, wParam) << 16;
			break;
		}
    }
    // pass all unhandled messages to DefWindowProc
    return CallWindowProc( BaseWindowProc, Hwnd, uMsg, wParam, lParam );
};
<|endoftext|>


<commit_before>#include "Catch/catch.hpp"
#include "slang.h"

using namespace slang;

namespace {

SVInt testParameter(const std::string& text, int index = 0) {
    const auto& fullText = "module Top; " + text + " endmodule";
    auto tree = SyntaxTree::fromText<ModuleDeclarationSyntax>(StringRef(fullText));

    auto instance = SemanticModel(tree).makeImplicitInstance(
        tree.root()->as<ModuleDeclarationSyntax>());

    auto module = instance->module;
    REQUIRE(module);
    const auto* param = reinterpret_cast<const ParameterSymbol*>(
        module->scope->getNth(SymbolKind::Parameter, index));
    REQUIRE(param);

    if (!tree.diagnostics().empty())
        WARN(tree.reportDiagnostics());

    return param->value.integer();
}

TEST_CASE("Bind parameter", "[binding:expressions]") {
    CHECK(testParameter("parameter foo = 4;") == 4);
    CHECK(testParameter("parameter foo = 4 + 5;") == 9);
    CHECK(testParameter("parameter bar = 9, foo = bar + 1;", 1) == 10);
    CHECK(testParameter("parameter logic [3:0] foo = 4;") == 4);
    CHECK(testParameter("parameter logic [3:0] foo = 4'b100;") == 4);
}

TEST_CASE("Evaluate assignment expression", "[binding:expressions") {
    // Evaluate an assignment expression (has an LValue we can observe)
    auto syntax = SyntaxTree::fromText<ExpressionSyntax>("i = i + 3");
    SemanticModel sem { syntax };

    // Fabricate a symbol for the `i` variable
    auto varToken = syntax.root()->getFirstToken();
    VariableSymbol local {
        varToken.valueText(), varToken.location(),
        sem.getKnownType(SyntaxKind::LogicType)
    };

    // Bind the expression tree to the symbol
    Scope scope;
    scope.add(&local);
    ExpressionBinder binder(sem, &scope);
    auto bound = binder.bindConstantExpression(syntax.root()->as<ExpressionSyntax>());
    REQUIRE(syntax.diagnostics().empty());

    // Initialize `i` to 1.
    ConstantEvaluator ce;
    auto& i = ce.createTemporary(&local);
    i = SVInt(1);

    // Evaluate the expression tree.
    ce.evaluate(bound);
    CHECK(i.integer() == 4);

    // Run it again, results should be as you'd expect
    ce.evaluate(bound);
    CHECK(i.integer() == 7);
}

TEST_CASE("Check type propagation", "[binding:expressions]") {
    // Assignment operator should increase RHS size to 20
    auto syntax = SyntaxTree::fromText<ExpressionSyntax>("i = 5'b0101 + 4'b1100");
    SemanticModel sem { syntax };

    // Fabricate a symbol for the `i` variable
    auto varToken = syntax.root()->getFirstToken();
    VariableSymbol local {
        varToken.valueText(), varToken.location(),
        sem.getIntegralType(20, false)
    };

    // Bind the expression tree to the symbol
    Scope scope;
    scope.add(&local);
    ExpressionBinder binder(sem, &scope);
    BoundExpression* bound = binder.bindConstantExpression(syntax.root()->as<ExpressionSyntax>());
    REQUIRE(syntax.diagnostics().empty());

    CHECK(bound->type->width() == 20);
    BoundExpression* rhs = ((BoundAssignmentExpression *)bound)->right;
    CHECK(rhs->type->width() == 20);
    BoundExpression* op1 = ((BoundBinaryExpression *)rhs)->left;
    CHECK(op1->type->width() == 20);
    BoundExpression* op2 = ((BoundBinaryExpression *)rhs)->right;
    CHECK(op2->type->width() == 20);
}

TEST_CASE("Check type propagation 2", "[binding:expressions]") {
    // Tests a number of rules of size propogation
    auto syntax = SyntaxTree::fromText<ExpressionSyntax>("i = 2'b1 & (((17'b101 >> 1'b1) - 4'b1100) == 21'b1)");
    SemanticModel sem { syntax };

    // Fabricate a symbol for the `i` variable
    auto varToken = syntax.root()->getFirstToken();
    VariableSymbol local {
        varToken.valueText(), varToken.location(),
        sem.getIntegralType(20, false)
    };

    // Bind the expression tree to the symbol
    Scope scope;
    scope.add(&local);
    ExpressionBinder binder(sem, &scope);
    BoundExpression* bound = binder.bindConstantExpression(syntax.root()->as<ExpressionSyntax>());
    REQUIRE(syntax.diagnostics().empty());

    CHECK(bound->type->width() == 20);
    BoundExpression* rhs = ((BoundAssignmentExpression *)bound)->right;
    CHECK(rhs->type->width() == 20);
    BoundExpression* rrhs = ((BoundAssignmentExpression *)rhs)->right;
    CHECK(rrhs->type->width() == 1);
    BoundExpression* op1 = ((BoundBinaryExpression *)rrhs)->left;
    BoundExpression* shiftExpr = ((BoundBinaryExpression *)op1)->left;
    CHECK(shiftExpr->type->width() == 17);
    CHECK(op1->type->width() == 17);
    BoundExpression* op2 = ((BoundBinaryExpression *)rrhs)->right;
    CHECK(op2->type->width() == 21);
}

TEST_CASE("Check type propagation real", "[binding:expressions]") {
    // Tests a number of rules of size propogation
    auto syntax = SyntaxTree::fromText<ExpressionSyntax>("i = 2'b1 & (((17'b101 >> 1'b1) - 2.0) == 21'b1)");
    SemanticModel sem { syntax };

    // Fabricate a symbol for the `i` variable
    auto varToken = syntax.root()->getFirstToken();
    LocalVariableSymbol local {
        varToken.valueText(), varToken.location(),
        sem.getIntegralType(20, false)
    };

    // Bind the expression tree to the symbol
    Scope scope;
    scope.add(&local);
    ExpressionBinder binder(sem, &scope);
    BoundExpression* bound = binder.bindConstantExpression(syntax.root()->as<ExpressionSyntax>());
    REQUIRE(syntax.diagnostics().empty());

    CHECK(bound->type->width() == 20);
    BoundExpression* rhs = ((BoundAssignmentExpression *)bound)->right;
    CHECK(rhs->type->width() == 20);
    BoundExpression* rrhs = ((BoundAssignmentExpression *)rhs)->right;
    CHECK(rrhs->type->width() == 1);
    BoundExpression* op1 = ((BoundBinaryExpression *)rrhs)->left;
    BoundExpression* shiftExpr = ((BoundBinaryExpression *)op1)->left;
    CHECK(shiftExpr->type->width() == 64);
    CHECK(shiftExpr->type->isReal());
    BoundExpression* rshiftOp = ((BoundBinaryExpression *)shiftExpr)->right;
    CHECK(rshiftOp->type->width() == 1);
    BoundExpression* lshiftOp = ((BoundBinaryExpression *)shiftExpr)->left;
    CHECK(lshiftOp->type->width() == 17);
    CHECK(op1->type->width() == 64);
    CHECK(op1->type->isReal());
    BoundExpression* op2 = ((BoundBinaryExpression *)rrhs)->right;
    CHECK(op2->type->width() == 21);
}

}
<commit_msg>fix issue after merge<commit_after>#include "Catch/catch.hpp"
#include "slang.h"

using namespace slang;

namespace {

SVInt testParameter(const std::string& text, int index = 0) {
    const auto& fullText = "module Top; " + text + " endmodule";
    auto tree = SyntaxTree::fromText<ModuleDeclarationSyntax>(StringRef(fullText));

    auto instance = SemanticModel(tree).makeImplicitInstance(
        tree.root()->as<ModuleDeclarationSyntax>());

    auto module = instance->module;
    REQUIRE(module);
    const auto* param = reinterpret_cast<const ParameterSymbol*>(
        module->scope->getNth(SymbolKind::Parameter, index));
    REQUIRE(param);

    if (!tree.diagnostics().empty())
        WARN(tree.reportDiagnostics());

    return param->value.integer();
}

TEST_CASE("Bind parameter", "[binding:expressions]") {
    CHECK(testParameter("parameter foo = 4;") == 4);
    CHECK(testParameter("parameter foo = 4 + 5;") == 9);
    CHECK(testParameter("parameter bar = 9, foo = bar + 1;", 1) == 10);
    CHECK(testParameter("parameter logic [3:0] foo = 4;") == 4);
    CHECK(testParameter("parameter logic [3:0] foo = 4'b100;") == 4);
}

TEST_CASE("Evaluate assignment expression", "[binding:expressions") {
    // Evaluate an assignment expression (has an LValue we can observe)
    auto syntax = SyntaxTree::fromText<ExpressionSyntax>("i = i + 3");
    SemanticModel sem { syntax };

    // Fabricate a symbol for the `i` variable
    auto varToken = syntax.root()->getFirstToken();
    VariableSymbol local {
        varToken.valueText(), varToken.location(),
        sem.getKnownType(SyntaxKind::LogicType)
    };

    // Bind the expression tree to the symbol
    Scope scope;
    scope.add(&local);
    ExpressionBinder binder(sem, &scope);
    auto bound = binder.bindConstantExpression(syntax.root()->as<ExpressionSyntax>());
    REQUIRE(syntax.diagnostics().empty());

    // Initialize `i` to 1.
    ConstantEvaluator ce;
    auto& i = ce.createTemporary(&local);
    i = SVInt(1);

    // Evaluate the expression tree.
    ce.evaluate(bound);
    CHECK(i.integer() == 4);

    // Run it again, results should be as you'd expect
    ce.evaluate(bound);
    CHECK(i.integer() == 7);
}

TEST_CASE("Check type propagation", "[binding:expressions]") {
    // Assignment operator should increase RHS size to 20
    auto syntax = SyntaxTree::fromText<ExpressionSyntax>("i = 5'b0101 + 4'b1100");
    SemanticModel sem { syntax };

    // Fabricate a symbol for the `i` variable
    auto varToken = syntax.root()->getFirstToken();
    VariableSymbol local {
        varToken.valueText(), varToken.location(),
        sem.getIntegralType(20, false)
    };

    // Bind the expression tree to the symbol
    Scope scope;
    scope.add(&local);
    ExpressionBinder binder(sem, &scope);
    BoundExpression* bound = binder.bindConstantExpression(syntax.root()->as<ExpressionSyntax>());
    REQUIRE(syntax.diagnostics().empty());

    CHECK(bound->type->width() == 20);
    BoundExpression* rhs = ((BoundAssignmentExpression *)bound)->right;
    CHECK(rhs->type->width() == 20);
    BoundExpression* op1 = ((BoundBinaryExpression *)rhs)->left;
    CHECK(op1->type->width() == 20);
    BoundExpression* op2 = ((BoundBinaryExpression *)rhs)->right;
    CHECK(op2->type->width() == 20);
}

TEST_CASE("Check type propagation 2", "[binding:expressions]") {
    // Tests a number of rules of size propogation
    auto syntax = SyntaxTree::fromText<ExpressionSyntax>("i = 2'b1 & (((17'b101 >> 1'b1) - 4'b1100) == 21'b1)");
    SemanticModel sem { syntax };

    // Fabricate a symbol for the `i` variable
    auto varToken = syntax.root()->getFirstToken();
    VariableSymbol local {
        varToken.valueText(), varToken.location(),
        sem.getIntegralType(20, false)
    };

    // Bind the expression tree to the symbol
    Scope scope;
    scope.add(&local);
    ExpressionBinder binder(sem, &scope);
    BoundExpression* bound = binder.bindConstantExpression(syntax.root()->as<ExpressionSyntax>());
    REQUIRE(syntax.diagnostics().empty());

    CHECK(bound->type->width() == 20);
    BoundExpression* rhs = ((BoundAssignmentExpression *)bound)->right;
    CHECK(rhs->type->width() == 20);
    BoundExpression* rrhs = ((BoundAssignmentExpression *)rhs)->right;
    CHECK(rrhs->type->width() == 1);
    BoundExpression* op1 = ((BoundBinaryExpression *)rrhs)->left;
    BoundExpression* shiftExpr = ((BoundBinaryExpression *)op1)->left;
    CHECK(shiftExpr->type->width() == 17);
    CHECK(op1->type->width() == 17);
    BoundExpression* op2 = ((BoundBinaryExpression *)rrhs)->right;
    CHECK(op2->type->width() == 21);
}

TEST_CASE("Check type propagation real", "[binding:expressions]") {
    // Tests a number of rules of size propogation
    auto syntax = SyntaxTree::fromText<ExpressionSyntax>("i = 2'b1 & (((17'b101 >> 1'b1) - 2.0) == 21'b1)");
    SemanticModel sem { syntax };

    // Fabricate a symbol for the `i` variable
    auto varToken = syntax.root()->getFirstToken();
    VariableSymbol local {
        varToken.valueText(), varToken.location(),
        sem.getIntegralType(20, false)
    };

    // Bind the expression tree to the symbol
    Scope scope;
    scope.add(&local);
    ExpressionBinder binder(sem, &scope);
    BoundExpression* bound = binder.bindConstantExpression(syntax.root()->as<ExpressionSyntax>());
    REQUIRE(syntax.diagnostics().empty());

    CHECK(bound->type->width() == 20);
    BoundExpression* rhs = ((BoundAssignmentExpression *)bound)->right;
    CHECK(rhs->type->width() == 20);
    BoundExpression* rrhs = ((BoundAssignmentExpression *)rhs)->right;
    CHECK(rrhs->type->width() == 1);
    BoundExpression* op1 = ((BoundBinaryExpression *)rrhs)->left;
    BoundExpression* shiftExpr = ((BoundBinaryExpression *)op1)->left;
    CHECK(shiftExpr->type->width() == 64);
    CHECK(shiftExpr->type->isReal());
    BoundExpression* rshiftOp = ((BoundBinaryExpression *)shiftExpr)->right;
    CHECK(rshiftOp->type->width() == 1);
    BoundExpression* lshiftOp = ((BoundBinaryExpression *)shiftExpr)->left;
    CHECK(lshiftOp->type->width() == 17);
    CHECK(op1->type->width() == 64);
    CHECK(op1->type->isReal());
    BoundExpression* op2 = ((BoundBinaryExpression *)rrhs)->right;
    CHECK(op2->type->width() == 21);
}

}
<|endoftext|>


<commit_before>// Based on Maximillian integration example, see https://github.com/micknoise/Maximilian/tree/master/openFrameworks

#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){

    //housekeeping
    ofSetFrameRate(60);
    ofSetVerticalSync(true);
    ofEnableAlphaBlending();
    ofEnableSmoothing();
    ofBackground(0,0,0);

    //Maximillian setup
    sampleRate 	= 44100; /* Sampling Rate */
    bufferSize	= 512; /* Buffer Size. you have to fill this buffer with sound using the for loop in the audioOut method */
    ofxMaxiSettings::setup(sampleRate, 2, bufferSize);

    //ofxAVUI setup
    //Zone 0
    zones[0].setup("zone1", 100, 100, 200, "sound.wav", ofColor(100,100,100, 0), ofColor(0,255,255, 255), bufferSize);
    ofxAVUIXYPad *pad1 = new ofxAVUIXYPad("Pad", "togglePlay", "volume", "pitch");
    zones[0].addUI(pad1, 100);
    ofxAVUIToggle *toggle1 = new ofxAVUIToggle("Looping", "looping");
    zones[0].addUI(toggle1, 100);
//    ofxAVUIButton *button1 = new ofxAVUIButton("Trigger", "trigger");
//    zones[0].addUI(button1, 100);

    //always put visual last as the zone height is not fixed before
    ofxAVUIVisualWave *visual1 = new ofxAVUIVisualWave();
    zones[0].addVisual(visual1);

    //zones[0].updateParameters();  //TODO: update UI position to routed soundFx parameters

    //Zone 1
    zones[1].setup("zone2", 300, 100, 200, "Low.wav", ofColor(100,100,100, 0), ofColor(255,255,0, 255), bufferSize);
    ofxAVUIXYPad *pad2 = new ofxAVUIXYPad("Pad", "trigger", "pitch", "volume");
    zones[1].addUI(pad2, 100);
    ofxAVUIEmpty *empty1 = new ofxAVUIEmpty("Empty");
    zones[1].addUI(empty1, 100);
    ofxAVUISlider *slider1 = new ofxAVUISlider("Slider", "pitch", "trigger");
    zones[1].addUI(slider1, 100);

    //Zone 2
    zones[2].setup("zone3", 500, 100, 200, "synth.wav", ofColor(100,100,100, 0), ofColor(255,0,255, 255), bufferSize);
    ofxAVUIXYPad *pad3 = new ofxAVUIXYPad("Pad", "trigger", "pitch", "volume");
    zones[2].addUI(pad3, 100);

    ofxAVUISoundFxFilter *filter1 = new ofxAVUISoundFxFilter();
    filter1->setup("filter", false, "frequency", 200, 20000, 5000, "resonance", 0, 100, 50);
    zones[2].addSoundFx(filter1);

    ofxAVUIXYPad *pad4 = new ofxAVUIXYPad("Filter Pad", "filter", "frequency", "resonance");
    zones[2].addUI(pad4, 100);

    ofxAVUISoundFxDelay *delay1 = new ofxAVUISoundFxDelay();
    delay1->setup("delay", false, "size", 10000, 40000, 20000, "feedback", 0.5, 0.75, 1.0);
    zones[2].addSoundFx(delay1);

    ofxAVUIXYPad *pad5 = new ofxAVUIXYPad("Delay Pad", "delay", "size", "feedback");
    zones[2].addUI(pad5, 100);

    //always put visual last as the zone height is not fixed before
    ofxAVUIVisualWave *visual2 = new ofxAVUIVisualWave();
    zones[2].addVisual(visual2);

    //OF sound start
    ofSoundStreamSetup(2,2,this, sampleRate, bufferSize, 4); /* this has to happen at the end of setup - it switches on the DAC */

}

//--------------------------------------------------------------
void ofApp::update(){

}

//--------------------------------------------------------------
void ofApp::draw(){

    for (int k=0; k<3; k++) {
        zones[k].draw();
    }

    /* You can use any of the data from audio received and audiorequested to draw stuff here. */

}

//--------------------------------------------------------------
void ofApp::audioOut(float * output, int bufferSize, int nChannels) {

    for (int i = 0; i < bufferSize; i++){

        output[i*nChannels    ] = 0;
        output[i*nChannels + 1] = 0;

        for (int k=0; k<3; k++) {
            zones[k].play(i);
            output[i*nChannels    ] += zones[k].getOutput(0);
            output[i*nChannels + 1] += zones[k].getOutput(1);
        }
    }
}

//--------------------------------------------------------------
void ofApp::audioIn(float * input, int bufferSize, int nChannels){

    for(int i = 0; i < bufferSize; i++){
        /* you can also grab the data out of the arrays*/
    }

}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){

}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y){

}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){

}
<commit_msg>Small commit for man<commit_after>// Based on Maximillian integration example, see https://github.com/micknoise/Maximilian/tree/master/openFrameworks

#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){

    //housekeeping
    ofSetFrameRate(60);
    ofSetVerticalSync(true);
    ofEnableAlphaBlending();
    ofEnableSmoothing();
    ofBackground(0,0,0);

    //Maximillian setup
    sampleRate 	= 44100; /* Sampling Rate */
    bufferSize	= 512; /* Buffer Size. you have to fill this buffer with sound using the for loop in the audioOut method */
    ofxMaxiSettings::setup(sampleRate, 2, bufferSize);

    //ofxAVUI setup
    //Zone 0
    zones[0].setup("zone1", 100, 100, 200, "sound.wav", ofColor(100,100,100, 0), ofColor(0,255,255, 255), bufferSize);
    ofxAVUIXYPad *pad1 = new ofxAVUIXYPad("Pad", "togglePlay", "volume", "pitch");
    zones[0].addUI(pad1, 100);
    ofxAVUIToggle *toggle1 = new ofxAVUIToggle("Looping", "looping");
    zones[0].addUI(toggle1, 100);
    ofxAVUIButton *button1 = new ofxAVUIButton("Trigger", "trigger");
    zones[0].addUI(button1, 100);

    //always put visual last as the zone height is not fixed before
    ofxAVUIVisualWave *visual1 = new ofxAVUIVisualWave();
    zones[0].addVisual(visual1);

    //zones[0].updateParameters();  //TODO: update UI position to routed soundFx parameters

    //Zone 1
    zones[1].setup("zone2", 300, 100, 200, "Low.wav", ofColor(100,100,100, 0), ofColor(255,255,0, 255), bufferSize);
    ofxAVUIXYPad *pad2 = new ofxAVUIXYPad("Pad", "trigger", "pitch", "volume");
    zones[1].addUI(pad2, 100);
    ofxAVUIEmpty *empty1 = new ofxAVUIEmpty("Empty");
    zones[1].addUI(empty1, 100);
    ofxAVUISlider *slider1 = new ofxAVUISlider("Slider", "pitch", "trigger");
    zones[1].addUI(slider1, 100);

    //Zone 2
    zones[2].setup("zone3", 500, 100, 200, "synth.wav", ofColor(100,100,100, 0), ofColor(255,0,255, 255), bufferSize);
    ofxAVUIXYPad *pad3 = new ofxAVUIXYPad("Pad", "trigger", "pitch", "volume");
    zones[2].addUI(pad3, 100);

    ofxAVUISoundFxFilter *filter1 = new ofxAVUISoundFxFilter();
    filter1->setup("filter", false, "frequency", 200, 20000, 5000, "resonance", 0, 100, 50);
    zones[2].addSoundFx(filter1);

    ofxAVUIXYPad *pad4 = new ofxAVUIXYPad("Filter Pad", "filter", "frequency", "resonance");
    zones[2].addUI(pad4, 100);

    ofxAVUISoundFxDelay *delay1 = new ofxAVUISoundFxDelay();
    delay1->setup("delay", false, "size", 10000, 40000, 20000, "feedback", 0.5, 0.75, 1.0);
    zones[2].addSoundFx(delay1);

    ofxAVUIXYPad *pad5 = new ofxAVUIXYPad("Delay Pad", "delay", "size", "feedback");
    zones[2].addUI(pad5, 100);

    //always put visual last as the zone height is not fixed before
    ofxAVUIVisualWave *visual2 = new ofxAVUIVisualWave();
    zones[2].addVisual(visual2);

    //OF sound start
    ofSoundStreamSetup(2,2,this, sampleRate, bufferSize, 4); /* this has to happen at the end of setup - it switches on the DAC */

}

//--------------------------------------------------------------
void ofApp::update(){

}

//--------------------------------------------------------------
void ofApp::draw(){

    for (int k=0; k<3; k++) {
        zones[k].draw();
    }

    /* You can use any of the data from audio received and audiorequested to draw stuff here. */

}

//--------------------------------------------------------------
void ofApp::audioOut(float * output, int bufferSize, int nChannels) {

    for (int i = 0; i < bufferSize; i++){

        output[i*nChannels    ] = 0;
        output[i*nChannels + 1] = 0;

        for (int k=0; k<3; k++) {
            zones[k].play(i);
            output[i*nChannels    ] += zones[k].getOutput(0);
            output[i*nChannels + 1] += zones[k].getOutput(1);
        }
    }
}

//--------------------------------------------------------------
void ofApp::audioIn(float * input, int bufferSize, int nChannels){

    for(int i = 0; i < bufferSize; i++){
        /* you can also grab the data out of the arrays*/
    }

}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){

}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y){

}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){

}
<|endoftext|>