Home > SuperSegger > cell > trackOptiClist.m

trackOptiClist

PURPOSE ^

trackOptiClist : generates an array called the clist

SYNOPSIS ^

function [clist] = trackOptiClist(dirname,CONST,header)

DESCRIPTION ^

 trackOptiClist : generates an array called the clist
 which contains non time dependent information for each cell.
 Fluorescence values contained are for at birth time.
 To see the information contained type clist.def'.

 INPUT :
       dirname : seg folder eg. maindirectory/xy1/seg
       CONST : segmentation constants
       header : string displayed with information
 OUTPUT :
       clist :
           .data : array of cell variables versus cells.
           .def : definitions of variables in clist
           .data3D : variables vs cells vs time
           .def3D : definititions of variables used in data3D.

 Copyright (C) 2016 Wiggins Lab
 Written by Paul Wiggins.
 University of Washington, 2016
 This file is part of SuperSegger.

 SuperSegger is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 SuperSegger is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with SuperSegger.  If not, see <http://www.gnu.org/licenses/>.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 function [clist] = trackOptiClist(dirname,CONST,header)
0002 % trackOptiClist : generates an array called the clist
0003 % which contains non time dependent information for each cell.
0004 % Fluorescence values contained are for at birth time.
0005 % To see the information contained type clist.def'.
0006 %
0007 % INPUT :
0008 %       dirname : seg folder eg. maindirectory/xy1/seg
0009 %       CONST : segmentation constants
0010 %       header : string displayed with information
0011 % OUTPUT :
0012 %       clist :
0013 %           .data : array of cell variables versus cells.
0014 %           .def : definitions of variables in clist
0015 %           .data3D : variables vs cells vs time
0016 %           .def3D : definititions of variables used in data3D.
0017 %
0018 % Copyright (C) 2016 Wiggins Lab
0019 % Written by Paul Wiggins.
0020 % University of Washington, 2016
0021 % This file is part of SuperSegger.
0022 %
0023 % SuperSegger is free software: you can redistribute it and/or modify
0024 % it under the terms of the GNU General Public License as published by
0025 % the Free Software Foundation, either version 3 of the License, or
0026 % (at your option) any later version.
0027 %
0028 % SuperSegger is distributed in the hope that it will be useful,
0029 % but WITHOUT ANY WARRANTY; without even the implied warranty of
0030 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0031 % GNU General Public License for more details.
0032 %
0033 % You should have received a copy of the GNU General Public License
0034 % along with SuperSegger.  If not, see <http://www.gnu.org/licenses/>.
0035 
0036 if ~exist('header','var')
0037     header = [];
0038 end
0039 
0040 if(nargin<1 || isempty(dirname))
0041     dirname = '.';
0042 end
0043 dirname = fixDir(dirname);
0044 
0045 % Get the track file names...
0046 contents=dir([dirname '*_err.mat']);
0047 
0048 
0049 if isempty( contents )
0050     clist.data = [];
0051     clist.def={};
0052     clist.gate=[];
0053 else
0054     data_c = loaderInternal([dirname,contents(end).name]);
0055     MAX_CELL = max(10000, max(data_c.regs.ID) + 100);
0056     if isempty(MAX_CELL)
0057         MAX_CELL = 10000;
0058     end
0059     num_im = numel(contents);
0060     
0061     if CONST.parallel.show_status
0062         h = waitbar( 0, 'Making Cells.');
0063         cleanup = onCleanup( @()( delete( h ) ) );
0064     else
0065         h = [];
0066     end
0067     
0068     clist = [];
0069     [setter,clist.def3D]  = clistSetter ();
0070     clist.def = setter(:,1)';
0071     tmpFields = setter(:,2)';
0072     clist3d_ind = find([setter{:,4}]);
0073     
0074     death_ind = find([setter{:,3}]); % death fields : updated in every frame
0075     clist_tmp = nan( MAX_CELL, numel( clist.def));
0076     clist_3D  = nan( MAX_CELL, numel( clist.def3D), num_im );
0077 
0078     clist_tmp(:,1) = 0;
0079     
0080     
0081     % calculating indexes of values used during calculations
0082     lengthFields = find(strcmp(tmpFields,'data_c.regs.L1'));
0083     index_lold = intersect(lengthFields,death_ind);
0084     index_lbirth = setdiff(lengthFields,death_ind);
0085     index_ID= find(strcmp(tmpFields,'ID'));
0086     index_dlmaxOld = find(strcmp(tmpFields,'dlmax'));
0087     index_dlminOld = find(strcmp(tmpFields,'dlmin'));
0088     index_ehist = find(strcmp(tmpFields,'error_frame'));
0089     % loop through all the images (*err.mat files)
0090     for i = 1:num_im
0091         
0092         
0093         data_c = loaderInternal([dirname,contents(i).name]);
0094         if ~isempty( data_c.CellA)
0095             % record the number of cell neighbors
0096             if CONST.trackOpti.NEIGHBOR_FLAG && ...
0097                     ~isfield( data_c.CellA{1}, 'numNeighbors' )
0098                 for ii = 1:data_c.regs.num_regs
0099                     nei_ = numel(trackOptiNeighbors(data_c,ii));
0100                     data_c.CellA{ii}.numNeighbors = nei_ ;
0101                 end
0102             end
0103 
0104 
0105             % figure out which cells are new born.
0106             maxID = max(clist_tmp(:,index_ID));
0107             ID = data_c.regs.ID;
0108             birthID_flag = (ID>maxID);
0109             ID_non_zero_flag = (ID>0);
0110 
0111             ci = and( ~birthID_flag, logical(ID));
0112 
0113             IDlog = ID>0;
0114             ID_non_zero = ID(IDlog);
0115 
0116             lold = nan(1,numel(ID));
0117             lbirth = nan(1,numel(ID));
0118             dlmaxOld = nan(1,numel(ID));
0119             dlminOld = nan(1,numel(ID));
0120             error_frame = nan(1,numel(ID));
0121 
0122             error_frame(IDlog) = clist_tmp(ID_non_zero,index_ehist);
0123             lold(IDlog) = clist_tmp(ID_non_zero,index_lold);
0124             lbirth(IDlog) = clist_tmp(ID_non_zero,index_lbirth);
0125             dlmaxOld(IDlog) = clist_tmp(ID_non_zero,index_dlmaxOld);
0126             dlminOld(IDlog) = clist_tmp(ID_non_zero,index_dlminOld);
0127 
0128             regnum = (1:data_c.regs.num_regs)';
0129             zz = zeros( data_c.regs.num_regs, 1);
0130 
0131             ehist = data_c.regs.ehist;
0132             set_error_this_frame = and( logical(ehist),isnan(error_frame) );
0133             error_frame(set_error_this_frame) = i;
0134 
0135             cell_dist = drill(data_c.CellA,'.cell_dist');
0136             pole_age  = drill(data_c.CellA,'.pole.op_age');
0137             fl1sum = drill(data_c.CellA,'.fl1.sum');
0138             fl2sum  = drill(data_c.CellA,'.fl2.sum');
0139             Area = drill(data_c.CellA,'.coord.A');
0140             xpos = drill(data_c.CellA,'.coord.rcm(1)');
0141             ypos = drill(data_c.CellA,'.coord.rcm(2)');
0142             numNeighbors = drill(data_c.CellA,'.numNeighbors');
0143             gray = drill(data_c.CellA,'.gray');
0144 
0145             locus1_L1 = drill(data_c.CellA, '.locus1(1).longaxis');
0146             locus1_L2 = drill(data_c.CellA, '.locus1(1).shortaxis');
0147             locus1_s = drill(data_c.CellA, '.locus1(1).score');
0148             locus1_i = drill(data_c.CellA, '.locus1(1).intensity');
0149 
0150             locus2_L1 = drill(data_c.CellA, '.locus1(2).longaxis');
0151             locus2_L2 = drill(data_c.CellA, '.locus1(2).shortaxis');
0152             locus2_s = drill(data_c.CellA, '.locus1(2).score');
0153             locus2_i = drill(data_c.CellA, '.locus1(2).intensity');
0154 
0155             locus3_L1 = drill(data_c.CellA, '.locus1(3).longaxis');
0156             locus3_L2 = drill(data_c.CellA, '.locus1(3).shortaxis');
0157             locus3_s = drill(data_c.CellA, '.locus1(3).score');
0158             locus3_i = drill(data_c.CellA, '.locus1(3).intensity');
0159 
0160             locus4_L1 = drill(data_c.CellA, '.locus1(4).longaxis');
0161             locus4_L2 = drill(data_c.CellA, '.locus1(4).shortaxis');
0162             locus4_s = drill(data_c.CellA, '.locus1(4).score');
0163             locus4_i = drill(data_c.CellA, '.locus1(4).intensity');
0164 
0165             locus5_L1 = drill(data_c.CellA, '.locus1(5).longaxis');
0166             locus5_L2 = drill(data_c.CellA, '.locus1(5).shortaxis');
0167             locus5_s = drill(data_c.CellA, '.locus1(5).score');
0168             locus5_i = drill(data_c.CellA, '.locus1(5).intensity');
0169 
0170             daughter1_id = drill(data_c.regs.daughterID,'(1)');
0171             daughter2_id = drill(data_c.regs.daughterID,'(2)');
0172 
0173             length1 = drill(data_c.CellA,'.length(1)');
0174             length2 = drill(data_c.CellA,'.length(2)');
0175 
0176             locus1_relL1 = (locus1_L1)./length1;
0177             locus2_relL1 = (locus2_L1)./length1;
0178             locus3_relL1 = (locus3_L1)./length1;
0179             locus4_relL1 = (locus4_L1)./length1;
0180             locus5_relL1 = (locus5_L1)./length1;
0181 
0182             locus1_relL2 = (locus1_L2)./length2;
0183             locus2_relL2 = (locus2_L2)./length2;
0184             locus3_relL2 = (locus3_L2)./length2;
0185             locus4_relL2 = (locus4_L2)./length2;
0186             locus5_relL2 = (locus5_L2)./length2;
0187             op_ori =  drill(data_c.CellA, '.pole.op_ori');
0188 
0189             locus1_PoleAlign_L1 = locus1_L1 .* op_ori;
0190             locus1_PoleAlign_L1 (op_ori ==0) = nan;
0191 
0192             locus1_PoleAlign_relL1 = locus1_relL1 .* op_ori;
0193             locus1_PoleAlign_relL1 (op_ori==0) = nan;
0194 
0195             locus1_fitSigma  = drill(data_c.CellA,'.locus1(1).fitSigma');
0196             locus2_fitSigma  = drill(data_c.CellA,'.locus1(2).fitSigma');
0197             locus3_fitSigma   = drill(data_c.CellA,'.locus1(3).fitSigma');
0198 
0199             lnew = data_c.regs.L1;
0200             dl = (lnew-lold);
0201             dlmin = nan(size(dl));
0202             dlmax = nan(size(dl));
0203 
0204             indTmp = isnan(dlminOld);
0205             dlmin( indTmp ) = dl(indTmp);
0206 
0207             indTmp = isnan(dlmaxOld);
0208             dlmax( indTmp ) = dl( indTmp);
0209 
0210             indTmp = isnan(dl);
0211             dlmin( indTmp ) = dlminOld( indTmp);
0212             dlmax( indTmp ) = dlmaxOld( indTmp);
0213 
0214             indTmp = ~isnan(dl+dlminOld);
0215             dlmin( indTmp ) = min( [dl(indTmp);dlminOld( indTmp )]);
0216 
0217             indTmp = ~isnan(dl+dlmaxOld);
0218             dlmax( indTmp ) = max( [dl( indTmp);dlmaxOld( indTmp )]);
0219 
0220             lrel = lnew./lbirth;
0221 
0222             longOverShort = data_c.regs.L1./data_c.regs.L2;
0223             neckWidth =  data_c.regs.info(:,3);
0224             maxWidth = data_c.regs.info(:,4);
0225 
0226 
0227             % putting all fields in tmp
0228             tmp = nan (numel(ID),numel(tmpFields));
0229             for u = 1 : numel(tmpFields)
0230                 tmp_var =  eval(tmpFields{u});
0231                 tmp_var = convertToColumn(tmp_var);
0232                 tmp(:,u) = tmp_var;
0233             end
0234 
0235             % keeping from tmp only the cell that were just born
0236             try
0237                 clist_tmp(ID(birthID_flag), : ) = tmp(birthID_flag, :);
0238                 clist_3D(ID(ID_non_zero_flag), :, i ) = tmp(ID_non_zero_flag, clist3d_ind);
0239 
0240             catch ME
0241                 printError(ME);
0242             end
0243 
0244             % update guys that you want to set to the death value
0245             clist_tmp(ID(ci), death_ind ) = tmp(ci, death_ind);
0246 
0247             if CONST.parallel.show_status
0248                 waitbar(i/num_im,h,['Clist--Frame: ',num2str(i),'/',num2str(num_im)]);
0249             elseif CONST.parallel.verbose
0250                 disp([header, 'Clist frame: ',num2str(i),' of ',num2str(num_im)]);
0251             end
0252         end
0253         
0254         
0255     end
0256     
0257     
0258     if CONST.parallel.show_status
0259         close(h);
0260     end
0261     
0262     % removes cells with 0 cell id
0263     clist.data   = clist_tmp(logical(clist_tmp(:,1)),:);
0264     clist.data3D = clist_3D(clist.data(:,1),:,:);
0265 
0266     clist = gateTool( clist, 'add3Dt' );
0267     
0268     %add3dtime stuff
0269     len_time_ind = grabClistIndex(clist, 'Long axis (L)', 1);
0270     
0271     ss = size( clist.data3D );
0272     if numel(ss) == 2
0273         ss(3) = 1;
0274     end
0275     len  = reshape( ~isnan(squeeze(clist.data3D(:,len_time_ind(1),:))),[ss(1),ss(3)]);
0276     age = cumsum( len, 2 );
0277     age(~len) = nan;
0278     
0279     age_rel = age;
0280     age_rel = age./(max(age,[],2)*ones([1,size(age,2)]));    
0281     time = ones([ss(1),1])*(1:ss(3));
0282     
0283     len_0_ind = grabClistIndex(clist, 'Long axis (L) birth');
0284     len_0 = clist.data(:,len_0_ind);
0285     len_1_ind = grabClistIndex(clist, 'Long axis (L) death');
0286     len_1 = clist.data(:,len_1_ind);
0287     age_ind = grabClistIndex(clist, 'Cell age');
0288     age = clist.data(:,age_ind);
0289     growth_rate = (log(len_1) - log(len_0)) ./ age;
0290     
0291 %     % add time
0292 %     clist = gateTool( clist, 'add3D', time, 'Time (Frames)' );
0293 %     % add age
0294 %      clist = gateTool( clist, 'add3D', age, 'Age (Frames)' );
0295 %    % add age_rel
0296 %     clist = gateTool( clist, 'add3D', age_rel, 'Relative Age' );
0297    %add growth rate
0298     clist = gateTool( clist, 'add', growth_rate, 'Growth Rate' );
0299     
0300 
0301     clist.gate = CONST.trackLoci.gate;
0302     clist.neighbor = [];
0303     
0304 
0305     if CONST.trackOpti.NEIGHBOR_FLAG
0306         clist.neighbor = trackOptiListNeighbor(dirname,CONST,[]);
0307     end
0308 end
0309 
0310 
0311 
0312 
0313 
0314 end
0315 
0316 
0317 function [setter,names_3dclist] = clistSetter ()
0318 % clistSetter : use this function to add new values to the clist
0319 % the first variable is the description, the second is the variabel to
0320 % which it will be set (needs to be calculated in the first function, and
0321 % the third is 0 if it is set at birth and 1 if it is set at death.
0322 % the fourth column is for whether the variable should be included in the 3d clist.
0323                         
0324 setter = [{'Cell ID'},{'ID'},0,1;
0325     {'Region num birth'},{'regnum'},0,0;
0326     {'Region num death'},{'regnum'},1,0;
0327     {'Cell birth time'},{'i + zz'},0,0;
0328     {'Cell death time'},{'i + zz'},1,0;
0329     {'Cell age'},{'i - data_c.regs.birth'},1,0;
0330     {'Old pole age'},{'pole_age'},0,0;
0331     {'Error frame'},{'error_frame'},1,0;
0332     {'stat0'},{'data_c.regs.stat0'},1,0;
0333     {'Long axis (L) birth'},{'data_c.regs.L1'},0,1;
0334     {'Long axis (L) death'},{'data_c.regs.L1'},1,0;
0335     {'Short axis birth'},{'data_c.regs.L2'},0,1;
0336     {'Short axis death'},{'data_c.regs.L2'},1,0;
0337     {'Area birth'},{'Area'},0,1;
0338     {'Area death'},{'Area'},1,0;
0339     {'Region score birth'},{'data_c.regs.scoreRaw'},0,0;
0340     {'Region score death'},{'data_c.regs.scoreRaw'},1,0;
0341     {'X position birth'},{'xpos'},0,0;
0342     {'Y position birth'},{'ypos'},0,0;
0343     {'Fluor1 sum'},{'fl1sum'},0,1;
0344     {'Fluor1 mean'},{'fl1sum./Area'},0,1;
0345     {'Fluor2 sum'},{'fl2sum'},0,1;
0346     {'Fluor2 mean'},{'fl2sum./Area'},0,1;
0347     {'Num of neighbors'},{'numNeighbors'},0,0;
0348     {'Region gray val'},{'gray'},0,0;
0349     {'Focus1(1) long axis birth'},{'locus1_L1'},0,1;
0350     {'Focus1(1) short axis birth'},{'locus1_L2'},0,1;
0351     {'Focus1(1) score birth'},{'locus1_s'},0,1;
0352     {'Focus1(1) intensity birth'},{'locus1_i'},0,1;
0353     {'Focus1(2) long axis birth'},{'locus2_L1'},0,1;
0354     {'Focus1(2) short axis birth'},{'locus2_L2'},0,1;
0355     {'Focus1(2) score birth'},{'locus2_s'},0,1;
0356     {'Focus1(2) intensity birth'},{'locus2_i'},0,1;
0357     {'Focus1(3) long axis birth'},{'locus3_L1'},0,0;
0358     {'Focus1(3) short axis birth'},{'locus3_L2'},0,0;
0359     {'Focus1(3) score birth'},{'locus3_s'},0,0;
0360     {'Focus1(3) intensity birth'},{'locus3_i'},0,0;
0361     {'Focus1(4) long axis birth'},{'locus4_L1'},0,0;
0362     {'Focus1(4) short axis birth'},{'locus4_L2'},0,0;
0363     {'Focus1(4) score birth'},{'locus4_s'},0,0;
0364     {'Focus1(4) intensity birth'},{'locus4_i'},0,0;
0365     {'Focus1(5) long axis birth'},{'locus5_L1'},0,0;
0366     {'Focus1(5) short axis birth'},{'locus5_L2'},0,0;
0367     {'Focus1(5) score birth'},{'locus5_s'},0,0;
0368     {'Focus1(5) intensity birth'},{'locus5_i'},0,0;
0369     {'Focus1(1) long axis pole align'},{'locus1_PoleAlign_L1'},0,1;
0370     {'Focus1(1) long axis norm pole align'},{'locus1_PoleAlign_relL1'},0,1;
0371     {'Focus1(1) long axis normalized'},{'locus1_relL1'},0,0;
0372     {'Focus1(2) long axis normalized'},{'locus2_relL1'},0,0;
0373     {'Focus1(3) long axis normalized'},{'locus3_relL1'},0,0;
0374     {'Focus1(4) long axis normalized'},{'locus4_relL1'},0,0;
0375     {'Focus1(5) long axis normalized'},{'locus5_relL1'},0,0;
0376     {'Focus1(1) short axis normalized'},{'locus1_relL2'},0,0;
0377     {'Focus1(2) short axis normalized'},{'locus2_relL2'},0,0;
0378     {'Focus1(3) short axis normalized'},{'locus3_relL2'},0,0;
0379     {'Focus1(4) short axis normalized'},{'locus4_relL2'},0,0;
0380     {'Focus1(5) short axis normalized'},{'locus5_relL2'},0,0;
0381     {'Focus1(1) gaussianFitWidth'},{'locus1_fitSigma'},0,0;
0382     {'Focus1(2) gaussianFitWidth'},{'locus2_fitSigma'},0,0;
0383     {'Focus1(3) gaussianFitWidth'},{'locus3_fitSigma'},0,0;
0384     {'Mother ID'},{'data_c.regs.motherID'},0,0;
0385     {'Daughter1 ID'},{'daughter1_id'},1,0;
0386     {'Daughter2 ID'},{'daughter2_id'},1,0;
0387     {'dL max'},{'dlmax'},1,0;
0388     {'dL min'},{'dlmin'},1,0;
0389     {'L death / L birth'},{'lrel'},1,0;
0390     {'Fluor1 sum death'},{'fl1sum'},1,0;
0391     {'Fluor1 mean death'},{'fl1sum./Area'},1,0;
0392     {'Fluor2 sum death'},{'fl2sum'},1,0;
0393     {'Fluor2 mean death'},{'fl2sum./Area'},1,0;
0394     {'Focus1(1) long axis death'},{'locus1_L1'},1,0;
0395     {'Focus1(1) short axis death'},{'locus1_L2'},1,0;
0396     {'Focus1(1) score death'},{'locus1_s'},1,0;
0397     {'Focus1(1) intensity death'},{'locus1_i'},1,0;
0398     {'Focus1(2) long axis death'},{'locus2_L1'},1,0;
0399     {'Focus1(2) short axis death'},{'locus2_L2'},1,0;
0400     {'Focus1(2) score death'},{'locus2_s'},1,0;
0401     {'Focus1(2) intensity death'},{'locus2_i'},1,0;
0402     {'Focus1(2) long axis death'},{'locus3_L1'},1,0;
0403     {'Focus1(3) short axis death'},{'locus3_L2'},1,0;
0404     {'Focus1(3) score death'},{'locus3_s'},1,0;
0405     {'Focus1(3) intensity death'},{'locus3_i'},1,0;
0406     {'Focus1(4) long axis death'},{'locus4_L1'},1,0;
0407     {'Focus1(4) short axis death'},{'locus4_L2'},1,0;
0408     {'Focus1(4) score death'},{'locus4_s'},1,0;
0409     {'Focus1(4) intensity death'},{'locus4_i'},1,0;
0410     {'Focus1(5) long axis death'},{'locus5_L1'},1,0;
0411     {'Focus1(5) short axis death'},{'locus5_L2'},1,0;
0412     {'Focus1(5) score death'},{'locus5_s'},1,0;
0413     {'Focus1(5) intensity death'},{'locus5_i'},1,0;
0414     {'Focus1(1) gaussian fit width death'},{'locus1_fitSigma'},1,0;
0415     {'Focus1(2) gaussian fit width death'},{'locus2_fitSigma'},1,0;
0416     {'Focus1(3) gaussian fit width death'},{'locus3_fitSigma'},1,0;
0417     {'Long axis/Short axis birth'},{'longOverShort'},0,0;
0418     {'Long axis/Short axis death'},{'longOverShort'},1,0;
0419     {'Neck width'},{'neckWidth'},0,0;
0420     {'Maximum width'},{'maxWidth'},0,0;
0421     {'Cell dist to edge'},{'cell_dist'},1,0;
0422     ];
0423 
0424 
0425 % used to add numbers in front of the description
0426 names_3dclist = [];
0427 counter = 0;
0428 for i = 1 : size(setter,1)
0429     fieldname = setter{i,1};
0430     nameWithNum = [num2str(i), ' : ',fieldname];
0431     setter(i,1) = {nameWithNum};
0432     if setter{i,4}
0433         counter = counter + 1;
0434         removeBirth  =strfind(fieldname,'birth');
0435         if removeBirth > 0
0436             fieldname = fieldname (1 :removeBirth-1);
0437         end
0438         names_3dclist{counter} = [num2str(counter), ' : ', fieldname];
0439     end
0440 end
0441 
0442 
0443 
0444 end
0445 
0446 
0447 function vector = convertToColumn (vector)
0448 % convertToColumn : converts vector to column vector if row vector
0449     if size(vector,1) == 1
0450         vector = vector';
0451     end
0452 end
0453 
0454 function data = loaderInternal( filename )
0455 data = load(filename);
0456 end

Generated on Thu 19-Jan-2017 13:55:21 by m2html © 2005