Commit 23533d6e authored by Andrey Filippov's avatar Andrey Filippov

more tweaking

parent ab9e5d99
html/*
attic/*
.project
.cproject
.pydevproject
.settings
*.directory
/.project
/.cproject
/.pydevproject
/.externalToolBuilders
/.settings
.directory
generated*
sysroots
bitbake-logs
\ No newline at end of file
PROGS = autocampars launch_php_script
PHPSCRIPTS = autocampars.php
SRCS = autocampars.c launch_php_script.c
OBJS = $(SRC:.c=.o)
#OBJS = autocampars.o launch_php_script.o
#OBJS = $(SRC:.c=.o)
OBJS = autocampars.o launch_php_script.o
BINDIR = $(DESTDIR)/usr/bin/
SYSCONFDIR = $(DESTDIR)/etc/
BINDIR = $(DESTDIR)/usr/bin
SYSCONFDIR = $(DESTDIR)/etc
CONFDIR = $(SYSCONFDIR)/elphel393
DOCUMENTROOT = $(DESTDIR)/www/pages
AUTOCAMPARS_PHP = /www/pages/autocampars.php
INSTALL = install
INSTMODE = 0755
INSTDOCS = 0644
OWN = -o root -g root
INCDIR = $(STAGING_DIR_HOST)/usr/include-uapi/elphel
CFLAGS += -Wall -I$(INCDIR)
INCDIR = $(STAGING_DIR_HOST)/usr/include-uapi
#CFLAGS += -Wall -I$(INCDIR)
CFLAGS += -Wall -I$(STAGING_DIR_HOST)/usr/include-uapi -D 'AUTOCAMPARS_PHP="$(AUTOCAMPARS_PHP)"'
all: $(PROGS)
$(PROGS): $(OBJS)
#$(PROGS): $(OBJS)
# $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
autocampars: autocampars.o
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
@echo "AUTOCAMPARS_PHP=$(AUTOCAMPARS_PHP)"
launch_php_script: launch_php_script.o
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
install: $(PROGS)
install: $(PROGS) $(PHPSCRIPTS)
$(INSTALL) -d $(BINDIR)
$(INSTALL) -d $(DOCUMENTROOT)
$(INSTALL) -d $(SYSCONFDIR)
$(INSTALL) -d $(CONFDIR)
$(INSTALL) $(OWN) -m $(INSTMODE) $(PROGS) $(BINDIR)
$(INSTALL) $(OWN) -m $(INSTMODE) $(PHPSCRIPTS) $(DOCUMENTROOT)
$(INSTALL) $(OWN) -m $(INSTMODE) $(PHPSCRIPTS) $(DOCUMENTROOT)
clean:
rm -rf $(PROGS) *.o core
......
/*!***************************************************************************
*! FILE NAME : autocampars.c
*! DESCRIPTION: Daemon to save/restore parameter (calls autocampars.php)
*! This program is needed not to have an extra instance of
*! PHP (2+ MB) just waiting as a daemon.
*! Copyright (C) 2008 Elphel, Inc.
*! -----------------------------------------------------------------------------**
*! 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 3 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, see <http://www.gnu.org/licenses/>.
*! -----------------------------------------------------------------------------**
*!
*! $Log: autocampars.c,v $
*! Revision 1.2 2008/12/08 08:13:37 elphel
*! added one more error check
*!
*! Revision 1.1.1.1 2008/11/27 20:04:01 elphel
*!
*!
*! Revision 1.4 2008/11/22 05:52:47 elphel
*! added TODO
*!
*! Revision 1.3 2008/11/18 07:37:10 elphel
*! snapshot
*!
*! Revision 1.2 2008/11/17 23:42:59 elphel
*! snapshot
*!
*! Revision 1.1 2008/11/17 06:41:20 elphel
*! 8.0.alpha18 - started autocampars - camera parameters save/restore/init manager
*!
*!
*/
*! FILE NAME : autocampars.c
*! DESCRIPTION: Daemon to save/restore parameter (calls autocampars.php)
*! This program is needed not to have an extra instance of
*! PHP (2+ MB) just waiting as a daemon.
*! Copyright (C) 2008 Elphel, Inc.
*! -----------------------------------------------------------------------------**
*! 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 3 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, see <http://www.gnu.org/licenses/>.
*! -----------------------------------------------------------------------------**
*!
*! $Log: autocampars.c,v $
*! Revision 1.2 2008/12/08 08:13:37 elphel
*! added one more error check
*!
*! Revision 1.1.1.1 2008/11/27 20:04:01 elphel
*!
*!
*! Revision 1.4 2008/11/22 05:52:47 elphel
*! added TODO
*!
*! Revision 1.3 2008/11/18 07:37:10 elphel
*! snapshot
*!
*! Revision 1.2 2008/11/17 23:42:59 elphel
*! snapshot
*!
*! Revision 1.1 2008/11/17 06:41:20 elphel
*! 8.0.alpha18 - started autocampars - camera parameters save/restore/init manager
*!
*!
*/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <asm/elphel/c313a.h>
#include <elphel/c313a.h>
#include <elphel/x393_devices.h>
#ifdef AUTOCAMPARS_PHP
#pragma message "content of AUTOCAMPARS_PHP: " AUTOCAMPARS_PHP
#else
#warning AUTOCAMPARS_PHP is NOT defined
#endif
int main (int argc, char *argv[]) {
const char framepars_driver_name[]="/dev/frameparsall";
// const char php_path[]="/usr/local/sbin/php";
const char script_path[]="/usr/html/autocampars.php";
int fd_fparmsall= open(framepars_driver_name, O_RDWR);
unsigned long write_data[4];
int rslt;
if (fd_fparmsall <0) {
ELP_FERR(fprintf(stderr, "Open failed: (%s)\n", framepars_driver_name));
exit (1);
}
///TODO: Use it to re-running ccamftp.php
/// see if any arguments are provided. If they are - they are bit number, sleep time in seconds and command/arguments of an external program
/// to be launched. Usually - a php script, so it makes sense not to keep the php instance in memory if it is not used most of the time
/// (done so for ccamftp.php)
///
/// Daemon loop - waiting for being enabled, run autocampars.php
/// NOTE: Requires sequencers and sensor to be running, to reset everything if stuck - use autocampars.php directly
int pid;
while (1) {
lseek(fd_fparmsall, LSEEK_DAEMON_FRAME+DAEMON_BIT_AUTOCAMPARS, SEEK_END); /// wait for autocampars bit to be enabled (let it sleep if not)
write_data[0]= FRAMEPARS_SETFRAMEREL;
write_data[1]= 1;
write_data[2]= P_DAEMON_EN_AUTOCAMPARS;
write_data[3]= 0;
rslt=write(fd_fparmsall, write_data, sizeof(write_data));
if (rslt < sizeof(write_data)) {
ELP_FERR(fprintf(stderr, "Failed writing to %s\n", framepars_driver_name));
exit (1);
}
fprintf(stderr, "autocampars triggered\n");
signal(SIGCHLD, SIG_IGN); // no zombies
//! do we need any fork at all if we now serve images to one client at a time?
if (((pid=fork())) <0) { /// error
ELP_FERR(fprintf(stderr, "fork() failed\n"));
exit (1);
} else if (pid == 0) { /// child
fflush(stdout);
fflush(stderr);
// rslt= execl(php_path, "-q", script_path, "", "--daemon", (char *) NULL); /// We do not need to pass any parameters here, but if we had to - first argument is lost (probably to "-q" in the script line 1
rslt= execl(script_path, "", "--daemon", (char *) NULL); /// We do not need to pass any parameters here, but if we had to - first argument is lost (probably to "-q" in the script line 1
ELP_FERR(fprintf(stderr, "execl failed, returned %d, errno=%d\n", rslt,errno));
_exit(2);/// comes here only if error
} // end of child process
lseek(fd_fparmsall, LSEEK_FRAME_WAIT_REL+1, SEEK_END); /// skip 1 frame before returning
}
return 0;
const char script_path[]= AUTOCAMPARS_PHP;
const char *framepars_driver_name[]={DEV393_PATH(DEV393_FRAMEPARS0), DEV393_PATH(DEV393_FRAMEPARS1),//"/dev/frameparsall";
DEV393_PATH(DEV393_FRAMEPARS2), DEV393_PATH(DEV393_FRAMEPARS3)};
int fd_fparmsall;
unsigned long write_data[4];
int rslt;
char sport[10];
int port = 0;
if (argc <2){
ELP_FERR(fprintf(stderr, "Sensor porft not provided (%s)\n", argv[0]));
exit (1);
}
port = strtol(argv[1], NULL,10) & 3;
sprintf(sport,"--port=%d",port);
//DEV393_FRAMEPARS0
// const char php_path[]="/usr/local/sbin/php";
fd_fparmsall= open(framepars_driver_name[port], O_RDWR);
if (fd_fparmsall <0) {
ELP_FERR(fprintf(stderr, "Open failed: (%s)\n", framepars_driver_name[port]));
exit (1);
}
///TODO: Use it to re-running ccamftp.php
/// see if any arguments are provided. If they are - they are bit number, sleep time in seconds and command/arguments of an external program
/// to be launched. Usually - a php script, so it makes sense not to keep the php instance in memory if it is not used most of the time
/// (done so for ccamftp.php)
///
/// Daemon loop - waiting for being enabled, run autocampars.php
/// NOTE: Requires sequencers and sensor to be running, to reset everything if stuck - use autocampars.php directly
int pid;
while (1) {
lseek(fd_fparmsall, LSEEK_DAEMON_FRAME+DAEMON_BIT_AUTOCAMPARS, SEEK_END); /// wait for autocampars bit to be enabled (let it sleep if not)
write_data[0]= FRAMEPARS_SETFRAMEREL;
write_data[1]= 1;
write_data[2]= P_DAEMON_EN_AUTOCAMPARS;
write_data[3]= 0;
rslt=write(fd_fparmsall, write_data, sizeof(write_data));
if (rslt < sizeof(write_data)) {
ELP_FERR(fprintf(stderr, "Failed writing to %s\n", framepars_driver_name[port]));
exit (1);
}
fprintf(stderr, "autocampars triggered\n");
signal(SIGCHLD, SIG_IGN); // no zombies
//! do we need any fork at all if we now serve images to one client at a time?
if (((pid=fork())) <0) { /// error
ELP_FERR(fprintf(stderr, "fork() failed\n"));
exit (1);
} else if (pid == 0) { /// child
fflush(stdout);
fflush(stderr);
// rslt= execl(php_path, "-q", script_path, "", "--daemon", (char *) NULL); /// We do not need to pass any parameters here, but if we had to - first argument is lost (probably to "-q" in the script line 1
rslt= execl(script_path, "", "--daemon", sport, (char *) NULL); /// We do not need to pass any parameters here, but if we had to - first argument is lost (probably to "-q" in the script line 1
ELP_FERR(fprintf(stderr, "execl failed, returned %d, errno=%d\n", rslt,errno));
_exit(2);/// comes here only if error
} // end of child process
lseek(fd_fparmsall, LSEEK_FRAME_WAIT_REL+1, SEEK_END); /// skip 1 frame before returning
}
return 0;
}
This diff is collapsed.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
<storageModule moduleId="org.eclipse.cdt.core.settings">
<cconfiguration id="0.1294322758">
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="0.1294322758" moduleId="org.eclipse.cdt.core.settings" name="Default">
<externalSettings/>
<extensions>
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.VCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
</extensions>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<configuration buildProperties="" description="" id="0.1294322758" name="Default" parent="org.eclipse.cdt.build.core.prefbase.cfg">
<folderInfo id="0.1294322758." name="/" resourcePath="">
<toolChain id="org.eclipse.cdt.build.core.prefbase.toolchain.1108581264" name="No ToolChain" resourceTypeBasedDiscovery="false" superClass="org.eclipse.cdt.build.core.prefbase.toolchain">
<targetPlatform id="org.eclipse.cdt.build.core.prefbase.toolchain.1108581264.424127023" name=""/>
<builder arguments="apps-autocampars" command="${workspace_loc:/elphel-apps-autocampars/run_bitbake.sh}" enableCleanBuild="false" id="org.eclipse.cdt.build.core.settings.default.builder.1258366388" incrementalBuildTarget="-c compile -f" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="org.eclipse.cdt.build.core.settings.default.builder"/>
<tool id="org.eclipse.cdt.build.core.settings.holder.libs.1885972775" name="holder for library settings" superClass="org.eclipse.cdt.build.core.settings.holder.libs"/>
<tool id="org.eclipse.cdt.build.core.settings.holder.2146200400" name="Assembly" superClass="org.eclipse.cdt.build.core.settings.holder">
<option id="org.eclipse.cdt.build.core.settings.holder.symbols.463610725" name="Symbols" superClass="org.eclipse.cdt.build.core.settings.holder.symbols" valueType="definedSymbols">
<listOptionValue builtIn="false" value="DOCUMENT_ROOT=/www/pages"/>
<listOptionValue builtIn="false" value="AUTOCAMPARS_PHP=&quot;/www/pages/autocampars.php&quot;"/>
<listOptionValue builtIn="false" value="&quot;size_t=unsigned int&quot;"/>
</option>
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.951580355" languageId="org.eclipse.cdt.core.assembly" languageName="Assembly" sourceContentType="org.eclipse.cdt.core.asmSource" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
</tool>
<tool id="org.eclipse.cdt.build.core.settings.holder.858897943" name="GNU C++" superClass="org.eclipse.cdt.build.core.settings.holder">
<option id="org.eclipse.cdt.build.core.settings.holder.symbols.643993596" name="Symbols" superClass="org.eclipse.cdt.build.core.settings.holder.symbols" valueType="definedSymbols">
<listOptionValue builtIn="false" value="DOCUMENT_ROOT=/www/pages"/>
<listOptionValue builtIn="false" value="AUTOCAMPARS_PHP=&quot;/www/pages/autocampars.php&quot;"/>
<listOptionValue builtIn="false" value="&quot;size_t=unsigned int&quot;"/>
</option>
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.1749320856" languageId="org.eclipse.cdt.core.g++" languageName="GNU C++" sourceContentType="org.eclipse.cdt.core.cxxSource,org.eclipse.cdt.core.cxxHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
</tool>
<tool id="org.eclipse.cdt.build.core.settings.holder.436601026" name="GNU C" superClass="org.eclipse.cdt.build.core.settings.holder">
<option id="org.eclipse.cdt.build.core.settings.holder.symbols.1876868272" name="Symbols" superClass="org.eclipse.cdt.build.core.settings.holder.symbols" valueType="definedSymbols">
<listOptionValue builtIn="false" value="AUTOCAMPARS_PHP=&quot;/www/pages/autocampars.php&quot;"/>
<listOptionValue builtIn="false" value="&quot;size_t=unsigned int&quot;"/>
</option>
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.719627942" languageId="org.eclipse.cdt.core.gcc" languageName="GNU C" sourceContentType="org.eclipse.cdt.core.cSource,org.eclipse.cdt.core.cHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
</tool>
<tool id="org.eclipse.cdt.build.core.settings.holder.1911394126" name="LLVM bytecode assembly" superClass="org.eclipse.cdt.build.core.settings.holder">
<option id="org.eclipse.cdt.build.core.settings.holder.symbols.1272169261" name="Symbols" superClass="org.eclipse.cdt.build.core.settings.holder.symbols" valueType="definedSymbols">
<listOptionValue builtIn="false" value="DOCUMENT_ROOT=/www/pages"/>
<listOptionValue builtIn="false" value="AUTOCAMPARS_PHP=&quot;/www/pages/autocampars.php&quot;"/>
<listOptionValue builtIn="false" value="&quot;size_t=unsigned int&quot;"/>
</option>
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.1321714537" languageId="org.eclipse.cdt.managedbuilder.llvm.ui.llvmAssembly" languageName="LLVM bytecode assembly" sourceContentType="org.eclipse.cdt.managedbuilder.llvm.ui.llvmAssemblySource" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
</tool>
<tool id="org.eclipse.cdt.build.core.settings.holder.690109893" name="UPC" superClass="org.eclipse.cdt.build.core.settings.holder">
<option id="org.eclipse.cdt.build.core.settings.holder.symbols.143356828" name="Symbols" superClass="org.eclipse.cdt.build.core.settings.holder.symbols" valueType="definedSymbols">
<listOptionValue builtIn="false" value="DOCUMENT_ROOT=/www/pages"/>
<listOptionValue builtIn="false" value="AUTOCAMPARS_PHP=&quot;/www/pages/autocampars.php&quot;"/>
<listOptionValue builtIn="false" value="&quot;size_t=unsigned int&quot;"/>
</option>
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.984057989" languageId="org.eclipse.cdt.core.parser.upc.upc" languageName="UPC" sourceContentType="org.eclipse.cdt.core.parser.upc.upcSource" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
</tool>
</toolChain>
</folderInfo>
<sourceEntries>
<entry excluding="sysroots/elphel393/usr/bin|sysroots/elphel393/usr/share|sysroots/elphel393/usr/lib|sysroots/elphel393/usr/include|sysroots/x86_64-linux|sysroots/elphel393-tcbootstrap" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
</sourceEntries>
</configuration>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
</cconfiguration>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<project id="elphel-apps-autocampars.null.1069086801" name="elphel-apps-autocampars"/>
</storageModule>
<storageModule moduleId="scannerConfiguration">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
<scannerConfigBuildInfo instanceId="0.1294322758">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
</scannerConfigBuildInfo>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
<storageModule moduleId="refreshScope" versionNumber="2">
<configuration configurationName="Default">
<resource resourceType="PROJECT" workspacePath="/elphel-apps-autocampars"/>
</configuration>
</storageModule>
</cproject>
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>elphel-apps-autocampars</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
<triggers>full,incremental,</triggers>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.cdt.core.cnature</nature>
<nature>org.eclipse.cdt.core.ccnature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
</natures>
</projectDescription>
......@@ -36,9 +36,10 @@
#include <errno.h>
#include <sys/wait.h>
#include <asm/elphel/c313a.h>
#include <elphel/c313a.h>
#include <elphel/x393_devices.h>
int main (int argc, char *argv[]) {
if (argc < 3) {
if (argc < 4) {
printf (" This is a companion program that works with PHP scripts to make a daemon,\n"
"conserving memory footprint when disabled.\n"
"It waits for the the specified bit in the global daemon control word (P_DAEMON_EN)\n"
......@@ -48,18 +49,20 @@ int main (int argc, char *argv[]) {
"when this bit is cleared) and launches the script again. That reduces memory usage\n"
"when the script is disabled - no need to keep PHP interpreter in teh memory (>2MB)\n\n"
"Usage:\n"
"%s <bit_number> <command> [<parameter>...]\n",argv[0]);
"%s <sensor_port> <bit_number> <command> [<parameter>...]\n",argv[0]);
exit (1);
}
int pid, status;
int en_bit=strtol(argv[1], NULL, 10);
if ((en_bit<0) || (en_bit>31)) {printf ("Invalid bit number %d (should be 0..31)\n", en_bit); exit (1);}
const char framepars_driver_name[]="/dev/frameparsall";
int fd_fparmsall= open(framepars_driver_name, O_RDONLY);
const char *framepars_driver_name[]={DEV393_PATH(DEV393_FRAMEPARS0), DEV393_PATH(DEV393_FRAMEPARS1),//"/dev/frameparsall";
DEV393_PATH(DEV393_FRAMEPARS2), DEV393_PATH(DEV393_FRAMEPARS3)};
int port = strtol(argv[1], NULL, 10) & 3;
int en_bit=strtol(argv[2], NULL, 10);
int rslt;
int fd_fparmsall;
if ((en_bit<0) || (en_bit>31)) {printf ("Invalid bit number %d (should be 0..31)\n", en_bit); exit (1);}
fd_fparmsall= open(framepars_driver_name[port], O_RDONLY);
if (fd_fparmsall <0) {
ELP_FERR(fprintf(stderr, "Open failed: (%s)\n", framepars_driver_name));
ELP_FERR(fprintf(stderr, "Open failed: (%s)\n", framepars_driver_name[port]));
exit (1);
}
/// Daemon loop - waiting for being enabled, run script
......@@ -74,7 +77,7 @@ int main (int argc, char *argv[]) {
} else if (pid == 0) { /// child
fflush(stdout);
fflush(stderr);
rslt= execv(argv[2], &argv[2]); /// script path, all parameters starting with the script path
rslt= execv(argv[3], &argv[3]); /// script path, all parameters starting with the script path
ELP_FERR(fprintf(stderr, "execl failed, returned %d, errno=%d\n", rslt,errno));
_exit(2);/// comes here only if error
} /// Only parent will get below here
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment