MyPitSelf
Welcome to MyPitSelf


 English(US)  Français(FR)


This documentation has been produced with MyPitSelf00817

   Welcome to MyPitSelf

MyPitSelf© is a tool to write information system linked to databases. Its design allows the reverse-engineering of the programs

It is an information system like an other but instead of dealing with bank accounts, mails, websites, process ... it deals with programs and databases.

Like the other Systems, one can always think of a new function to implement, there is no limit.

And what allows a System to be able to evolve without limits is linked to the recursivity principle which says that by feed-back on all or a part of the initials elements, a small number of initial elements are enough to build an infinite serie of elements.

Reverse-ingenering is a recursive process. MyPitSelf is a possibility to implement programs with this principle.

Keeping this way of thinking, the first program written with MyPitSelf is MyPitSelf itself (it doesn't seem important but it is, really).

This principle is implemented with:
- A method to resolve the paradigme of the access to the data in database.
- A language which uses this method and which also allows to put the sentences as data and back.

A part of this documentation is not too technical ( see general presentation ), the other chapters are.


MyPitself uses MySql, Php, SVG, Apache, HTMLArea, linux, firefox, Win2K/XP/IE6/7, and last but not the least itself .

The name MyPitSelf comes from MySql, Php and itself


. . . .




General presentation


- When it is complicated...

I had a difficulties when I had to maintain or develop programs with data designs like the one presented underneath:


Click and look at the picture during 5 seconds, no more Use the button on top of the new window to close it.

In general, you have seen boxes (data) and arrows which link them (connections between data). The problem was that this was becoming too complicated for me because the data and their connections were too numerous.

In this case, one calls colleagues and does big projects, costing a lot of time and the users often end unsatisfied.

But the user wants more because there is the permanent threat that customers will to go to the competitors if a strategic new function cannot be done, immediately.


- ... one find solutions ...

In this case one updates the programs and now, one can really start to enjoy the work because with the appreciation of what the designer understood, and the consideration of what the programer intended to program we have to tell the user that the job will be done in x days for a price of y$. This has always been, for me, a task between a probability level (It should fit in these constraints) and a mystic level (Hope it will work).

So, as I didn't like this situation, I started to develop a tool to help myself.

I went on and as the program grew up, I reached the conclusion that one had to industrialize the development of the programs. To do this, the design stage and the writing stage of the programs had to be industrialize.
And to do this, I reached the second conclusion that programs had to be able to be reverse-engineered by it's own means.

But I had to find the way to do it.



- ... build them ...

As one is never better helped than by one self, I built MyPitSelf . As the reverse-engineering is set up and the first program done with MyPitSelf is MyPitself, I think that the foundations are not too bad. The data model you have seen above during 5 seconds is the MyPitSelf data design !

Once I asked a teatcher in science history and science philosophy what was the limit of this development. He ansewered by the sentence you have read upper about unlimitted systems.

Practically, the limit of the system is bordered by the computer speed and memory but at least, it is far enough now.



- ... and talks about them!

Simple programs can be set up fast once one knows the development environment. But it's not all that obvious because it's different from what I have seen before. (You have been warned).

One can also make some more complicated things, for example MyPitSelf is not simple. It's a development environment which contains multi user access with rights, multilingual, multibase, with several environments ( development, tests, production), backups, documentation with screen copies, etc ...
I have used MyPitSelf to build programs with other users than myself and data designs that looked like these
.

I started to use the reverse-engineering to maintain MyPitSelf: for example, I once defined the use of a function which was not very clean and I wanted to update all programs to change this. As I used this function very often, I wrote a program in the MyPitSelf language to do this. MyPitSelf can maintain MyPitSelf ! As this program has already been written, it will not be too complicated to update it, if I have to write a modification on an other function.
Some people also call this refactoring.

An other example comes when one renames a field in the database. In this case, all function that use this field are treated to replace the old name by the new one.

What follows on this web site is more serious stuff because I explain how all this works. These explanations can make you believe that I contemplated before I proceeded. As a matter of fact, in the whole process actions have preceded the thought process. I prefer a tool that works rather than a concept that does not work.

There is still work to do, some parts are still dirty but now, I'm not afraid to clean up, and I am sure I will be able to benefit from it.

Actually, at the moment, I am setting up the environment to work with ajax, you will see my first attempts here.


Now, let's go to work !



- How ?


- - The core

The a part of the core is written in Php, the rest is written in the MyPitSelf language.

The programs written with MyPitSelf are done with the MyPitSelf design with :

- A "system" database containing the description of your system (databases, functions ...)

- One or more "data" databases with the datas of your program.




- - Define the data

You start by defining a working environment ie databases (fields, tables, indexes, links between data ...) and other features (constants, user rights, menu ...).

Then you generate simple SQL requests with the help of a tool that keeps the request parameters in the system (type of request, tables and fields of the request).

Some request are used to see the data (SELECT of a certain value or SELECT of a list of values).

Others are translated to functions that you can use in the MyPitSelf language (SELECT, INSERT, UPDATE, DELETE).

This is where the database paradigme is resolved: as the access to the data is done with functions and these functions are used in the programs, there are no SQL request in the middle of the programs.




- - Programs

A language based on function calls is used to write functions in source format. It uses usual features of other languages (variables, tests, loops, files/IOs, ...) and the functions produced by the requests.

This language is compiled and interpreted for interactive programs.

After source parsing, the system produces a table format.

The table format can be put in the database to be computed (reverse-engineered). Functions become data.

The system can regenerate the source format from the table format.

Out of the table format, the system produces executable code (in php today).


The difference with an other language is that the table format of the program which is the result of the parsing is available and can be treated with the means of the language.

It is like if you were the person who had written the compiler and so you would know how to write the parser, and, at the end of the parsing process, you would be able to rewrite the source.



- So What ?

So, I think that MyPitSelf resolves ( and will resolve ) some problems in information technology:



- - Complex treatments

Problem:

An application evolves in two directions: data to maintain and function to give. Today one can add data ( for example if you have 50 or 100 emails in your email box doesn't change many things ) but to add a function is less evident ( for example the sum of mails from Paul and Jack )

The need of complexity requires an industrial treatment. If the code checking is done by humans, some bugs will probaly appear goes in the programs


Answer:

When the basic functions on data are set up, the arrengement of these function to give more complex functions is easier to set up if we consider them as operations on data ( add the mails from Paul to the mails from Jack ).

If MyPitSelf, functions are transformed as organized as data in database and a data check is a current operation that can be done whith the right program.



- - Adaptation

Problème:

The data to manage are defined with a model and some rules that are justified during the primary design and according to the person who does the design.
But the resultant system must evolve in the time because during it's use some new functions are neded.
And furthermore, some parts that were important during the primary design become less important and some new ones become more important. In this case, the primary design must evolve to adapt to these new parts.

The important point is not the primary design but its flexibility and the possibility to use the existing parts.


Réponse:

The first system done with MyPitSelf is itself. First there was only the core then data heve been added then functions on these data, then the core has been updated and so on. In othe words the first data and system design has evolved along its growing. Systems done with MyPitSelf grow with the same logical way.

Today the data are enough for the development in the current version. The functions needed to build a development environment represent a good part of what one can imagine to build an information system, but some new needs like statistics or graphical outputs may be needed. Once they will be inserted in MyPitSelf, the other systems will be able to use them.



- - Conclusion

MyPitSelf is good enough even if it is only version 0.8 because the reverse-engineering is ready.
This means that if MyPitSelf Evolves, programs built with older versions will follow the new versions.



- Work frame

95 % of the developments are done via a web browser, with only the administrator having access to the server

It is multilingual at the system level, MyPitSelf is in English (well, my English) and in French

It is multilingual at the program level, the programs one develops can be seen in the languages the user selects

The functionnal documentation of your programs is facilitated due to the reverse-engineering and


The user rights management is in the core and can be extended to match your program specification : user rights on the menus, on the functions ...

It helps the conception of applications based on data designs with many links.
Screen copies

These screen copies come from the development example given under.
MyPitself lets you record the pages where one goes to, for example, create the software documentation.

Request generation: .

Function creation: .


Technical stuffs


- What is MyPitSelf ?

MyPitSelf is a system to develop and maintain programs and data in a database.
Each development has its own environment with:

One "system" database containing:
- the description of the data,
- the source of the programs,
- a list of settings like constants, working directories....

One or more "data" databases containing the data to maintain.

During the development, environments are included in the main environment.

After the development mode, one can produce a set which is independant of the main environment.



As a developer, with MyPitSelf, you will build the environments for other programs and fill the "system" databases of the other programs.

Its target is to develop multi-user programs so there is a user authorization context with password entry.



- Why MyPitSelf ?

Three main reasons:

1°) Databases are good to store and use data. They can also be good to store and use programs. The programs had to be written in a way that they can be organized in a database, so that they can be linked to the data they compute. That is why there is a language. This also means that programs are considered as data, consequently, one can treat programs like data.

2°) Once the data are defined, the programs compute them. In this system, the first step is to define all the data needed, after which the programs can be written. The original types of data are those given by the database.

3°) The first program done with this system is the system itself because if this system can organize and compute any data, it can organize and compute a system to organize and compute data.

This explains the loop in this image



- How is it done ?

Thanks to PHP, MySql, Javascript and Apache with Linux/Win2K on Firefox/IE.

The tools used are mainly MyPitSelf, The W2k NotePad, and PhpMyAdmin.
Lcc has been used to write a program to launch Batch jobs, It is an adaptation of mikehup.exe written by Michael Kohn (naken@naken.cc), Web page: http://www.naken.cc/

I use SVG to draw the tables with the links.

PHP us used to write the basic functions.

All user functions should be written in the MyPitSelf language. The basis of this language is:
 

It is also based on:
 

Note on the translation: although I'm french, I started to write this software in english afterwhich I added the possibility to have a localised ( french in my case ) version on-line, so I could write in both languages, especially this documentation.
Some chapters have been written directly in french, then translated into english. For others, it is the opposite. Mark has corrected a part of the English translation, The good english comes from him, I assume all the errors.
As a result of time constraints, there are sometimes differences in documentation but I think these are of minor importance and you will know how to deal with them.


I will will concentrate on the French version and the English version. If other contributors accept to translate this software in other languages, I'll be able to propose their traductions in the distribution.
Later in this documentation, ( chap How TO'S ), I talk about the translation.




- State of MyPitSelf

Never Finished because I always want to add some more functions! But good enough to have some production programs.

Currently, functions like versioning, testcase scenarios, automatic documentation, Internationalisation ... that I have started but they are not achieved yet.
At least, the existing ones allowed me to do what you are going to see ( if you go on ).

I can't tell you when the next version will come out because I can't do this at 100%.

Now, let's see what it looks like.




- An example


- - Data

Suppose you have a data model with a table of information about people (names, age etc.).

Also suppose that you have generated several requests with the system, including the one which has the number, say, 1012.

SELECT   T0.Id,T0.Name,T0.Age 
FROM     $Data.People T0 
WHERE    T0.Age <= %SQLPAR0% 
ORDER BY T0.Name ASC
A function called R_1012_Select() has then been generated and it takes one parameter which is the age (xxx).

The system must generate the requests thanks to your specifications because all the parameters (tables, fields, conditions, sort orders) are stored in the system.

Then, the system can generate the SQL sentence and the function using this sentence


- - Program

A possible use of this function could be to output all the people whose ages are >= 30.
This will give a program which looks like (comments are preceded by //) :

Tac(                // Take and call: put values in the call stack and/or call functions.
 Cst(30),           // constant 30 pushed in the call stack
 R_1012_Select(     // select list of these people (1 parameter xxx taken from the call stack)
  Do(
   Take(T0.Name),   // Pushes the name in the call stack
   out(1)           // displays the first element contained in the call stack
  )                 // The name is popped here
 )
)                           
Remarque: lines breaks are ignored, one can also write this function like:
Tac(Cst(30),R_1203_Select(Do(Take(T0.Nom),out(1))))

Comas are not mandatory after ), an other way to write this function would be :
Tac(
 Cst(30)
 R_1203_Select(
  Do(Take(T0.Nom),out(1))
 )
)
Blocks comments are delimited by /* and */ , they MUST start at the first column and can be nested.


- - Table program

This program has this table format: :

Ind Function # Parent # Order In
Parent
Function
Name
Function
Type
Number Of
Children
Level C1 C2
0 0 -1 0 0 INIT 1 0
1 1 0 1 Tac formula 2 1
2 2 1 1 Cst formula 1 2
3 3 2 1 30 Value 0 3
4 4 1 2 R_1203_Select formula 1 2
5 5 4 1 Do formula 2 3
6 6 5 1 Take formula 1 4
7 7 6 1 T0.Name zone 0 5
8 8 5 2 out formula 1 4
9 9 8 1 1 Value 0 5

With this format, a program can analyse and identify the treatments with the data implied because all information about request #1012 are stored in the system.

In other words, one can reverse-engineer this program.

If you put this table format in the database, you can update the records with a program. Then, the system can regenerate the source format.


- - Source

< ? php
function f_5001(){
 global $XVS,$XCS;  // variable stack and call stack
 $xxSI=sizeof($XCS);  // call stack init pos
 $xxSC=0;  // Stack push count
 //===== Start of function =====
 //===================
 $req4 = "
 SELECT  T0.Nom  FROM  `Gens` T0
 WHERE  T0.Age<=30
 ORDER BY  T0.Nom ASC " ;
 //===================
 $result4=mysql_query($req4);
 if(mysql_errno()==0){
  while($mpsrow4=mysql_fetch_row($result4)){
   echo ''.$mpsrow4[0].'
'; // output } }else{ return(xxErrSql('1203_SELECT',mysql_error(),$req4,$xxSI)); } mysql_free_result($result4); //===== End of function ===== return(true); } ?>
This example is quite simple but you will see by a click here something which is not: it is one of the function which does reverse ingineering of the execution of a program, it updates the table format of the function.



- Installation

I assume that Apache (1.3.29), Php (4.3.3), MySql (4.0), firefox or IE(6.0) are running fine on your system. The versions numbers are the one I currently use but I suppose that it will work with newer versions.

I assume that you know a minimum on these software and particulary the way to make them run together.
If this is not the case, please see the enormous amount of documentation about them.



- - Unzip

There are two files to Unzip:
The mypitselfw ( Web files ) to unzip in the htdocs folder of the web server
The mypitselfp ( Program files ) to unzip somewhere else but not in a htdocs subfolder.

On a linux system, you should thew execute these commands:

cd /var/www # assuming that you have put the folders mypitselfw and mypitselfp in /var/www
chmod -R o+w mypitselfp
chmod -R o+w mypitselfw
cd mypitselfp
chown root:root batch_linux.exe
chmod -R o+x batch_linux.exe



- - Php and Apache


- - - Php Configuration

The use of php.ini-recommended given with your php installation is strongly recommended
Anyway, if you use something else at your own risk, at least check that that the settings below are:
register_globals = Off


I use the setting
display_errors = on
display_startup_errors = On
error_reporting = E_ALL
Even if those settings are not recommended but it is for debuggings reasons.



- - - Apache Configuration

I assume Apache/php is running on your system.
Add this setting to go directly to the index.php

< IfModule mod_dir.c>
 DirectoryIndex index.php
< /IfModule>



- - MyPitSelf Installation


When you tried to connect to the first screen, you saw a screen like this one

If this is not the case, something went wrong. Try to re-install it, deleting the folders and the database.

MyPitSelf installation.
Enter here the connection string to mysql
Enter here a valid user name
to access to mysql
Enter here a valid password to access to mysql
Enter the full name ( path included ) of the file
MyPitSelf root web path.txt
( It should be already filled )
Use the button to point on the file
MyPitself root program path.txt
( It is in the MyPitSelfP directory )
Database initialisation
Create database Delete database






If you have entered correct information in the fields and then have clicked on Create database and after a while you should have seen this screen

MyPitSelf installation.
Enter here the connection string to mysql
Enter here a valid user name to access to mysql
Enter here a valid password to access to mysql
Enter the full name ( path included ) of the file
MyPitSelf root web path.txt
( It should be already filled )
Use the button to point on the file
MyPitself root program path.txt
( It is in the MyPitSelfP directory )

Database MyPitSelfxxyzz created successfully. you can go to the menu.

or you can Delete database




If you did see it, it is all right, you should obtain a screen that ask you a user name and a password.
If this is not the case, well, something went wrong, try to reinstall it, deleting the folders and the database.


- - First Loggin

Click on this button: Go to MyPitSelf
You should see a window asking you for a user name and a password

Enter 1 in both fields and click on the "Enter" Button. Now if you see a window that looks like the one below, you can be happy :).




MyPitSelf



On this screen, there are several buttons in a menu bar that lead to number of lists.
You can click on them if you want but please, for the moment, avoid clicking the non-menu buttons.

Let's look at the 3 first options :

The button: allows you to come back to the initial screen.

The button: allows you to come back to the previous screen if it was a list or a "view" screen ( a screen to see informations ).

The button: allows you to quit. Try it now and re-enter 1/1 as user/password to come back to the initial screen.

You will see in examples to see how to use MyPitSelf some screen copies containing buttons with a standard meaning:
: New element
: Duplicate an element
: see an element
: update an element
: supress an element
: properties of an element
: Move an element




- Generated documentation

Out of the informations you have entered to create your program, MyPitSelf can generate a technical documentation
Click here to see it.



Examples


- First example: world

It's a programme to see the data from the "world" database avaible on the MySql website.

The database design is this one.


Click here to test this.




- Second example: CRM

This program is a little CRM for IT services providers to give the possibility to client companies to manage their own contacts.

Every company will have a main user called manager in the rest.
The manager creates the contacts ( first name, name ....)
The manager defines informations that will be linked to the concacts according to the company needs.

These informations are two types:
Event: it is a meeting, a meal at one date.
Relation: it is a fact concerning the contact like he is important, medium, small, he speaks french, english, or italien ...

The list of contacts is unique for every company, and it will be shared between the company users with relation with the contacts.

The manager defines the users ( login, name last name, password ).

The user will have a list of contacts that he will pick from the list of contacts of the company.

For every contact, he will be able to add relations or events that the manager hed previously defined.

A contact can be shared by several users.

A request system allow the user to list among his own contacts the ones that satisfy certains relation. The result of these requests can be combined with AND, OR, NOT, XOR functions.

The manager can do requests on all contacts of the company.
The data design is the one under.



You can see the general documentation ( normaly there is one specific for every type of user ) clicking here .

If you want to try it online, send me a mail with the contact page of this site and I will send you a login/password. This programm can be reached here .

It's only a little CRM but you have seen the possibility of MyPitSelf.

I didn't want to load this program with many buttons but it's quite easy to add for example the list of user that use a contact from the contact file.

One can add also company tables, links between companies and contacts and many other things that require a little more programming.

A bientôt.



- Third example

Now we are going to use this examples to see the use of this system.
The aim is to build a program in this environment.
There is a minimal set of explanations. Don't worry if you don't catch all of them, it will come later.
The project approach will have three different layers :

Organisation layer ( Client needs )
The client wants to have a system to do his task list. Each user of the system will be able to put some new tasks in the system with a name and a priority level. The priority level is a number and each user will be able to see the task list according to its priority level.
The client also wants to find tasks according defined sequences ( word match research ).
Some users ( eg managers ) must be able to see the tasks of all other users but most of then will see only their own tasks.
A user can modify each task ( priority and text ), add or delete one.

Functional layer ( what do we have to do )
A Task table with a user ID, a task name and a task priority.
A user table with the user ID, his logging name, first name and last name.

We will need to have a function to display a list of tasks according to its priority and according to the fact that the task contains a certain word. From this list, one will be able to create new tasks, modify existing ones or delete them.
An other functon ( manager ) will display a task list with the user name.
So according to the user profile, differents menu will be displayed.
User: See my tasks Manager: See my tasks, see all tasks

A super user will have the possibility to enable other users and to assign them a user level ( manager or user ).
A manager will be considered as a user for his ( or her ) own tasks.

Technical layer ( how are we going to do this ? ).
See the next chapters.

Comment: During the modification of a record, a lock is set up and during the next procedures, you might close windows during a modification and so, the lock will remain.
To take it off, go to the Profil menu then choose the option See the locks then click on the Unlock button.



- - A new environment


Click here to open a new window on MyPitSelf , enter 1/1 as username / password

The first thing to do is to create a new environment.

Note: for the moment, I have not worked enough on the privileges on the database so there is not a fine tunning of them.
The way it works is to define for each environment a mysql user/password ( or have always the same one ) and authorizations are set um for this user.
I advise you to use MyPitSelfDev, it works !

To do this, click here and perform the actions described.

To create a new environment means to create directories and a system database. ( look in folders mypitselfp and mypitselfw )



- - A new manager

Click here to open a window if it's not already open. on the MyPitSelf environment and log in as 1/1.

We have to create a manager who will have the ability to use the new environment.
For the moment, there are 3 profiles in MyPitSelf:

so we will have to To do this, click here and perform the actions described.

A user has been created, his name is m, his password is 1.


- - Start to develop


- - - Initialize the environment

Cliquez ici pour ouvrir une nouvelle fenetre si ce n'est déjà fait
Quittez l'environnement principal si vous êtes connecté en tant qu'utilisateur 1/1
et connectez vous en tant que m/1

Comme vous vous êtes connecté en tant qu'utilisateur m, vous ne voyez pas les mêmes menus que précédamment, en particulier, les menus permettant de gérer les utilisateurs sont réservés au super utilisateur.

En revanche d'autres menus sont apparus et vous permettront de développer.
Il faut tout d'abord créer une image de la base de donnée. En fait cette image a déjà été créée lors de la création de l'environnement. Vous pouvez la voir en cliquant sur le bouton base du menu.

Puis il faut donner à cette image une existance réelle c'est à dire créer réellement la base dans MySql.
Pour ce faire, exécutez les actions que vous voyez en cliquant ici .

Remarque: La base contient déjà 2 tables: Une table utilisateurs et Lock ( verrous ).
Ces deux tables sont créées car MyPitSelf est conçu pour travailler en environnement multi utilisateur.
Elles peuvent être supprimées ou modifiées mais pour l'instant, nous n'allons pas y toucher.



- - - Create a table

Puis il faut créer la table des tâches. Cette table est rattachée à la base et contient :



Des types de données existent déjà, nous allons les utiliser sans créer des nouveaux types. Voir le bouton donnee du menu.

Pour ce faire, exécutez les actions que vous voyez en cliquant ici .



- - - Create a list request

Maintenant il faut créer une requête permettant de lister les tâches. Elle resemblera à:

SELECT T0.ID,T0.Nom,T0.Priorite,T0.xRefUser FROM $Data.Taches T0 WHERE T0.Priorite <= %SQLPAR0% and T0.Nom LIKE '%%SQLPAR1%%' and T0.xRefUser = %SQLPAR2% ORDER BY T0.Priorite DESC , T0.ID DESC LIMIT $xxxlistStart , $xxxlistCount

%SQLPAR0% et %SQLPAR1% sont les deux critères de recherche possibles des tâches,
%SQLPAR2% limite la recherche à un utilisateur donné.

MyPitSelf contient un utilitaire permettant de générer les requêtes sur la base de donnée.

Nous allons l'utiliser pour créer une requête de type SELECT LIST.
Ce type de requêtes a été défini car il permet de générer des instructions propres à l'affichage d'une liste.

Pour l'utiliser, exécutez les actions que vous voyez en cliquant ici .

Le résultat de cette action, visible en cliquant sur le menu Requête est une requête SQL ayant un Code 1201 dans notre cas.

Nous avons coché le champ Hidden et Constant car lors de l'affichage de la liste des tâches, il ne faut pas afficher l'ID utilisateur ( c'est l'utilisateur en cours ) et le critère d'affichage des tâches est pour l'utilisateur en cours donc constant.



- - - Create a menu

Maintenant, il faut créer un menu permettant d'afficher la liste des tâches.
Ceci passe tout d'abord par la création d'une fonction écrite en langage MyPitSelf.
Cette fonction sera ensuite attachée à un menu.
Pour ce faire, exécutez les actions que vous voyez en cliquant ici .
Utilisez un copier/coller pour éviter de réécrire la fonction.
Un petit mot ici sur le langage MyPitSelf puisque cette fonction a été écrite dans ce langage:
Cette fonction permettant d'afficher la liste des tâches de l'utilisateur

Tac( Cst(999999999), // paramètre priorité de la tâche Cst(), // paramètre Nom de la tâche ( chaine vide ) VarG(xxUserCode), // Code de l'utilisateur ( variable globale ) Cst(3), // 3 paramètres a0_list( // afficher la liste basée sur ... Sql(1201) // ... la requête 1201 ) ) veut dire:
Tac ==> Take and Call: c'est l'INSTRUCTION principale de ce langage: Elle permet Ici, on met des constantes dans la pile d'appel ( 999999999, chaine vide et la valeur 3)
On met aussi une variable globale initialisée par le système. Elle représente l'unique ID de l'utilisateur.
La fonction appelée est a0_list avec un paramètre qui est le numéro de la requête à appeler.

L'instruction Tac sait reconnaître les fonctions permettant de mettre des variables dans la pile et celles exécutant des actions.
Ce langage est basé sur des fonctions qui peuvent être imbriquées les unes dans les autres ou appelées séquentiellement.
cette fonction peut aussi s'écrire de la façon suivante:
Tac( Cst(999999999), Cst(), VarG(xxUserCode), Cst(3), a0_list( Sql(1201) ) ) La fonction a0_list par définition prend 1 ou plusieurs paramètres dans la pile de variables, le premier paramètre ( 3 dans notre cas ) indiquant le nombre de paramètres à prendre dans la pile ( 99999, chaine vide, code utilisateur.

Vous avez compris que // indique un commentaire.



- - - Créer les fonctions

Maintenant, il faut créer une fonction permettant d'ajouter une tâche.

Nous allons utiliser l'outil pour créer une requête de type SELECT VALUE.
Ce type de requêtes a été défini car il permet de générer des instructions propres à l'affichage d'une entrée dans la base. Pour ce faire, exécutez les actions que vous voyez en cliquant ici .

Enfin, nous pouvons créer la fonction de type LISTTOP rattachée à la liste affichant la requête 1201
Pour ce faire, exécutez les actions que vous voyez en cliquant ici .

Enfin la dernière étape sera de regénérer toutes les requêtes, de compiler toutes las fonctions, d'établir la langue par défaut du programme et de créer les utilisateurs initiaux ( 0 = tous, 1 = super user )
Pour ce faire, exécutez les actions que vous voyez en cliquant ici .

Finalement, on peut commencer à tester l'application qui contient maintenant quelque chose.



- - Testing


- - - Add Todos

Cliquez iciet choisisez le bouton Test pour ouvrir une fenêtre sur votre nouveau programme en vous connectant avec le nom/mot de passe 1/1.

Maintenant, vous êtes le super utilisateur du NOUVEAU PROGRAMME, vous pourrez définir les autres utilisateurs et leurs droits tout comme vous avez défini un nouvel utilisateur dans l'environnement principal.

Tout d'abord, il faut savoir que par défaut, le super utilisateur est aussi un utilisateur normal et peut avoir accès à tous les menus.Si lors de la création du menu ( plus haut ) , vous ne cochez pas la case "pas pour super", le menu est disponible pour le super utilisateur.

Maintenant, nous allons tester le menu tâches en cliquant ici .




- - - Ajouter des utilisateurs

Puis nous allons ajouter deux utilisateurs en les rattachant à des groupes d'utilisateurs manager et utilisateurs qu'il faudra ensuite créer dans l'environnement de développement.
Pour créer ces utilisateurs, exécutez les actions que vous voyez en cliquant ici .




- - - Ajouter les groupes

Puis nous allons définir deux groupes d'utilisateurs ( manager et utilisateurs ) dans l'environnement de développement
Les actions à faire sont celles que vous obtenez en cliquant ici .

Pour leur assigner des menus, les actions à faire sont celles que vous obtenez en cliquant ici .



- - Add functions

Return to the development environment clicking here and log in as m/1.

We will add functions to be able to see, update, duplicate or supress a task.

To supress a task, we need to create a request with a DELETE VALUE type. Look the request number created, we will use it in the functions.
Then we will create functions with LISTFUNCT type.
To do this, perform the actions you see when you click here .

Now we are going to test these functions
Click hereand choose the Test button to open a window on your new program, log in as user/password m1/1.
Then test doing what you see when you click here

Voilà, the first part of the organisational part is finished, now we will add functions to allow the manager to see all tasks.



- - A New request.

Now we will built a menu to see tasks of all users for the managers.
To do this, we will have to create a request to list the tasks and the name of the user who has created this task.
This request will have two tables : the User table and the task table.

And, finally, we will create a new function and a new menu attached to this function.
Perform the action you see when you click here .

Then click here and choose the Test button to open a window on your new program, log in as 1/1.

Attach the new menu to the manager group performing the actions you see when you click here .

As you are user 1, you can try to click on the button of the menu now.



- - linked table

The client wants to add functions:
From the task list, the mananager should be able to
Create a task for a use other than himself.
Update a user task and particulary, change the user of the task.

How can this be done ?

I think you understood that MyPitSelf uses linked tables.
For example, during the development, you have noticed that we have attached a menu to a function, a table to a database, a field to a table, a menu to a group of users, etc ...
We are going to create a link specification.

The link here is that a task is attached to a user.
When a manager has to give a user task to an other user, he must be able to choose a user in the existing user list ie the user table.

We will have to create

Connect to MyPitSelf with the user m/1 and perform the actions you see when you click here .

Connect to MyPitSelf with the user m/1 and perform the actions you see when you click here .

Now, go to your program, with user/password m/1 and perform the actions you see when you click here .

Now we are going to add the function ( type LISTTOP ) to create a new task.

Connect to MyPitSelf with the user m/1 and perform the actions you see when you click here .

Now go to your program, log in as 1/1 and do the actions you see when you click here

now, log out and log in as user u/1 and you will see that this user has a new task.


- - Conclusion

These examples have showed you how to develop with MyPitSelf and a part of its functionnalities.

As MyPitSelf is mostly done with MyPitSelf, the best example of developement can be obtained when you connect to the MyPitSelf environment with user/password 1/1 .
Then click on the "tool" menu and then choose the button "Set or unset developing mode for MyPitSelf".
All menus will be seen then and you will be able to see the core.
You also can use the button "See/hide function call" in the "profile" menu to see which requests/functions are used.

An essential point in MyPitSelf is that fonctions written in its language are parsed to units that are visible using the button print facing the source of the functions in the function list ( try it in front of function 4003 ).
The ressult of this parsing is a grid that can be put in a database table.
Records of this table can be analysed and updated with the MyPitSelf Language.
One can then reverse ingeener the functionnalities on this grid and regenerate the source.
See the chapter "language reference" for more details about this subject.

See also the next chapters.

I haven't mentioned many other aspects, I have to enhance this documentation but I'm pretty sure you got the main points.
MyPitSelf will evolve because there are still functionnal gaps, but as nearly everything is in a database, including programs, that programs and data are linked and programs are finally considered as data to treat , the "only thing" to do is to add data and treat them.


When one has to develop data models that look like the MyPitself data model you have seen on the home page, it is nice to have a tool to help.

I think MyPitSelf is cool to deal with data models with many links.



Language


- General

The MyPitSelf language evolves constantly because of its own concept and because improvements are brought, but it will remain with only function calls returning true or false.

It is a "blending" of
lisp for the nested treatments and true or false return values
C for the function calls
Assembler for the stack mechanism

The best method to learn this language is like for all languages:
- Look and do the development examples given above, this will make you familiar to the basic concepts and the development environment.
- See examples of this language. for this, go to the MyPitSelf environment as user 1/1 and to choose in the tool menu the button "Set or unset Developping mode for MyPitSelf" and to look at the functions.

This function refererence is mostly done so that when I need to write some source, I can copy the example and then paste it in the source.

When you are in the function list, the button gives a result under a table view.
In other words, if a function is f(g(x),h(y)), the table result of this function is

Function# Parent
Number
Order In
Parent
Function
Name
Function
Type
Number Of
Children
Level
0-100INIT10
101fformula21
211gformula12
321xzone03
412hformula12
541yzone03

With these data, a procedure can implode it to rebuilt the original string [ f(g(x),h(y)) ].
This means that if some modification are done on the language structure, by putting this table in a database table and working on it ( ie add/move/suppress records ), one can make the functions evolve.
For example, like in the functions attached to a list, I decided once to put the field specification inside a Field() function.
The old format was:
Tac(
 T0.ID,
 doSomething(),
)
And the new format is:
Tac(
 Field(T0.ID),
 doSomething(),
)
To do this, I wrote functions that did that job.
That is the reason why even if I know that certains things have to be corrected, I do not panic about correcting all the sources.

Furthermore, the possibility to put the function in tables helps to trace every use of data. As the SQL phrases are written in database in an organized way and then translated into languages functions, one can know which data is used where.

The use of this possibility is for the moment in only few places but will be generalized to have a trace of everything.

Some functions have no arguments, some others fixed arguments, some others fixed functions arguments and other variable functions arguments.
A function always return true or false.

The arguments of the functions are inclosed in parenthesis and separated by comas.

Line comments start with // and they end with the end of line.
Block comments start with /*, end with */, these delimiters must be on the first column and can be nested.
The ' is a string delimitter, the escape character is \


- Variables

Variables can contain any basic type of data ( strings, dates, times...) but not yet arrays
There are two sets of variables.
Some are declared and named ( see SetVar below ) and are contained in a stack: It's the variable stack.

Others are put in a stack by programs. It's the Call Stack.
As MyPitSelf is based on data, some instructions extract data from the databases and puts them in the call stack.

The way to reach the variables put in the call stack is by giving a number which represents the position in the call stack:
If the call stack contains ( it is filled going downwards )

hello
world

1 represents world
2 represents hello

Some variables are globals ( particulary predefined variables )

The hw() function displays the content of the call stack ( "hello, world" )
the pvs() function displays the content of the variable stack. ( print variable stack )


- - SetVar

SetVar(xxxx,yyyy[,yyyy]) for local variables
or
SetVarG(xxxx,yyyy[,yyyy]) for global variables

Where xxxx can be:
a variable name ( no spaces or special characters admitted )
Var(xxxx) : The content of the variable whose name is xxxx. ( equivalent to the $$ in php ).

yyyy can be:
-Var(zzzz) or VarG(zzzz): The content of the variable zzzz, zzzz must exist.
-Chr(n): where n is the ascii code of a character. It is useful for specials characters like Chr(10) or Chr(13)
-Cst(xxxx) : A constant, it can be a string or a number.
-n: A number which represents the niest last character of the CallStack.
-Display(nnnn) : nnnn is the message number in the msg list ( usefull for internationalisation )
-Funct(nnnn) : nnnn is a function number: It replaces the Cst(nnnn) because if someone give a new number mmmm to nnnn, all Funct(nnnn) will be moved to Funct(mmmm).
-Stack(oooo) : oooo is a name of a variable which contain the position of the element to fetch in stack.
- SessionVar(ssss) : ssss is a name of a constant to get in $_SESSION .
- HttpPostVar(pppp) : pppp is a name of a constant to get in $_POST .
- Num(qqqq,x) : qqqq is a name of a variable, x is the number of decimals.
- Env(rrrr) : rrrr is a constant representing the environment variable to get ( php getenv() )
- XVS(zzzz) : gets the content of the variable which is in the Variable stack ( zzz is the variable name )

Examples:

SetVar(MyVar01,Cst(Hello),Chr(39),Chr(32),Cst(world)), // puts "hello, world" in MyVar01.
SetVar(MyVar01,Cst(25.5)),                             // now, it contains 25.5
SetVar(MyVar01,Cst(0)),                                // now, it contains 0
SetVar(MyVar02,Cst(ACombinedvar),Var(MyVar01)),        // MyVar02 contains ACombinedVar0
SetVar(Var(MyVar02),Cst(25.5))                         // ACombinedVar0 is created as a new variable
                                                       // and contains 25.5
SetVar(toto,Display(1000011)) // puts the content of the message n# 1000011 in toto



- - Predefined variables

An environment has it's own variables like
the folder of it's programs
The user code of the current user,
Default values for data ....

Go to the profile menu and use the "see/hide function call" button to see function calls.
Then a button appears on the main menu ( print variable stack ).
These predefined variables can be seen using this button. They start with xxx.
These variable are in the variable stack just like the ones the ones declared with SetVarG.
The pvs() function can be used to display variables in a program.

For the moment, one can update these variable which is absolutely not correct and has not to be done but this will be enhanced to have more control on the use of the "system variables" according to the user profile.



- - Operations on variables

They are basic because most operations are done using values in the call stack.

AddVar(xxxx,yyyy) Adds to xxxx ( must exist ) yyyy, yyyy can be: Cst(), Var(), n ( a value in the call stack )

SubVar(xxxx,yyyy) Subs to xxxx ( must exist ) yyyy, yyyy can be: Cst(), Var(), n ( a value in the call stack )

MultVar(xxxx,yyyy) Multiply to xxxx ( must exist ) yyyy, yyyy can be: Cst(), Var(), n ( a value in the call stack )

DivVar(xxxx,yyyy) Divide xxxx ( must exist ) by yyyy, yyyy can be: Cst(), Var(), n ( a value in the call stack ) If yyyy = 0, it returns false.

RemainderVar(xxxx,yyyy) xxxx % yyyy . If yyyy = 0, it returns false.

To test if a variable exist, use this kind of source : Tac( Test( Cond(IsSet(Var(MyVar))), // or Cond(IsSet(VarG(MyGlobalVar))) IfTrue( // do something ), IfFalse( // do something else ) ) )


- - Tac

Tac: pushes values into the callstack

Tac( Var(xxxx), // xxxx is a variable name VarG(xxxx), // xxxx is a variable name Cst(yyyy) // yyyy is a constant. Chr(zzzz) // zzzz is a numeric value for an ascii code Display(nnnn) // nnnn is a message number. Field(Tn.FieldName) // The FieldName can be use in LISTFUNCT functions, ie T0.Name Funct(oooo) // oooo is the number of the function to call ffff(), // ffff is a function to call whose name is not // one of the previous in this list // The Function is called for execution )

Example: Tac( SetVar(MyVar,Cst(Hello,world)), // defines a variable "myVar" and puts hello, world in it Var(MyVar), // push the variable in the call stack out(1) // outputs the last variable in the call stack ) // all variables pushed in this Tac() are poped
The Tn.Field name must be at the level one of the function. In this case the variable is transformed into a constant. ( use the Show source of your browser to see how the FUNCTION field is filled in any list screen ).
So if a LISTFUNCT function is Tac( Field(T0.ID), out(1) ) and the result button is in front of the record ID 1234, the source will show something like: onclick="document.XXFNCT.value='Tac( Cst(1234), out(1) )'"



- - Swap

Puts in the call stack the value of a variable.
It is usually used to return some values: as this language returns only true or false, if you want to get something different from a function call, you can use the call stack and put some values in it.
Example

// Receives the field code and builds the string to build the sql for this field SetVar(FieldCode,1), Tac( Var(FieldCode), R_1523_Select( Do( Take(T0.Name,T0.xRefData), SetVar(FieldName,2), SetVar(DataCode,1), Tac( Cst(0), // not system Var(DataCode) Funct(6091), // builds for example ' varchar(50) NOT NULL SetVar(SqlString,Cst('`')Var(FieldName),Cst('`'),Ret(1)) // now, SqlString contains `TheFieldName` varchar(50) NOT NULL ) ) ) Swap(SqlString,1), // the function calling this one can do a // SetVar(SqlField,Ret(1)) )


- - FillVar

Fills a variable with a value according to it's data type:
It is mostly used for ENUM and FLAG types
Example:

Tac(
 SetVar(DataType,Cst(1002)),
 SetVar(Value,Cst(1)),
 
 FillVar(Libelle,DataType,Value),  // Now Libelle contains 
 FillPgmVar(Libelle,DataType,Value),  // Now $Libelle contains <img src="img/picto/13x13/cc.png" />

 Ech(Var(Lib)),
)



- - DataVal

Tac( SetVar(ExternalRule,DataVal(InternalRuleName,Data(1034))), SetVar(out,Var(out),sp(),Var(ExternalRule),Cst(':')), )


- Numbers


- - Format a number

To put a number in the local format, do:

Tac( SetVar(Value,Cst(1234.567)) SetVar(DisplayValue,Num(Value,3)), // Display value contains // 1 234,567 in french format // 1,234.567 in us format )


- - Round a number

Tac( SetVar(R,Cst(0)) SetVar(Value,Round(Value,R)) )


- arrays

Content for doc chapter arrays



- - explode tab

Tac( SetVar(sep,Cst(',')), SetVar(value,Cst('hello,world')), SetVar(myTab,explode(sep,value)), SetVar(Co,1), SetVar(myVal,tab(myTab,Co)), // myVal contains "world" )


- Control and call functions


- - Test

Tests a contition to execute or not execute a treatment

Test( Cond(xxx), [IfTrue(yyy),] [IfFalse(zzz),] ) where xxx is the condition: It can be a function.
yyy is the series of function to do if the condition returns true
zzzz is the series of function to do if the condition returns false
If one or both of ReturnIfxxxx() are not mentioned, the returned value is true if the condition matches the ReturnIf ommitted.
Example 1: SetVar(ValueToTest,1), Tac( Var(ValueToTest), Test( Cond(Equal(0)), // the function Equal return true if the last value in varstack = it's argument. IfFalse( out(This will never be displayed but the program continues) ) ) )
The Equal function can take as argument:
a constant: can be a string or a number
Var(xxx): a variable whose name is xxx
f(): a function. Example 2: SetVar(ValueToTest,Cst(1)), Tac( Var(ValueToTest), Test( Cond(Equal(1)), IfTrue( out(I do not want to continue so I exit the program ), ReturnFalse() // this instruction stops the program returning false ) ) ) Example 3: SetVar(ValueToTest,Cst()), Tac( Var(ValueToTest), Test( Cond(IsVoid()), IfTrue( out(I DO want to continue ), ), IfFalse( out(I DO NOT want to continue ), Test( Cond(Funct(123456)) // writes in errorlog something IfTrue( ReturnFalse() // if we can't write in error log, BIG ERROR ) ) ) ) ) Test a function result: Tac( Var(TableCode), Var(FieldCode), Test( Cond(Funct(Var(T0TestFunct))), // Var(T0TestFunct) contains the function number IfTrue( Tac( // do something ) ) ) )


- - LoopVar

Loops n times a treatment.

LoopVar( xxxx, yyyy, Do(zzzz) ) where xxx is a variable containing the number of loops to do.
When the loop is executed, yyyy is set to the current loop number
zzzz is the series of functions

Example: SetVar(ValueToLoop,3), LoopVar( ValueToLoop,ind, Do( SetVar(Message,Cst('hello world '),Var(ind)), Tac( Var(Message), out(1) // outputs the 1st value in the call stack ) ) ) this loop displays hello, world 1 hello, world 2 hello, world 3


- - SwitchCase


Compares the last value in the call stack to some constants to execute functions

SwitchCase( x01,f01(), x02,f02(), ., ., ., [flast()] ) x0i are constants, f0i are functions
If none of the constants are matched and there is NOT a last function, without a constant before, it returns false
If none of the constants are matched and there IS a last function, without a constant before, it executes this last function
Examples: Tac( Cst(0), SwitchCase( 0, out(OK), 1, Tac( DoManyThings(), out(OK) ), out(KO) // default ) ) outputs OK and continues

Tac( Cst(2), SwitchCase( 0, out(OK), 1, out(OK), out(KO) ) ) outputs KO, and continues

Tac( Cst(2), SwitchCase( 0, out(OK), 1, out(OK) ) ) returns false ( it's a bug because the case has not been considered )



- - Funct

Funct(xxxx) where xxxx is the number of the function to call
or xxxx = Var(yyyy) where yyyy is a variable that contains the function number to call


- - Comparison

Compares with the last value un the call stack

Equal(xxxx), EEqual(FALSE),EEQUAL(NULL) // does a type check ( === in php ) Greater(xxxx), Lower(xxxx), LowerEqual(xxxx) GreaterEqual(xxxx) IsVoid() IsNotVoid() IsNumeric() where xxxx is a constant or xxxx = Var(yyyy)
with yyyy = variable name

Example: Tac( SetVar(src,Cst('this is a . bug ;')), // SetVar(src,Cst('$temp="This correct";')), PhpTest(retour,src), Var(retour), Test( Cond(EEqual(FALSE)), IfTrue( out(KO), ReturnFalse() ), IfFalse( out(<br /><br />OK) ) ) )


- Files


- - a0_File

Opens and close a file after treatment. The syntax is:

a0_File( 
 FileName(xxxx),
 FilePtr(yyyy),
 Action(z),
 Do(ffff())
)

where:
xxxx is a variable in the variable stack which contains the name of the function.
yyyy is a variable name which is created in the variable stack which will contain the name of the pointer to the file. This variable can be used in the ffff() function.
z : equals a ( append ) or w ( write ).
ffff : is a function name to call.

You don't have to close the file, it is called when the function is finished.
Example:


Setvar(MyFileName,VarG(xxPtaW),Cst(hello.htm)), // Fills the variable MyFileName with
                                                          // the the file name
SetVar(MyFileContent,Cst('<body>Hello, world</body>')), // Fills the File content
a0_File(
 FileName(MyFileName),
 FilePtr(MyFilePointer),
 Action(w),                                            // the file is [re]created
 Do(
  a0_WriteVarStackInFile(MyFileContent,MyFilePointer)  // file is written
 )
) // file is closed here




- - a0_WriteInFile

Writes the content of a variable in the variable stack into a file.
Example:

SetVar(FileName,Cst('helloworld.htm')), SetVar(FileContent,Cst('hello, world')), a0_File( FileName(FileName), FilePtr(fp), Action(w), Do( a0_a0_WriteInFile(FileContent,fp) ) ) this writes a file "helloworld.htm" containing the string "hello world".


- - a0_WriteInSourceFile

Writes the content of a variable in the variable stack into a file adding a Begin Php Tag at the begining of the file and a End Php Tag at the end of the file.
Example:

SetVar(FileName,Cst('helloworld.php')), SetVar(FileContent,Cst(' echo "hello, world\\n" ;')), a0_File( FileName(FileName), FilePtr(fp), Action(w), Do( a0_WriteInSourceFile(FileContent,fp) ) ),


- - a0_ReadFileInVarStack

Read the content of a file and put it in VarStack. The syntax is:

a0_ReadFileInVarStack( xxxx, yyyy ) where
xxxx is the variable name which will contain the content of the file
yyyy is the variable name which contains the name of the file pointer
Example: To copy a file a into a file b, use this a0_File( FileName(SourceFile), // complete path FilePtr(sfp), Action(r), Do( SetVar(FileContent,Cst()), a0_ReadFileInVarStack(FileContent,sfp), a0_File( FileName(TargetFile), // complete path FilePtr(tfp), Action(w), Do( a0_WriteVarStackInFile(FileContent,tfp), ) ) ) )


- - a0_WriteInBinaryFile

Writes a file content as binary data, useful for copying images.
example: Copy the content of img directory which contains images

SetVar(FilePath,VarG(xxPaWr),VarG(xxDatB),Cst(/../img/)), SetVar(FileName,Cst(^.*$)), Tac( Var(FilePath), Var(FileName), a0_DirList( SetVar(FileName,3), SetVar(FileSize,2), SetVar(FileTime,1), SetVar(SourceFileContent,Cst()), SetVar(SourceFile,VarG(xxPaWr),VarG(xxDatB),Cst(/../img/),Var(FileName)), SetVar(TargetFile,VarG(xxPtaW),Cst(../img/),Var(FileName)), a0_File( FileName(SourceFile), FilePtr(SourceFp), Action(rb), Do( a0_ReadFileInVarStack(SourceFileContent,SourceFp), a0_File( FileName(TargetFile), FilePtr(TargetFp), Action(wb), Do( a0_WriteInBinaryFile(SourceFileContent,TargetFp) ) ) ) ) ) )


- - a0_Directory

Creates or delete a directory, the syntax is:

a0_Directory(x,path) Where x = c ( create ) or d ( delete ).
and path is the variable containing the path of the directory
When the directory is deleted, all the files included are deleted but not the sub dir.

Example Tac( SetVar(TargetBackup,VarG(xxPtaB),LowerCase(SystemDbToBackUp)), a0_Directory(c,TargetBackup), )


- - a0_DeleteFile

deletes a file.
The syntax is:

a0_DeleteFile(xxxx) Where xxxx = Var(yyyy), yyyy is a variable contaning the name of the file to delete or xxxx = the name of the file


- - a0_DirList

Puts in the call stack a list of files in a directory according to a file name ( ereg function )
Example: to list the skin files, the function used in MyPitSelf is:

SetVar(FilePath,Cst()), // The path is void ( current path ) SetVar(FileName,Cst(^styles.*\php$)), // file name looks like styles_*.php Tac( Var(FilePath), Var(FileName), SetVar(CurrentSkin,Display(1000063),VarG(xxUserSkin),Cst(<br />)), Ech(Var(CurrentSkin)), // the current skin is: a0_DirList( SetVar(FileName,3), SetVar(FileSize,2), SetVar(FileTime,1), SetVar(Button,Funct(239)), Tac( Var(FileName), Cst(1), Cst(OPTION), // CLASS of the button Cst(.), // Image Var(FileName), // TITLE (Tool tip of the button) Var(FileName), // text displayed on the button Var(Button), // Function number to call Funct(1001), SetVar(Button1,1,Cst(<br /><br />)), // Put the html code in a variable to display it ), Ech(Var(Button1)) // displays the button ) )


- - a0_DirDirList

List directories of a directory.
Example: The .css files are created in the MyPitSelf environment. After their creation, they must be copied in the other programs so this function is used:

Tac( SetVar(DirPath,VarG(xxPaWr)), SetVar(Patern,Cst('^.*$')), Var(DirPath), Var(Patern), a0_DirDirList( SetVar(DirName,2), SetVar(DirTime,1), Tac( Var(DirName), Test( Cond(Equal(VarG(xxVers))), IfFalse( Tac( SetVar(FromDir,VarG(xxPaWd),Cst('img/')), SetVar(ToDir,VarG(xxPaWr),Var(DirName),Cst('/img/')), SetVar(FileName,Cst('^a0_styles_[0-9]*\\..*s$')), // .js or .css Cst(0), // silent does not echo the copy if 1 Var(FromDir), Var(ToDir), Var(FileName), a0_CopyFileDir(), ) ) ) ) ) )


- - a0_CopyFileDir

Copy file matching a given pattern from a directory to an other one.
Example: The .css files are created in the MyPitSelf environment. After their creation, they must be copied in the other programs so this function is used:

Tac( SetVar(DirPath,VarG(xxPaWr)), SetVar(Patern,Cst('^'),VarG(xxVers),Cst('.*$')), Var(DirPath), Var(Patern), a0_DirDirList( SetVar(DirName,2), SetVar(DirTime,1), Tac( Var(DirName), Test( Cond(Equal(VarG(xxVers))), IfFalse( Tac( SetVar(FromDir,VarG(xxPaWd),Cst('img/')), SetVar(ToDir,VarG(xxPaWr),Var(DirName),Cst('/img/')), SetVar(FileName,Var(ToDir),Cst('mps_style_*.*')), a0_DeleteFile(Var(FileName)), SetVar(silent,Cst(0)), // silent does not echo the copy if 1 SetVar(FileName,Cst('^mps_style_.*s$')), // .js or .css a0_CopyFileDir(FileName,FromDir,ToDir,silent), // ..... etc ) ) ) ) ) )


- - FileExist

Check if a file exist, must be put in a test

SetVar(FileName,Cst('file/'),Var(T0name),Cst('.png')), Var(FileName), Test( Cond(FileExist()), IfTrue( Tac( ) ), IfFalse( Tac( ) ) ),


- Interactive functions


- - a0_list

Displays a list of values obtained from an SQL request.
The syntax is

a0_list( Sql(xxxx), [ShowVar(zzzz),] [FieldToUpdate(iiii),FieldToSee(jjjj),] [Header(Funct(kkkk)),Line(Funct(llll)),] [NoCounter(),] [Hidden(Var(mmmm)),] [Range(Var(nnnn))] ) where xxxx is the number of the sql request. It must be a SELECT LIST type.

zzzz is a variable which contains a string to display

a0_list is also used when there is a value to fetch in an other table ( see the XREF functions ). In that case iiii is the name of the field to fetch ( generally, T0.ID )
jjjj is the name of the field to see ( generally T0.Name )

kkkk is the number of a MyPitSelf function called to output the line header of the table
llll is the number of a MyPitSelf function called to output each line
nnnn is the number of a MyPitSelf function before displaying the list
oooo is the number of a MyPitSelf function after displaying the list
nnnn is the first line to display

Important point begin:
A request for a list has generally some input criterias. The todo request for example is SELECT T0.Code,T0.Priority,T0.Name,T0.TimeStampCreate,T0.TimeStampUpdate FROM $xxDatB.yTodo T0 WHERE T0.User = %SQLPAR0% and T0.Priority >= %SQLPAR1% and ucase( T0.Name ) LIKE ucase( '%yDoc%' ) and T0.Code <= %SQLPAR3% ORDER BY T0.Priority ASC , T0.Code DESC LIMIT 30 The values %SQLPARn% are the input criterias for the todo list. These values must be put in the call stack before the call to a0_list and you must add the number of parameters of the request as the last value in the call stack.

Example: for the request 1001, the use of this function is: Tac( Var(xxUserCode), // parameter 1: user code ( %SQLPAR0% ) Cst(0), // parameter 2: priority ( %SQLPAR1% ) Cst(), // parameter 3: content of the todo ( yDoc ) Cst(999999999999999999), // parameter 4: code of the todo ( %SQLPAR3% ) Cst(4), // There are 4 parameters. a0_list( Sql(101) ) ) Important point end:

Some properties for a request list type can be added, they are:
SELECT DISTINCT add a "DISTINCT" in front of the select
LIST LIMIT Fixees the number of record to be output
Line height Line height in pixel of the list
Cell padding Cell padding in pixelx of the values in the list
OPTION COLUMN WIDTH width of the column that contains the option buttons
Do not put the list in a table Normally, a list is put in a table, setting this flag to 1 prevents it.
GoTo buttons in a list Add one more access buttons in a list
Line function Reference of the line function to use to display the data
Header function
NoMenu
Before list function
After list function
SetVar(ToDisplay,VarG(xxxHeader)), Tac( Var(ToDisplay), Cst(<), CutWithoutLastCharEqual(), // take off </td> SetVar(ToDisplay,1,Cst(<td>Stack</td></tr>)), Ech1(Var(ToDisplay)) ) An example of a Line function is Tac( // Line function of list of 1453 SetVar(Option,VarG(xxxOptionLine)), SetVar(Button,Funct(5574)), VarG(T0Code), Cst(1), Cst(.), // CLASS Cst(u.gif), Display(2000215), Display(2000214), // text displayed on the button Var(Button), Funct(1001), SetVar(Option,Var(Option),1), SetVar(ToDisplay,VarG(xxxStartLine),Var(Option),Cst(</td>),VarG(xxxValueLine),Cst(</tr>)), Ech1(Var(ToDisplay)) ),

NoCounter() : The and buttons to see the next records and the counter (xxx->yyyy)/zzz on the top of the list are not displayed

Hidden(Var(mmmm)) : A variable is put in the Variable stack with the name xxx



- - a0_Screen


Display a record on the screen for Create, View, Update or duplicate.
The syntax is

a0_Screen( Mode(xxxx), Sql(yyyy), [ShowVar(zzzz),] [After(Funct(iiii))|ScreenAfter(Funct(iiii),] [Replace(T0.jjjj,Var(kkkk)),] [NoLock(),] [NoLog(),] [Under(Funct(llll))] ) where
xxxx = Create or View or Update or Duplicate: Action to do with the record
yyyy = the sql number to use
zzzz = name of the variable containing a string to display
iiii = Function number to call after an Update, a Duplicate or a Create.
The difference between After() and ScreenAfter is the type of the function iiii.
The ScreenAfter function usually ask some data .
Example:
When the super user creates a new user, the next screen that comes after the "CREATE" button is the one that ask the user password which is function # 4021, so it gives: a0_Screen( Mode(Create), Sql(1014), ScreenAfter(Funct(4021)) )
jjjj,kkkk if some fields are hidden in the Sql request, this lets you fill the field with a value.
NoLock(): Usually, an update must lock the record so that someone else can't modify it. But in certain cases, the lock is not wanted.
NoLog(): Usually, a View option is logged in the system so that when you click on the Back button, you can see the screen again. But, in certain cases, the loggin must not be done so you can use this verb.
Under(Funct(llll)): where llll is a function number: If the Mode() type is update or View, llll represents a function that is called after displaying the screen. This last function receives as a parameter the ID of the record being displayed.

The values of the parameters must be pushed in the call stack before this call.


Example: the request (1002) to get a todo record by Code is: SELECT T0.Code,T0.Priority,T0.Name FROM $xxDatB.yTodo T0 WHERE T0.Code = %SQLPAR0% Note that the T0.Code, the auto incremented field is hidden ( go to the Request menu for select 1002, click on the Fields button, and View the T0.Code Field ).
So the creation of a todo record looks like: a0_Screen( Mode(Create), Sql(1002) )
The update of a todo record looks like: Tac( Field(T0.Code), // first and only parameter of the request a0_Screen( Mode(Update), Sql(1002), NoLock() ) )
Note: If a function is attached to the main table of the request then this function is called before the Update/create/Duplicate of the record.

The fields in these functions are available as VarG ( global variables ) and are referenced as TnFieldName WITHOUT a . between Tn and FiendName.
This comes because it's the value from the screen which is tested and not the value from the table.

See the TABLETEST functions for more examples.


- - a0_AskData

Interactive input ask to the user
Syntax:

a0_AskData( [Display(xxxx),] LaunchButton(Display(ZZZZZZ)), Par(yyyy,zzzz,Default(Var(kkkk)),OnUpdate(Funct(1234)),[,,,] [LaunchButton(llll),|NoLaunchButton()] Tac( SetVar(Value0,Input(0)),[,,,] ffff() ) ) where
xxxx: can be a number and it displays the message number xxxx or Var(VariableName) ant it displays the content of the variable VariableName

llll = Display(iiiii) or Var(eeeee) to display a different text on the launch button than "GO"

yyyy: a string and if equals to Display(nnnn) it displays the message number nnnn

zzzz: either Data(iiii) where iiii is a number of a data in the Data menu
or a function to get the value from a table like Tac( Cst(i),[,,,] Cst(j), a0_list( Sql(llll), FieldToUpdate(T0.FieldToUpdate), FieldToSee(T0.FieldToSee) ) ) (see the a0_list function for the syntax )

kkkkk is the name of a variable for an initial value

To get the parameters entered, use the syntax: SetVar(Par0,Input(0)), SetVar(Par1,Input(1)), .... See below for an example.

This command can also be used to upload a file. In this case, 5 parameters are filled.
Example: SetVar(idRoot,1), a0_AskData( Display(2000409), Par( Display(2000320), Upload() ), Tac( SetVar(FileName,Input(0)), SetVar(FileType,Input(1)), SetVar(FileTmp,Input(2)), SetVar(FileSize,Input(3)), SetVar(FileErr,Input(4)), Var(FileErr), Test( Cond(Equal(0)), // no error IfTrue( Tac( Var(FileSize), Test( Cond(Lower(5000000)), IfTrue( // do stuff ), IfFalse( out(file greater than 5000000) ) ) ) ) ) ) ) a big example I use for my own tests is: SetVar(MonTest,Cst('<b>hello, world</b>')), SetVar(hidd,Cst(1)), SetVar(show,Cst(0)), SetVar(MyDataType,Cst(14)), a0_AskData( Display(2000276), LaunchButton(Display(2000340)), Par(Display(2000292),Data(Var(MyDataType)),Default(Cst(9999-12-31)),Hide(Var(show))), Par(Display(2000292),Data(21),Default(Cst(12:00:00)),Hide(Var(hidd))), Par( Display(2000292), Tac( Cst(),Cst(INTEGER),Cst(0),Cst(9999-12-31),Cst(23:59:59), VarG(xxDefValDateTime),Cst(9999999), Cst(7), a0_list( Sql(1526), FieldToUpdate(T0.ID), FieldToSee(T0.Text) Data(22) ) ), Default(Cst(0)), Hidden(Var(show)), ), Par(Display(2000292),Data(25),Default(Var(MonTest))), // html type Par(Display(2000292),Data(27),Default(VarG(xxDefValTimeStamp))), Par(Display(2000292),Data(9), Default(VarG(xxDefValDateTime))), Par(Display(2000292),Data(2), Default(Cst(1))), Par(Display(2000292),Data(26),Default(Cst(1235.02003))), Par(Display(2000292),Data(20),Default(Cst(1235.02))), Par(Display(2000292),Data(1002)), Par(Display(2000292),Data(1015)), Tac( out(liste des valeurs egal), out(11), out(10), out(9), out(8), out(7), out(6), out(5), out(4), out(3), out(2), out(1) ) ) Tac( Var(xxxShowForm), Test( Cond(Equal(1)), IfTrue( Tac( // if form display ) ) ) )


- - out, Display, Ech

out(n) // outputs the n'iest last value in the call stack ( for debug purposes )
out(bla bla) // outputs bla bla
out() // outputs a line break
ShowMsg(n) // outputs the message number n.
Ech(Var(MyVar)) // outputs the string contained in MyVar in span LISTTITLE attribute.
Ech1(Var(MyVar)) // outputs the string contained in MyVar without any HTML attribute.
Example, let's suppose that msg # 1000011 contains "hello, world"

Tac( Cst(Hello), Cst(world), out(2), // outputs Hello out(1), // outputs world out(hello world) // outputs hello world ShowMsg(1000011) // outputs Hello SetVar(TheMessage,Display(1000011)), Ech(Var(TheMessage)), // outputs Hello, world )


- - nap

Delays the execution of the outputs of n seconds.
Syntax:

Tac( Cst(Wait for 2 seconds please), // message displayed out(1), Nap(2) // 2 seconds )


- - Back, Home


Back(n) // Return to the n'iest previous screen.
Home() // go to the Home screen



- - Menu

Displays the menu
For the Example: to display the documentation chapters in MyPitSelf, the function starts with

Tac( menu(), LogTheCall(), SetVar(NbTotChap,Cst(0)) R_1798_Select( Do( Take(T0.Code), AddVar(NbTotChap,Cst(1)) ) ), .... ) This function is usually used with the LogTheCall() function


- - LogTheCall

Usually, the back button only displays the list functions.
But sometimes the menus call functions that are not lists, so if you wish to use the backs button in this case, use this function.
Example: to display the documentation chapters in MyPitSelf, the function 6770 starts with

Tac( menu(), LogTheCall(), SetVar(NbTotChap,Cst(0)) R_1798_Select( Do( Take(T0.Code), AddVar(NbTotChap,Cst(1)) ) ), .... ) This function is usually used with the menu() function


- Strings


- - String conversion

As we use HTML, PHP, JavaScript containing HTML or Javascript containing Alert() function, many cases are possible because the string delimiter, the carriage return, the ditable fields can contain many cases.
Keep in mind that the string delimiter in MyPitSelf is '.
The ' can be put in a string using \'.
The \ can be put in a string using \\.



- - - ToHTML

Converts the content of a variable to htlm characters

Tac( SetVar(MyVar,Cst('<br />hello')), SetVar(MyHtm,ToHTML(MyVar)), // contains & lt ; br & gt ; hello )


- - - ToJsAlert

Converts a string to a string that can be the content of a javaScript alert message.
The line feed (lf) is converted to the \n
The carriage return ( cr ) is converted to nothing
the \ is converted to \\
the ' is converted to \'

R_1585_Select( Do( Take(T0.Value), SetVar(Val,1), SetVar(JsFileContent,Cst(' Alert(\''),ToJsAlert(Val),Cst('\');\n')) ) )


- - - ToJsHtml

Converts a string to a string that can be the content of a javaScript variable.
The line feed (lf) is converted to the BR tag
The carriage return (cr) is converted to nothing
the \ is converted to \\
the ' is converted to \'

R_1585_Select( Do( Take(T0.Value), SetVar(Val,1), SetVar(JsFileContent,Cst(' var MyJsVariable=\''),ToJsHTML(Val),Cst('\';\n')) ) )


- - - ToHtmlEdit

Converts a string to an html edit
the carriage return is converted to nothing,
the line feed (lf) is converted to & # 10 ;,
the ' is converted to & # 39 ;,
the \ is converted to & # 92 ;,

Tac( SetVar(T0Value,ToHtmlEdit(T0Value)) )


- - - ToQuotes

Converts a string with
\ is converted to \\,
' is converted to \',

Tac( SetVar(T0Value,ToQuotes(T0Value)) )


- - - FunctionEntities

Converts a string to a Constant.
Example: in the Tool menu, the function that converts a string is:

Menu(), //Convert to function a0_AskData( Par(Display(2000121),Data(6)), Tac( SetVar(Original,Input(0)), SetVar(Original,FunctionEntities(Original)), SetVar(out,Cst('<pre>Cst(\''),Var(Original),Cst('\')</pre>')), Ech1(Var(out)), ) ) So if in input there is ( there is a line feed at the end )

hello, 'world', with " and ( and '
in output we have this

Cst('hello, \'world\', with " and ( and \' \n')


- - Match


Does an ereg() on the last value in call stack
Syntax:
Match(xxxx)
where xxxx is the ereg string
For example, to test that a new password is correct, MyPitSelf uses the function

SetVar(NewPassword,2), SetVar(NewPasswordConfirm,1), Test( // is the new password = confirmation ( passwords have to be entered twice ) Cond(Equal(Var(NewPassword))), IfFalse(ShowMsg(1000009),ReturnFalse()) ), Test( Cond(Match('^([a-zA-Z0-9]{6,32})$')) // contains only alpha IfFalse( ShowMsg(1000010),ReturnFalse() ) )


- - CutWithLastChar


CutWithLastChar(MyVar,Var(Value),Cst(',')),
Cut the value from the last position+1 founded of the third parameter ( Cst(',') here ) in value to the end and puts the result in MyVar.
Example

Tac( SetVar(DataValueList,Cst('a, b , c , bla bla ')), CutWithLastChar(DataValueList,Var(DataValueList),Cst(',')), Ech1(Var(DataValueList)) // outputs "a, b , c ," )


- - CutWithoutLastChar


CutWithoutLastChar(MyVar,Var(Value),Cst(',')),
Cut the value from the last position founded of the third parameter ( Cst(',') here ) in value to the end and puts the result in MyVar.
Example

Tac( SetVar(DataValueList,Cst('a, b , c , bla bla ')), CutWithoutLastChar(DataValueList,Var(DataValueList),Cst(',')), Ech1(Var(DataValueList)) // outputs "a, b , c " )


- - CutString

Cut the value in call stack from a position ( starts with 0 ) for a length
Example

Tac( SetVar(FieldList,Cst(,toto,tata,titi)) SetVar(FieldList,CutString(FieldList,1,1000)), // now contains toto,tata,titi SetVar(FieldList,Cst(toto,tata,titi,)) SetVar(FieldList,CutString(FieldList,0,-1)), // now contains toto,tata,titi ) or SetVar(x,VarG(xxPaWr)), SetVar(x,Len(x)), SetVar(Path,VarG(xxPtaI)), SetVar(Path,Cst('../'),CutString(Path,Var(x),1000)),


- - Lower or upper case

Example:

Tac( //==================== LowerCase ============ SetVar(str,Cst(HeLLo)), SetVar(str,LowerCase(str)) // contains hello // or SetVar(str,Cst(HeLLo)), Var(str), SetVar(str,LowerCase(1)) // contains hello // or SetVar(str,LowerCase(VarG(xxxVarGvalue))) //==================== UpperCase ============ SetVar(str,Cst(HeLLo)), SetVar(str,UpperCase(str)) // contains HELLO // or SetVar(str,Cst(HeLLo)), Var(str), SetVar(str,UpperCase(1)) // contains HELLO // or SetVar(str,UpperCase(VarG(xxxVarGvalue))) )


- - ReplaceString

ReplaceString: replace a string with an other in a string
Example:

Tac( Cst(:), Chr(32), Var(FileName), ReplaceString(), // replace ":" with " " in last value in stack SetVar(FileName,1) )


- - RepPreg

RepPreg: replace a string with an other in a string using the preg specification
Example:

Tac( SetVar(Content,Cst('MyFunct(hello)')), SetVar(Replace,Cst('/MyFunct\\((\\w*)\\)/')), SetVar(With,Cst('<A HREF="javascript:popup(\'\\\\1\')"><img src=../img/sc.gif border=0></a>')), RepPreg(Replace,With,Content), )


- - StringIsInString

Return true if a string is found in an other string
Example:

Tac( SetVar(ToSearch,Cst('-'),Var(Parent),Cst('-')), Var(ToSearch), Var(DocList), Test( Cond(StringIsInString()), IfTrue(   // do the job )  ) )


- - strpos, strrpos

Returns the position of a string in an other string, strrpos starts the research from the end of the string

SetVar(ToSearch,Cst('/')), Var(ToSearch), Var(T0NewValue), Test( Cond(StringIsInString()), IfTrue( SetVar(pos,strpos(T0NewValue,ToSearch)) // pos contains the position of the string to search. ) )


- - ToArray

Tac( // ElementName contains '123-456 ToArray(RuleType,ElementName,Cst(-)), // RuleType contains now Array('123','456') )


- - Len

Returns the lenght of the string
Example: To show the database schema:

SetVar(x,VarG(xxPaWr)), SetVar(x,Len(x)), SetVar(Path,VarG(xxPtaI)), SetVar(Path,Cst('../'),CutString(Path,Var(x),1000)),


- - H2D

Converts an hexadecimal string to a decimal string

Tac( SetVar(MyVar,Cst('FF')), SetVar(MyVar,H2D(MyVar)), // Now, MyVar is 255 )


- - BranchHeader()

Creates a head string for the trees.

Tac( SetVar(Level,Cst(5)), // level can be 0 SetVar(out,BranchHeader(Level)) Ech1(Var()), outputs '<tr class=""><td><img width={level}"> ' }


- Html

Some various JS/Html functions.



- - span

Content for doc chapter span



- - - span

Puts a value in a span

Tac( SetVar(ToSearch,Cst('-'),Var(DocDisp),Cst('-')), Var(ToSearch), Var(DocHiLight), Test( Cond(StringIsInString()), IfTrue( SetVar(Name,span(ECHO,Name)) // $Name='<span class="ECHO">'.$Name.'</span>'; ) ), ) or declare a span with an ID SetVar(Name,SpanId(MYSPAN,ECHO)) // $Name='<span id="MYSPAN" class="ECHO"></span>'; or declare a span with an ID as variable with or without a class SetVar(Ms,Cst('createFields_'),Var(TableCode)), SetVar(out,SpanVar(Ms),Var(BAll),SpanEnd()), // $Out='<span id="'.$Ms.'">'; or SetVar(out,SpanVar(Ms,ZZHID),Var(BAll),SpanEnd()), // $Out='<span id="'.$Ms.'" class="ZZHID">'; or declare a span with an ID and a style SpanStyle(SvgC,display:inline;), // $Out='<span id="SvgC" style="display:inline;">'; or declare a span with a class SpanClass(ECHO), // $Out='<span class="ECHO">'; or declare a span START with an ID SetVar(Name,SpanIdSt(MYSPAN,ECHO)) // $Name='<span id="MYSPAN" class="ECHO">'; // or SetVar(Name,SpanIdSt(MYSPAN)) // $Name='<span id="MYSPAN">'; or declare a span End SetVar(Name,SpanEnd()) // $Name='</span>';


- - - HiddenSpan

Put the content of stack in a hidden span.
Setvar(aVariable,HiddenSpan(SPANNAME,i)),
i is the stack position of the element to put in the span
example:

Tac( SetVar(Button,Funct(6202)), Cst(0), Cst(.), Cst(p.gif), Display(2000079), Display(2000079), Var(Button), Funct(1001), SetVar(Button,HiddenSpan(BOT1,1)), Ech1(Var(Button)), CopySpan(BOT1,AFTERFUNCTIONLIST), // or AFTERLISTTITLE for example )


- - - CopySpan

Copy the content of a span to an other.

Tac( SetVar(Button,Cst('<span id="BOT1" style="display:none">'),1,Cst('</span>')), Ech1(Var(Button)), CopySpan(BOT1,AFTERLISTTITLE), ) Or Tac( SetVar(Spa01,Cst(BOT1)), SetVar(Spa02,Cst(AFTERLISTTITLE)), SetVar(Button,Cst('<span id="BOT1" style="display:none">'),1,Cst('</span>')), Ech1(Var(Button)), CopySpan(Var(Spa01),Var(Spa02)), // copy Spa01 in Spa02 )


- - - ClearSpan

Puts nothing in a span

ClearSpan(MYSPAN), //document.getElementById("MYSPAN").innerHTML="";


- - - HideSpan

Hide the content of a span

Tac( SetVar(SpNa,Cst('SPLO'),Var(Id)), HideSpan(SpNa), // echo '<script>document.getElementById("'.$SpNa.'").style.display="none";</script>'; HideParentSpan(SpNa), // echo '<script>this.parent.document.getElementById("'.$SpNa.'").style.display="none";</script>'; )


- - div

DIVSTYLE



- - - div

Declare a div with an ID and a style

DivStyle(SvgC,display:inline;), // $Out='<div id="SvgC" style="display:inline;">';

or declare a div End SetVar(Name,DivEnd()) // $Name='</div>';


- - table

Content for doc chapter table



- - - table0

use as : SetVar(temp,table0()), Ech1(var(temp)), equivalent to

<table border="0" cellpadding="0" cellspacing="0" summary="">



- - - table1

use as : SetVar(temp,table0()), Ech1(var(temp)), equivalent to

<table border="0" cellpadding="0" cellspacing="0" summary="" align="left">



- - - tr0

use as : SetVar(temp,tr0()), Ech1(var(temp)), equivalent to

<tr>



- - - td0

use as : SetVar(temp,td0()), Ech1(var(temp)), equivalent to

<td>



- - - tdnowrap0

use as : SetVar(temp,tdnowrap0()), Ech1(var(temp)), equivalent to

<td class="nowrap0">



- JsTree

This set of function does a tree management

They may seem a little complex but in fact they are generated by a set of functions that takes a table that is self-referenced.

See the use of this tree generation in the How To's



- - JsTreeInit

This function initialises a tree:
The tipical use of this function is:

Tac( SetVar(out,Cst('<table><tr><td class="RECORD">')), Ech(Var(out)), // the tree is embeded into a table JsTreeInit(d1,treeCurr,treeInit,Funct(0001),Funct(0002)), // d1 is the javascript tree object // funct 0001 is the function to activate a branch // treeCurr is the reference to the current displayed Id // treeInit is the reference to the root id of the tree // funct 0002 is the function to manage the fold/unfold + and - buttons //========= <branches Cst(d1), // name of the JsTree object Var(treeInit), Var(treeInit), Var(treeCurr), Var(treeList), Cst(0), Funct(0003) // function to display a branch //========= branches> JsTreeOutput(d1,treeList), // outputs the tree SetVar(out,Cst('</td></tr></table>')), Ech(Var(out)), )
An other function is used for the root of a function that manages the possibility to move the branches of a tree. Tac( JsTreeInitMove(treeTree,treeCurr,treeInit,Funct(0004),treeToMove), )


- - Branches

There are two functions:
- One for the root
- One for the branches

These functions output a tree branch
A typical use of them is:

Tac( Var(treeDisp), Test( Cond(Equal(Var(treeInit))), IfTrue( JsTreeRoot(TreeRef,treeDisp,Name,HasChild) ), IfFalse( JsTreeElement(TreeRef,treeDisp,Name,HasChild,Parent) ) ) )


- - Buttons

This function is used to add buttons to the current selected branches
A typical use of this function is:

JsTreeAdd(TreeRef,treeDisp,BEdit,BAjsBr,BAjApr,BDepla,BSupp), // BEdit,BAjsBr,BAjApr,BDepla,BSupp are the buttons to display


- javascripts

Content for doc chapter javascripts



- - Update Parent Field

Updates the "field" in the parent window with a NUMERICAL value

Arg(field), Arg(Value), Tac( JsUpdateParentFieldNumber(field,Value), ) Equivalent to <script type="text/javascript"> this.parent.document.getElementById(\''.$field.'\').value=numberToFormat(\''.$Value.'\'); </script> Updates the "field" in the parent window with a TEXT value Arg(field), Arg(Value), Tac( JsUpdateParentFieldTEXT(field,Value), ) Equivalent to <script type="text/javascript"> this.parent.document.getElementById(\''.$field. '\').value = \''.str_replace( '\'' , '\\\'' , str_replace( '\\' , '\\\\',$Valeur ) ) . '\'; </script>


- SQL functions

Every sql request with a type = SELECT or INSERT or UPDATE or DELETE or DELETE VALUE you create will produce a function.
This function can be used in the language to do the work


The FIRST EXAMPLE section of this documentation give some examples of the use of this button.
When you use this button, all the informations about the request are put in tables so the request can be regenerated and can be analysed according to it's type and thus, it's use.

The request generated with this button are simple. No LEFT/RIGHT JOIN are possible yet.
You can add some little enhancements by using the "Complementary field" or the "And more" fields.

If you need a very complex request, you can create one, then change its type to MANUAL and then write what you want.
Be careful in that case to respect the good number of parameters in the request specification.



- - SELECT


a select request that looks like this:
Select T0.FIELD1 , T0.FIELD2,,,T0.FIELDn From MyTable T0
Produces a function named R_nnnn_Select() where nnnn is the request number.

The use of this function is

R_nnn_Select( Do( Take(T0.FIELDi,T0.FIELDj,,,), // value of the fields are pushed in the call stack ffff() // function[s] is[are] called ) // values of the fields are poped ) The field order given in the request can be anything.
The instructions in the Do block are repeated for each value found in the select.




- - DELETE, DELETE VALUE

a DELETE request that looks like this:
DELETE From MyTable where FIELD = %SQLPAR0%
Produces a function named R_nnn_Delete() where nnn is the request number.

The use of this function is

Tac( Var(IndiceToDelete), R_nnn_Delete() ) The Call stack should contain the parameters of the Delete.


The DELETE VALUE type is reserved to delete records with the key = the unique ID of the Table.
Every table must contain a AUTO_INCREMENT field, other tables may refer to that field as a reference.
So an other function is produced: it is called R_nnn_CrossRef() and checks that no other table refer to the record which is deleted.
You can use this function independently but it is always called before a delete occurs.


The DELETE Type opposed to a DELETE VALUE is also delete BUT with no CrossRef check. Use it with care!



- - UPDATE


an UPDATE request that looks like this:
UPDATR MyTable set FIELD = %SQLPAR1% where record = %SQLPAR0%
Produces a function named R_nnn_Update() where nnn is the request number.

The use of this function is

Tac( Var(RecordToUpdate), Var(FieldToUpdate), R_nnn_Update() ) The Call stack should contain the parameters of the Update.



- - INSERT

An INSERT request that looks like this:
INSERT into MyTable set FIELD = %SQLPAR1%
Produces a function named R_nnnn_Insert() where nnnn is the request number.

The use of this function is

Tac( Var(ValueToInsert), R_nnnn_Insert(1) // or R_nnnn_Insert(0) if you do not // want to want to know the last_insert_id SetVar(NewId,Var(R_nnnn_IOne)), // if R_nnnn_Insert(1) ) The Call stack should contain the parameters of the Insert.

If the Insert is Correct and the parameter is 1, it puts into the variable Stack a variable named R_nnnn_IOne which contains the number of the Auto_Increment field of the new record.


- - MANUAL


an MANUAL request that looks like this:
SELECT count(*) as res from MyTable where FIELD = %SQLPAR0%
Produces a function named R_nnn_Manual() where nnn is the request number.

The use of this function is

Tac( Var(ValueToInsert), R_nnn_Manual(ffff()) ) The Call stack should contain the parameters of the request.

Be careful to give the good number of parameters in the definition of the Request


- - ExecuteSQL


Execute the SQL string contained in the Last value of the call stack



- Session and http variables

One can update session predefined variables ( SessionVar function)
or
define new session variables ( SessionValue functions )



- - SetSessionVar

SetSessionVar(xxx) Updates a session variable with the 2nd last value contained in the call stack.

Example: when the user logs in, he is in a group but if you want to give the possibility to a user to change his group dynamically to allow some functions according to the context, use this type of function: Tac( Var(NewGroupValue), SetSessionVar(xxUserGroup), Home() ) Now, the user will have the menus of the group number contained in the variable NewGroupValue



- - SessionValue

If you need a session variable, you can define one and update or get it's value using these functions.
Example: you can put in the loggin function (4003) this code.

Tac( CreateSessionValue(TheNewSessionValue), // define the session value, now, // xxxSessionTheNewSessionValue exists in the VarStack Var(TheValue), SetSessionValue(TheNewSessionValue) // puts TheValue in xxxSessionTheNewSessionValue ) Then, anywhere in the program, you can use the code: Tac( Cst(), // put a space in the call stack GetSessionValue(TheNewSessionValue), // puts the session value in the call stack ( replaces the space) SetVar(TheValue,1) // puts the value in a variable. )


- - HttpPostVar

Gets a POST variable
Example: This example is the source to get the user name when the user logs in

Tac( SetVar(UserLogginName,HttpPostVar(XXNAME)), SetVar(UserLogginPassword,HttpPostVar(XXPASS)), )


- - HttpGetVar

Gets a GET variable, Example:

Tac( SetVar(MyVar,HttpGetVar(GETNAME)), )


- - SetHttpPost

Sets a Post variable

Tac( VarG(xxAct), Test( Cond(NEqual(GO)), IfTrue( Tac( Cst(0), SetHttpPost(INPUT2), Cst(0), SetHttpPost(INPUT3) ) ) ) )


- - Server variables

Gets the $_SERVER variable
Example:

Tac( SetVar(where,Env('SERVER_SOFTWARE')), ) The values can be for example:
HTTP_REFERER
DOCUMENT_ROOT
PHP_SELF
SERVER_NAME
HTTP_USER_AGENT



- - IsSetSessionVar

Check that a session value exist. Example

Tac( Cst(xxxSessionTargetIsOutside), Test( Cond(IsSetSessionVar()), IfTrue( // do something ) ) )


- - IsSetPostVar

Check that a $_POST value exist.
example:

Tac( Cst(INPUT), Test( Cond(IsSetPostVar()), IfTrue( // do something ) ) )


- - IsSetGetVar

Check that a $_GET value exist.
example:

Tac( Cst(s), Test( Cond(IsSetGetVar()), IfTrue( // do something ) ) )


- Cookies


- - DefineCookie

This will create a cookie
DefineCookie(Cst(x)|Var(x),Cst(y)|Var(y)),



- - SetCookie

This will set a cookie:
SetCookie(Cst(x)|Var(x),Cst(y)|Var(y))



- - Get a cookie

There are 2 ways to gat a cookie:
First way: put it in the stack:

Tac( Cookie(Cst(MyCookieName)), // puts the cookie value of MyCookieName in the stack Test( Cond(Greater(Var(Total))), IfTrue( SetCookie(Cst(MyCookie),Cst(0)) ) ) ) Second way: put it in a variable Tac( SetVar(MyCookieValue,Cookie(Cst(MyCookieName))), Var(MyCookieValue), Test( Cond(Greater(Var(Total))), IfTrue( SetCookie(Cst(MyCookie),Cst(0)) ) ) )


- Date and time

These functions are set to work with date and time.
Note: I suggest that one creates a table with a calandar, fill it once every five or ten years and work on these values instead of going on computing always the same things.



- - now

Tac( SetVar(now,now()) // $now='2008-09-14 12:49:35'; )



- - Date

Convert a system format date (yyyy-mm-dd) to a date according to the system setup
Example:

Tac( // these functions use javascript to display the date SetVar(MyDate,Cst(2003-10-05)), SetVar(MyDate,DateUser(MyDate,0)), // Contains 05/10/03 if we are in france ( DMY format ) SetVar(MyDate,DateUser(MyDate,1)), // Contains Lu 05/10/03 if we are in france ( DMY format ) SetVar(MyDate,DateUser(MyDate,2)), // Contains Lundi 05/10/03 if we are in france ( DMY format ) SetVar(MyDate,DateUser(MyDate,3)), // Contains Lundi 05 Octobre 2003 // If you want to use php to convert the date, use DateServer instead of DateUser )


- - a0_AddOneDay:

Computes the day after the one in the call stack. The date must be in a system format (yyyy-mm-dd)
Example:

Tac( Cst(2003-12-31), a0_AddOneDay(), out(1) // outputs 2004-01-01 )


- - a0_DayOfWeek

Gives the day yhe week of the dates placed in the call stack:
0:sunday
1:monday
2:tuesday
3:wednesday
4:thursday
5:friday
6:saturday
Example:

Tac( Cst(2003-12-31), FormatDate(), out(1), UnformatDate(), out(1), a0_AddOneDay(), out(1), a0_DayOfWeek(), out(1), // outputs 4 )


- - SetTimeLimit


add n seconds to the execution of an interactive function. A SetTimeLimit(0) (no limit) is always called before a batch function.
Syntax
setTimeLimit(10) // adds 10 seconds to the php time limit, see the php doc for this.



- Reverse engineering

Functions for reverse engineering
you must include the function
a0_useRev_0()
before using them



- - Rev_SourceToArray

Converts a text function to an array

Tac( a0_useRev_0(), SetVar(TheSource, Cst('Tac(Cst(30),R_1203_Select(Do(Take(T0.Nom),out(1))))') ), Rev_SourceToArray(FunctionSource,tf), ) Now, tf is an array containing :
Ind Function
Number
Parent
Number
Order
in Parent
Function
Name
Function
Type
Number of
Children
Level C1 C2
0 0 -1 0 0 INIT 1 0
1 1 0 1 Tac formula 2 1
2 2 1 1 Cst formula 1 2
3 3 2 1 30 Value 0 3
4 4 1 2 R_1203_Select formula 1 2
5 5 4 1 Do formula 2 3
6 6 5 1 Take formula 1 4
7 7 6 1 T0.Nom zone 0 5
8 8 5 2 out formula 1 4
9 9 8 1 1 Value 0 5



- - Rev_ArrayToSource

Converts an array function to a source function

Tac( a0_useRev_0(), Rev_ArrayToSource(tf,FunctionSource), // now, Function source contains // Cst('Tac(Cst(30),R_1203_Select(Do(Take(T0.Nom),out(1)))) )


- - Rev_ArrayToTable

Load an array in the table yArrayFunct

Tac( a0_useRev_0(), Rev_SourceToArray(FunctionSource,tf), Rev_ArrayToTable(tf), // Load an array in the table yArrayFunct // Do big work on table yArrayFunct Rev_TableToArray(tf), Rev_ArrayToSource(tf,newSource), )


- - Rev_TableToArray

Load the content of table yArrayFunct to an array

Tac( a0_useRev_0(), Rev_SourceToArray(FunctionSource,tf), Rev_ArrayToTable(tf), // Do big work on table yArrayFunct Rev_TableToArray(tf), // Load the content of table yArrayFunct to an array Rev_ArrayToSource(tf,newSource), )


- - Rev_TakeOffFunct

Rev_TakeOffFunct() takes off functions in a source

Tac( Cst(a0_AskData), Cst(a0_list), Cst(a0_Screen), Cst(3), // function count to take off Rev_TakeOffFunct(FormuleFinale), )


- Predefined functions

These functions are considered as "system" functions.



- - Buttons

As  one has to create buttons quite often, some function do this



- - - A standard button

Two functions, 1001 and 1002, can be used to build a button that appear on the screen.
1001 builds a button without a javascript confirmation
1002 builds a button with a javascript confirmation

An example of the use of these functions is given above:

Tac( SetVar(Button,Funct(xxxx)), // put the function to call (xxxx) with this button in a variable Var(Value01), // argument 1 for the function xxxx Var(Value02), // argument 2 for the function xxxx Var(Value03), // argument 3 for the function xxxx Cst(3), // argument count Cst(.), // CLASS ( . = normal link ) Cst(.), // Image . if none or the name of the image in the /img directory Display(2000018), // TITLE (Tool tip of the button) Display(2000019), // text if no images Var(Button), // Function number to call Funct(1001), // or 1002 for confirm SetVar(Button,1), // Put the html code in a variable to display it Ech(Var(Button)) // displays the button ) The result is a button that executes the function Tac( Cst(1), // content of Var(Value01) Cst(2), // content of Var(Value02) Cst(3), // content of Var(Value03) Funct(xxxx) ) 1, 2 and 3 were contained in Valus01, Valus02, Valus03.


- - - Open an other window

Functions, 1003 builds a button that opens an other window.
An example of the use of this function is given above:

Tac( SetVar(BMajTitre,Funct(6783)), // function to call Var(DocDict), // argument one Cst(1), // 1 argument Cst(OPTION), // CLASS of the button Cst(u.gif), // Image Display(2000308), // TITLE (Tool tip of the button) Display(2000308), // text displayed if no image Cst(0), // x top Cst(0), // y left Cst(0), // x width Cst(0), // y height Var(BMajTitre), // funct number to call Funct(1003), SetVar(BMajTitre,1), // BMajTitre contains the code ), The result is a button that opens an other window and executes the function Tac( Cst(123456), // content of Var(DocDict) Funct(6783) )
Function 1004 does the same but the list parameters are saved before
Function 1016 does the same but the subwindow is hidden


- - - On the main window

This function is used when you want to submit the main window with a function.
As the main window is submitted, the sub window is closed.

Tac( SetVar(ToCall,Cst('Funct('),Funct(5001),Cst(')')), Var(ToCall), Funct(1009) )


- - Lock and unlock a record

To unlock manually a user record, you can use function 1006 with the paramaters:
TableCode
FieldCode



- - Update a innerHTML

Set the HTML content of an element with an ID (innerHTML) to a value.
example:

Tac( SetVar(SpanValue,Cst('hello')), SetVar(Sid,Cst('MySpanId')), Var(SpanValue), Var(Sid), Funct(1015) // updates the content of a span )


- Miscellaneous





- - CallFormulaInStack

Executes the function in stack and submit
Example: to create a new request, one choose a table to get the table code and then the program ac_yTable_CreateSelectRequest is called. To do this, we use

SetVar(Formula, Cst('Tac(Cst('), Var(TableCode), Cst('),ac_yTable_CreateSelectRequest())') ), Tac( Var(Formula), CallFormulaInStack() // The function is submited )


- - ExecuteFormulaInStack

Executes a function and continues the execution without submitting.
It is a kind of an "Eval" function.
Example, In the little CRM, in the sub window that contains a list of the other user that have a contact in their list, I want to keep track of the list filter the user enters ( criterias ). But as it is in "only" a sub window, I don't want to keep track of this in a session variable or any other method.
So in the first list I Build this string :

SetVar(Hidden, Cst('SetVar(IdContact,Cst('),Var(IdContact),Cst(')),'), Cst('SetVar(Critere,Cst(\'\'))'), ), And in the line function, I use Tac( VarG(xxHidd), ExecuteFormulaInStack(), SetVar(IdContact,VarG(IdContact)) )


- - TestFormula

Return true if the MyPitSelf function looks OK.
Example: when one creates or update a function source, the test which is done is:

Tac( VarG(T0Source), // See if the function is good first Test( Cond(TestFormula()), IfFalse(ReturnFalse()) ) )


- - PrintFormulaInStack


Print the formula in a table view



- - CryptValue


md5 of the last value in call stack



- - a0_Batch

Executes the function in a batch mode
Syntax:

Tac( a0_Batch(Funct(xxxx)[,Log(0|1)]), // or a0_Batch(a0_yyyy([a0_zzzz])[,Log(0|1)]) ) where xxxx is the function number to execute
yyyy is a core function
zzzz is a core librairy ( type a0_useXml ) containing yyyy

Log(0) doesn't outputs a log file that can be seen with the tool/see batch result

If the debug mode is on, Log is always set to 1 by a0_Batch
Default is Log(1)


- - IncludePhp

Example
IncludePhp(xxx)
xxx is a variable name



- - OutputBuffering

If wou want to save the html output in a variable
Example:

OutputBuffering( // start buffering Tac( // do the job Var(RFileContent), PhpEvalNoReturn(), // I want to save the result of this action OutputBufferingGetContents(), // I call this, the VarStack now contains the output SetVar(WFileContent,1) // and I save it in a variable a0_File( FileName(CSSFile), FilePtr(fpw), Action(w), Do( a0_WriteVarStackInFile(WFileContent,fpw) ) ) ) )


- - PhpTest

To be used after a compilation, tests if a php source is correct. Example:

Tac( PhpTest(ret,FileContent), Var(ret), Test( Cond(EEqual(FALSE)), // test this php function IfTrue( ShowMsg(2000252), ReturnFalse() ) ) )


- source examples


- - HTML to tidy Html

// replace in ySource html by tidy html a0_useHtml_0() Cst(0), R_1892_Select( Do( Take(T0.Code,T0.Type,T0.Name,T0.Source), SetVar(T0Code,4), SetVar(T0Type,3), SetVar(T0Name,2), SetVar(T0Source,1), Tac( Var(T0Code), Var(T0Type), Test( Cond(Equal(DOC)), IfTrue( Tac( SetVar(IsHt,Cst(0)) SetVar(ToSearch,Cst('.htm')), Var(ToSearch), Var(T0Name), Test(Cond(StringIsInString()),IfTrue(SetVar(IsHt,Cst(1)))) SetVar(ToSearch,Cst('.html')), Var(ToSearch), Var(T0Name), Test(Cond(StringIsInString()),IfTrue(SetVar(IsHt,Cst(1)))) Var(IsHt), Test( Cond(Equal(2)), // change this to 1 to do the job IfTrue( Tac( SetVar(T0Source,html_ToXhtml(T0Source)), SetVar(T0Source,html_getBodyContent(T0Source)), Var(T0Code), Var(T0Source), R_1698_Update() ) ), ), Var(T0Code), Test( Cond(Equal(12)), // do it for one source IfTrue( Tac( Var(T0Code), Var(T0Source), // R_1698_Update() Ech1(Var(T0Source)),out() ) ), ), ) ), ), ) ) ), // 1892


How to


- Define css

A screen copy of this
tool can be seen here.
As the css definition was a real nightmare, a tool to produce the css files is avaible in the menu Tools/Set up css.

The tool can be used only with firefox for the moment and produces css files, they are compatible also with IE.

See an example of the result with the Maquillage button


- Create trees

Suppose you have two table that looks like this ( The CRM example uses it ).

In this example, the table MyTree is seld-referenced so it is a tree.

Furthermore, the user table is using it for reference.

A function to generate the source for managing this tree can be used. See this .

The set of functions to manage this tree can bee seen here .

Then you can create the first record of the tree doing this:

Finally, you can use this tree. See the example here:

Now, we are going to generate the function so that when we create/update a user, we will be able to assign him/her a branch of a tree.

A function to generate the source for managing this can be used. See this .

The set of functions to manage this tree can bee seen here .

Then you have to update one of the functions generated to match the field name and tell the screen to update a user to use this function to fetch the tree reference like this : .

Finally, you can use this tree. See the example here:


- Reset the main user password

The md5 password of the user with login/password=1/1 is
6512bd43d9caa6e02c990b0a82652dca
So if you want to update it in the database, use this SQL request:.

update yUser SET Name='1', PassWord='6512bd43d9caa6e02c990b0a82652dca' WHERE Code=1


- Record the screens

I think the best way to make a documentation of a program is to give screen copies of the actions to do.

If you want to do this, use the menu "profile/Record the next actions for documentation".
When this mode is set, a screen copy of each screen will be output in an html file.

You can see the result of this in the example chapter.



- Produce the documentation

Perform the actions described here



- Know more

Go to http://en.wikipedia.org/ to know more about reverse engineering.



- Convert an access database

As I do not like ODBC, I prefered do this convertion program in VB and work directly in MySql
First, check that you have something like this in the visual basic project library list ( tools/references )

Then create a new module containing the code under and read carefully the first 10 lines of comments

Option Compare Database Option Explicit '==================================================================================== ' This VB procedure extract from an Access database to a mysql format : ' the table structure and puts it in a file named c:\temp\stru.sql, ' the table values and puts it in a file named c:\temp\data.sql, '================================== It can be easily modified to match your criterias '==================================================================================== '<<<<<<<<<<<<<<< UPDATE THIS FOR your local window setting >>>>>>>>>>>>>>>>>>>>>>>>>> Const Mydecimalseparator = "," ' france,italy,spain:"," , US,GB:"." , '==================================================================================== 'Create a directory name c:\temp\ 'Insert this in a vb module, place your cursor inside the extract function, and press ' the F5 key (run) on your keyboard ' If a case is not provided, the output contains an XX string so you can find ' problems looking for the "XX" string '==================================================================================== Type typfld nam As String typ As Integer End Type '==================================================================================== Sub Extract() Dim tdf As DAO.TableDef Dim fld As DAO.Field Dim i As Integer Dim j As Integer Dim typ As String Dim dba As Database Dim rst0 As Recordset Dim shea As String Dim sdat As String Dim ttypfld(0 To 499) As typfld Dim val As Variant Dim fou As Boolean Dim dattim As Date Dim auto As String Dim dbl As Double Open "c:\temp\stru.sql" For Output Access Write As #1 Open "c:\temp\data.sql" For Output Access Write As #2 For Each tdf In CurrentDb.TableDefs If Mid(tdf.Name, 1, 4) = "MSys" Then ' do not take MSACCESS system tables Else Print #1, "CREATE TABLE `" & MyNam(tdf.Name) & "` (" i = 0 auto = "" For Each fld In tdf.Fields ttypfld(i).nam = fld.Name ttypfld(i).typ = fld.Type typ = "" If fld.Type = 1 Then typ = "ENUM('0','1')" If fld.Type = 3 Then typ = "INTEGER" If fld.Type = 4 Then typ = "BIGINT" If fld.Type = 5 Then typ = "DECIMAL(17,2)" If fld.Type = 6 Then typ = "FLOAT" If fld.Type = 7 Then typ = "DOUBLE" If fld.Type = 8 Then typ = "datetime" If fld.Type = 10 Then typ = "varchar(" & fld.Size & ")" If fld.Type = 11 Then typ = "BLOB" If fld.Type = 12 Then typ = "TEXT" If typ = "" Then typ = "XX " & fld.Type & " XX" If fld.Required Then typ = typ & " NOT NULL" End If If fld.Attributes = 17 Then typ = typ & " AUTO_INCREMENT NOT NULL" auto = MyNam(fld.Name) ElseIf fld.Attributes = 1 Or fld.Attributes = 2 Then typ = typ ' I don't know ElseIf fld.Attributes = 32770 Then typ = typ & "" ' hypertext link Else typ = typ & " XXX" & fld.Attributes & "XXX " End If If fld.AllowZeroLength Then typ = typ & " fld.AllowZeroLength" End If Print #1, " `" & MyNam(fld.Name) & "` " & typ & "," i = i + 1 Next If auto <> "" Then Print #1, " PRIMARY KEY (`" & auto & "`)," Print #1, ");" Print #1, "" shea = "INSERT INTO " & MyNam(tdf.Name) & " VALUES(" Set dba = CurrentDb() Set rst0 = dba.OpenRecordset(" SELECT * FROM [" & tdf.Name & "] ", dbOpenDynaset) Do Until rst0.EOF sdat = "" For j = 0 To i - 1 val = rst0(ttypfld(j).nam) fou = False If ttypfld(j).typ = 1 Then sdat = sdat & "'" If val Then sdat = sdat & "1'," Else sdat = sdat & "0'," End If fou = True End If If ttypfld(j).typ = 3 Or ttypfld(j).typ = 4 Or ttypfld(j).typ = 5 Or ttypfld(j).typ = 6 Or ttypfld(j).typ = 7 Then If IsNull(val) Then sdat = sdat & "NULL," Else dbl = val sdat = sdat & Replace(CStr(dbl), Mydecimalseparator, ".") & "," End If fou = True End If If ttypfld(j).typ = 10 Or ttypfld(j).typ = 12 Then If IsNull(val) Then sdat = sdat & "NULL," Else sdat = sdat & "'" & Replace(Replace(Replace(val, "\", "\\"), "'", "\'"), vbCrLf, "\r\n") & "'," End If fou = True End If If ttypfld(j).typ = 8 Then If IsNull(val) Then sdat = sdat & "NULL," Else dattim = val sdat = sdat & "'" & Format(dattim, "yyyy") & "-" & Format(dattim, "mm") & "-" & Format(dattim, "dd") & " " & Format(dattim, "hh:mm:ss") & "'," End If fou = True End If If ttypfld(j).typ = 11 Then If IsNull(val) Then sdat = sdat & "NULL," Else sdat = sdat & "''," End If fou = True End If If fou Then Else sdat = sdat & " XXX " & val & " XXX " End If Next sdat = Mid(sdat, 1, Len(sdat) - 1) & ");" If fou Then Print #2, shea & sdat Else Print #2, "#" & shea & sdat End If rst0.MoveNext Loop End If Print #2, "" Next Close #1 Close #2 End Sub '==================================================================================== Function MyNam(nam) As String ' Converts a fancy table name like "Détails commandes" ' to "details_commandes" Dim i As Integer MyNam = "" Dim c As String For i = 1 To Len(nam) c = Mid(nam, i, 1) If (Asc(c) >= Asc("a") And Asc(c) <= Asc("z")) Or (Asc(c) >= Asc("A") And Asc(c) <= Asc("Z")) Or (Asc(c) >= Asc("0") And Asc(c) <= Asc("9")) Then MyNam = MyNam & LCase(c) ElseIf c = "é" Or c = "è" Then ' ( this is for france, update it for other languages ) MyNam = MyNam & "e" ElseIf c = "à" Then MyNam = MyNam & "a" Else MyNam = MyNam & "_" End If Next End Function '====================================================================================


- One page

To see this documentation in one page click here.

To see this documentation in multipage, click here.




- Use google maps

To play with Google maps, click here.




- SQL JOIN

This documentation helps me sometimes ( I do NOT like SQL Join but I must admit that sometimes, it helps ! )

DROP TABLE IF EXISTS `Group`; CREATE TABLE `Group` ( `IdGroup` BIGINT( 20 ) UNSIGNED NOT NULL AUTO_INCREMENT , UNIQUE (`IdGroup` ) ); INSERT INTO `Group` VALUES (1),(2),(3),(4),(5); DROP TABLE IF EXISTS `Auth`; CREATE TABLE `Auth` ( `groupId` BIGINT(20) UNSIGNED NOT NULL default '0', `menuId` BIGINT(20) UNSIGNED NOT NULL default '0' ); INSERT INTO `Auth` VALUES (0, 1); INSERT INTO `Auth` VALUES (2, 1) , (2, 2) , (2, 3) , (2, 4) , (2, 5) ; INSERT INTO `Auth` VALUES (3, 1) , (3, 2) , (3, 3) , (3, 4) , (3, 9) ; # tous les groupes et leurs autorisations ( NULL si aucune autorisation pour un utilisateur ) SELECT T1.IdGroup, T0.menuId FROM `Auth` T0 RIGHT OUTER JOIN `Group` T1 ON ( T0.groupId = T1.IdGroup ) ; #returns: 1,NULL| 2,1 | 2,2 | 2,3 | 2,4 | 2,5 | 3,1 | 3,2 | 3,3 | 3,4 | 3,9 | 4,NULL | 5,NULL # tous les groupes qui n'ont pas d'autorisations SELECT T1.IdGroup, T0.menuId FROM `Auth` T0 RIGHT OUTER JOIN `Group` T1 ON ( T0.groupId = T1.IdGroup ) WHERE T0.menuId IS NULL ; #returns: 1,NULL | 4,NULL | 5,NULL # tous les groupes avec autorisations SELECT T1.IdGroup, T0.menuId FROM `Auth` T0 INNER JOIN `Group` T1 ON (T0.groupId=T1.IdGroup); #returns: 2,1 | 2,2 | 2,3 | 2,4 | 2,5 | 3,1 | 3,2 | 3,3 | 3,4 | 3,9 # Groupes dans la table des autorisations qui ne sont pas référencés dans la table des groupes SELECT T0.groupId , T0.menuId FROM Auth T0 LEFT JOIN `Group` T1 ON T0.groupId=T1.IdGroup WHERE T1.IdGroup IS NULL; #returns: 0,1


- fckEditor configuration

The fck editor may be used and if you define a data as HTML type and you give the name mypsFckHtml1 to this type, then you must add this definition to the file fckconfig.js.

FCKConfig.ToolbarSets["mypsFckHtml1"] = [ ['Source','NewPage','Cut','Copy','Paste','PasteText','PasteWord'], ['Undo','Redo','Find','Replace','SelectAll','RemoveFormat','JustifyLeft','JustifyCenter','JustifyRight','JustifyFull'], ['OrderedList','UnorderedList'], '/', ['Bold','Italic','Underline','StrikeThrough','Subscript','Superscript','FontSize','TextColor','BGColor'], ['Outdent','Indent','Blockquote'], ['Table','Rule','SpecialChar','PageBreak','ShowBlocks','About'] ] ;


- Pangramme

Ceci est un nouveau texte créé dans « word » sans mise en forme initial. On ajoute des retours à la ligne comme après le point suivant. Maintenant, on ajoute des caractères GRAS ou italiques ou soulignés, voir même, les trois à la fois.

Avec un double saut de ligne et un saut de ligne forcé en restant dans le même paragraphe ( shift entrée ).

Portez ce vieux whisky au juge blond qui fume sur son île intérieure, à côté de l'alcôve ovoïde, où les bûches se consument dans l'âtre, ce qui lui permet de penser à la cænogenèse de l'être dont il est question dans la cause ambiguë entendue à Moÿ, dans un capharnaüm qui, pense-t-il, diminue çà et là la qualité de son œuvre

L'île exiguë
Où l'obèse jury mûr
Fête l'haï volapük,
Âne ex æquo au whist,
Ôtez ce vœu déçu.

Dès Noël où un zéphyr haï me vêt de glaçons würmiens, je dîne d’exquis rôtis de bœuf au kir à l’aÿ d’âge mûr & cætera ! ·
il y a une tabulation à la fin de la ligne précédente.

&é~'{}'()[]-|è`_\ç^ à@°+=¨µ*%ù§!/:.;?,<>¤£²
L’essai a-t-il été concluant ? modif 1 € , un backtick => ` “Guillemets bizarres” de « word » ‘ça passe ?′ ‘’‚‛“”„‰…•!"#$%&'()*+,-./:;<=>?[\]^_`{|}~°®©¡£¤¥¦§¨©ª «ÉÈËÊ¿¾½¼»±²³´µ·¸¹ºæ÷ αβγδεζηθικμνξοπρςστυφχψω ℅™€⅓⅔⅛⅜⅝⅞♠♣♥♦♪♫'...



- simpleXml sub tree

<?php $string = <<<XML <a> <b> <c>text <b>hello</b><i>hello</i></c> <c>stuff</c> </b> <d> <c>hella</c> </d> </a> XML; function subTree( $s , $tag ){ if(substr($s,0,1+strlen($tag))!='<'.$tag) return false; $news=''; for($i=1+strlen($tag);$i<strlen($s);$i++){ if(substr($s,$i,1) == '>') break; } $news=substr($s,$i+1); if( substr($news,strlen($news)-strlen($tag)-3) !='</'.$tag.'>') return false; return(substr($news,0,strlen($news)-strlen($tag)-3)); } $xml = new SimpleXMLElement($string); echo '<textarea rows="10" cols="40">' . $xml->asXML() . '</textarea><br />'; echo '<textarea rows="6" cols="40">' . $xml->b->asXML() . '</textarea><br />' ; echo '<textarea rows="6" cols="40">' . subTree( $xml->b->asXML() , 'b' ) . '</textarea><br />' ; ?>


- Happy links :-)


Where the hell is matt ?
TED.COM:
Paradox of choice
Why are we happy
Why are we happy (more)
the expected value of any of our actions that is the goodness that we can count on getting
is the product of
the odd that this action will allow us to gain something
and
the value of that gain to us
8 secrets of success

Bouing ! :-))

koolsol : a progressive web app solitaire game :-))

lighthouse score rank for pwa



Contact