[Problem] DALi leaves options that it has handled in the command line arguments.
[Cause] N/A
[Solution] Take the options that are handled by DALi out.
Change-Id: I8766b67bf9a578da9dc6fc6678fc13bdf25a975c
Signed-off-by: Adeel Kazmi <adeel.kazmi@samsung.com>
// reset is used to store a new value associated with this thread
gThreadLocalApplication.reset(this);
- mCommandLineOptions = new CommandLineOptions(*argc, *argv);
+ mCommandLineOptions = new CommandLineOptions(argc, argv);
mFramework = new Framework(*this, argc, argv, name);
}
#include <stdlib.h>
#include <string.h>
#include <iostream>
+#include <vector>
namespace Dali
{
namespace
{
- const char * RENDER_NO_VSYNC_OPTION = "no-vsync";
- const char * RENDER_NO_VSYNC_DETAIL = "Disable VSync on Render";
-
- const char * RENDER_WIDTH_OPTION = "width";
- const char * RENDER_WIDTH_DETAIL = "Stage Width";
+struct Argument
+{
+ const char * const opt;
+ const char * const optDescription;
- const char * RENDER_HEIGHT_OPTION = "height";
- const char * RENDER_HEIGHT_DETAIL = "Stage Height";
+ void Print()
+ {
+ std::cout << std::left << " --";
+ std::cout.width( 15 );
+ std::cout << opt;
+ std::cout << optDescription;
+ std::cout << std::endl;
+ }
+};
- const char * RENDER_DPI_OPTION = "dpi";
- const char * RENDER_DPI_DETAIL = "Emulated DPI";
+Argument EXPECTED_ARGS[] =
+{
+ { "no-vsync", "Disable VSync on Render" },
+ { "width", "Stage Width" },
+ { "height", "Stage Height" },
+ { "dpi", "Emulated DPI" },
+ { "help", "Help" },
- const char * USAGE = "help";
+ { NULL, NULL }
+};
- struct Arguments
- {
- const char * opt;
- const char * optDescription;
+enum Option
+{
+ OPTION_NO_VSYNC = 0,
+ OPTION_STAGE_WIDTH,
+ OPTION_STAGE_HEIGHT,
+ OPTION_DPI,
+ OPTION_HELP
+};
- void Print()
- {
- std::cout << "--" << opt << " " << optDescription;
- }
- };
-
- Arguments arguments[] =
- {
- { RENDER_NO_VSYNC_OPTION, RENDER_NO_VSYNC_DETAIL },
- { RENDER_WIDTH_OPTION, RENDER_WIDTH_DETAIL },
- { RENDER_HEIGHT_OPTION, RENDER_HEIGHT_DETAIL },
- { RENDER_DPI_OPTION, RENDER_DPI_DETAIL },
- { NULL, NULL }
- };
+typedef std::vector< int > UnhandledContainer;
} // unnamed namespace
-
-CommandLineOptions::CommandLineOptions(int argc, char *argv[])
+CommandLineOptions::CommandLineOptions(int *argc, char **argv[])
: noVSyncOnRender(0),
stageWidth(0), stageHeight(0)
{
- const struct option options[]=
+ if ( *argc > 1 )
{
- { arguments[0].opt, no_argument, &noVSyncOnRender, 1 }, // "--no-vsync"
- { arguments[1].opt, required_argument, NULL, 'w' }, // "--width"
- { arguments[2].opt, required_argument, NULL, 'h' }, // "--height"
- { arguments[3].opt, required_argument, NULL, 'd' }, // "--dpi"
- { USAGE, no_argument, NULL, 'u'},
- { 0, 0, 0, 0 } // end of options
- };
+ // We do not want to print out errors.
+ int origOptErrValue( opterr );
+ opterr = 0;
+ int help( 0 );
- int opt(0);
- int optIndex(0);
+ const struct option options[]=
+ {
+ { EXPECTED_ARGS[OPTION_NO_VSYNC].opt, no_argument, &noVSyncOnRender, 1 }, // "--no-vsync"
+ { EXPECTED_ARGS[OPTION_STAGE_WIDTH].opt, required_argument, NULL, 'w' }, // "--width"
+ { EXPECTED_ARGS[OPTION_STAGE_HEIGHT].opt, required_argument, NULL, 'h' }, // "--height"
+ { EXPECTED_ARGS[OPTION_DPI].opt, required_argument, NULL, 'd' }, // "--dpi"
+ { EXPECTED_ARGS[OPTION_HELP].opt, no_argument, &help, 1 }, // "--help"
+ { 0, 0, 0, 0 } // end of options
+ };
- const char* optString = "w:h:d:?";
+ int shortOption( 0 );
+ int optionIndex( 0 );
- do
- {
- opt = getopt_long(argc, argv, optString, options, &optIndex);
+ const char* optString = "-w:h:d:"; // The '-' ensures that argv is NOT permuted
+ bool optionProcessed( false );
+
+ UnhandledContainer unhandledOptions; // We store indices of options we do not handle here
+
+ do
+ {
+ shortOption = getopt_long( *argc, *argv, optString, options, &optionIndex );
+
+ switch ( shortOption )
+ {
+ case 0:
+ {
+ // Check if we want help
+ if ( help )
+ {
+ std::cout << "Available options:" << std::endl;
+ Argument* arg = EXPECTED_ARGS;
+ while ( arg->opt )
+ {
+ arg->Print();
+ ++arg;
+ }
+ optionProcessed = true;
+ }
+ break;
+ }
+
+ case 'w':
+ {
+ if ( optarg )
+ {
+ stageWidth = atoi( optarg );
+ optionProcessed = true;
+ }
+ break;
+ }
+
+ case 'h':
+ {
+ if ( optarg )
+ {
+ stageHeight = atoi( optarg );
+ optionProcessed = true;
+ }
+ break;
+ }
+
+ case 'd':
+ {
+ if ( optarg )
+ {
+ stageDPI.assign( optarg );
+ optionProcessed = true;
+ }
+ break;
+ }
- switch (opt)
+ case -1:
+ {
+ // All command-line options have been parsed.
+ break;
+ }
+
+ default:
+ {
+ unhandledOptions.push_back( optind - 1 );
+ break;
+ }
+ }
+ } while ( shortOption != -1 );
+
+ // Take out the options we have processed
+ if ( optionProcessed )
{
- case 0:
- // if setting vsync getopt set flag already
- break;
- case 'w':
- stageWidth = atoi(optarg);
- break;
- case 'h':
- stageHeight = atoi(optarg);
- break;
- case 'd':
- stageDPI.assign(optarg);
- break;
- case 'u':
- // show usage
- std::cout << "Available options:" << std::endl;
- for ( int i = 0; arguments[i].opt != NULL; ++i)
+ if ( !unhandledOptions.empty() )
+ {
+ int index( 1 );
+
+ // Overwrite the argv with the values from the unhandled indices
+ const UnhandledContainer::const_iterator endIter = unhandledOptions.end();
+ for ( UnhandledContainer::iterator iter = unhandledOptions.begin(); iter != endIter; ++iter )
{
- arguments[i].Print();
- std::cout << std::endl;
+ (*argv)[ index++ ] = (*argv)[ *iter ];
}
- break;
- default:
- // -1 will exit here (no more options to parse)
- break;
+ *argc = unhandledOptions.size() + 1; // +1 for the program name
+ }
+ else
+ {
+ // There are no unhandled options, so we should just have the program name
+ *argc = 1;
+ }
+
+ optind = 1; // Reset to start
}
- }
- while (opt != -1);
- // Ignores any unknown options
+ opterr = origOptErrValue; // Reset opterr value.
+ }
}
CommandLineOptions::~CommandLineOptions()
/**
* Parses the passed command line arguments and sets the values stored within this
* class appropriately.
+ *
+ * The following options are supported:
+ *
+ * @code
+ * --no-vsync Disable VSync on Render
+ * -w|--width Stage Width
+ * -h|--height Stage Height
+ * -d|--dpi Emulated DPI
+ * --help Help
+ * @endcode
+ *
+ * When the above options are found, they are stripped from argv, and argc is updated appropriately.
*/
struct CommandLineOptions
{
/**
* Constructor
- * @param[in] argc The number of arguments
- * @param[in] argv The argument list
+ * @param[in,out] argc The number of arguments
+ * @param[in,out] argv The argument list
+ * @note Supported options are stripped from argv, and argc is updated appropriately.
*/
- CommandLineOptions(int argc, char *argv[]);
+ CommandLineOptions(int *argc, char **argv[]);
/**
* Destructor
* function and instead should connect to the Init signal of the
* Application and create the Dali objects in the connected callback.
*
- * Linux Applications should follow the example below:
+ * Applications should follow the example below:
*
* @code
* void CreateProgram(Application app)
* MyApplication app;
* app.ResumeSignal().Connect(&app, &MyApplication::Resume);
* @endcode
+ *
+ * This class accepts command line arguments as well. The following options are supported:
+ *
+ * @code
+ * --no-vsync Disable VSync on Render
+ * -w|--width Stage Width
+ * -h|--height Stage Height
+ * -d|--dpi Emulated DPI
+ * --help Help
+ * @endcode
+ *
+ * When the above options are found, they are stripped from argv, and argc is updated appropriately.
*/
class Application : public BaseHandle
{
public:
/**
- * This is the constructor for Linux & SLP applications.
- * @param argc A pointer to the number of arguments
- * @param argv A pointer the the argument list
+ * This is the constructor for applications.
+ *
+ * @param[in,out] argc A pointer to the number of arguments
+ * @param[in,out] argv A pointer the the argument list
+ *
* @note The default base layout (DeviceLayout::DEFAULT_BASE_LAYOUT) will be used with this constructor.
+ * @note Supported options are stripped from argv, and argc is updated appropriately.
*/
static Application New( int* argc, char **argv[] );
/**
- * This is the constructor for Linux & SLP applications with a name
- * @param argc A pointer to the number of arguments
- * @param argv A pointer the the argument list
- * @param name A name of application
+ * This is the constructor for applications with a name
+ *
+ * @param[in,out] argc A pointer to the number of arguments
+ * @param[in,out] argv A pointer the the argument list
+ * @param[in] name A name of application
+ *
* @note The default base layout (DeviceLayout::DEFAULT_BASE_LAYOUT) will be used with this constructor.
+ * @note Supported options are stripped from argv, and argc is updated appropriately.
*/
static Application New( int* argc, char **argv[], const std::string& name );
/**
- * This is the constructor for Linux & SLP applications when a layout for the application is specified.
- * @param argc A pointer to the number of arguments
- * @param argv A pointer the the argument list
- * @param baseLayout The base layout that the application has been written for
+ * This is the constructor for applications when a layout for the application is specified.
+ *
+ * @param[in,out] argc A pointer to the number of arguments
+ * @param[in,out] argv A pointer the the argument list
+ * @param[in] baseLayout The base layout that the application has been written for
+ *
+ * @note Supported options are stripped from argv, and argc is updated appropriately.
*/
static Application New( int* argc, char **argv[], const DeviceLayout& baseLayout );
/**
- * This is the constructor for Linux & SLP applications with a name and when a layout for the application is specified.
- * @param argc A pointer to the number of arguments
- * @param argv A pointer the the argument list
- * @param name A name of application
- * @param baseLayout The base layout that the application has been written for
+ * This is the constructor for applications with a name and when a layout for the application is specified.
+ *
+ * @param[in,out] argc A pointer to the number of arguments
+ * @param[in,out] argv A pointer the the argument list
+ * @param[in] name A name of application
+ * @param[in] baseLayout The base layout that the application has been written for
+ *
+ * @note Supported options are stripped from argv, and argc is updated appropriately.
*/
static Application New( int* argc, char **argv[], const std::string& name, const DeviceLayout& baseLayout );
--- /dev/null
+utc-Dali-CommandLineOptions
--- /dev/null
+../master-makefile.mk
\ No newline at end of file
--- /dev/null
+TARGETS += \
+ utc-Dali-CommandLineOptions \
--- /dev/null
+/dali-internal-test-suite/command-line-options/utc-Dali-CommandLineOptions
--- /dev/null
+//
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Flora License, Version 1.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://floralicense.org/license/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an AS IS BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <iostream>
+
+#include <stdlib.h>
+#include <tet_api.h>
+#include <getopt.h>
+
+#include <dali/dali.h>
+
+#include <internal/command-line-options.h>
+
+#include <dali-test-suite-utils.h>
+
+using namespace Dali;
+using namespace Dali::Internal::Adaptor;
+
+static void Startup();
+static void Cleanup();
+
+extern "C" {
+ void (*tet_startup)() = Startup;
+ void (*tet_cleanup)() = Cleanup;
+}
+
+enum {
+ POSITIVE_TC_IDX = 0x01,
+ NEGATIVE_TC_IDX,
+};
+
+#define MAX_NUMBER_OF_TESTS 10000
+extern "C" {
+ struct tet_testlist tet_testlist[MAX_NUMBER_OF_TESTS];
+}
+
+TEST_FUNCTION( UtcDaliCommandLineOptionsNoArgs, POSITIVE_TC_IDX );
+TEST_FUNCTION( UtcDaliCommandLineOptionsDaliShortArgs, POSITIVE_TC_IDX );
+TEST_FUNCTION( UtcDaliCommandLineOptionsDaliLongArgsEqualsSign, POSITIVE_TC_IDX );
+TEST_FUNCTION( UtcDaliCommandLineOptionsDaliLongArgsSpaces, POSITIVE_TC_IDX );
+TEST_FUNCTION( UtcDaliCommandLineOptionsNonDaliArgs, POSITIVE_TC_IDX );
+TEST_FUNCTION( UtcDaliCommandLineOptionsMixture, POSITIVE_TC_IDX );
+TEST_FUNCTION( UtcDaliCommandLineOptionsMixtureDaliOpsAtStart, POSITIVE_TC_IDX );
+TEST_FUNCTION( UtcDaliCommandLineOptionsMixtureDaliOpsAtEnd, POSITIVE_TC_IDX );
+
+int gOriginalOptIndValue(0);
+
+// Called only once before first test is run.
+static void Startup()
+{
+ gOriginalOptIndValue = optind;
+}
+
+// Called only once after last test is run
+static void Cleanup()
+{
+ optind = gOriginalOptIndValue; // Reset overall value
+}
+
+void UtcDaliCommandLineOptionsNoArgs()
+{
+ optind = 1; // Reset opt for test
+
+ int argc( 1 );
+ char* argList[1] = { "program" };
+ char** argv = argList;
+
+ CommandLineOptions options( &argc, &argv );
+
+ DALI_TEST_EQUALS( argc, 1, TEST_LOCATION );
+
+ // Check values
+ DALI_TEST_EQUALS( options.noVSyncOnRender, 0, TEST_LOCATION );
+ DALI_TEST_EQUALS( options.stageWidth, 0, TEST_LOCATION );
+ DALI_TEST_EQUALS( options.stageHeight, 0, TEST_LOCATION );
+ DALI_TEST_EQUALS( options.stageDPI, "", TEST_LOCATION );
+
+ optind = 1; // Reset opt for test
+}
+
+void UtcDaliCommandLineOptionsDaliShortArgs()
+{
+ optind = 1; // Reset opt for test
+
+ char* argList[] =
+ {
+ "program",
+ "-w", "800",
+ "-h", "1000",
+ "-d", "4x5",
+ };
+ int argc( sizeof( argList ) / sizeof( argList[0] ) );
+ char** argv = argList;
+
+ CommandLineOptions options( &argc, &argv );
+
+ // Should strip out the height and width
+ DALI_TEST_EQUALS( argc, 1, TEST_LOCATION );
+
+ // Check values
+ DALI_TEST_EQUALS( options.noVSyncOnRender, 0, TEST_LOCATION );
+ DALI_TEST_EQUALS( options.stageWidth, 800, TEST_LOCATION );
+ DALI_TEST_EQUALS( options.stageHeight, 1000, TEST_LOCATION );
+ DALI_TEST_EQUALS( options.stageDPI, "4x5", TEST_LOCATION );
+
+ optind = 1; // Reset opt for test
+}
+
+void UtcDaliCommandLineOptionsDaliLongArgsEqualsSign()
+{
+ optind = 1; // Reset opt for test
+
+ char* argList[] =
+ {
+ "program",
+ "--width=800",
+ "--height=1000",
+ "--dpi=3x4",
+ "--no-vsync",
+ "--help"
+ };
+ int argc( sizeof( argList ) / sizeof( argList[0] ) );
+ char** argv = argList;
+
+ CommandLineOptions options( &argc, &argv );
+
+ // Should strip out the height and width
+ DALI_TEST_EQUALS( argc, 1, TEST_LOCATION );
+
+ // Check values
+ DALI_TEST_EQUALS( options.noVSyncOnRender, 1, TEST_LOCATION );
+ DALI_TEST_EQUALS( options.stageWidth, 800, TEST_LOCATION );
+ DALI_TEST_EQUALS( options.stageHeight, 1000, TEST_LOCATION );
+ DALI_TEST_EQUALS( options.stageDPI, "3x4", TEST_LOCATION );
+
+ optind = 1; // Reset opt for test
+}
+
+void UtcDaliCommandLineOptionsDaliLongArgsSpaces()
+{
+ optind = 1; // Reset optind
+
+ char* argList[] =
+ {
+ "program",
+ "--width", "800",
+ "--height", "1000",
+ "--dpi", "3x4",
+ "--no-vsync",
+ "--help"
+ };
+ int argc( sizeof( argList ) / sizeof( argList[0] ) );
+ char** argv = argList;
+
+ CommandLineOptions options( &argc, &argv );
+
+ // Should strip out the height and width
+ DALI_TEST_EQUALS( argc, 1, TEST_LOCATION );
+
+ // Check values
+ DALI_TEST_EQUALS( options.noVSyncOnRender, 1, TEST_LOCATION );
+ DALI_TEST_EQUALS( options.stageWidth, 800, TEST_LOCATION );
+ DALI_TEST_EQUALS( options.stageHeight, 1000, TEST_LOCATION );
+ DALI_TEST_EQUALS( options.stageDPI, "3x4", TEST_LOCATION );
+
+ optind = 1; // Reset opt for test
+}
+
+void UtcDaliCommandLineOptionsNonDaliArgs()
+{
+ optind = 1; // Reset opt for test
+
+ char* argList[] =
+ {
+ "program",
+ "hello-world",
+ "-y", "600",
+ };
+ int argc( sizeof( argList ) / sizeof( argList[0] ) );
+ char** argv = argList;
+
+ CommandLineOptions options( &argc, &argv );
+
+ // Should still be the same
+ DALI_TEST_EQUALS( argc, 4, TEST_LOCATION );
+
+ // Ensure order has not changed
+ DALI_TEST_EQUALS( argList[0], "program", TEST_LOCATION );
+ DALI_TEST_EQUALS( argList[1], "hello-world", TEST_LOCATION );
+ DALI_TEST_EQUALS( argList[2], "-y", TEST_LOCATION );
+ DALI_TEST_EQUALS( argList[3], "600", TEST_LOCATION );
+
+ optind = 1; // Reset opt for test
+}
+
+void UtcDaliCommandLineOptionsMixture()
+{
+ optind = 1; // Reset opt for test
+
+ char* argList[] =
+ {
+ "program",
+ "--width=800",
+ "hello-world",
+ "-y", "600",
+ "--height", "1000",
+ "-r",
+ };
+ int argc( sizeof( argList ) / sizeof( argList[0] ) );
+ char** argv = argList;
+
+ CommandLineOptions options( &argc, &argv );
+
+ // Should still be the same
+ DALI_TEST_EQUALS( argc, 5, TEST_LOCATION );
+
+ // Ensure order of program name and unhandled options has not changed
+ DALI_TEST_EQUALS( argList[0], "program", TEST_LOCATION );
+ DALI_TEST_EQUALS( argList[1], "hello-world", TEST_LOCATION );
+ DALI_TEST_EQUALS( argList[2], "-y", TEST_LOCATION );
+ DALI_TEST_EQUALS( argList[3], "600", TEST_LOCATION );
+ DALI_TEST_EQUALS( argList[4], "-r", TEST_LOCATION );
+
+ optind = 1; // Reset opt for test
+}
+
+void UtcDaliCommandLineOptionsMixtureDaliOpsAtStart()
+{
+ optind = 1; // Reset opt for test
+
+ char* argList[] =
+ {
+ "program",
+ "--width=800",
+ "--height", "1000",
+ "-r",
+ "hello-world",
+ "-y", "600",
+ };
+ int argc( sizeof( argList ) / sizeof( argList[0] ) );
+ char** argv = argList;
+
+ CommandLineOptions options( &argc, &argv );
+
+ // Should still be the same
+ DALI_TEST_EQUALS( argc, 5, TEST_LOCATION );
+
+ // Ensure order of program name and unhandled options has not changed
+ DALI_TEST_EQUALS( argList[0], "program", TEST_LOCATION );
+ DALI_TEST_EQUALS( argList[1], "-r", TEST_LOCATION );
+ DALI_TEST_EQUALS( argList[2], "hello-world", TEST_LOCATION );
+ DALI_TEST_EQUALS( argList[3], "-y", TEST_LOCATION );
+ DALI_TEST_EQUALS( argList[4], "600", TEST_LOCATION );
+
+ optind = 1; // Reset opt for test
+}
+
+void UtcDaliCommandLineOptionsMixtureDaliOpsAtEnd()
+{
+ optind = 1; // Reset opt for test
+
+ char* argList[] =
+ {
+ "program",
+ "hello-world",
+ "-y", "600",
+ "-r",
+ "--width=800",
+ "--height", "1000",
+ };
+ int argc( sizeof( argList ) / sizeof( argList[0] ) );
+ char** argv = argList;
+
+ CommandLineOptions options( &argc, &argv );
+
+ // Should still be the same
+ DALI_TEST_EQUALS( argc, 5, TEST_LOCATION );
+
+ // Ensure order of program name and unhandled options has not changed
+ DALI_TEST_EQUALS( argList[0], "program", TEST_LOCATION );
+ DALI_TEST_EQUALS( argList[1], "hello-world", TEST_LOCATION );
+ DALI_TEST_EQUALS( argList[2], "-y", TEST_LOCATION );
+ DALI_TEST_EQUALS( argList[3], "600", TEST_LOCATION );
+ DALI_TEST_EQUALS( argList[4], "-r", TEST_LOCATION );
+
+ optind = 1; // Reset opt for test
+}
include ../../rules.mk
include ../../coverage.mk
-CXXFLAGS += -I../../..
+CXXFLAGS += -I../../.. -I../../../adaptors/tizen
all: $(TARGETS)
# Test scenario
TEST
- :include:/dali-test-suite/tilt-sensor/tslist
- :include:/dali-test-suite/timer/tslist
- :include:/dali-test-suite/key/tslist
- :include:/dali-internal-test-suite/image-loaders/tslist
+ ^PUBLIC
+ ^INTERNAL
##### PUBLIC Tests #####
PUBLIC
- :include:/dali-test-suite/timer/tslist
- :include:/dali-test-suite/tilt-sensor/tslist
- :include:/dali-test-suite/key/tslist
+ ^timer
+ ^tilt-sensor
+ ^key
timer
:include:/dali-test-suite/timer/tslist
##### INTERNAL Tests #####
INTERNAL
- :include:/dali-internal-test-suite/image-loaders/tslist
+ ^image-loaders
+ ^command-line-options
image-loaders
:include:/dali-internal-test-suite/image-loaders/tslist
+command-line-options
+ :include:/dali-internal-test-suite/command-line-options/tslist
+
##### DEBUG #####
# EOF
cov_data:
@test -z $(COVERAGE_DIR) || mkdir -p $(COVERAGE_DIR)
@rm -f $(COVERAGE_DIR)/*
+ @cp dali-adaptor/.libs/*.gcda dali-adaptor/.libs/*.gcno $(COVERAGE_DIR)
+ @for i in `find $(COVERAGE_DIR) -name "libdali_adaptor_la-*.gcda" -o -name "libdali_adaptor_la-*.gcno"` ;\
+ do mv $$i `echo $$i | sed s/libdali_adaptor_la-//` ; echo $$i ; done
@cp common/.libs/*.gcda common/.libs/*.gcno $(COVERAGE_DIR)
@for i in `find $(COVERAGE_DIR) -name "libdali_adaptor_common_la-*.gcda" -o -name "libdali_adaptor_common_la-*.gcno"` ;\
do mv $$i `echo $$i | sed s/libdali_adaptor_common_la-//` ; echo $$i ; done