Commit e9cf927c authored by Ogier Maitre's avatar Ogier Maitre

New Makefile

parent b08f027d
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -173,6 +173,7 @@ exponent ([Ee][+-]?[0-9]+)
if (bVERBOSE) printf ("Inserting initialisation function.\n");
yyreset();
yyin = fpGenomeFile; // switch to .ez file and analyser
lineCounter = 1;
BEGIN COPY_INITIALISATION_FUNCTION;
}
......@@ -188,10 +189,14 @@ exponent ([Ee][+-]?[0-9]+)
<TEMPLATE_ANALYSIS>"\\INSERT_BEGIN_GENERATION_FUNCTION" {
//DEBUG_PRT_PRT("insert beg");
if (bVERBOSE) printf ("Inserting at the begining of each generation function.\n");
if( bLINE_NUM_EZ_FILE )
fprintf(fpOutputFile,"#line %d \"%s.ez\"\n",lineCounter+1, sRAW_PROJECT_NAME);
yyreset();
yyin = fpGenomeFile;
bBeginGeneration = true;
bEndGeneration = false;
lineCounter = 1;
BEGIN COPY_BEG_GENERATION_FUNCTION;
}
......@@ -559,6 +564,7 @@ exponent ([Ee][+-]?[0-9]+)
yyreset();
yyin = fpGenomeFile;
if (bVERBOSE) printf ("Evaluation population in a single function!!.\n");
lineCounter = 1;
BEGIN COPY_INSTEAD_EVAL;
}
......@@ -900,6 +906,7 @@ exponent ([Ee][+-]?[0-9]+)
<TEMPLATE_ANALYSIS>"\\INSERT_INITIALISER" {
yyreset();
yyin = fpGenomeFile; // switch to .ez file and analyser
lineCounter = 1;
BEGIN COPY_INITIALISER;
}
......@@ -907,6 +914,7 @@ exponent ([Ee][+-]?[0-9]+)
if (bVERBOSE) printf ("Inserting Finalization function.\n");
yyreset();
yyin = fpGenomeFile; // switch to .ez file and analyser
lineCounter=1;
BEGIN COPY_FINALIZATION_FUNCTION;
}
......@@ -1281,9 +1289,11 @@ if(OPERATING_SYSTEM=WINDOWS)
}
<COPY_INITIALISATION_FUNCTION>"\\Before"[ \t\n]+"everything"[ \t\n]+"else"[ \t\n]+"function"[ \t\n]*":" {
fprintf (fpOutputFile,"// Initialisation function\nvoid EASEAInitFunction(int argc, char *argv[]){");
fprintf (fpOutputFile,"// Initialisation function\nvoid EASEAInitFunction(int argc, char *argv[]){\n");
bFunction=1; bInitFunction=1;
if( bLINE_NUM_EZ_FILE )
fprintf(fpOutputFile,"#line %d \"%s.ez\"\n",lineCounter, sRAW_PROJECT_NAME);
BEGIN COPY;
}
<COPY_INITIALISATION_FUNCTION><<EOF>> {bInitFunction=0; // No before everything else function was found in the .ez file
......@@ -1291,16 +1301,21 @@ if(OPERATING_SYSTEM=WINDOWS)
fprintf(fpOutputFile,"\n// No before everything else function.\n");
rewind(fpGenomeFile);
yyin = fpTemplateFile;
BEGIN TEMPLATE_ANALYSIS;
bNotFinishedYet=1;
}
<COPY_INITIALISATION_FUNCTION>.|\n {}
<COPY_INITIALISATION_FUNCTION>. {}
<COPY_INITIALISATION_FUNCTION>\n {lineCounter++;}
//****************************************
// Easea GPGPU & EO Finalization function
//****************************************
<COPY_FINALIZATION_FUNCTION>"\\After"[ \t\n]+"everything"[ \t\n]+"else"[ \t\n]+"function"[ \t\n]*":" {
fprintf (fpOutputFile,"// Finalization function\nvoid EASEAFinalization(CPopulation* population){");
fprintf (fpOutputFile,"// Finalization function\nvoid EASEAFinalization(CPopulation* population){\n");
if( bLINE_NUM_EZ_FILE )
fprintf(fpOutputFile,"#line %d \"%s.ez\"\n",lineCounter, sRAW_PROJECT_NAME);
bFunction=1; bFinalizationFunction=1;
BEGIN COPY;
}
......@@ -1313,7 +1328,8 @@ if(OPERATING_SYSTEM=WINDOWS)
BEGIN TEMPLATE_ANALYSIS;
bNotFinishedYet=1;
}
<COPY_FINALIZATION_FUNCTION>.|\n {}
<COPY_FINALIZATION_FUNCTION>. {}
<COPY_FINALIZATION_FUNCTION>\n {lineCounter++;}
<COPY_END_GENERATION_FUNCTION>"\\At"[ \t\n]+"the"[ \t\n]+"end"[ \t\n]+"of"[ \t\n]+"each"[ \t\n]+"generation"[ \t\n]+"function"[ \t\n]*":" {
......@@ -1347,6 +1363,8 @@ if(OPERATING_SYSTEM=WINDOWS)
bFunction=1;
bBeginGeneration = 0;
bBeginGenerationFunction = 1;
if( bLINE_NUM_EZ_FILE )
fprintf(fpOutputFile,"#line %d \"%s.ez\"\n",lineCounter, sRAW_PROJECT_NAME);
BEGIN COPY_USER_GENERATION;
}
}
......@@ -1356,11 +1374,15 @@ if(OPERATING_SYSTEM=WINDOWS)
if( (TARGET==CUDA || TARGET==STD)){
fprintf (fpOutputFile,"{\n");
bFunction=1;
if( bLINE_NUM_EZ_FILE )
fprintf(fpOutputFile,"#line %d \"%s.ez\"\n",lineCounter, sRAW_PROJECT_NAME);
BEGIN COPY_USER_GENERATION;
}
}
<COPY_INSTEAD_EVAL>.|\n {}
<COPY_INSTEAD_EVAL>. {}
<COPY_INSTEAD_EVAL>\n {lineCounter++;}
<COPY_INSTEAD_EVAL><<EOF>> {
bBeginGenerationFunction=0; // No Generation function was found in the .ez file
......@@ -1384,7 +1406,8 @@ if(OPERATING_SYSTEM=WINDOWS)
BEGIN TEMPLATE_ANALYSIS;
bNotFinishedYet=1;
}
<COPY_BEG_GENERATION_FUNCTION>.|\n {}
<COPY_BEG_GENERATION_FUNCTION>\n {lineCounter++;}
<COPY_BEG_GENERATION_FUNCTION>. {}
......
......@@ -18,7 +18,7 @@ ifeq ($(UNAME), Darwin)
@echo "export EZ_PATH=\"$(PWD)/\"">>$(HOME)/.profile
else
echo "this one"
@if [ $(EZ_PATH) != $(PWD)/ ] ; then echo -e "\nexport EZ_PATH=$(PWD)/">>$(HOME)/.bashrc ; fi
@if [ -z "$(EZ_PATH)" -a "$(EZ_PATH)" != $(PWD)/ ] ; then echo "\nexport EZ_PATH=$(PWD)/">>$(HOME)/.bashrc ; fi
endif
#
# Congratulations ! It looks like you compiled EASEA successfully.
......
/*_________________________________________________________
Test functions
log normal adaptive mutation
Selection operator: Tournament
__________________________________________________________*/
\User functions:
\end
\At the beginning of each generation function:
\end
\At the end of each generation function:
\end
\At each generation before reduce function:
\end
\GenomeClass::display:
\end
\User declarations :
#include <base.h>
#include <genome.h>
#include <tree.h>
#include <omp.h>
#define X_MIN -1.
#define X_MAX 1.
#define ITER 120
#define Abs(x) ((x) < 0 ? -(x) : (x))
#define MAX(x,y) ((x)>(y)?(x):(y))
#define MIN(x,y) ((x)<(y)?(x):(y))
#define SIGMA 1. /* mutation parameter */
#define PI 3.141592654
#define G_SIZE 96 // fixme this size is defined in genome.h as GENOME_SIZE
float pMutPerGene=0.15;
float pMutDesCard = 0.1;
struct base* train_table = NULL;
struct base* car_table = NULL;
float* uniq_instances[2];
unsigned uniq_cnt[2];
\end
\User classes :
GenomeClass {
float x[G_SIZE];
}
\end
\Before everything else function:
{
INSTEAD_EVAL_STEP = true;
cout << "Seed : " << globalRandomGenerator->get_seed() << endl;
//cout<<"Before everything else function called "<<endl;
train_table = ba_postgres_load_train();
car_table = ba_postgres_load_car();
ba_set_links(train_table,car_table);
ba_mix_instances(train_table);
//ba_print_db(train_table);
uniq_instances[0] = ba_compute_uniq_values(car_table, 1, uniq_cnt+0);
uniq_instances[1] = ba_compute_uniq_values(car_table, 2, uniq_cnt+1);
printf("%d %d\n",uniq_cnt[0],uniq_cnt[1]);
for( unsigned i=0 ; i<uniq_cnt[0] ; i++ ){
printf("%f,",uniq_instances[0][i]);
}
printf("\n");
for( unsigned i=0 ; i<uniq_cnt[1] ; i++ ){
printf("%f,",uniq_instances[1][i]);
}
printf("\n");
}
\end
\After everything else function:
{
EA->population->sortParentPopulation();
IndividualImpl* best = (IndividualImpl*)EA->population->parents[0];
printf("best fitness %f\n",best->evaluate());
for( unsigned i=0 ; i<G_SIZE ; i+=3 ){
printf("%f %f >= %f\n",best->x[i],best->x[i+1],best->x[i+2]);
}
printf("\n");
cTreeNode* root = generate_tree(best->x,train_table,car_table);
struct base* tmp_table = table_from_genome(best->x,train_table,car_table);
show_tree(tmp_table,root);
struct base* tmp_learning_table, * tmp_test_table; // fixme
tmp_learning_table = (struct base*)malloc(sizeof(*tmp_learning_table));
tmp_test_table = (struct base*)malloc(sizeof(*tmp_test_table));
printf("depth of resulting tree %d\n",root->tree_depth());
#if 0
// prepare learning and test table.
tmp_test_table->hdr = tmp_learning_table->hdr = tmp_table->hdr; // affect tmp hdr to every table.
tmp_learning_table->no_instances = (unsigned)(tmp_table->no_instances*(2.f/3));
tmp_test_table->no_instances = (unsigned)(tmp_table->no_instances*(1./3));
tmp_learning_table->instances = new float*[tmp_learning_table->no_instances];
tmp_test_table->instances = new float*[tmp_test_table->no_instances];
memcpy(tmp_learning_table->instances,tmp_table->instances,
sizeof(*tmp_learning_table->instances)*tmp_learning_table->no_instances);
memcpy(tmp_test_table->instances,tmp_learning_table->no_instances+tmp_table->instances,
sizeof(*tmp_learning_table->instances)*tmp_test_table->no_instances);
for( unsigned i=0 ; i<tmp_test_table->no_instances ; i++ ){
unsigned predicted_class = root->classify_instance(tmp_test_table->instances[i]);
unsigned real_class = (unsigned)tmp_test_table->instances[i][tmp_test_table->hdr->whichis_class];
printf("%d - %d\n",predicted_class,real_class);
}
#endif
delete root;
ba_delete( tmp_table );
}
\end
\GenomeClass::initialiser :
{
for( unsigned i=0; i<G_SIZE ; i+=3 ) {
//Genome.x[i] = random(0,101);
//Genome.x[i+1] = random(0,101);
//Genome.x[i] = car_table->hdr->attributes[1]->threshold[random(0,car_table->hdr->attributes[1]->no_threshold)];
//Genome.x[i+1] = car_table->hdr->attributes[2]->threshold[random(0,car_table->hdr->attributes[2]->no_threshold)];
Genome.x[i] = car_table->instances[random(0,car_table->no_instances)][i+1];
Genome.x[i+1] = car_table->instances[random(0,car_table->no_instances)][i+2];
if( tossCoin(pMutDesCard))
Genome.x[i+2] = 0;
else
Genome.x[i+2] = random(1,11);
}
}
\end
\GenomeClass::crossover :
{
for (int i=0; i<G_SIZE; i++){
if( tossCoin(0.5) )
child.x[i] = parent1.x[i];
else
child.x[i] = parent2.x[i];
}
}
\end
\GenomeClass::mutator : // Must return the number of mutations
{
int NbMut=0;
for (int i=0; i<G_SIZE; i+=GENE_SIZE){
// mutate the cardinality
if( tossCoin(pMutPerGene) ){
if( tossCoin(pMutDesCard) ){
Genome.x[i+GENE_SIZE-1] = 0;
NbMut++;
}
else{
float value = random_gauss(Genome.x[GENE_SIZE*i+GENE_SIZE-1],2);
value = (value<0 ? 0 : value); //if value less than 0, then value is 0
value = (value>10 ? 10 :value); // if value grether than 10 then value is 10
Genome.x[i+GENE_SIZE-1] = roundf(value);
NbMut++;
}
}
for( unsigned j=0 ; j<GENE_SIZE-1 ; j++ ){
if( tossCoin(pMutPerGene) ){
//Genome.x[i+j] = car_table->instances[random(0,car_table->no_instances)][j+1];
//Genome.x[i+j] = car_table->hdr->attributes[j+1]->threshold[random(0,car_table->hdr->attributes[j+1]->no_threshold)];
float value = random_gauss(Genome.x[i+j],2);
//value = (value<0 ? 0 : value); //if value less than 0, then value is 0
//value = (value>101 ? 101 :value); // if value grether than 10 then value is 10
//Genome.x[i+j] = value;
Genome.x[i+j] = ba_nearest_greather_table_value(car_table,j+1,value);
NbMut++;
}
} // for each threshold
}// for each gene
return NbMut;
}
\end
// The population evaluation.
\Instead evaluation function:
{
ba_mix_instances(train_table);
#pragma omp parallel for
for( unsigned i=0 ; i<popSize ; i++ ){
population[i]->evaluate();
}
}
\end
\GenomeClass::evaluator : // Returns the score
{
struct base* tmp_table = table_from_genome(Genome.x,train_table,car_table);
struct base* tmp_learning_table, * tmp_test_table; // fixme
float fitness_value = 0;
tmp_learning_table = (struct base*)malloc(sizeof(*tmp_learning_table));
tmp_test_table = (struct base*)malloc(sizeof(*tmp_test_table));
// prepare learning and test table.
tmp_test_table->hdr = tmp_learning_table->hdr = tmp_table->hdr; // affect tmp hdr to every table.
tmp_learning_table->no_instances = (unsigned)(tmp_table->no_instances*(2.f/3));
tmp_test_table->no_instances = (unsigned)(tmp_table->no_instances*(1./3));
tmp_learning_table->instances = new float*[tmp_learning_table->no_instances];
tmp_test_table->instances = new float*[tmp_test_table->no_instances];
memcpy(tmp_learning_table->instances,tmp_table->instances,
sizeof(*tmp_learning_table->instances)*tmp_learning_table->no_instances);
memcpy(tmp_test_table->instances,tmp_learning_table->no_instances+tmp_table->instances,
sizeof(*tmp_learning_table->instances)*tmp_test_table->no_instances);
cTreeNode* t = genereate_decision_tree(tmp_learning_table);
for( unsigned i=0 ; i<tmp_test_table->no_instances ; i++ ){
unsigned predicted_class = t->classify_instance(tmp_test_table->instances[i]);
unsigned real_class = (unsigned)tmp_test_table->instances[i][tmp_test_table->hdr->whichis_class];
// here compute classification error, or any quality measurment
if( predicted_class!=real_class ){
fitness_value++;
}
}
fitness_value += ((float)t->tree_depth());
delete t;
delete[] tmp_learning_table->instances;
delete[] tmp_test_table->instances;
free( tmp_learning_table );
free( tmp_test_table );
ba_delete(tmp_table);
return fitness_value;
}
\end
\User Makefile options:
CXXFLAGS+=-I/home/maitre/sources/c4.5/include/ -fopenmp -O3 -pg
LDFLAGS+= -lpq -O3 -lm -fopenmp libc45.a -pg
\end
\Default run parameters : // Please let the parameters appear in this order
Number of generations : 100 // NB_GEN
Time limit: 0 // In seconds, 0 to deactivate
Population size : 100 //POP_SIZE
Offspring size : 100 // 40%
Mutation probability : 0 // MUT_PROB
Crossover probability : 1 // XOVER_PROB
Evaluator goal : minimise // Maximise
Selection operator: Tournament 2.0
Surviving parents: 100%//percentage or absolute
Surviving offspring: 100%
Reduce parents operator: Tournament 2
Reduce offspring operator: Tournament 2
Final reduce operator: Tournament 2
Elitism: Strong //Weak or Strong
Elite: 1
Print stats:1 //Default: 1
Generate csv stats file:0
Generate gnuplot script:0
Generate R script:0
Plot stats:0 //Default: 0
\end
......@@ -36,10 +36,10 @@ __________________________________________________________*/
#define K 5
#define GENE_SIZE 4
#define GENOME_SIZE 32
#define GENOME_SIZE 128
float pMutPerGene=0.1;
float pMutPerGene=0.01;
float pMutDesCard = 0.05;
float pMutDesThre = 0.5;
......@@ -69,9 +69,10 @@ GenomeClass {
cout << "Seed : " << globalRandomGenerator->get_seed() << endl;
srand(globalRandomGenerator->get_seed());
t1 = ba_postgres_load_ilot(1);
t2 = ba_postgres_load_batiment(1);
t1 = ba_postgres_load_ilot(2);
t2 = ba_postgres_load_batiment(2);
ba_set_links(t1,t2);
//ba_print_links(t1);
//printf("+ %d - %d\n",t1->class_repartition[1],t1->class_repartition[0]);
for( unsigned i=0 ; i<t1->hdr->attributes[t1->hdr->whichis_class]->no_values; i++ )
......@@ -79,14 +80,14 @@ GenomeClass {
uniq_instances[0] = ba_compute_uniq_values(t2, 1, uniq_cnt+0);
uniq_instances[1] = ba_compute_uniq_values(t2, 2, uniq_cnt+1);
printf("%d %d\n",uniq_cnt[0],uniq_cnt[1]);
// allocating K packets
generate_k_fold(K,packets_size,t1,k_tables);
#if 1
#if 0
// try the perfect solution
IndividualImpl* i = new IndividualImpl();
i->x[0] = 30;
......@@ -104,7 +105,7 @@ GenomeClass {
show_tree(tc,t,0);
#endif
exit(-1);
//exit(-1);
}
\end
......@@ -143,7 +144,6 @@ GenomeClass {
printf(" error on the whole set : %d\n",error);
#endif
delete root;
ba_delete( tmp_table );
}
......@@ -153,11 +153,11 @@ GenomeClass {
{
for( unsigned i=0; i<GENOME_SIZE ; i+=GENE_SIZE ) {
Genome.x[i] = random(9,11364);
Genome.x[i+1] = random(77,999);
Genome.x[i+2] = random(569,1000);
Genome.x[i] = random(9.,11364.);
Genome.x[i+1] = random(77.,999.);
Genome.x[i+2] = random(569.,1000.);
Genome.x[i+GENE_SIZE-1] = random(0,5);
Genome.x[i+GENE_SIZE-1] = roundf(random(0.,10.));
}
}
\end
......@@ -206,15 +206,31 @@ GenomeClass {
for( unsigned j=0 ; j<GENE_SIZE-1 ; j++ ){
if( tossCoin(pMutPerGene) ){
if( tossCoin(pMutDesThre) ){
Genome.x[i+j] = INFINITY;
Genome.x[i+j] = INFINITY;
}
else{
float value;
if( __isinf(Genome.x[i+j]) ) Genome.x[i+j] = random(0,1000);
float value = random_gauss(Genome.x[i+j],10);
Genome.x[i+j] = roundf(value);
//value = ba_nearest_table_value(t2,j+1,value);
switch(j){
case 0:
value = random_gauss(Genome.x[i+j],100);
Genome.x[i+j] = roundf(value);
Genome.x[i+j] = ba_nearest_table_value(t2,j+1,value);
break;
case 1:
value = random_gauss(Genome.x[i+j],20);
Genome.x[i+j] = roundf(value);
Genome.x[i+j] = ba_nearest_table_value(t2,j+1,value);
break;
case 2:
value = random_gauss(Genome.x[i+j],10);
Genome.x[i+j] = roundf(value);
Genome.x[i+j] = ba_nearest_table_value(t2,j+1,value);
break;
}
//}
NbMut++;
}
NbMut++;
}
} // for each threshold
......@@ -331,7 +347,7 @@ GenomeClass {
}
fitness_value = (((float)error) / t1->no_instances)*100;// + ((float)tree_size)/K;
fitness_value = (((float)error) / t1->no_instances)*100 ;//+ ((float)tree_size)/K;
for( unsigned i=0 ; i<K ; i++ ){
ba_delete(k_tmp_tables[i]);
......@@ -346,14 +362,14 @@ LDFLAGS+= -lpq -lm -fopenmp ../c4.5_common/libc45.a
\end
\Default run parameters : // Please let the parameters appear in this order
Number of generations : 100 // NB_GEN
Number of generations : 200 // NB_GEN
Time limit: 0 // In seconds, 0 to deactivate
Population size : 200 //POP_SIZE
Population size : 100 //POP_SIZE
Offspring size : 100 // 40%
Mutation probability : 1 // MUT_PROB
Crossover probability : 1 // XOVER_PROB
Evaluator goal : minimise // Maximise
Selection operator: Tournament 6.0
Selection operator: Tournament 4.0
Surviving parents: 100%//percentage or absolute
Surviving offspring: 100%
Reduce parents operator: Tournament 2
......
......@@ -516,17 +516,17 @@
\GenomeClass::crossover:
int locusC = random(0,child1.Size-1);
int locusC = random(0,child.Size-1);
int locusP2 = random(0,parent2.Size-1);
Element * elt1=chercheNoeud(child1.arbre,locusC);
Element * elt1=chercheNoeud(child.arbre,locusC);
Element * eltParent2=chercheNoeud(parent2.arbre,locusP2);
Element *elt11 = copierSousArbreRec(eltParent2, elt1->profondeur,profondeurMax1);
remplace(child1.arbre,elt11,locusC);
regenSize(child1.arbre);
child1.Size=SIZE;
remplace(child.arbre,elt11,locusC);
regenSize(child.arbre);
child.Size=SIZE;
\end
......
......@@ -306,7 +306,7 @@ void CEvolutionaryAlgorithm::showPopulationStats(struct timeval beginTime){
#ifdef __linux__
if(this->params->plotStats && this->gnuplot->valid){
if(currentGeneration==0)
fprintf(this->gnuplot->fWrit,"plot \'%s.dat\' using 3:4 t \'Best Fitness\' w lines, \'%s.dat\' using 3:5 t \'Average\' w lines, \'%s.dat\' using 3:6 t \'StdDev\' w lines\n", params->outputFilename,params->outputFilename,params->outputFilename);
fprintf(this->gnuplot->fWrit,"plot \'%s.dat\' using 3:4 t \'Best Fitness\' w lines ls 1, \'%s.dat\' using 3:5 t \'Average\' w lines ls 4, \'%s.dat\' using 3:6 t \'StdDev\' w lines ls 3\n", params->outputFilename,params->outputFilename,params->outputFilename);
else
fprintf(this->gnuplot->fWrit,"replot\n");
fflush(this->gnuplot->fWrit);
......
......@@ -49,7 +49,7 @@ CGnuplot::CGnuplot(int nbEval){
this->fWrit = (FILE *)fdopen(toFils[1],"w");
this->fRead = (FILE *)fdopen(toPere[0],"r");
this->pid = sonPid;
fprintf(this->fWrit,"set term x11 persist\n");
fprintf(this->fWrit,"set term wxt persist\n");
fprintf(this->fWrit,"set grid\n");
fprintf(this->fWrit,"set xrange[0:%d]\n",nbEval);
fprintf(this->fWrit,"set xlabel \"Number of Evaluations\"\n");
......
......@@ -623,7 +623,7 @@ LDFLAGS=-lboost_program_options $(LIBAESAE)libeasea.a
#USER MAKEFILE OPTIONS :
\INSERT_MAKEFILE_OPTION#END OF USER MAKEFILE OPTIONS
CPPFLAGS+= -I$(LIBAESAE)include
CPPFLAGS+= -I$(LIBAESAE)include -I/usr/local/cuda/include/
NVCCFLAGS+=
......
......@@ -448,6 +448,11 @@ clean:
rm -f $(OBJS) $(TARGET)
easeaclean:
rm -f $(TARGET) *.o *.cpp *.hpp EASEA.png EASEA.dat EASEA.prm EASEA.mak Makefile EASEA.vcproj EASEA.csv EASEA.r EASEA.plot
gen:
../../easea EASEA
gent:
../../easea tl EASEA
\START_VISUAL_TPL<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
......
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