Monday, 25 April '16
by sebataz

I coded a simple chat, however since I was the only one using it it was pretty boring. So I decided to implement a chatbot. Unfortunately any solution that I found uses complex AIML brains and more complex implementations.

Since I wanted to implement my own interpreter from scratch I had to come up with a fairly simple idea. Searching the web for an implementation I came across an idea for an incredibly simple solution.

This implementation uses an array of array of replies for the brain, instead of the complex AIML; the index of the main array is a regex which will match the user's query. The interpreter cycles through the array matching the user's query against the regex of the array and then randomly chooses a reply.

In order to use this solution you need a basic knowledge of regular expression, the use of the PHP function preg_replace() and the use of references.

Here is my own implementation of the brain and the interpreter:


// the index of the array is a regular expression
// the content of the array is an array of replies
// a reply can reference matched content from user's query
$brain['\b(hello|hi|hey)\b'] = array('Hello!', 'Hi!');
$brain['how are you.*\?'] = array('I\'m fine, thx!', 'Couldn\'t be better.', 'Very well.');
$brain['are you (.*)\?'] = array('What if I am $1.', 'What does it matter what I am.', 'Would you prefer it if I was $1.', 'I may be $1, what do you think?');

// cycles through the brain array associating the index of the array to the variable $regex and the list of replies to the variable $replies
foreach ($brain as $regex => $replies) {

    // checks if the regex matches the user's query
    if (preg_match('/' . $regex . '/i',  $input)) {

        // replaces the whole user's query with a reply
        $output = preg_replace(
            '/^.*' . $regex . '.*$/i',              // expands the brain regex to match the whole query
            $replies[rand(0, count($replies)-1)],   // chooses a random reply from the list
            $input                                  // the query to replace
        );
        
        // echoes the chatbot reply
        echo $output;
        
        // breaks the cycle after having matched a query and returned a reply
        break;
    }
}

The fun starts when you have to program and test the brain for your chatbot.

Thursday, 21 April '16
by sebataz

I cünta sü che ia trovaa di toomb, probabilment da la preistoria.

In dal 1202 Gordün faseva part da la Castalderia da Claro e gha pagava ammò un censo anüal fin al 1405. In dal 1374 Gordün faseva part, con Gnosca, da una circoscrizion aministrativa sota da un Podestà milanes.

In dal 1198 sa cüntava sü da un castel, dì anca da San Carpoforo, che l'è pö stai ricostrui in dal 1402.

Al sitt gh'era già da vesig in dal medioevo, ma la prima volta che i na parla l'è in dal 1538 (comünicazion dal patriziaa). Anca chi come in altri sitt dal canton, i gent i stava prima in colina, in doa gh'era costruit i prim cà, per pö na gio in pian. Per Gordün e Gnosca al sitt in colina, che l'è pö in munt, sa ciamava Sassa, che l'è stai abandonaa in dal 1570.

Thursday, 21 April '16
by sebataz

Switzerland has seen some tough and harsh history as well, in which battles and rebellions where fought to grant the freedom of the Swiss folk.

In the midst of battle, where the bravery of one self is tested to the limit, some of our countrymen gave it all sacrificing even their own life for a single purpose.

  • Wilhelm Tell: the tale tells that he became the leader of the rebellion against the tyranny of the Austrians. He was condemned by Gessler, the Vogt of Altdorf, to shoot an apple on the head of is son because he refused to bow in front of a hat. However, Wilhelm was an excellent marksman with the crossbow and split the apple with a single bolt. And so he made an example for all of his countrymen to resist and fight against the Habsburg invaders.(on wikipedia)

  • Arnold von Winkelried: during the battle of Sempach against the Habsburg, Arnold von Winkelried sacrificed his life by throwing himself upon the Austrian pikes. By doing so he opened a passage allowing the Swiss to win the battle. The last cry of Arnold went to his family: "I will open a passage into the line; protect, dear countrymen and confederates, my wife and children..." (on wikipedia)

  • Ueli Rotach: while fighting the Austrian besides his brothers in arms it is said that he was cornered into a barn. He fought with bravery to the end, even when the Austrian set fire to the barn.

Sunday, 17 April '16
by sebataz

CKEditor is very good WYSIWYG editor for your web pages, and it has a ton of documentation.

It may happen that you want to create multiple instances of the editor on the same page, with different configuration.

I had some difficulties to apply this solution to my project, moreover the documentation on this point is a bit shady.

For this reason I want to provide a useful example.

In this example I create two instances of CKEditor with different toolbars, but of course the configuration can be whatever you need.


// create first configuration
var cfgFirst = {
    toolbar: [
       ['Bold','Italic','Underline','StrikeThrough','-','Undo','Redo','-','Cut','Copy','Paste'],
    ]
};         

// create second configuration
var cfgSecond = {
    toolbar: 'Full',
};

// disable the auto-creation of the editor for editable content
CKEDITOR.disableAutoInline = true;
                
// create an instance with custom configuration
var eFirst = CKEDITOR.inline('firstDiv', cfgFirst);
var eSecond = CKEDITOR.inline('secondDiv', cfgSecond);

Of course, this can be applied to any number of instances.

Sunday, 17 April '16
by sebataz

piöf! piöf!
la galina la fa l'öf
el gatin al piza 'l föc
la Pepina meza mata fa 'l cafè con l'insalata.

Sunday, 03 April '16
by sebataz

Friday, 01 August '14
by sebataz

Unused, old, and quite unknown the swiss dialect was once the main language with which people would communicate. Of course, this is not possible anymore since those dialect were so very different from one another. Unfortunately, nowadays a base ground is needed in order to be able to tolerate one another, thus the four national language have been adopted instead.

The dialect survives, still, among valley people and drunkard (which is almost the same person). Many idioms (not idiots) are still in use to this day, in which the wisdom of our fathers and granfathers is preserved.

This weird sounding language is a real national treasure in which a full load of history, stories, idioms, and wisdom is hidden.

It is unfortunate that youngester of this new generation have forgotten the tongue of our elders, and with it they keep losing the true Swiss identity.

In my opinion, if things keep going down this road, soon enough the dialect will be found only in theatres or musem. Which is, I think, quite sad.

However, in my family this unusual tounge is used quite a lot, and on my side I will keep this tradition alive as much as I can.

Sunday, 13 April '14
by eliza

Swigert (CMP): Okay, Houston, we've had a problem here.
CAPCOM Jack Lousma (CC): This is Houston. Say again, please.
Lovell (CDR): Uh, Houston, we've had a problem.
Lovell (CDR): We've had a MAIN B BUS undervolt.
CAPCOM Jack Lousma (CC): Roger MAIN B undervolt.
CAPCOM Jack Lousma (CC): Okay, stand by Thirteen, we're looking at it.



Thursday, 13 March '14
by sebataz

A step-by-step guide to set up a basic HyperV cluster environement

In this article I will go through the steps to create a working Hyper-V cluster environment. All the needed machine are virtualized with the hypervisor VMware ESXi 5.5 server1. The failover cluster will permit you to have roles and services virtually always running; in case of a disaster, in one of the node, the failover cluster will resume the execution of any interrupted virtual serivce to another node.

Step 1: the domain controller2

The failover needs a domain controller to correctly operate, I will dedicate an entire VM just for that.

  1. Install a new fresh Windows 2012 R2 machine.
  2. Set-up the machine's network interface: IP:172.17.10.1, Subnet Mask:255.255.0.0, Gateway: 172.17.0.1, DNS: 172.17.0.1.
  3. Rename the machine to WIN2012R2-DC.
  4. Open the Add Roles and Features Wizard and add the role Active Directory Domain Services on this server, the feature Group Policy Management will automatically be installed by the wizard.
  5. After the role and feature have been correctly installed you should see a notice that will ask you to Promote this server to a domain controller, click on that link to open the wizard and promote the server to a domain controller.
  6. Add a new forest and insert the Domain: 2012r2cluster.local
  7. Leave the forest and domain functional level to Windows Server 2012 R2 if you don't plan to have lower OS version installed in the domain, leave the Domain Name System (DNS) server capability enabled and set the Directory Services Restore Mode (DSRM) password.
  8. Create a DNS delegation if you need the domain's hosts to be resolved from outside this domain, which is not my case.
  9. The NetBIOS will be set to 2012R2CLUSTER.
  10. For a simple configuration I will move the location for the AD DS database, log files and SYSVOL into the folder C:\ActiveDirectoy\*.
  11. Review your selections and apply the correction if needed, you can see and save a script for the automatic installation on other servers.
  12. The wizard will check if all the prerequisites can be validated before letting you install the services.
  13. You will be signed out of the machine during the installation, you will then have to login with the domain user 2012R2CLUSTER\Administrator.

Step 2: creating a node

Each single node will be installed and configured with the same roles and features, and the nodes IP will range in 172.17.100.1-254.

  1. Install a new fresh Windows 2012 R2 machine.
  2. Set-up the machine's network interface: IP:172.17.100.1-254, Subnet Mask:255.255.0.0, Gateway: 172.17.0.1, DNS: 172.17.10.1.
  3. Set the name of the machine WIN2012R2-N0 and set the previously configured domain 2012r2cluster.local for the machine.
  4. You can now login into the machine using the domain user 2012R2CLUSTER\Administrator.

Step 3: installing the Hyper-V role on a node

Since the main objective of this guide is to virtualize machines in a cluster we will need to install the Hyper-V role on each node, for this the VM's configuration has to be tweaked a little.

  1. Shut down the VM if running.
  2. The virtual hardware must be upgraded to at least version 9.
  3. In order to be able to install the Hyper-V role on the machine edit the VM's settings, switch to the VM Options tab and expand the Advanced item. Click on the button Configuration Parameters and add the new configuration row hypervisor.cpuid.v0 = FALSE.
  4. Edit the virtual machine CPU settings and set it to Expose hardware assisted virtualization to the guest OS for the Hardware virtualization.
  5. Power on the VM and open the Add Roles and Features Wizard and add the role Hyper-V on this server.
  6. You will be asked to provide one or more Network adapter for Hyper-V, I will use the only one I configured on the node.
  7. Insert the default locations for virtual hard disks and for virtual machine configurations, or simply leave the Microsoft defaults.
  8. At the end of the installation you will have to reboot the machine, after that you can manage your Hyper-V from the Hyper-V Manager.

Step 4: configure share storage for nodes3

You will need to setup a network storage shared across the nodes in order to store virtual machines or cluster services. I will be using a preconfigured iSCSI server on a Windows Server 2012.

  1. Using the iSCSI Initiator connect to the iSCSI target (server), insert the IP or host name of the target and click the Quick Connect... button.
  2. Switch to the tab Volumes and Devices and click on the button Auto Configure, this will configure/connect the disk to the machine.
  3. In the Serve Manager disks overview make sure that you see all the configured disks.

Step 5: create the cluster

Now comes the bit you've all been waiting for, we will be installing and configuring the cluster service for each node.

  1. Open the Add Roles and Features Wizard and add the feature Failover Clustering on this server.4
  2. When the installation is completed open the Failover Cluster Manager.
  3. Click on the Validate Configuration... link to start the validation wizard.
  4. Insert the name of the node/s you want to validate.
  5. It is recommended to Run all tests the first time; the validation process might take a little while, wait till it finishes.
  6. You should be reported that the validation is completed and the configuration is suitable for clustering; if not, correct any mistake and restart the validation.
  7. Click on the Create Cluster... link to create a new cluster.
  8. Add all the names of the hosts you wish to include in the cluster and proceed.
  9. Choose a name for your cluster and set cluster IP address (i.e.: WIN2012R2-CLUSTER:172.17.10.2).
  10. Once you've added all the nodes to your cluster, if you repeat the validation process the wizard should automatically configure all the cluster storage based on the iSCSI previously configured. This is true if the iSCSI are shared across all the added nodes, and are not yet reserved for others clusters or services.

Thursday, 13 February '14
by sebataz

How to read, parse and output the history of a repository

It is possible with php to send commands to the server shell, this can easily be done using the php function exec()1. We'll be sending the Git command git log2, to retrieve the history. In this particular example we'll see how to get the history of a Git repository, parse it and show it in a nice human readable form. Enjoy!!!

First of all we'll want to ask Git for the history, which can be done using the command git log. If you don't want the whole history, but let's say only the first 7 commits you can use the option -n, like so: git log -n 7.

The command will be invoked using the exec() function, this will give back a raw input in a string. What you want to do now is to parse it into an array (like the example below) or you could directly format it into an HTML output. Since I love array I will parse the output into a nice associative array, so that I can use it anywhere I like.


// will hold the history
$git_history = array(); 

// query git for history
exec('git log', $output);

// commit counter
$i = 0; 

// loop output for parsing
foreach($output as $line){
    if (strpos($line, 'commit') === 0){
        $i++;
        $git_history[$i]['Hash'] = substr($line, strlen('commit'));
    }
    
    else if(strpos($line, 'Author') === 0){
        $git_history[$i]['Author'] = substr($line, strlen('Author:'));
    }
    
    else if(strpos($line, 'Date') === 0){
        $git_history[$i]['Date'] = substr($line, strlen('Date:'));
    }
    
    else{		
        $git_history[$i]['Message'][] = $line;
    }
}
    

Let me explain a bit

As I mentioned above the resulting output is a string, we'll read that line by line in order to create an associative array holding the history.

As you can see the increment operation of the counter $i is enclosed into an if statement, that will be true only when the keyword commit is found. We need to enclose the counter into an if statement because we only want to count the commits and not every line of the output.

With the strlen() function we check where a particular section of the commit starts, (i.e.: after the keyword) once we know the position we simply get out a sub-string of the output line into an array element.

Try it out yourself!

Once you have an array holding the history you can do whatever you like with it. You could, for example, parse it once more to a JSON array. Like I did, check it out at this link: http://sebataz.ch/api/eliza/service.php?GitHistory. Or, if you prefer you can parse the output into a nice HTML formatted output, like so:

  • 2017.07.12: minor change
  • 2017.07.03: docs updated
  • 2017.06.05: ElizaService.js refactored, minor bug fixes
  • 2017.05.28: added HTMLDocument, and minor bug fixes
  • 2017.05.19: improved service, improved file system access
  • 2017.05.12: added upload plugin, beta trial on sebataz.ch
  • 2017.05.12: improved XML/HTML, updated docs, ElizaPlugin implementation
  • Thursday, 13 February '14
    by sebataz

    OOTBDev is a complete development environment mainly thought for php, but not only, that runs on Windows. It is based on the web server nginx/php/mysql. The environment includes the git versioning control system with tools (bash, msys, minigw, ssh, ...).

    Downloads

    You can download OOTBDev here, 32-bit and 64-bit version are available. Since OOTBDev is a set of open-source tools you can freely download them separately, here I give you the link and version I used for the current release:

    How to use

    The environment does not need any installation, it is ready to run as it is. To deploy the environment double-click on the batch file launch.bat. When finished to shutdown the environment double-click on the batch file quit.bat.

    Folder structure

    • bin: Binaries and executable
    • conf: Configuration for PHP/Mysql/nginx
    • logs: Server logs
    • temp: Server temp files
    • workbench: Default document root for server (a.k.a. your work!)

    Updates

    05.11.2013 The folder structure is organized in a way that you have direct access to important file like your work or configurations. All the server components binaries and executables have been placed in the directory /bin. A new launcher in one single window. The launcher will check for the proper components to run correctly, if not it waits.

    Monday, 13 January '14
    by sebataz

    A simple guide to set up an environment for PHP and MySQL with Nginx.

    Setting up PHP

    We will be running PHP scripts with FastCGI, first of all we need the PHP binaries in order to be able to run anything. Go to this link and download the PHP version you wish to use, for this article I downloaded VC11 x86 Non Thread Safe (2013-Nov-13 20:57:43), since we will be running CGI scripts we do not need the Thread Safe version.

    We have now to set up Nginx to pass the PHP request to a CGI server. Add the following location to your Nginx configuration file. This location will test a request against the regular expression ~ \.php$, meaning all the requests that end with ".php":

    
            #This  will test for any request that ends with
            #the ".php" extension. We will be using this 
            #location and FastCGI to interpret and serve
            #PHP pages.
            location ~ \.php$ {
                
                #the address of the *FASTCGI* server. In our case
                #where PHPCGHI.exe will be listening.
                fastcgi_pass   127.0.0.1:9000;
                
                #same as *INDEX* for FastCGI
                fastcgi_index  index.php;
                
                #the request's *QUERY_STRING* 
                fastcgi_param  QUERY_STRING       $query_string;
                
                #the request's *FILENAME*
                fastcgi_param  SCRIPT_FILENAME $request_filename;
                
                #or you can include the *STANDARD* FastCGI params
                #by including the standard config file:
                #include fastcgi.conf
            }
        

    Now that Nginx is set up all the PHP requests will be passed to FastCGI, we have now to start PHP-CGI and make it listen on the address and port that we configured Nginx (i.e.: IP: 127.0.0.1; PORT: 9000) to pass a PHP request. In order to do this we will need to start the executable php-cgi.exe from command line: php-cgi.exe -b 127.0.0.1:9000 -c path/to/php.ini

    Setting up MySQL

    Now that the webserver and the PHP-CGI are running it is time to set up a database, for this purpose we'll be using the well re-known MySQL, go to this link and download the full archive of MySQL Windows (x86, 32-bit), ZIP Archive. An installation of MySQL is not needed, but if you prefer you can install the MySQL server on your machine, in this article I will not go through the installation of MySQL itself; just some settings are needed in order to make the all thing work. So without losing any more time let's see what's needed to make MySQL behave.

    We want PHP to be able to query a MySQL server, for this we will need to enable some extensions. Go to your php.ini and make sure to apply the following settings; you can uncomment the existing lines or paste this lines at the bottom of the file:

    
            extension=php_bz2.dll
            extension=php_gd2.dll
            extension=php_imap.dll
            extension=php_mbstring.dll
            extension=php_mysql.dll
            extension=php_mysqli.dll
        

    The MySQL configuration is fairly easy to set up, and anyway the web is full of tutorial on this topic. Here I just give you the minimal configuration in order to run PHP scripts with MySQL. And this is it:

    
            [client]
            port=3306
            socket=/tmp/mysql.sock
    
            [mysqld]
            port=3306
            socket=/tmp/mysql.sock
            key_buffer_size=16M
            max_allowed_packet=8M    
        

    Now that the configuration is set we will need to start the MySQL Daemon, this service will be listening for the MySQL server. You can start the daemon from command line it can be useful to start it with specifying a configuration file: mysqld --defaults-file=path/to/mysql.ini

    Portable solution

    As I stated in the introduction Nginx is very handy when it comes to having a portable server on the go. If you don't want to put yourself through the work of configuring your own portable webserver you can go and download the bundle I put together: OOTBDev - Out Of The Box Development.

    Conclusion

    That's all folks. You should now be able to run Nginx with PHP and MySQL on a Windows machine.

    Monday, 13 January '14
    by sebataz

    In these two articles I will go through the configuration of a lightweight server running PHP and MySQL on Windows. For this purpose I chose the fairly new webserver Nginx (pronounced "engine x"). The main focus of this open source project is on high concurrency, high performance and low memory usage; which is the ideal to set up a small development environment1.

    Moreover, it will be a simple matter of tweaking a couple of setting and downloading the right packages in order to turn this environment into a portable solution, but more about this later.

    Nginx webserver

    So, let us start from the beginning. I had a need for a small and easy to configure server. That I could just start and develop on. When I heard about this new Nginx server I was almost sure I would have had to kick and scream for days to get it working, but it only took a few steps to run it for the first time and a couple more to deploy PHP and MySQL.

    Nginx is pretty straightforward, download it, run it and enjoy your served pages. Don't believe me? Try it out for yourself: download the Nginx archive here, make sure to download the Windows version (for this article I downloaded nginx/Windows-1.5.6) extract the archive and run the executable nginx.exe. Et voilà! Your webserver is up and running, try it at this link: http://localhost/

    Nginx configuration

    The Nginx configuration file is organized in blocks each one representing a context in which a setting is valid. Block can be nested and will inherit the configuration from its parent block. Single settings are called directives, and can be for any context2. I am now going to give you a simple configuration "as-is". Please feel free to edit and use it:

    
            #main configuration context for Nginx
            http {
            
                #you can define multiple *SERVERS* by defining the port
                #to listen to or by server name. Nginx will then 
                #decide which server processes the request received
                server {
                
                    #this server will *LISTEN* on port 8080. If no port
                    #is specified the default 80 will be used instead.
                    listen 8080;
                    
                    #this server is identified by the *SERVER NAME* "localhost"
                    server_name localhost;
                    
                    #the *DOCUMENT ROOT* directory from where files are served. 
                    #I suggest you to set an absolute path to your document root.
                    root C:\html;
                                            
                    #Nginx will serve the pages from a *LOCATION* by testing
                    #the request against the parameters of the directive.
                    #This location will be valid for any request which do not
                    #have a particular location defined:
                    location / {
                    
                        #if no file is specified the *INDEX* will be served,
                        #you can add multiple names.
                        index index.html index.htm index.php;
                        
                        #you can set a location to *AUTO INDEX* itself, this
                        #comes handy if you want to set a directory browsable.
                        autoindex on;   
                    }
                    
                    #you can use *REGULAR EXPRESSIONS* to test a request,
                    #regex must be preceded with ~. This  will test for 
                    #any request that ends with the ".php" extension. 
                    #We will be using this location and FastCGI to 
                    #interpret and serve PHP pages.
                    location ~ \.php$ {
                        
                        #the address of the *FASTCGI* server. In our case
                        #where PHPCGHI.exe will be listening.
                        fastcgi_pass   127.0.0.1:9000;
                        
                        #same as *INDEX* for FastCGI
                        fastcgi_index  index.php;
                        
                        #the request's *QUERY_STRING* 
                        fastcgi_param  QUERY_STRING       $query_string;
                        
                        #the request's *FILENAME*
                        fastcgi_param  SCRIPT_FILENAME $request_filename;
                        
                        #or you can include the *STANDARD* FastCGI params
                        #by including the standard config file:
                        #include fastcgi.conf
                    }
                }
            }
        

    As you can see the configuration file is quite small and you don't need a lot of settings to run a simple webserver. The above is the configuration I usually use to launch Nginx with PHP and MySQL for my development environment.

    Nginx command line

    Nginx can be controlled directly from command line by sending a signal to the master process, once the executable has been started, using the -s parameter3.

    To apply a new configuration, start Nginx if not yet started or send the reload signal to the Nginx’s master process, by executing: nginx -s reload

    To stop the server you have two signals command you can use:

    • nginx -s stop to fast shutdown
    • nginx -s quit to gracefully shutdown

    Another possibility to shutdown Nginx is to kill its main process, which is not very nice to do but gets the job done. On Windows systems you can do this from the command prompt as well, like so: taskkill /f /IM nginx.exe

    Nginx executable, when starting from command prompt, accepts a series of useful parameters that are worth having a look into. I give you here a couple that I use most of the time:

    • nginx.exe -c path/to/file to set the path to the configuration file
    • nginx.exe -p path/to/dir to set the prefix path (or server root)