#!/usr/bin/perl -w
# This script (sophomorix-project) is maintained by Rüdiger Beck
# It is Free Software (License GPLv3)
# If you find errors, contact the author
# jeffbeck@web.de  or jeffbeck@linuxmuster.net

# modules
use strict;
#use Quota;
use Getopt::Long;
Getopt::Long::Configure ("bundling");
use Sophomorix::SophomorixConfig;
use List::MoreUtils qw(uniq);
#use IMAP::Admin;
#use DBI;
use Net::LDAP;
use Data::Dumper;
$Data::Dumper::Indent = 1;
$Data::Dumper::Sortkeys = 1;
$Data::Dumper::Useqq = 1;
$Data::Dumper::Terse = 1; 
use JSON;
use Sophomorix::SophomorixBase qw(
                                 print_line
                                 print_title
                                 unlock_sophomorix
                                 lock_sophomorix
                                 log_script_start
                                 log_script_end
                                 log_script_exit
                                 backup_auk_file
                                 get_passwd_charlist
                                 get_plain_password
                                 check_options
                                 config_sophomorix_read
                                 result_sophomorix_init
                                 result_sophomorix_add
                                 result_sophomorix_check_exit
                                 result_sophomorix_print
                                 remove_from_list
                                 json_dump
                                 );
use Sophomorix::SophomorixSambaAD qw(
                                 AD_school_create
                                 AD_bind_admin
                                 AD_dns_get
                                 AD_unbind_admin
                                 AD_user_create
                                 AD_group_create
                                 AD_group_kill
                                 AD_group_addmember
                                 AD_get_schoolname
                                 AD_get_name_tokened
                                 AD_project_fetch
                                 AD_group_update
                                 AD_project_sync_members
                                 AD_dn_fetch_multivalue
                                 AD_group_list
                                 AD_get_passwd
                                 AD_get_groups_v
                                 AD_get_full_groupdata
                                    );

my @arguments = @ARGV;

my $gidnumber_migrate;

############################################################
# Option handling
############################################################
my %options=();
$options{'CONFIG'}{'ACTION'}{'GROUP'}="create,".
                                      "kill,".
                                      "description,".
                                      "quota,".
                                      "mailquota,".
                                      "status,".
                                      "maxmembers,".
                                      "creationdate,".
                                      "gidnumber-migrate,".
                                      "mailalias,".
                                      "maillist,".
                                      "join,".
                                      "hide,".
                                      "admins,".
                                      "addadmins,".
                                      "removeadmins,".
                                      "members,".
                                      "addmembers,".
                                      "admingroups,".
                                      "addadmingroups,".
                                      "removeadmingroups,".
                                      "removemembers,".
                                      "membergroups,".
                                      "addmembergroups,".
                                      "removemembergroups,".
                                      "addquota,".
                                      "addmailquota";

# define which options deliver which object
$options{'CONFIG'}{'ONE_OF'}{'GROUP'}="project";

$options{'CONFIG'}{'SINGLE'}{'ACTION'}="update-maildomain";

# define more dependencies
$options{'CONFIG'}{'DEPENDS'}{'gidnumber-migrate'}="create";
$options{'CONFIG'}{'DEPENDS'}{'skip-school-creation'}="create";

# Parsen der Optionen
my $testopt=GetOptions(\%options, 
                       "help|h",
                       "info|i",
                       "json|j+",
                       "verbose|v+",
                       "create|c",
                       "gidnumber-migrate=i",
                       "kill",
                       "skip-school-creation",
                       "join!",
                       "hide!",
                       "school=s",
                       "description=s",
                       "status=s",
                       "members=s",
                       "addmembers=s",
                       "removemembers=s",
                       "admins=s",
                       "addadmins=s",
                       "removeadmins=s",
                       "membergroups=s",
                       "addmembergroups=s",
                       "removemembergroups=s",
                       "admingroups=s",
                       "addadmingroups=s",
                       "removeadmingroups=s",
                       "sync-all-memberships",
                       "project|p=s",
                       "addquota=s",
                       "addmailquota=s",
                       "maxmembers=s",
                       "creationdate=s",
                       "mailalias!",
                       "maillist!",
		       "update-maildomain",
                      );

my %sophomorix_result=&result_sophomorix_init("sophomorix-project");
# Prüfen, ob Optionen erkannt wurden
&check_options($testopt,\%sophomorix_result,$options{'json'},\%options);
if (not defined $options{'school'}){
    $options{'school'}="---";
}

if ($options{'school'} eq "global"){
    print "\n";
    print "Global projects are not allowed at the moment.\n";
    print "Global sophomorix-groups can be created with sophomorix-group.\n\n";
    exit;
}

# Reading Configuration
my ($ldap,$root_dse) = &AD_bind_admin(\@arguments,\%sophomorix_result,$options{'json'});
my $root_dns=&AD_dns_get($root_dse);
my %sophomorix_config=&config_sophomorix_read($ldap,$root_dse,\%sophomorix_result);
my ($smb_admin_pass)=&AD_get_passwd($DevelConf::sophomorix_file_admin,
                                     $DevelConf::secret_file_sophomorix_file_admin);

if (defined $options{'project'} and not defined $options{'create'} and not defined $options{'kill'}){
#if (defined $options{'project'}){
    # append p_ if omitted
    unless ($options{'project'} =~ m/^p\_/) { 
        $options{'project'}="p_".$options{'project'};
    }
}



# --help
if (defined $options{'help'}) {
   # Scriptname ermitteln
   my @list = split(/\//,$0);
   my $scriptname = pop @list;
   # Befehlbeschreibung
   print('
sophomorix-project adds projects to the sophomorix database and adds users
   or groups as members to the project

Options
  -h  / --help
  -v  / --verbose
  -vv / --verbose --verbose

Choose the school:
  --school <school>

Getting information:
  --admininfo
  --tree
  -i / --info
  -i -p projectname
  -u  / --user / --user-info -p <project>

Changing/creating/killing a project:
  --create -p <project>
  --kill -p <project>

  -p <project>, / --project <project> 
    --description \'multiple words possible\'
    --addquota <share1>:<quota1 in MiB>:<comment1>,<share2>:<quota2 in MiB>:<comment2>,...
    --addmailquota <mailquota in MiB>:<Comment>
    --mailalias, --nomailalias
    --maillist, --nomaillist 
    --status <letter>
    --join,  --nojoin
    --hide,  --nohide
    --maxmembers number
    --creationdate <20150529093330.0Z> (only for migration)

    --admins user1,user2,user3, ... 
    --addadmins user1,user2,user3, ...
    --removeadmins user1,user2,user3, ...

    --members user1,user2,user3, ... 
    --addmembers user1,user2,user3, ...
    --removemembers user1,user2,user3, ...

    --admingroups group1,group2,group3, ... 
    --addadmingroups group1,group2,group3, ...
    --removeadmingroups group1,group2,group3, ...

    --membergroups group1,group2,group3, ... 
    --addmembergroups group1,group2,group3, ...
    --removemembergroups group1,group2,group3, ...

Syncing memberships of all projects (sophomorix* -> members):
  --sync-all-memberships

Updating changes from school.conf
    --update-maildomain  (for all schools)

This is for migration/testing/fixing only:
  sophomorix-project --skip-school-creation --create --project <project> --gidnumber-migrate <num>


Please see the sophomorix-project(8) man pages for full documentation
');
   print "\n";
   exit;
}


# --info
# show all projects when no specific projects is given
if ($options{'info'}==1 and not defined $options{'project'} ){
    my $ref_group_v=&AD_get_groups_v({ldap=>$ldap,
                                   root_dse=>$root_dse,
                                   root_dns=>$root_dns,
                                   school=>$options{'school'},
                                   sophomorix_config=>\%sophomorix_config,
                                 });
    #print Dumper($ref_group_v);
    #print Dumper($ref_group_v->{'GROUPS'}{'p_Chemie-AG23'});
    my $jsoninfo="PROJECTS_OVERVIEW";
    my $jsoncomment="All Groups";
    &json_dump({json => $options{'json'},
                jsoninfo => $jsoninfo,
                jsoncomment => $jsoncomment,
                object_name => $options{'school'},
                log_level => $options{'verbose'},
                hash_ref => $ref_group_v,
                sophomorix_config => \%sophomorix_config,
               });
   exit;
}



# --info --project <project>
# list project(s) and exit
if ($options{'info'}==1 and defined $options{'project'}){
    my $ref_groups=&AD_get_full_groupdata({ldap=>$ldap,
                                           root_dse=>$root_dse,
                                           root_dns=>$root_dns,
                                           grouplist=>$options{'project'},
                                           sophomorix_config=>\%sophomorix_config,
                                      });
    #print Dumper($ref_groups);
    my $jsoninfo="PROJECT";
    my $jsoncomment="Project";
    &json_dump({json => $options{'json'},
                jsoninfo => $jsoninfo,
                jsoncomment => $jsoncomment,
                object_name => $options{'school'},
                log_level => $options{'verbose'},
                hash_ref => $ref_groups,
                sophomorix_config => \%sophomorix_config,
               });
    exit;
}



&result_sophomorix_check_exit(\%sophomorix_result,\%sophomorix_config,$options{'json'});
############################################################
# Start
############################################################
&log_script_start(\@arguments,\%sophomorix_result,\%sophomorix_config);



# --update-maildomain
if (defined $options{'update-maildomain'}){
    my $ref_group_v=&AD_get_groups_v({ldap=>$ldap,
                                   root_dse=>$root_dse,
                                   root_dns=>$root_dns,
                                   school=>$options{'school'},
                                   sophomorix_config=>\%sophomorix_config,
				     });
    #print Dumper($ref_group_v);
    foreach my $school (@{ $sophomorix_config{'LISTS'}{'SCHOOLS'} }){
	foreach my $project (@{ $ref_group_v->{'LISTS'}{'GROUP_by_sophomorixSchoolname'}{$school}{'project'} }){
	    my $type=$ref_group_v->{'GROUPS'}{$project}{'sophomorixType'};
	    my $dn=$ref_group_v->{'GROUPS'}{$project}{'DN'};
	    my $mail = $project."\@".$root_dns;
	    my $maildomain_key;
            if ($school eq $DevelConf::name_default_school){
                $maildomain_key=$type;
            } else {
                $maildomain_key=$school."-".$type;
            }
	    if (exists $sophomorix_config{'TYPES'}{$maildomain_key}{'MAILDOMAIN'}){
                if ($sophomorix_config{'TYPES'}{$maildomain_key}{'MAILDOMAIN'} ne ""){
                    $mail=$project."\@".
                    $sophomorix_config{'TYPES'}{$maildomain_key}{'MAILDOMAIN'};
	        }
            }

	    &AD_group_update({ldap=>$ldap,
                              root_dse=>$root_dse,
                              dn=>$dn,
                              school=>$school,
                              type=>$type,
                              mail=>$mail,
                              sophomorix_config=>\%sophomorix_config,
                            });
	}
    }
    &log_script_end(\@arguments,\%sophomorix_result,\%sophomorix_config,$options{'json'});
}



# --create --project <name>
############################################################
if (defined $options{'create'} and defined $options{'project'}){
    # abort if p_project exits already
    my $p_project=$options{'project'};
    # append p_ if omitted
    unless ( $p_project =~ m/^p\_/) { 
        $p_project = "p_".$p_project;
    }

    my %existing_projects=();
    my $filter="(&(objectClass=group)(sophomorixType=project))";
    my $mesg = $ldap->search( # perform a search
                   base   => $root_dse,
                   scope => 'sub',
                   filter => $filter,
                         );
    my $max_pro = $mesg->count;
    for( my $index = 0 ; $index < $max_pro ; $index++) {
        my $entry = $mesg->entry($index);
	my $sam=$entry->get_value('sAMAccountName');
        $existing_projects{$sam}="exists";
    }

    #print Dumper(\%existing_projects);

    if (exists $existing_projects{$p_project}){
        &log_script_exit("Project $p_project exists already | Cannot be used with option --create",1,1,0,
                         \@arguments,\%sophomorix_result,\%sophomorix_config,$options{'json'});
    }

    # --gidnumber-migrate
    ############################################################
    if (defined $options{'gidnumber-migrate'}){
        $gidnumber_migrate=$options{'gidnumber-migrate'};
    } 

    if (defined $options{'skip-school-creation'}){
        # do nothing
    } else {
        &AD_school_create({ldap=>$ldap,
                           root_dse=>$root_dse,
                           root_dns=>$root_dns,
                           school=>$options{'school'},
                           smb_admin_pass=>$smb_admin_pass,
                           sophomorix_config=>\%sophomorix_config,
                           sophomorix_result=>\%sophomorix_result,
                         });
    }
    my $group_token=&AD_get_name_tokened($options{'project'},$options{'school'},"project");
    &AD_group_create({ldap=>$ldap,
                      root_dse=>$root_dse,
                      root_dns=>$root_dns,
                      school=>$options{'school'},
                      group=>$group_token,
                      group_basename=>$options{'project'},
                      description=>$group_token,
                      type=>"project",
                      status=>"P",
                      sub_ou=>$sophomorix_config{'INI'}{'OU'}{'AD_project_ou'},
                      gidnumber_migrate=>$gidnumber_migrate,
                      smb_admin_pass=>$smb_admin_pass,
                      sophomorix_config=>\%sophomorix_config,
                      sophomorix_result=>\%sophomorix_result,
                    });
}



# --kill --project <name>
############################################################
if (defined $options{'kill'} and defined $options{'project'}){
    my $group_token=&AD_get_name_tokened($options{'project'},$options{'school'},"project");
    &AD_group_kill({ldap=>$ldap,
                    root_dse=>$root_dse,
                    root_dns=>$root_dns,
                    group=>$group_token,
                    smb_admin_pass=>$smb_admin_pass,
                    type=>"project",
                    sophomorix_config=>\%sophomorix_config,
                  });
    &log_script_end(\@arguments,\%sophomorix_result,\%sophomorix_config,$options{'json'});
    exit;
}


##################################################
# --sync-all-memberships
if (defined $options{'sync-all-memberships'}){
    print "Syncing memberships of the following projects:\n";
    my @projects_dn=&AD_group_list($ldap,$root_dse,"project",0);

    foreach my $pro_dn (@projects_dn){
        &AD_project_sync_members($ldap,$root_dse,$pro_dn);
    }
    exit;
}





# get dn if project exists and continue
############################################################
my ($dn_pro,$count,$school_AD)=&AD_project_fetch($ldap,$root_dse,$options{'project'},$options{'school'},$options{'info'});

if ($count>1){
    print "\n$count Projects found.\n";
    print "Specify the school-token to choose a project\n\n";
    &log_script_exit("Specify the school-token to choose a project",$count,1,0,
                     \@arguments,\%sophomorix_result,\%sophomorix_config,$options{'json'});
} elsif ($count==0){
    print "\nERROR retrieving project $options{'project'}: $count project found.\n\n";
    &log_script_exit("ERROR retrieving project $options{'project'}: $count project found.",$count,1,0,
                     \@arguments,\%sophomorix_result,\%sophomorix_config,$options{'json'});
}




# all actions from now on work on the dn retrieved
############################################################

# --description <strg>
if (defined $options{'description'}){
    &AD_group_update({ldap=>$ldap,
                      root_dse=>$root_dse,
                      dn=>$dn_pro,
		      school=>$school_AD,
                      type=>"project",
                      description=>$options{'description'},
                      sophomorix_config=>\%sophomorix_config,
                    });
}


# --addquota <strg>
if (defined $options{'addquota'}){
    &AD_group_update({ldap=>$ldap,
                      root_dse=>$root_dse,
                      dn=>$dn_pro,
		      school=>$school_AD,
                      type=>"project",
                      addquota=>$options{'addquota'},
                      sophomorix_config=>\%sophomorix_config,
                    });
}


# --addmailquota <strg>
if (defined $options{'addmailquota'}){
    &AD_group_update({ldap=>$ldap,
                      root_dse=>$root_dse,
                      dn=>$dn_pro,
		      school=>$school_AD,
                      type=>"project",
                      addmailquota=>$options{'addmailquota'},
                      sophomorix_config=>\%sophomorix_config,
                    });
}


# --mailalias/nomailalias
if (defined $options{'mailalias'}){
    &AD_group_update({ldap=>$ldap,
                      root_dse=>$root_dse,
                      dn=>$dn_pro,
		      school=>$school_AD,
                      type=>"project",
                      mailalias=>$options{'mailalias'},
                      sophomorix_config=>\%sophomorix_config,
                    });
}

# --maillist/--nomaillist
if (defined $options{'maillist'}){
    &AD_group_update({ldap=>$ldap,
                      root_dse=>$root_dse,
                      dn=>$dn_pro,
		      school=>$school_AD,
                      type=>"project",
                      maillist=>$options{'maillist'},
                      sophomorix_config=>\%sophomorix_config,
                    });
}

# --status <P>
if (defined $options{'status'}){
    &AD_group_update({ldap=>$ldap,
                      root_dse=>$root_dse,
                      dn=>$dn_pro,
		      school=>$school_AD,
                      type=>"project",
                      status=>$options{'status'},
                      sophomorix_config=>\%sophomorix_config,
                    });
}

# --join/--nojoin
if (defined $options{'join'}){
    &AD_group_update({ldap=>$ldap,
                      root_dse=>$root_dse,
                      dn=>$dn_pro,
		      school=>$school_AD,
                      type=>"project",
                      join=>$options{'join'},
                      sophomorix_config=>\%sophomorix_config,
                    });
}

# --hide/--nohide
if (defined $options{'hide'}){
    &AD_group_update({ldap=>$ldap,
                      root_dse=>$root_dse,
                      dn=>$dn_pro,
		      school=>$school_AD,
                      type=>"project",
                      hide=>$options{'hide'},
                      sophomorix_config=>\%sophomorix_config,
                    });
}

# --maxmembers <strg>
if (defined $options{'maxmembers'}){
    &AD_group_update({ldap=>$ldap,
                      root_dse=>$root_dse,
                      dn=>$dn_pro,
		      school=>$school_AD,
                      type=>"project",
                      maxmembers=>$options{'maxmembers'},
                      sophomorix_config=>\%sophomorix_config,
                    });
}

# --creationdate <strg>
if (defined $options{'creationdate'}){
    &AD_group_update({ldap=>$ldap,
                      root_dse=>$root_dse,
                      dn=>$dn_pro,
		      school=>$school_AD,
                      type=>"project",
                      creationdate=>$options{'creationdate'},
                      sophomorix_config=>\%sophomorix_config,
                    });
}

##################################################
# members
# --members <user1,user2>
if (defined $options{'members'}){
    &AD_group_update({ldap=>$ldap,
                      root_dse=>$root_dse,
                      dn=>$dn_pro,
		      school=>$school_AD,
                      type=>"project",
                      members=>$options{'members'},
                      sophomorix_config=>\%sophomorix_config,
                    });
}

# --addmembers <user1,user2>
if (defined $options{'addmembers'}){
    my @addmembers=split(/,/,$options{'addmembers'});
    my @old_members = &AD_dn_fetch_multivalue($ldap,$root_dse,$dn_pro,"sophomorixMembers");
    my @members = uniq(@old_members,@addmembers); 
    my $members=join(",",@members);
    &AD_group_update({ldap=>$ldap,
                      root_dse=>$root_dse,
                      dn=>$dn_pro,
		      school=>$school_AD,
                      type=>"project",
                      members=>$members,
                      sophomorix_config=>\%sophomorix_config,
                    });
}
 
# --removemembers <user1,user2>
if (defined $options{'removemembers'}){
    my @old_members = &AD_dn_fetch_multivalue($ldap,$root_dse,$dn_pro,"sophomorixMembers");
    my @members = &remove_from_list($options{'removemembers'},@old_members);
    my $members=join(",",@members);
    &AD_group_update({ldap=>$ldap,
                      root_dse=>$root_dse,
                      dn=>$dn_pro,
		      school=>$school_AD,
                      type=>"project",
                      members=>$members,
                      sophomorix_config=>\%sophomorix_config,
                    });
}



##################################################
# admins
# --admins <user1,user2>
if (defined $options{'admins'}){
    &AD_group_update({ldap=>$ldap,
                      root_dse=>$root_dse,
                      dn=>$dn_pro,
		      school=>$school_AD,
                      type=>"project",
                      admins=>$options{'admins'},
                      sophomorix_config=>\%sophomorix_config,
                    });
}

# --addadmins <user1,user2>
if (defined $options{'addadmins'}){
    my @addadmins=split(/,/,$options{'addadmins'});
    my @old_admins = &AD_dn_fetch_multivalue($ldap,$root_dse,$dn_pro,"sophomorixAdmins");
    my @admins = uniq(@old_admins,@addadmins); 
    my $admins=join(",",@admins);
    &AD_group_update({ldap=>$ldap,
                      root_dse=>$root_dse,
                      dn=>$dn_pro,
		      school=>$school_AD,
                      type=>"project",
                      admins=>$admins,
                      sophomorix_config=>\%sophomorix_config,
                    });
}

# --removeadmins <user1,user2>
if (defined $options{'removeadmins'}){
    my @old_admins = &AD_dn_fetch_multivalue($ldap,$root_dse,$dn_pro,"sophomorixAdmins");
    my @admins = &remove_from_list($options{'removeadmins'},@old_admins);
    my $admins=join(",",@admins);
    &AD_group_update({ldap=>$ldap,
                      root_dse=>$root_dse,
                      dn=>$dn_pro,
		      school=>$school_AD,
                      type=>"project",
                      admins=>$admins,
                      sophomorix_config=>\%sophomorix_config,
                    });
}



##################################################
# membergroups
# --membergroups <group1,group2>
if (defined $options{'membergroups'}){
    &AD_group_update({ldap=>$ldap,
                      root_dse=>$root_dse,
                      dn=>$dn_pro,
		      school=>$school_AD,
                      type=>"project",
                      membergroups=>$options{'membergroups'},
                      sophomorix_config=>\%sophomorix_config,
                    });
}

# --addmembergroups <group1,group2>
if (defined $options{'addmembergroups'}){
    my @addmembergroups=split(/,/,$options{'addmembergroups'});
    my @old_membergroups = &AD_dn_fetch_multivalue($ldap,$root_dse,$dn_pro,"sophomorixMemberGroups");
    my @membergroups = uniq(@old_membergroups,@addmembergroups); 
    my $membergroups=join(",",@membergroups);
    &AD_group_update({ldap=>$ldap,
                      root_dse=>$root_dse,
                      dn=>$dn_pro,
		      school=>$school_AD,
                      type=>"project",
                      membergroups=>$membergroups,
                      sophomorix_config=>\%sophomorix_config,
                    });
}

# --removemembergroups <user1,user2>
if (defined $options{'removemembergroups'}){
    my @old_membergroups = &AD_dn_fetch_multivalue($ldap,$root_dse,$dn_pro,"sophomorixMemberGroups");
    my @membergroups = &remove_from_list($options{'removemembergroups'},@old_membergroups);
    my $membergroups=join(",",@membergroups);
    &AD_group_update({ldap=>$ldap,
                      root_dse=>$root_dse,
                      dn=>$dn_pro,
		      school=>$school_AD,
                      type=>"project",
                      membergroups=>$membergroups,
                      sophomorix_config=>\%sophomorix_config,
                    });
}



##################################################
# admingroups
# --admingroups <group1,group2>
if (defined $options{'admingroups'}){
    &AD_group_update({ldap=>$ldap,
                      root_dse=>$root_dse,
                      dn=>$dn_pro,
		      school=>$school_AD,
                      type=>"project",
                      admingroups=>$options{'admingroups'},
                    });
}

# --addadmingroups <group1,group2>
if (defined $options{'addadmingroups'}){
    my @addadmingroups=split(/,/,$options{'addadmingroups'});
    my @old_admingroups = &AD_dn_fetch_multivalue($ldap,$root_dse,$dn_pro,"sophomorixAdminGroups");
    my @admingroups = uniq(@old_admingroups,@addadmingroups); 
    my $admingroups=join(",",@admingroups);
    &AD_group_update({ldap=>$ldap,
                      root_dse=>$root_dse,
                      dn=>$dn_pro,
		      school=>$school_AD,
                      type=>"project",
                      admingroups=>$admingroups,
                      sophomorix_config=>\%sophomorix_config,
                    });
}

# --removeadmingroups <user1,user2>
if (defined $options{'removeadmingroups'}){
    my @old_admingroups = &AD_dn_fetch_multivalue($ldap,$root_dse,$dn_pro,"sophomorixAdminGroups");
    my @admingroups = &remove_from_list($options{'removeadmingroups'},@old_admingroups);
    my $admingroups=join(",",@admingroups);
    &AD_group_update({ldap=>$ldap,
                      root_dse=>$root_dse,
                      dn=>$dn_pro,
		      school=>$school_AD,
                      type=>"project",
                      admingroups=>$admingroups,
                      sophomorix_config=>\%sophomorix_config,
                    });
}



&AD_unbind_admin($ldap);
&log_script_end(\@arguments,\%sophomorix_result,\%sophomorix_config,$options{'json'});
