Commit:    d718fd0f726cc04289b74f3a7ec3466d0a79ad9b
Author:    Matt Ficken <mattfic...@php.net>         Wed, 20 Jun 2018 19:36:17 
-0700
Parents:   a6b3e5b47bdd498fb3255059de6b2425a3ba7f58
Branches:  master

Link:       
http://git.php.net/?p=pftt2.git;a=commitdiff;h=d718fd0f726cc04289b74f3a7ec3466d0a79ad9b

Log:
updates for Azure App Services, Nanoserver and other changes

Changed paths:
  A  bin/NanoServerApiScan.exe
  A  src/com/mostc/pftt/model/ApplicationSourceTestPack.java
  A  src/com/mostc/pftt/model/app/AppUnitTestCase.java
  A  src/com/mostc/pftt/model/sapi/GenericWebServerManager.java
  A  src/com/mostc/pftt/runner/AbstractApplicationUnitTestCaseRunner.java
  A  src/com/mostc/pftt/runner/CliSimpleTestCaseRunner.java
  A  src/com/mostc/pftt/runner/HttpSimpleTestCaseRunner.java
  A  src/com/mostc/pftt/runner/LocalSimpleTestPackRunner.java

diff --git a/bin/NanoServerApiScan.exe b/bin/NanoServerApiScan.exe
new file mode 100644
index 0000000..4fbbea9
Binary files /dev/null and b/bin/NanoServerApiScan.exe differ
diff --git a/src/com/mostc/pftt/model/ApplicationSourceTestPack.java 
b/src/com/mostc/pftt/model/ApplicationSourceTestPack.java
new file mode 100644
index 0000000..ce4a290
--- /dev/null
+++ b/src/com/mostc/pftt/model/ApplicationSourceTestPack.java
@@ -0,0 +1,155 @@
+package com.mostc.pftt.model;
+
+import java.io.File;
+import java.io.IOException;
+
+import javax.annotation.Nullable;
+
+import com.github.mattficken.Overridable;
+import com.github.mattficken.io.StringUtil;
+import com.mostc.pftt.host.AHost;
+import com.mostc.pftt.host.LocalHost;
+import com.mostc.pftt.model.core.EBuildBranch;
+import com.mostc.pftt.results.ConsoleManager;
+import com.mostc.pftt.scenario.AzureWebsitesScenario;
+import com.mostc.pftt.scenario.FileSystemScenario;
+import com.mostc.pftt.scenario.SAPIScenario;
+
+public abstract class ApplicationSourceTestPack<A extends ActiveTestPack, T 
extends TestCase> extends SourceTestPack<A,T> {
+       protected String test_pack_root;
+       
+       /** installs the tests after they have been copied to storage (if 
needed)
+        * 
+        * @see #getRoot() returns the location the tests and their php files 
have been copied to (if they were
+        * copied, if not copied, returns location they are stored at)
+        * 
+        * @param cm
+        * @param host
+        * @return
+        * @throws Exception
+        */
+       protected abstract boolean openAfterInstall(ConsoleManager cm, AHost 
host) throws Exception;
+       
+       /** the base directory within the PFTT directory to find the test case 
files and required php files
+        * 
+        * Typically, test-packs will call #ensureAppDecompressed
+        * 
+        * @param cm
+        * @param host - determine the absolute path on this host
+        * @see AHost#getPfttDir
+        * @return
+        */
+       protected abstract String getSourceRoot(ConsoleManager cm, AHost host);
+       
+       protected void doInstallInPlace(ConsoleManager cm, AHost host) throws 
IOException, Exception {
+               final String src_root = getSourceRoot(cm, 
LocalHost.getInstance());
+               if (!new File(src_root).isDirectory()) {
+                       throw new IOException("source-test-pack not found: 
"+src_root);
+               }
+               setRoot(src_root);
+               
+               openAfterInstall(cm, host);
+       }
+       
+       protected void doInstallNamed(ConsoleManager cm, AHost host) throws 
IOException, Exception {
+               final String src_root = getSourceRoot(cm, 
LocalHost.getInstance());
+               if (!new File(src_root).isDirectory()) {
+                       throw new IOException("source-test-pack not found: 
"+src_root);
+               }
+               setRoot(src_root);
+               
+               openAfterInstall(cm, host);
+       }
+       
+       protected void doInstall(SAPIScenario sapi_scenario, ConsoleManager cm, 
AHost host, String local_test_pack_dir, String remote_test_pack_dir) throws 
IOException, Exception {
+               LocalHost local_host = LocalHost.getInstance();
+               final String src_root = getSourceRoot(cm, local_host);
+               if (!new File(src_root).isDirectory()) {
+                       throw new IOException("source-test-pack not found: 
"+src_root);
+               }
+               
+               // using #uploadCompressWith7Zip instead of just #upload makes 
a huge difference
+               // for PhpUnit test-packs because of the large number of small 
files that have to be uploaded
+               // TODO temp azure host.uploadCompressWith7Zip(cm, getClass(), 
src_root, local_host, remote_test_pack_dir);
+               System.out.println("71 "+local_test_pack_dir);
+               //System.exit(0);
+               
+               if (AzureWebsitesScenario.check(sapi_scenario)) {
+                       
setRoot("D:\\HOME\\SITE\\WWWROOT\\"+FileSystemScenario.basename(getName()).replace("-12.3",
 "").replace("-1.20.2", ""));//MEDIAWIKI");//local_test_pack_dir);
+               } else {
+                       setRoot(src_root);// TODO temp azure ?? 
local_test_pack_dir);
+               }
+               
+               openAfterInstall(cm, local_host);
+       }
+       
+       private boolean decompressed = false;
+       protected void ensureAppDecompressed(ConsoleManager cm, AHost host, 
String zip7_file) throws IllegalStateException, IOException, Exception {
+               if (decompressed)
+                       return;
+               decompressed = true;
+               if (!StringUtil.endsWithIC(zip7_file, ".7z"))
+                       zip7_file += ".7z";
+               
+               // TODO temp azure host.decompress(cm, host, 
host.getPfttDir()+"/app/"+zip7_file, host.getPfttDir()+"/cache/working/");
+       }
+       
+       /** Sometimes there are multiple tests that share a common resource 
(such as a file directory
+        * or database) and can not be run at the same time. Such tests are 
non-thread-safe (known as NTS tests).
+        * 
+        * Return the full or partial filenames of NTS tests here. The returned 
array is processed in
+        * order. If any string from the same string array matches, all tests 
matching that array will
+        * be run in the same thread.
+        * 
+        * @return
+        */
+       @Nullable
+       public String[][] getNonThreadSafeTestFileNames() {
+               return null;
+       }
+       
+       public String getName() {
+               return getNameAndVersionString();
+       }
+       
+       /** file path to test-pack */
+       public void setRoot(String test_pack_root) {
+               this.test_pack_root = test_pack_root;
+       }
+       @Override
+       public String getSourceDirectory() {
+               return getRoot();
+       }
+       /** file path to test-pack */
+       public String getRoot() {
+               return this.test_pack_root;
+       }
+       
+       /** TRUE if test-pack is 'under development'. FALSE if its stable.
+        * 
+        * test runner will include extra info(stack traces, etc...) for 
test-packs that are under development
+        * 
+        * @return
+        */
+       @Overridable
+       public boolean isDevelopment() {
+               return false;
+       }
+       
+       @Override
+       public EBuildBranch getTestPackBranch() {
+               return null;
+       }
+       
+       @Override
+       public String getTestPackVersionRevision() {
+               return getNameAndVersionString();
+       }
+       
+       @Override
+       public String toString() {
+               return getName();
+       }
+       
+} // end public abstract class ApplicationSourceTestPack
+ 
\ No newline at end of file
diff --git a/src/com/mostc/pftt/model/app/AppUnitTestCase.java 
b/src/com/mostc/pftt/model/app/AppUnitTestCase.java
new file mode 100644
index 0000000..707620c
--- /dev/null
+++ b/src/com/mostc/pftt/model/app/AppUnitTestCase.java
@@ -0,0 +1,77 @@
+package com.mostc.pftt.model.app;
+
+import com.github.mattficken.io.StringUtil;
+import com.mostc.pftt.model.TestCase;
+import com.mostc.pftt.scenario.FileSystemScenario;
+
+public abstract class AppUnitTestCase extends TestCase {
+       protected final String rel_filename, abs_filename;
+       
+       public AppUnitTestCase(String rel_filename, String abs_filename) {
+               this.rel_filename = rel_filename;
+               // don't need to call #normalizeFilename here usually. it's 
called in PhpUnitSourcetestPack#readDir...
+               // calling it (again )here would be a performance hit
+               this.abs_filename = abs_filename;
+       }
+
+       public boolean fileNameStartsWithAny(String[] ext_names) {
+               return StringUtil.startsWithAnyIC(getFileName(), ext_names);
+       }
+       
+       /** name of file.
+        * 
+        * file is case preserved to avoid breaking posix.
+        * 
+        * windows slashes \\ are standardized to / posix.
+        * 
+        * for case-insensitive matching @see #isFileName or @see 
#fileNameStartsWithAny
+        * 
+        * @return
+        */
+       public String getFileName() {
+               return rel_filename;
+       }
+       
+       public String getAbsoluteFileName() {
+               return abs_filename;
+       }
+       
+       public boolean isFileName(String file_name) {
+               return 
this.rel_filename.toLowerCase().equals(file_name.toLowerCase()) 
+                               || 
this.abs_filename.toLowerCase().equals(file_name.toLowerCase());
+       }
+       
+       @Override
+       public String toString() {
+               return getName();
+       }
+       
+       @Override
+       public boolean equals(Object o) {
+               if (o==this)
+                       return true;
+               else if (o instanceof AppUnitTestCase) 
+                       return o.toString().equals(this.toString());
+               else
+                       return false;
+       }
+       
+       @Override
+       public int hashCode() {
+               return getName().hashCode();
+       }
+       
+       /** fixes slashes to Posix forward slash /.
+        * 
+        * this is case-preserving (to avoid breaking on posix). case is not 
changed.
+        * 
+        * to do case-insenstive matching @see #isFileName
+        * 
+        * @param test_name
+        * @return
+        */
+       public static String normalizeFileName(String test_name) {
+               return FileSystemScenario.toUnixPath(test_name);
+       }
+       
+} // end public abstract class AppUnitTestCase
diff --git a/src/com/mostc/pftt/model/sapi/GenericWebServerManager.java 
b/src/com/mostc/pftt/model/sapi/GenericWebServerManager.java
new file mode 100644
index 0000000..8c97afa
--- /dev/null
+++ b/src/com/mostc/pftt/model/sapi/GenericWebServerManager.java
@@ -0,0 +1,74 @@
+package com.mostc.pftt.model.sapi;
+
+import java.util.Map;
+
+import com.mostc.pftt.host.AHost;
+import com.mostc.pftt.model.core.PhpIni;
+import com.mostc.pftt.scenario.FileSystemScenario;
+
+public class GenericWebServerManager extends UnmanagedWebServerManager {
+       protected final String hostname, web_server_software, docroot;
+       protected final int port;
+       protected final boolean ssl;
+       
+       public GenericWebServerManager(String hostname, int port, String 
docroot, String web_server_software, boolean ssl) {
+               if (port<1)
+                       port = 80;
+               
+               this.hostname = hostname;
+               this.port = port;
+               this.docroot = docroot;
+               this.web_server_software = web_server_software;
+               this.ssl = ssl;
+       }
+       
+       public GenericWebServerManager(String hostname, int port, String 
docroot, String web_server_software) {
+               this(hostname, port, docroot, web_server_software, false);
+       }
+       
+       @Override
+       protected UnmanagedWebServerInstance createUnmanagedWebServerInstance() 
{
+               return new GenericWebServerInstance(null, null, null, null, 
null, null);
+       }
+       
+       protected class GenericWebServerInstance extends 
UnmanagedWebServerInstance {
+
+               public GenericWebServerInstance(FileSystemScenario fs, AHost 
host,
+                               WebServerManager ws_mgr, String[] cmd_array, 
PhpIni ini,
+                               Map<String, String> env) {
+                       super(fs, host, ws_mgr, cmd_array, ini, env);
+               }
+
+               @Override
+               public String getName() {
+                       return web_server_software;
+               }
+
+               @Override
+               public String getHostname() {
+                       return hostname;
+               }
+
+               @Override
+               public int getPort() {
+                       return port;
+               }
+
+               @Override
+               public String getDocroot() {
+                       return docroot;
+               }
+               
+       }
+
+       @Override
+       public String getName() {
+               return "Generic-Web-Server";
+       }
+
+       @Override
+       public boolean isSSLSupported() {
+               return ssl;
+       }
+
+}
diff --git 
a/src/com/mostc/pftt/runner/AbstractApplicationUnitTestCaseRunner.java 
b/src/com/mostc/pftt/runner/AbstractApplicationUnitTestCaseRunner.java
new file mode 100644
index 0000000..730d06a
--- /dev/null
+++ b/src/com/mostc/pftt/runner/AbstractApplicationUnitTestCaseRunner.java
@@ -0,0 +1,34 @@
+package com.mostc.pftt.runner;
+
+import java.util.regex.Pattern;
+
+import com.mostc.pftt.host.AHost;
+import com.mostc.pftt.model.core.PhpBuild;
+import com.mostc.pftt.model.core.PhpIni;
+import com.mostc.pftt.results.ConsoleManager;
+import com.mostc.pftt.results.ITestResultReceiver;
+import com.mostc.pftt.runner.AbstractLocalTestPackRunner.TestPackThread;
+import com.mostc.pftt.scenario.FileSystemScenario;
+import com.mostc.pftt.scenario.SAPIScenario;
+import com.mostc.pftt.scenario.ScenarioSetSetup;
+
+public abstract class AbstractApplicationUnitTestCaseRunner<T extends 
TestPackThread,R extends AbstractLocalTestPackRunner> extends 
AbstractTestCaseRunner<T,R> {
+       protected final T thread;
+       protected boolean is_crashed, is_timeout;
+       
+       protected static Pattern PAT_CLASS_NOT_FOUND, PAT_REQUIRE_ONCE_FAIL, 
PAT_SYNTAX_ERROR, PAT_FATAL_ERROR;
+       static {
+               PAT_CLASS_NOT_FOUND = Pattern.compile(".*Fatal error.*Class 
'.*' not found.*");
+               PAT_REQUIRE_ONCE_FAIL = Pattern.compile(".*Fatal 
error.*require_once.*Failed opening required.*");
+               PAT_FATAL_ERROR = Pattern.compile(".*Fatal error.*");
+               PAT_SYNTAX_ERROR = Pattern.compile(".*No syntax errors 
detected.*");
+       }
+       
+       public AbstractApplicationUnitTestCaseRunner(FileSystemScenario fs, 
SAPIScenario sapi_scenario, T thread, ITestResultReceiver twriter, 
ConsoleManager cm, AHost host, ScenarioSetSetup scenario_set, PhpBuild build, 
PhpIni ini) {
+               super(fs, sapi_scenario, twriter, cm, host, scenario_set, 
build, ini);
+               this.thread = thread;
+       }
+       
+       protected abstract String generatePhpScript();
+       
+} // end public abstract class AbstractApplicationUnitTestCaseRunner
diff --git a/src/com/mostc/pftt/runner/CliSimpleTestCaseRunner.java 
b/src/com/mostc/pftt/runner/CliSimpleTestCaseRunner.java
new file mode 100644
index 0000000..b104c52
--- /dev/null
+++ b/src/com/mostc/pftt/runner/CliSimpleTestCaseRunner.java
@@ -0,0 +1,100 @@
+package com.mostc.pftt.runner;
+
+import java.io.IOException;
+
+import com.github.mattficken.io.IOUtil;
+import com.mostc.pftt.host.AHost;
+import com.mostc.pftt.host.AHost.ExecHandle;
+import com.mostc.pftt.model.app.SimpleTestCase;
+import com.mostc.pftt.model.core.PhpBuild;
+import com.mostc.pftt.model.core.PhpIni;
+import com.mostc.pftt.results.ConsoleManager;
+import com.mostc.pftt.results.ITestResultReceiver;
+import com.mostc.pftt.runner.LocalSimpleTestPackRunner.SimpleTestThread;
+import com.mostc.pftt.scenario.FileSystemScenario;
+import com.mostc.pftt.scenario.SAPIScenario;
+import com.mostc.pftt.scenario.ScenarioSetSetup;
+import com.mostc.pftt.util.NTStatus;
+
+public class CliSimpleTestCaseRunner extends AbstractSimpleTestCaseRunner {
+       protected ExecHandle running_test_handle;
+       protected String output_str;
+       
+       public CliSimpleTestCaseRunner(FileSystemScenario fs, SAPIScenario 
sapi_scenario, SimpleTestThread thread, ITestResultReceiver tmgr, 
ConsoleManager cm, AHost host, ScenarioSetSetup scenario_set, PhpBuild build, 
PhpIni ini, SimpleTestCase test_case) {
+               super(fs, sapi_scenario, thread, tmgr, cm, host, scenario_set, 
build, ini, test_case);
+       }
+
+       @Override
+       public String getSAPIOutput() {
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+       @Override
+       public String getSAPIConfig() {
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+       //@Override
+       protected void stop(boolean force) {
+               if (running_test_handle==null)
+                       return;
+               running_test_handle.close(cm, force);
+       }
+       
+       private void doExecute(String template_file, String ini_dir) throws 
Exception {
+               template_file = fs.fixPath(template_file);
+               
+               String cmd = build.getPhpExe()+" "+template_file;
+               System.out.println("49 "+cmd);
+               running_test_handle = host.execThread(
+                               //build.getPhpExe()+" -c "+ini_dir+" 
"+template_file//,
+                               build.getPhpExe()+" "+template_file//,
+                               //env,
+                               
//test_case.getPhpUnitDist().getPath().getAbsolutePath()
+                       );
+               
+               StringBuilder output_sb = new StringBuilder(128);
+               System.out.println(output_sb);
+               running_test_handle.run(
+                               cm, 
+                               output_sb, 
+                               null, 
+                               
SimpleTestCase.MAX_TEST_TIME_SECONDS,//getMaxTestRuntimeSeconds(), 
+                               null, 
+                               0, cm.getSuspendSeconds(), 
+                               IOUtil.HALF_MEGABYTE
+                       );
+               
+               output_str = output_sb.toString();
+               
+               is_crashed = running_test_handle.isCrashed();
+               is_timeout = running_test_handle.isTimedOut();
+       }
+       
+       @Override
+       protected String execute(String template_file) throws IOException, 
Exception {
+               final String ini_dir = build.prepare(cm, fs, host); // XXX 
store PhpIni in my_temp_dir ?
+               
+               doExecute(template_file, ini_dir);
+               if (is_crashed && running_test_handle.getExitCode() != -2
+                               && running_test_handle.getExitCode() != 
NTStatus.STATUS_ACCESS_VIOLATION) {
+                       // try a second time to be sure
+                       is_crashed = false;
+                       
+                       doExecute(template_file, ini_dir);
+               }
+               
+               if (is_crashed) {
+                       int exit_code = running_test_handle.getExitCode();
+                       
+                       output_str += "PFTT: crashed: exit_code="+exit_code+" 
status="+AHost.guessExitCodeStatus(host, exit_code);
+               }
+               
+               running_test_handle = null;
+               
+               return output_str;
+       }
+
+}
diff --git a/src/com/mostc/pftt/runner/HttpSimpleTestCaseRunner.java 
b/src/com/mostc/pftt/runner/HttpSimpleTestCaseRunner.java
new file mode 100644
index 0000000..975a97c
--- /dev/null
+++ b/src/com/mostc/pftt/runner/HttpSimpleTestCaseRunner.java
@@ -0,0 +1,42 @@
+package com.mostc.pftt.runner;
+
+import java.io.IOException;
+
+import com.mostc.pftt.host.AHost;
+import com.mostc.pftt.model.app.SimpleTestCase;
+import com.mostc.pftt.model.core.PhpBuild;
+import com.mostc.pftt.model.core.PhpIni;
+import com.mostc.pftt.results.ConsoleManager;
+import com.mostc.pftt.results.ITestResultReceiver;
+import com.mostc.pftt.runner.LocalSimpleTestPackRunner.SimpleTestThread;
+import com.mostc.pftt.scenario.FileSystemScenario;
+import com.mostc.pftt.scenario.SAPIScenario;
+import com.mostc.pftt.scenario.ScenarioSetSetup;
+
+public class HttpSimpleTestCaseRunner extends AbstractSimpleTestCaseRunner {
+
+       public HttpSimpleTestCaseRunner(FileSystemScenario fs, SAPIScenario 
sapi_scenario, SimpleTestThread thread, ITestResultReceiver tmgr, 
ConsoleManager cm, AHost host, ScenarioSetSetup scenario_set, PhpBuild build, 
PhpIni ini, SimpleTestCase test_case) {
+               super(fs, sapi_scenario, thread, tmgr, cm, host, scenario_set, 
build, ini, test_case);
+       }
+
+       @Override
+       public String getSAPIOutput() {
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+       @Override
+       public String getSAPIConfig() {
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+       @Override
+       protected String execute(String template_file) throws IOException,
+                       Exception {
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+
+}
diff --git a/src/com/mostc/pftt/runner/LocalSimpleTestPackRunner.java 
b/src/com/mostc/pftt/runner/LocalSimpleTestPackRunner.java
new file mode 100644
index 0000000..2e8f331
--- /dev/null
+++ b/src/com/mostc/pftt/runner/LocalSimpleTestPackRunner.java
@@ -0,0 +1,81 @@
+package com.mostc.pftt.runner;
+
+import java.io.IOException;
+import java.util.Map;
+
+import com.mostc.pftt.host.AHost;
+import com.mostc.pftt.model.app.SimpleTestActiveTestPack;
+import com.mostc.pftt.model.app.SimpleTestCase;
+import com.mostc.pftt.model.app.SimpleTestSourceTestPack;
+import com.mostc.pftt.model.core.PhpBuild;
+import com.mostc.pftt.model.core.PhpIni;
+import com.mostc.pftt.model.sapi.TestCaseGroupKey;
+import com.mostc.pftt.results.LocalConsoleManager;
+import com.mostc.pftt.results.PhpResultPackWriter;
+import com.mostc.pftt.scenario.IScenarioSetup;
+import com.mostc.pftt.scenario.ScenarioSet;
+
+public class LocalSimpleTestPackRunner extends 
AbstractLocalApplicationTestPackRunner<SimpleTestActiveTestPack, 
SimpleTestSourceTestPack, SimpleTestCase> {
+
+       public LocalSimpleTestPackRunner(LocalConsoleManager cm,
+                       PhpResultPackWriter tmgr, ScenarioSet scenario_set, 
PhpBuild build,
+                       AHost host, AHost host2) {
+               super(cm, tmgr, scenario_set, build, host, host2);
+       }
+
+       @Override
+       protected void showTally() {
+               
+       }
+       
+       @Override
+       protected boolean tryPrepare(PhpIni ini) {
+               return true;
+       }
+
+       @Override
+       protected TestPackThread<SimpleTestCase> createTestPackThread(boolean 
parallel) throws IllegalStateException, IOException {
+               return new SimpleTestThread(parallel);
+       }
+       
+       public class SimpleTestThread extends TestPackThread<SimpleTestCase> {
+
+               protected SimpleTestThread(boolean parallel) {
+                       super(parallel);
+               }
+
+               @Override
+               protected void prepareExec(TestCaseGroupKey group_key, PhpIni 
ini, Map<String, String> env, IScenarioSetup s) {
+               }
+
+               @Override
+               protected void runTest(TestCaseGroupKey group_key, 
SimpleTestCase test_case, boolean debugger_attached) throws IOException, 
Exception, Throwable {
+                       sapi_scenario.createSimpleTestCaseRunner(
+                                       this, 
+                                       twriter, 
+                                       cm, 
+                                       runner_fs, 
+                                       runner_host, 
+                                       scenario_set_setup,
+                                       build,
+                                       group_key.getPhpIni(), test_case
+                               ).runTest(cm, this, 
LocalSimpleTestPackRunner.this);
+               }
+
+               @Override
+               protected void stopRunningCurrentTest() {
+               }
+
+               @Override
+               protected int getMaxTestRuntimeSeconds() {
+                       return SimpleTestCase.MAX_TEST_TIME_SECONDS;
+               }
+
+               @Override
+               protected void recordSkipped(SimpleTestCase test_case) {
+                       
+               }
+               
+       } // end public class SimpleTestThread
+
+} // end public class LocalSimpleTestPackRunner
-- 
PHP Quality Assurance Mailing List <http://www.php.net/>
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to