bugGNU Octave - Bugs: bug #51388, Current directory does not change...

 
 

bug #51388: Current directory does not change immediatly with "cd" on some systems

Submitted by:  Markus Mützel <mmuetzel>
Submitted on:  Wed 05 Jul 2017 09:23:41 AM UTC  
 
Category:  Octave Function Severity:  3 - Normal
Priority:  5 - Normal Item Group:  Unexpected Error
Status:  Invalid Assigned to:  None
Originator Name:  Open/Closed:  Closed
Release:  dev Operating System:  Microsoft Windows

Add a New Comment (Rich Markup)
   

You are not logged in

Please log in, so followups can be emailed to you.

 

( Jump to the original submission)

Mon 17 Jul 2017 10:27:00 AM UTC, comment #34: 

@Markus
Thank you too.
An any dialog is benefit for me :-)

Andrey Aleshin Igorevich <iamandreyaleshin>
Mon 17 Jul 2017 10:22:33 AM UTC, comment #33: 

Thank you, Andrey.
So it very much looks like there is nothing wrong with "cd". I think we can close this report as invalid.
Sorry for the commotion.

Markus Mützel <mmuetzel>
Project Member
Mon 17 Jul 2017 09:44:02 AM UTC, comment #32: 

@Markus:

Elapsed time is 18.213 seconds. And no more is nothing. Empty command window

Regards

Andrey Aleshin Igorevich <iamandreyaleshin>
Mon 17 Jul 2017 08:43:45 AM UTC, comment #31: 

Thank you, Andrey. Together with your results from your latest tests in bug #51203, it looks like "cd" is working as expected. There might still be a small chance that something is off when calling "cd" just before spawning a sub-process with "system".
Can you run the following script and report whether it gives any output for you?

d1='C:\05octave\1';
d2='C:\05octave\2';

for i = 1:200
  cd (d1)
  [~, scd] = system ("cd");
  while ~strncmpi (d1, scd, length(d1))
    warning ('bug triggered');
    cd (d1)
  endwhile
  cd (d2)
  [~, scd] = system ("cd");
  while ~strncmpi (d2, scd, length(d2))
    warning ('bug triggered');
    cd (d2)
  endwhile
endfor

Markus Mützel <mmuetzel>
Project Member
Mon 17 Jul 2017 08:20:27 AM UTC, comment #30: 

@Markus

Here
I took cwdtest.cc from com16

I opened Octave, launched "mkoctfile cwdtest.cc", received "cwdtest.o
cwdtest.oct".

Then:
d1='C:\05octave\1'
d2='C:\05octave\2'

I'm launched
cwdtest(d1,d2)
and I not saw nothing

I'm sorry

Andrey Aleshin Igorevich <iamandreyaleshin>
Mon 17 Jul 2017 04:40:34 AM UTC, comment #29: 

@Dear Markus:
I compiled: mkoctfile cwdtest.cc. from 51388 com16:
d1='C:\05octave\1\'
d2='C:\05octave\2\'

"more off", "launched" - no even 1 message or result. I'm don't see nothing.

Andrey Aleshin Igorevich <iamandreyaleshin>
Sat 15 Jul 2017 03:39:37 PM UTC, comment #28: 

Changing the status back to "works for me" since it seems so far like changing the directory works correctly. It could be the premise that this bug was opened on is false, maybe it has nothing to do with changing the directory, but rather that the zip/unzip programs think they are done while the operating system hasn't allowed the files to appear in the destination path.

Mike Miller <mtmiller>
Project Administrator
Fri 14 Jul 2017 08:16:15 PM UTC, comment #27: 

Thank you, Philip. That might indeed be a good idea. Going back through the files I sent Andrey for bug #51203, I am no longer sure that the loop was actually necessary. Although it seemed to have notably reduced the frequency of the error, we still had to let InfoZip compress to the temporary directory and move the resulting file with "movefile" for it to work reliably. We never tried without the loop afterwards. Sorry for not realizing earlier.
I am going to upload a modified patch without the loop to bug #51203. If you can reproduce the original issue on your computer, maybe you could try with that patch.

Markus Mützel <mmuetzel>
Project Member
Fri 14 Jul 2017 07:42:16 PM UTC, comment #26: 

Yes Mike, IMO the whole issue is related to zip/infozip and cwd, and maybe even specific for the io package, who knows.

The point to start is the patch in bug #51203 comment #53 (the
while ! strcmpi(opwd, pwd)
  :
loop.)

Having cleaned up some big distractions lately I can finally turn back to the io package stuff where the whole issue was initiated. I'll see if I can book any progress with it this weekend.

Philip Nienhuis <philipnienhuis>
Project Member
Fri 14 Jul 2017 07:24:23 PM UTC, comment #25: 

Right. So now we are back to how to create a simple reproducible example of what this bug is about. So far it appears that when the chdir function returns, the working directory has been changed successfully, and we have no evidence that anything is wrong here. But in bug #51203, it appeared like the zip or unzip subprocess was working in two different directories after Octave had supposedly changed the working directory.

Mike Miller <mtmiller>
Project Administrator
Fri 14 Jul 2017 06:13:00 PM UTC, comment #24: 

(I knew that little note of me it would induce confusing)

The subject is drifting towards file name comparison, fine, yet the actual issue is rather that cd apparently takes so long to have effect on some systems. Or at least, that was inferred from bug #51203.

As to the point of string comparison:

@Markus:
The code in comment #2 works fine with backward slash and fails with forward slash.
The same results with changing strcmpi to strcmp
But see below.

Here's amended code from comment #2 and the results:

somedirectory1 = 'c:/tmp'
somedirectory2 = 'f:/tmp'

for i = 1:200
  cd (somedirectory1)
  while ~strcmp (somedirectory1, pwd)
    warning ('bug triggered  %s  <->  %s', somedirectory1, pwd);
    cd (somedirectory1)
  endwhile
  cd (somedirectory2)
  while ~strcmp (somedirectory2, pwd)
    warning ('bug triggered  %s  <->  %s', somedirectory2, pwd);
    cd (somedirectory2)
  endwhile
endfor

giving:

:
warning: bug triggered  c:/tmp  <->  c:\tmp
warning: bug triggered  c:/tmp  <->  c:\tmp
:
(repeated and repeated)

so the code in comment #2 isn't really useful for testing as-is because the fileseps are morphed by MSYS/MinGW into the default backslash.
Changing it into:

somedirectory1 = 'c:\tmp'
somedirectory2 = 'f:\tmp'

for i = 1:200
  cd (somedirectory1)
  while ~strcmp (strrep (somedirectory1, '/', '\'), pwd)
    warning ('bug triggered  %s  <->  %s', somedirectory1, pwd);
    cd (somedirectory1)
  endwhile
  cd (somedirectory2)
  while ~strcmp (strrep (somedirectory2, '/', '\'), pwd)
    warning ('bug triggered  %s  <->  %s', somedirectory2, pwd);
    cd (somedirectory2)
  endwhile
endfor

works fine with any file separator (no bugs triggered).
So I'm tempted to conclude that cd seems to work fine.

Back to cd working slowly? and how to verify that?

Philip Nienhuis <philipnienhuis>
Project Member
Fri 14 Jul 2017 04:44:50 PM UTC, comment #23: 

That could indeed have been the case: "pwd" always returns the path with the default filesep "\".
Philip, does the test in comment #2 fail for you if you use backslash "\" as the directory separator?

Andrey reported that neither the code in comment #2 nor comment #10 gave an error for him. He got the same error as jwe for the code in comment #11.

Markus Mützel <mmuetzel>
Project Member
Fri 14 Jul 2017 03:27:38 PM UTC, comment #22: 

The original m code snippet in comment #2 was using strcmpi, and was reported to be failing as well.

Now I have to wonder if the original loop was failing because cd was given a path that had one type of slash, but pwd reports the working directory with a different kind of slash.

All of which is very confusing, but nothing indicating that cd isn't working yet.

Mike Miller <mtmiller>
Project Administrator
Fri 14 Jul 2017 03:24:19 PM UTC, comment #21: 

On Windows, / and \ are both accepted as directory separators, but won't compare equal if we just do string comparisons.

Maybe we need "same_file" or "same_directory" functions?

Oh, we do have a same_file function.  It doesn't look at the names, but uses stat (or the Windows equivalent) and checks inodes and device ids.  The idea was to know whether two links (hard or symbolic) refer to the same file.

John W. Eaton <jwe>
Project Administrator
Fri 14 Jul 2017 03:16:32 PM UTC, comment #20: 

It also failed when I ran it on a Windows systems.  Then I added a couple of lines to show what directory names were being compared:

--- cwdtest.cc~        2017-07-14 10:42:38.406610572 -0400
+++ cwdtest.cc        2017-07-14 11:10:25.000259589 -0400
@@ -93,6 +93,9 @@
           std::string new_pwd = octave::sys::env::get_current_directory ();
           new_pwd = octave::sys::canonicalize_file_name (new_pwd);

+          std::cerr << "new: " << new_pwd << std::endl;
+          std::cerr << "old: " << dir << std::endl;
+
           while (new_pwd != dir)
             {
               num_failures++;

and in my case, it was failing like this:

>> cwdtest c:\users\jwe z:\downloads
new: C:\Users\jwe
old: c:\users\jwe
cwdtest: FAIL getcwd != destdir

Those are really the same directory, but the strings obviously don't compare equal.

John W. Eaton <jwe>
Project Administrator
Fri 14 Jul 2017 02:51:30 PM UTC, comment #19: 

What do you mean about the file separator making a difference? If you use one kind of slash this problem does not occur but it does with the other?

I can upload a new version of cwdtest to print the path names that appear to not be equal after changing directory, that might illuminate whether it's the directory that is not changing or if there is some file separator issue going on here.

The wchdir test might be interesting as well.

Mike Miller <mtmiller>
Project Administrator
Fri 14 Jul 2017 02:44:51 PM UTC, comment #18: 

Mike,
I did not get any message with your cwdtest from comment #16 on Windows (hg id 528b124e337f). But I could never replicate the problem in the first place (neither with the io-example nor with the loop in comment #2).

Philip,
amongst other things, the patch in bug #49118 changes "chdir" to use the wchar_t API on Windows. I wonder whether that would change anything for the issue here.
Are you willing to try with that patch?
It doesn't apply on a recent tip at the moment. I will refresh it and ping you here again when it is ready.

Markus Mützel <mmuetzel>
Project Member
Fri 14 Jul 2017 01:54:53 PM UTC, comment #17: 

After renaming cwdtest-1.cc to cwdtest.cc and building with mkoctfile, I get

>> cwdtest ('c:/tmp', 'f:/tmp')
cwdtest: FAIL getcwd != destdir
cwdtest: FAIL getcwd != destdir
cwdtest: FAIL getcwd != destdir
cwdtest: FAIL getcwd != destdir
cwdtest: FAIL getcwd != destdir
cwdtest: FAIL getcwd != destdir
cwdtest: FAIL getcwd != destdir
cwdtest: FAIL getcwd != destdir
cwdtest: FAIL getcwd != destdir
cwdtest: FAIL getcwd != destdir
cwdtest: FAIL getcwd != destdir
cwdtest: FAIL getcwd != destdir
cwdtest: FAIL getcwd != destdir
:

(repeated seemingly indefinitely, I just hit Ctrl-C)

This is with a cross-built 4.3.0+ hg id 58cb2f52ce67 ("maint: Periodic merge of stable to default.") on Win7 Prof. 64-bit.

Note:
Specifying forward or backward slash as filesep (in SQ string filenames) makes no difference for cwdtest.oct.
However, that does make a difference in the code in comment #2.

Philip Nienhuis <philipnienhuis>
Project Member
Thu 13 Jul 2017 12:36:23 AM UTC, comment #16: 

Second version, first version was a bit buggy. Second revision actually sets the two directories correctly. Also allows you to interrupt in case it takes a long time for some reason, the working directory should always be restored to where you started from, interrupt or not. And a third argument is allowed to control the number of iterations.

>> cwdtest /usr/lib /home/mike
>> cwdtest ("/usr/lib", "/home/mike/src", 1e6);

(file #41196)

Mike Miller <mtmiller>
Project Administrator
Wed 12 Jul 2017 08:19:51 PM UTC, comment #15: 

Philip or Markus - please try the attached oct file. It's a C++ port of Markus' loop example.

If the oct file returns silently with no messages printed on stderr, then chdir and getcwd are completely consistent as we expect.

If the m file loop failed to change the directory, then this oct file should fail as well.

On my system:

>> cwdtest /usr/lib /usr/share
>> ## success

You should be able to pass it either absolute or relative paths.

When I run it under strace here, I can see that the system library functions chdir and getcwd are called back to back within microseconds of each other and are always consistent over thousands of test iterations.

(file #41195)

Mike Miller <mtmiller>
Project Administrator
Thu 06 Jul 2017 07:44:30 PM UTC, comment #14: 

@Mike comment #9 - I only used the inline code.

Then:
"_According to Philip, all affected systems have SSDs_"
To be precise, all affected systems I saw have fast HDDs or SSDs. I noted it first when at work I got a very fast desktop PC some 4 years ago, at that time fitted with a very fast HDD (SATA).
On my old multiboot laptop with a Pentium M and PATA (IDE) HDD I never saw this bug happen.

It's correct that "not all systems with SSD are affected" - on my multiboot laptop (core i5 with an SSD), the bug shows up running Windows 7, but not while running Linux.

FWIW, I only saw this bug/behavior when invoking the zip/unzip functions.  And as I told Markus in bug #51203, LibreOffice (invoked from Octave through the Java-UNO bridge) also seems affected although AFAIK that invokes its own built-in zip/unzip routines. But that does not have to be the same issue, it can be another (L.O.) issue with the same effects.

Philip Nienhuis <philipnienhuis>
Project Member
Thu 06 Jul 2017 12:35:38 PM UTC, comment #13: 

On Windows, programs called with "system" run synchronously. When I run the following command, the Octave command line is blocked until I close notepad:

system ('C:\Windows\notepad.exe')

Interestingly, when I run the following command, the command line is still blocked in Octave. In Matlab, notepad executes asynchronously:

system ('C:\Windows\notepad.exe &')

But that is probably just a compatibility issue.

I will try and summarize what we tested for bug #51203 (leaving out the dead ends but still quite long. Sorry.):

Calling the test script attached to comment #2, sometimes unexpected files and folders appeared in the current directory on some systems. These files and folders turned out to be the unpacked content of an xlsx template file.
xlswrite uses the Octave function "unpack" to un-zip the template to a temporary folder (called in io's "__OCT_spsh_open__.m"). It turns out that "unpack" lets InfoZip "unzip" decompress to the current directory. Thus it has to change directories before calling "unzip". Somehow, the following lines in "unpack" did not work as expected ("dir" being a temporary directory passed from io - interesting choice of variable name ;-) ):

  unwind_protect
    cd (dir);
    [status, output] = system (sprintf ([command " 2>&1"], file));
  unwind_protect_cleanup
    cd (origdir);
  end_unwind_protect

The files were unzipped to the cwd before the "cd (dir)" command.
Calling "unzip" directly (instead of "unpack") to unzip the template file to the temporary folder (without cd'ing to it) did prevent that.

However, at that point the xlsx file was still missing sometimes. The cause was: InfoZip "zip" is called from io's "__OCT_spsh_close__.m". It turns out that it is necessary to change to the temporary folder to have the correct relative directory structure inside the resulting zip file. The symptoms were the same: Sometimes zip executed as if the cwd was still the directory before cd'ing to the temporary folder. Thus, it could not find the files to compress.
The following construct helped to prevent that:

      while ! strcmpi(xls.workbook, pwd)
        cd (xls.workbook);
            pause (0.05);
      endwhile

That is probably what Mike led to suspect that something might be wrong with "cd". (I think that he may be right.)

The only thing that was still necessary to make xlswrite succeed even in 2000 loops of the test script on Andrey's affected system, was to let "zip" compress to the current directory (the temporary directory) and move the file to the destination directory afterwards. (No "pause" necessary there any more.)

For what I can tell, it looks like "cd" returns before the directory has actually changed on some systems ("cd" running async?).

According to Philip, all affected systems have SSDs. But not all systems with SSDs are affected. I could not reproduce on the two systems I have access to (both with SSDs).

I hope that helps analyzing the behavior.

Markus Mützel <mmuetzel>
Project Member
Wed 05 Jul 2017 11:10:38 PM UTC, comment #12: 

I was the one who suggested in bug #51203 "Do we need to fix cd / chdir?" which is how we got here. I have no idea how it was determined that this while-strcmp-pwd-cd loop was necessary, but according to those who were investigating bug #51203, it is for some users on some systems. It's still not clear to me whether it's really a bug in the chdir / getcwd library calls, or whether it's some interaction with Octave and zip / unzip, or something else.

We need someone with Windows who is affected by bug #51203 to drill down and determine whether something is really wrong with the state of chdir / getcwd or not.

It doesn't look to me like zip and unzip are being called asynchronously, unless every system() call in Windows is async.

Mike Miller <mtmiller>
Project Administrator
Wed 05 Jul 2017 10:24:01 PM UTC, comment #11: 

For an example of something that will likely fail often, and that will serve as an example of what I'm talking about, try this example.  It fails immediately with the "file not created" message on my Debian system:

more off

filename = [mfilename('fullpath'), '.xlsx'];
for i= 1:10000
  if exist(filename, "file")==2
    delete(filename);
  end
  if exist(filename, "file")==2
    error ("File NOT deleted!, i = %d", i);
  end
  t_xlsx = tic;
  system (sprintf ("touch %s", filename), false, "async");
  toc (t_xlsx)
  if !exist (filename)
    error ("xlsx file NOT created!, i = %d", i);
  endif
endfor

Adding a delay after the call to system will probably allow it to work more often, depending on the length of the delay.  But this is clearly an interprocess race condition and not a bug in Octave.

Is it possible this is the kind of thing that is happening with xlswrite?  Is the writing and closing of the file happening directly in Octave code (a DEFUN function or .m code) or is it happening in some external process that may not actually create before xlswrite returns?

John W. Eaton <jwe>
Project Administrator
Wed 05 Jul 2017 10:16:34 PM UTC, comment #10: 

I didn't notice the attached file earlier.  I used the code in the inline code block.

If it is the attached file that shows the problem for you, then I don't understand why you are blaming cd.  Where is the cd in that?

Is the problem that the file that xlswrite is supposed to produce is not created before the call to exist?  If so, how is xlswrite creating the file on the systems where it fails?  Is it using some external process that might not be flushing the file contents before it returns?

Can you reproduce the problem if you use fopen/fwrite/fclose instead?  For example, something like this:

more off

filename = [mfilename('fullpath'), '.xlsx'];
for i= 1:10000
  if exist(filename, "file")==2
    delete(filename);
  end
  if exist(filename, "file")==2
    error ("File NOT deleted!, i = %d", i);
  end
  t_xlsx = tic;
  fid = fopen (filename, "w");
  fwrite (fid, rand (100));
  fclose (fid);
  toc (t_xlsx)
  if !exist (filename)
    error ("xlsx file NOT created!, i = %d", i);
  endif
endfor

John W. Eaton <jwe>
Project Administrator
Wed 05 Jul 2017 09:49:32 PM UTC, comment #9: 

Philip - the code in the attachment posted in comment #2 or the inline code block that doesn't require the io package?

Can you give an example of somedirectory1 and somedirectory2, what their contents look like?

Mike Miller <mtmiller>
Project Administrator
Wed 05 Jul 2017 09:27:54 PM UTC, comment #8: 

The code in comment #2 reliably triggers the bug on Windows 7. Trying on Linux (on the same multiboot box) does not trigger it.

So apparently it is mingw that is severely affected.

Philip Nienhuis <philipnienhuis>
Project Member
Wed 05 Jul 2017 08:02:36 PM UTC, comment #7: 

I'm unable to see any problem with the test code from comment #2 when running in the GUI or with octave-cli with the current development version of Octave (hg id 85f1d31956c0).  For the test, I created two directories, /tmp/dir1 and /tmp/dir2, each with 1000 subdirectories.

I'd be glad to look at this problem if someone can create a test case that I can use to reproduce it.

John W. Eaton <jwe>
Project Administrator
Wed 05 Jul 2017 05:43:13 PM UTC, comment #6: 

CC'ing Andrey: Can you trigger the issue in bug #51203 when you run the test script from the CLI?

Markus Mützel <mmuetzel>
Project Member
Wed 05 Jul 2017 05:11:47 PM UTC, comment #5: 

If this problem occurs inside of a block of code, a script, or a function, then it seems less likely that it is related to the GUI. The GUI current directory state is only updated when control is returned to the interactive prompt.

Calling cd and pwd in a loop in a script or function should not have any interaction with the GUI state. It's possible that the fact of the GUI running has some incidental impact on the overall state of the system, but there should be no additional code delays or race conditions due to the GUI running while this loop is trying to change the working directory.

Mike Miller <mtmiller>
Project Administrator
Wed 05 Jul 2017 04:28:45 PM UTC, comment #4: 

An observation that may play a role here is that in the GUI, heavily populated directories sometimes take ages to be shown in the File Browser pane.

But admittedly I never checked/verified that in the CLI - could well be as bad, and in fact that's what I expect - the GUI itself isn't that slow.

Philip Nienhuis <philipnienhuis>
Project Member
Wed 05 Jul 2017 02:08:51 PM UTC, comment #3: 

Forgot to mention: The bug is only triggered for Andrey if he created many folders in the working dir (system ("mkdir 1 2 3 4 5 6 7 8 9")) before running the test.

Markus Mützel <mmuetzel>
Project Member
Wed 05 Jul 2017 02:00:38 PM UTC, comment #2: 

Attached is a test case that is very specific to the io package. It triggers the bug quite reliably for Andrey (without the patch in bug #51203). I will try to narrow it down to a more generic one. But something like this might trigger the bug as well:

for i = 1:200
  cd (somedirectory1)
  while ~strcmpi (somedirectory1, pwd)
    warning ('bug triggered');
    cd (somedirectory1)
  endwhile
  cd (somedirectory2)
  while ~strcmpi (somedirectory2, pwd)
    warning ('bug triggered');
    cd (somedirectory2)
  endwhile
endfor

It might be possible that it is more likely to trigger under load (as in [de-]compressing a file with InfoZip).

(file #41125)

Markus Mützel <mmuetzel>
Project Member
Wed 05 Jul 2017 12:47:18 PM UTC, comment #1: 

Markus,

There are numerous examples in the io package but they are a bit hidden (see e.g., the various pause statements in io_xls_testscript.m, io_ods_testscript.m and test_spsh.m functions in the io package).

IIUC you made a test case or test script with Andrey - could you share that?

Philip Nienhuis <philipnienhuis>
Project Member
Wed 05 Jul 2017 09:23:41 AM UTC, original submission:  

The issue originally reported in bug #51203 could be tracked down to "cd" returning before the current working directory (cwd) has actually changed.
As Mike suggested there, "cd" must not return before the cwd has actually changed.

Philip said that the issue was present on other systems as well (non-Windows systems also affected?).

The issue is, I cannot reproduce the "cd-sluggishness" on any PC I have direct access to and was relying on Andrey (iamandreyaleshin) to repeatedly check modified m-files. It is slightly more complicated when it comes to functions in core Octave that are implemented in C++.
Can anyone, who knows how to compile and cross-compile Octave, reliably reproduce the issue?

Markus Mützel <mmuetzel>
Project Member

 

(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attach Files:
   
   
Comment:
   

Attached Files
file #41196:  cwdtest.cc added by mtmiller (4KiB - text/x-c++src)
file #41125:  o076xls_with_check.m added by mmuetzel (517B - application/octet-stream)

 

Depends on the following items: None found

Items that depend on this one: None found

 

Carbon-Copy List
  • -email is unavailable- added by iamandreyaleshin (Posted a comment)
  • -email is unavailable- added by jwe (Posted a comment)
  • -email is unavailable- added by mmuetzel
  • -email is unavailable- added by mtmiller (Posted a comment)
  • -email is unavailable- added by mmuetzel (Submitted the item)
  • -email is unavailable- added by mmuetzel
  • -email is unavailable- added by mmuetzel
  •  

    Do you think this task is very important?
    If so, you can add your encouragement to it.
    This task has 0 encouragements so far.

    Only project members can vote.

     

     

     

    Follow 10 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2017-07-17 mmuetzel StatusWorks For Me => Invalid
        Open/ClosedOpen => Closed
    2017-07-15 mtmiller StatusConfirmed => Works For Me
    2017-07-13 mtmiller Attached File#41195 => Removed
    2017-07-13 mtmiller Attached File- => Added cwdtest.cc, #41196
    2017-07-12 mtmiller Attached File- => Added cwdtest.cc, #41195
    2017-07-05 mmuetzel Carbon-Copy- => Added iamandreyaleshin
    2017-07-05 mmuetzel Attached File- => Added o076xls_with_check.m, #41125
    2017-07-05 mmuetzel Carbon-Copy- => Added mtmiller
        Carbon-Copy- => Added philipnienhuis

    Back to the top


    Powered by Savane 3.5