mirror of https://github.com/KLayout/klayout.git
Some debugging, tests added
This commit is contained in:
parent
3eff75433c
commit
7d2113ffe1
|
|
@ -29,6 +29,8 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "edtCommon.h"
|
||||||
|
|
||||||
#include "layObjectInstPath.h"
|
#include "layObjectInstPath.h"
|
||||||
#include "laySnap.h"
|
#include "laySnap.h"
|
||||||
|
|
||||||
|
|
@ -54,17 +56,17 @@ class Service;
|
||||||
* This implements the standard modifiers for angle constraints - i.e.
|
* This implements the standard modifiers for angle constraints - i.e.
|
||||||
* ortho for "Shift".
|
* ortho for "Shift".
|
||||||
*/
|
*/
|
||||||
extern lay::angle_constraint_type ac_from_buttons (unsigned int buttons);
|
EDT_PUBLIC lay::angle_constraint_type ac_from_buttons (unsigned int buttons);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Serializes PCell parameters to a string
|
* @brief Serializes PCell parameters to a string
|
||||||
*/
|
*/
|
||||||
std::string pcell_parameters_to_string (const std::map<std::string, tl::Variant> ¶meters);
|
EDT_PUBLIC std::string pcell_parameters_to_string (const std::map<std::string, tl::Variant> ¶meters);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Deserializes PCell parameters from a string
|
* @brief Deserializes PCell parameters from a string
|
||||||
*/
|
*/
|
||||||
std::map<std::string, tl::Variant> pcell_parameters_from_string (const std::string &s);
|
EDT_PUBLIC std::map<std::string, tl::Variant> pcell_parameters_from_string (const std::string &s);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Fetch PCell parameters from a cell and merge the guiding shapes into them
|
* @brief Fetch PCell parameters from a cell and merge the guiding shapes into them
|
||||||
|
|
@ -74,13 +76,13 @@ std::map<std::string, tl::Variant> pcell_parameters_from_string (const std::stri
|
||||||
* @param parameters_for_pcell Will receive the parameters
|
* @param parameters_for_pcell Will receive the parameters
|
||||||
* @return true, if the cell is a PCell and parameters have been fetched
|
* @return true, if the cell is a PCell and parameters have been fetched
|
||||||
*/
|
*/
|
||||||
bool
|
EDT_PUBLIC bool
|
||||||
get_parameters_from_pcell_and_guiding_shapes (db::Layout *layout, db::cell_index_type cell_index, db::pcell_parameters_type ¶meters_for_pcell);
|
get_parameters_from_pcell_and_guiding_shapes (db::Layout *layout, db::cell_index_type cell_index, db::pcell_parameters_type ¶meters_for_pcell);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A helper class that identifies clipboard data for edt::
|
* @brief A helper class that identifies clipboard data for edt::
|
||||||
*/
|
*/
|
||||||
class ClipboardData
|
class EDT_PUBLIC ClipboardData
|
||||||
: public db::ClipboardData
|
: public db::ClipboardData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -90,7 +92,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* @brief A cache for the transformation variants for a certain layer and cell view index for a lay::LayoutView
|
* @brief A cache for the transformation variants for a certain layer and cell view index for a lay::LayoutView
|
||||||
*/
|
*/
|
||||||
class TransformationVariants
|
class EDT_PUBLIC TransformationVariants
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TransformationVariants (const lay::LayoutViewBase *view, bool per_cv_and_layer = true, bool per_cv = true);
|
TransformationVariants (const lay::LayoutViewBase *view, bool per_cv_and_layer = true, bool per_cv = true);
|
||||||
|
|
|
||||||
|
|
@ -404,6 +404,12 @@ public:
|
||||||
return f_configure.can_issue () ? f_configure.issue<PluginBase, bool, const std::string &, const std::string &> (&PluginBase::configure, name, value) : lay::Plugin::configure (name, value);
|
return f_configure.can_issue () ? f_configure.issue<PluginBase, bool, const std::string &, const std::string &> (&PluginBase::configure, name, value) : lay::Plugin::configure (name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for testing
|
||||||
|
void configure_test (const std::string &name, const std::string &value)
|
||||||
|
{
|
||||||
|
configure_edt (name, value);
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool configure (const std::string &name, const std::string &value)
|
virtual bool configure (const std::string &name, const std::string &value)
|
||||||
{
|
{
|
||||||
configure_edt (name, value);
|
configure_edt (name, value);
|
||||||
|
|
@ -633,21 +639,43 @@ public:
|
||||||
lay::EditorServiceBase::add_edge_marker (p, cv_index, cv.context_trans (), *tv_list, emphasize);
|
lay::EditorServiceBase::add_edge_marker (p, cv_index, cv.context_trans (), *tv_list, emphasize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for testing
|
||||||
|
bool has_tracking_position_test () const
|
||||||
|
{
|
||||||
|
return has_tracking_position ();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_tracking_position_base () const
|
||||||
|
{
|
||||||
|
return lay::EditorServiceBase::has_tracking_position ();
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool has_tracking_position () const
|
virtual bool has_tracking_position () const
|
||||||
{
|
{
|
||||||
if (f_has_tracking_position.can_issue ()) {
|
if (f_has_tracking_position.can_issue ()) {
|
||||||
return f_has_tracking_position.issue<lay::EditorServiceBase, bool> (&lay::EditorServiceBase::has_tracking_position);
|
return f_has_tracking_position.issue<lay::EditorServiceBase, bool> (&lay::EditorServiceBase::has_tracking_position);
|
||||||
} else {
|
} else {
|
||||||
return lay::EditorServiceBase::has_tracking_position ();
|
return has_tracking_position_base ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for testing
|
||||||
|
db::DPoint tracking_position_test () const
|
||||||
|
{
|
||||||
|
return tracking_position ();
|
||||||
|
}
|
||||||
|
|
||||||
|
db::DPoint tracking_position_base () const
|
||||||
|
{
|
||||||
|
return lay::EditorServiceBase::tracking_position ();
|
||||||
|
}
|
||||||
|
|
||||||
virtual db::DPoint tracking_position () const
|
virtual db::DPoint tracking_position () const
|
||||||
{
|
{
|
||||||
if (f_tracking_position.can_issue ()) {
|
if (f_tracking_position.can_issue ()) {
|
||||||
return f_tracking_position.issue<lay::EditorServiceBase, db::DPoint> (&lay::EditorServiceBase::tracking_position);
|
return f_tracking_position.issue<lay::EditorServiceBase, db::DPoint> (&lay::EditorServiceBase::tracking_position);
|
||||||
} else {
|
} else {
|
||||||
return lay::EditorServiceBase::tracking_position ();
|
return tracking_position_base ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -662,13 +690,17 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(HAVE_QTBINDINGS)
|
#if defined(HAVE_QTBINDINGS)
|
||||||
std::vector<lay::EditorOptionsPage *> editor_options_pages ()
|
std::vector<QWidget *> editor_options_pages ()
|
||||||
{
|
{
|
||||||
lay::EditorOptionsPages *eo_pages = view ()->editor_options_pages ();
|
lay::EditorOptionsPages *eo_pages = view ()->editor_options_pages ();
|
||||||
if (!eo_pages) {
|
if (!eo_pages) {
|
||||||
return std::vector<lay::EditorOptionsPage *> ();
|
return std::vector<QWidget *> ();
|
||||||
} else {
|
} else {
|
||||||
return eo_pages->pages ();
|
std::vector<QWidget *> pages;
|
||||||
|
for (auto p = eo_pages->pages ().begin (); p != eo_pages->pages ().end (); ++p) {
|
||||||
|
pages.push_back (*p);
|
||||||
|
}
|
||||||
|
return pages;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -1281,6 +1313,7 @@ Class<gsi::PluginBase> decl_Plugin ("lay", "Plugin",
|
||||||
"When a menu item is clicked which was registered with the plugin factory, the plugin's 'menu_activated' method is "
|
"When a menu item is clicked which was registered with the plugin factory, the plugin's 'menu_activated' method is "
|
||||||
"called for the current view. The symbol registered for the menu item is passed in the 'symbol' argument."
|
"called for the current view. The symbol registered for the menu item is passed in the 'symbol' argument."
|
||||||
) +
|
) +
|
||||||
|
method ("configure_test", &gsi::PluginBase::configure_test, gsi::arg ("name"), gsi::arg ("value"), "@hide") +
|
||||||
callback ("configure", &gsi::PluginBase::configure_impl, &gsi::PluginBase::f_configure, gsi::arg ("name"), gsi::arg ("value"),
|
callback ("configure", &gsi::PluginBase::configure_impl, &gsi::PluginBase::f_configure, gsi::arg ("name"), gsi::arg ("value"),
|
||||||
"@brief Sends configuration requests to the plugin\n"
|
"@brief Sends configuration requests to the plugin\n"
|
||||||
"@param name The name of the configuration variable as registered in the plugin factory\n"
|
"@param name The name of the configuration variable as registered in the plugin factory\n"
|
||||||
|
|
@ -1384,6 +1417,8 @@ Class<gsi::PluginBase> decl_Plugin ("lay", "Plugin",
|
||||||
"\n"
|
"\n"
|
||||||
"The cursor type is one of the cursor constants in the \\Cursor class, i.e. 'CursorArrow' for the normal cursor."
|
"The cursor type is one of the cursor constants in the \\Cursor class, i.e. 'CursorArrow' for the normal cursor."
|
||||||
) +
|
) +
|
||||||
|
method ("has_tracking_position_test", &gsi::PluginBase::has_tracking_position_test, "@hide") +
|
||||||
|
method ("has_tracking_position", &gsi::PluginBase::has_tracking_position_base, "@hide") +
|
||||||
callback ("has_tracking_position", &gsi::PluginBase::has_tracking_position, &gsi::PluginBase::f_has_tracking_position,
|
callback ("has_tracking_position", &gsi::PluginBase::has_tracking_position, &gsi::PluginBase::f_has_tracking_position,
|
||||||
"@brief Gets a value indicating whether the plugin provides a tracking position\n"
|
"@brief Gets a value indicating whether the plugin provides a tracking position\n"
|
||||||
"The tracking position is shown in the lower-left corner of the layout window to indicate the current position.\n"
|
"The tracking position is shown in the lower-left corner of the layout window to indicate the current position.\n"
|
||||||
|
|
@ -1392,6 +1427,8 @@ Class<gsi::PluginBase> decl_Plugin ("lay", "Plugin",
|
||||||
"\n"
|
"\n"
|
||||||
"This method has been added in version 0.27.6."
|
"This method has been added in version 0.27.6."
|
||||||
) +
|
) +
|
||||||
|
method ("tracking_position_test", &gsi::PluginBase::tracking_position_test, "@hide") +
|
||||||
|
method ("tracking_position", &gsi::PluginBase::tracking_position_base, "@hide") +
|
||||||
callback ("tracking_position", &gsi::PluginBase::tracking_position, &gsi::PluginBase::f_tracking_position,
|
callback ("tracking_position", &gsi::PluginBase::tracking_position, &gsi::PluginBase::f_tracking_position,
|
||||||
"@brief Gets the tracking position\n"
|
"@brief Gets the tracking position\n"
|
||||||
"See \\has_tracking_position for details.\n"
|
"See \\has_tracking_position for details.\n"
|
||||||
|
|
|
||||||
|
|
@ -141,8 +141,14 @@ public:
|
||||||
*/
|
*/
|
||||||
void show_error (tl::Exception &ex);
|
void show_error (tl::Exception &ex);
|
||||||
|
|
||||||
protected:
|
/**
|
||||||
|
* @brief Sets a configuration option
|
||||||
|
*/
|
||||||
virtual bool configure (const std::string &name, const std::string &value);
|
virtual bool configure (const std::string &name, const std::string &value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Called when the plugin is deactivated
|
||||||
|
*/
|
||||||
virtual void deactivated ();
|
virtual void deactivated ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -602,20 +602,25 @@ void LayoutViewBase::create_plugins (const lay::PluginDeclaration *except_this)
|
||||||
clear_plugins ();
|
clear_plugins ();
|
||||||
|
|
||||||
// create the plugins
|
// create the plugins
|
||||||
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
|
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ) {
|
||||||
|
|
||||||
if (&*cls != except_this) {
|
// NOTE: during "create_plugin" a plugin may be unregistered, so don't increment the iterator after
|
||||||
|
auto current = cls.operator-> ();
|
||||||
|
std::string current_name = cls.current_name ();
|
||||||
|
++cls;
|
||||||
|
|
||||||
|
if (current != except_this) {
|
||||||
|
|
||||||
// TODO: clean solution. The following is a HACK:
|
// TODO: clean solution. The following is a HACK:
|
||||||
if (cls.current_name () == "ant::Plugin" || cls.current_name () == "img::Plugin") {
|
if (current_name == "ant::Plugin" || current_name == "img::Plugin") {
|
||||||
// ant and img are created always
|
// ant and img are created always
|
||||||
create_plugin (&*cls);
|
create_plugin (current);
|
||||||
} else if ((options () & LV_NoPlugins) == 0) {
|
} else if ((options () & LV_NoPlugins) == 0) {
|
||||||
// others: only create unless LV_NoPlugins is set
|
// others: only create unless LV_NoPlugins is set
|
||||||
create_plugin (&*cls);
|
create_plugin (current);
|
||||||
} else if ((options () & LV_NoGrid) == 0 && cls.current_name () == "GridNetPlugin") {
|
} else if ((options () & LV_NoGrid) == 0 && current_name == "GridNetPlugin") {
|
||||||
// except grid net plugin which is created on request
|
// except grid net plugin which is created on request
|
||||||
create_plugin (&*cls);
|
create_plugin (current);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,7 @@ RUBYTEST (layMainWindow, "layMainWindow.rb")
|
||||||
RUBYTEST (layMarkers, "layMarkers.rb")
|
RUBYTEST (layMarkers, "layMarkers.rb")
|
||||||
RUBYTEST (layMacro, "layMacro.rb")
|
RUBYTEST (layMacro, "layMacro.rb")
|
||||||
RUBYTEST (layMenuTest, "layMenuTest.rb")
|
RUBYTEST (layMenuTest, "layMenuTest.rb")
|
||||||
|
RUBYTEST (layPluginTests, "layPluginTests.rb")
|
||||||
RUBYTEST (layPixelBuffer, "layPixelBuffer.rb")
|
RUBYTEST (layPixelBuffer, "layPixelBuffer.rb")
|
||||||
RUBYTEST (laySession, "laySession.rb")
|
RUBYTEST (laySession, "laySession.rb")
|
||||||
RUBYTEST (laySaveLayoutOptions, "laySaveLayoutOptions.rb")
|
RUBYTEST (laySaveLayoutOptions, "laySaveLayoutOptions.rb")
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,145 @@
|
||||||
|
# encoding: UTF-8
|
||||||
|
|
||||||
|
# KLayout Layout Viewer
|
||||||
|
# Copyright (C) 2006-2025 Matthias Koefferlein
|
||||||
|
#
|
||||||
|
# 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 St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
if !$:.member?(File::dirname($0))
|
||||||
|
$:.push(File::dirname($0))
|
||||||
|
end
|
||||||
|
|
||||||
|
load("test_prologue.rb")
|
||||||
|
|
||||||
|
class PluginFactory < RBA::PluginFactory
|
||||||
|
def initialize()
|
||||||
|
register(1000, "plugin_for_test", "Plugin")
|
||||||
|
@pi = nil
|
||||||
|
end
|
||||||
|
def create_plugin(manager, unused, view)
|
||||||
|
@pi = RBA::Plugin::new
|
||||||
|
@pi
|
||||||
|
end
|
||||||
|
def pi
|
||||||
|
@pi
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Plugin2 < RBA::Plugin
|
||||||
|
def set_tp(tp)
|
||||||
|
@tp = tp
|
||||||
|
end
|
||||||
|
def has_tracking_position
|
||||||
|
!!@tp
|
||||||
|
end
|
||||||
|
def tracking_position
|
||||||
|
@tp || RBA::DPoint::new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class PluginFactory2 < RBA::PluginFactory
|
||||||
|
def initialize()
|
||||||
|
register(1001, "plugin_for_test2", "Plugin2")
|
||||||
|
@pi = nil
|
||||||
|
end
|
||||||
|
def create_plugin(manager, unused, view)
|
||||||
|
@pi = Plugin2::new
|
||||||
|
@pi
|
||||||
|
end
|
||||||
|
def pi
|
||||||
|
@pi
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class LayPlugin_TestClass < TestBase
|
||||||
|
|
||||||
|
def test_1
|
||||||
|
|
||||||
|
assert_equal(RBA::Plugin::AC_Global.to_s, "AC_Global")
|
||||||
|
assert_equal(RBA::Plugin::AC_Any.to_s, "AC_Any")
|
||||||
|
assert_equal(RBA::Plugin::AC_Diagonal.to_s, "AC_Diagonal")
|
||||||
|
assert_equal(RBA::Plugin::AC_Horizontal.to_s, "AC_Horizontal")
|
||||||
|
assert_equal(RBA::Plugin::AC_Vertical.to_s, "AC_Vertical")
|
||||||
|
|
||||||
|
assert_equal(RBA::Plugin::ac_from_buttons(0), RBA::Plugin::AC_Global)
|
||||||
|
assert_equal(RBA::Plugin::ac_from_buttons(1), RBA::Plugin::AC_Ortho)
|
||||||
|
assert_equal(RBA::Plugin::ac_from_buttons(2), RBA::Plugin::AC_Diagonal)
|
||||||
|
|
||||||
|
begin
|
||||||
|
|
||||||
|
dpi = PluginFactory::new
|
||||||
|
dpi2 = PluginFactory2::new
|
||||||
|
|
||||||
|
# Create a new layout
|
||||||
|
main_window = RBA::MainWindow.instance()
|
||||||
|
main_window.close_all
|
||||||
|
main_window.create_layout(2)
|
||||||
|
|
||||||
|
pi = dpi.pi
|
||||||
|
pi2 = dpi2.pi
|
||||||
|
|
||||||
|
# smoke test
|
||||||
|
pi.grab_mouse
|
||||||
|
pi.ungrab_mouse
|
||||||
|
pi.set_cursor(RBA::Cursor::Wait)
|
||||||
|
pi.add_edge_marker(RBA::DEdge::new)
|
||||||
|
pi.add_mouse_cursor(RBA::DPoint::new)
|
||||||
|
pi.clear_mouse_cursors
|
||||||
|
|
||||||
|
# virtual methods
|
||||||
|
assert_equal(pi.has_tracking_position_test, false)
|
||||||
|
pi.clear_mouse_cursors
|
||||||
|
pi.add_mouse_cursor(RBA::DPoint::new(1, 2))
|
||||||
|
assert_equal(pi.has_tracking_position_test, true)
|
||||||
|
assert_equal(pi.tracking_position_test.to_s, "1,2")
|
||||||
|
pi.clear_mouse_cursors
|
||||||
|
assert_equal(pi.has_tracking_position_test, false)
|
||||||
|
|
||||||
|
assert_equal(pi2.has_tracking_position_test, false)
|
||||||
|
pi2.set_tp(RBA::DPoint::new(2, 3))
|
||||||
|
assert_equal(pi2.has_tracking_position_test, true)
|
||||||
|
assert_equal(pi2.tracking_position_test.to_s, "2,3")
|
||||||
|
pi2.set_tp(nil)
|
||||||
|
assert_equal(pi2.has_tracking_position_test, false)
|
||||||
|
|
||||||
|
pi.configure_test("edit-grid", "0.0")
|
||||||
|
assert_equal(pi.snap(RBA::DPoint::new(0.01, 0.02)).to_s, "0.01,0.02")
|
||||||
|
assert_equal(pi.snap(RBA::DVector::new(0.01, 0.02)).to_s, "0.01,0.02")
|
||||||
|
pi.configure_test("edit-grid", "0.1")
|
||||||
|
assert_equal(pi.snap(RBA::DPoint::new(0.11, 0.18)).to_s, "0.1,0.2")
|
||||||
|
assert_equal(pi.snap(RBA::DVector::new(0.11, 0.18)).to_s, "0.1,0.2")
|
||||||
|
|
||||||
|
pi.configure_test("edit-connect-angle-mode", "ortho")
|
||||||
|
assert_equal(pi.snap(RBA::DPoint::new(1.5, 2.1), RBA::DPoint::new(1, 2), true).to_s, "1.5,2")
|
||||||
|
assert_equal(pi.snap(RBA::DPoint::new(1.5, 2.1), RBA::DPoint::new(1, 2), false).to_s, "1.5,2.1")
|
||||||
|
assert_equal(pi.snap(RBA::DPoint::new(1.5, 2.1), RBA::DPoint::new(1, 2), false, RBA::Plugin::AC_Ortho).to_s, "1.5,2")
|
||||||
|
|
||||||
|
pi.configure_test("edit-connect-angle-mode", "ortho")
|
||||||
|
assert_equal(pi.snap(RBA::DVector::new(0.5, 2.1), true).to_s, "0,2.1")
|
||||||
|
assert_equal(pi.snap(RBA::DVector::new(0.5, 2.1), false).to_s, "0.5,2.1")
|
||||||
|
assert_equal(pi.snap(RBA::DVector::new(0.5, 2.1), false, RBA::Plugin::AC_Ortho).to_s, "0,2.1")
|
||||||
|
|
||||||
|
ensure
|
||||||
|
main_window.close_all
|
||||||
|
dpi._destroy
|
||||||
|
dpi2._destroy
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
load("test_epilogue.rb")
|
||||||
|
|
||||||
Loading…
Reference in New Issue