[icedtea-web] RFC: add proxy auto config support

Dr Andrew John Hughes ahughes at redhat.com
Fri Feb 25 13:46:48 PST 2011


On 10:38 Fri 25 Feb     , Omair Majid wrote:

snip (this is essentially a rewrite of the build work :-)

> 
> Any thoughts on the attached patch? Also, do you have any links to good 
> documentation on AC_CONFIG_FILES and good practices for it? I would like 
> to use it if possible for build.properties but so far I dont have much 
> to go on.
> 

The autoconf manual is what I usually use.  I'm not aware of anything else.
Of course, you do have the source for it... ;-)

I think it's just simple subsitution - i.e. @x@ is replaced with the value of x.
Nothing clever.  So you'd need to create a RHINO_AVAILABLE in configure and
then allow it to be substituted.

Comments below.  Only issue for this patch is the IT_FIND_JAVA macro.
The autoconf changes should be in a separate patch.  This one is already
big enough ;-)

> Thanks,
> Omair

> diff -r d7fee305bd4f Makefile.am
> --- a/Makefile.am	Wed Feb 23 13:37:10 2011 -0500
> +++ b/Makefile.am	Thu Feb 24 19:34:38 2011 -0500
> @@ -8,7 +8,14 @@
>  # Build directories
>  
>  BOOT_DIR = $(abs_top_builddir)/bootstrap/jdk1.6.0
> -RUNTIME = $(BOOT_DIR)/jre/lib/rt.jar:$(BOOT_DIR)/jre/lib/jsse.jar
> +
> +if WITH_RHINO
> +  RHINO_RUNTIME=:$(RHINO_JAR)
> +else
> +  RHINO_RUNTIME=
> +endif
> +
> +RUNTIME = $(BOOT_DIR)/jre/lib/rt.jar:$(BOOT_DIR)/jre/lib/jsse.jar$(RHINO_RUNTIME)
>  

Looks good.

>  # Flags
>  IT_CFLAGS=$(CFLAGS) $(ARCHFLAG)
> @@ -18,8 +25,8 @@
>  IT_JAVACFLAGS=$(IT_JAVAC_SETTINGS) -source $(IT_LANGUAGE_SOURCE_VERSION) -target $(IT_CLASS_TARGET_VERSION)
>  
>  JRE='"$(SYSTEM_JDK_DIR)/jre"'
> -LAUNCHER_BOOTCLASSPATH="-J-Xbootclasspath/a:$(DESTDIR)$(datadir)/$(PACKAGE_NAME)/netx.jar"
> -PLUGIN_BOOTCLASSPATH='"-Xbootclasspath/a:$(DESTDIR)$(datadir)/$(PACKAGE_NAME)/netx.jar:$(DESTDIR)$(datadir)/$(PACKAGE_NAME)/plugin.jar"'
> +LAUNCHER_BOOTCLASSPATH="-J-Xbootclasspath/a:$(DESTDIR)$(datadir)/$(PACKAGE_NAME)/netx.jar$(RHINO_RUNTIME)"
> +PLUGIN_BOOTCLASSPATH='"-Xbootclasspath/a:$(DESTDIR)$(datadir)/$(PACKAGE_NAME)/netx.jar:$(DESTDIR)$(datadir)/$(PACKAGE_NAME)/plugin.jar$(RHINO_RUNTIME)"'
>  
>  # Fake update version to shut up the plugin detector hosted by Oracle.
>  # If Oracle ever release a JDK update greater than 50, this needs to be increased.
> @@ -88,8 +95,10 @@
>  all-local: stamps/netx-dist.stamp extra-lib/about.jar stamps/plugin.stamp $(NETX_DIR)/launcher/javaws \
>   javaws.desktop stamps/docs.stamp $(NETX_DIR)/launcher/controlpanel/itweb-settings itweb-settings.desktop
>  
> +check-local: check-pac-functions
> +
>  clean-local: clean-netx clean-plugin clean-liveconnect clean-extra clean-bootstrap-directory \
> - clean-native-ecj clean-desktop-files clean-docs
> + clean-native-ecj clean-desktop-files clean-docs clean-tests
>  	if [ -e stamps ] ; then \
>  	  rmdir stamps ; \
>  	fi
> @@ -241,8 +250,20 @@
>  
>  netx-source-files.txt:
>  	find $(NETX_SRCDIR) -name '*.java' | sort > $@
> +if !WITH_RHINO
> +	sed -i '/RhinoBasedPacEvaluator/ d' $@
> +endif
>  
> -stamps/netx.stamp: netx-source-files.txt stamps/bootstrap-directory.stamp
> +build.properties:
> +	echo "# This contains build-time settings " > $@
> +if WITH_RHINO
> +	echo "rhino.available=true" >> $@
> +else
> +	echo "rhino.available=false" >> $@
> +endif
> +
> +stamps/netx.stamp: netx-source-files.txt stamps/bootstrap-directory.stamp \
> + build.properties
>  	mkdir -p $(NETX_DIR)
>  	$(BOOT_DIR)/bin/javac $(IT_JAVACFLAGS) \
>  	    -d $(NETX_DIR) \
> @@ -255,6 +276,7 @@
>  	   ${INSTALL_DATA} -D $${files} \
>  	   $(NETX_DIR)/net/sourceforge/jnlp/resources/$${files}; \
>  	 done)
> +	cp -pPR build.properties $(NETX_DIR)/net/sourceforge/jnlp/
>  	mkdir -p stamps
>  	touch $@
>  
> @@ -274,6 +296,7 @@
>  
>  clean-netx:
>  	rm -rf $(NETX_DIR)
> +	rm -f build.properties
>  	rm -f stamps/netx-dist.stamp
>  	rm -f netx-source-files.txt
>  	rm -f stamps/netx.stamp
> @@ -378,6 +401,28 @@
>  	rm -rf ${abs_top_builddir}/docs/plugin
>  	rm -f stamps/plugin-docs.stamp
>  
> +
> +# check
> +# ==========================
> +
> +jrunscript:
> +if WITH_RHINO
> +	echo '$(BOOT_DIR)/bin/java -cp $(RHINO_JAR) org.mozilla.javascript.tools.shell.Main $$@' > jrunscript
> +	chmod u+x jrunscript
> +else
> +	echo "jrunscript requires rhino support"
> +	exit 1
> +endif

autoconf could do this too FWIW.  Look at javac.in in IcedTea.

> +
> +check-pac-functions: stamps/bootstrap-directory.stamp jrunscript
> +	./jrunscript $(abs_top_srcdir)/tests/netx/pac/pac-funcs-test.js \
> +	  $$(readlink -f $(abs_top_srcdir)/netx/net/sourceforge/jnlp/runtime/pac-funcs.js)
> +
> +clean-tests: clean-jrunscript
> +
> +clean-jrunscript:
> +	rm -f jrunscript
> +
>  # plugin tests
>  
>  if ENABLE_PLUGIN
> @@ -414,6 +459,7 @@
>  # bootstrap
>  stamps/bootstrap-directory.stamp: stamps/native-ecj.stamp
>  	mkdir -p $(BOOT_DIR)/bin stamps/
> +	ln -sf $(JAVA) $(BOOT_DIR)/bin/java

Wasn't this already present?

>  	ln -sf $(JAR) $(BOOT_DIR)/bin/jar
>  	ln -sf $(abs_top_builddir)/javac $(BOOT_DIR)/bin/javac
>  	ln -sf $(JAVADOC) $(BOOT_DIR)/bin/javadoc
> diff -r d7fee305bd4f acinclude.m4
> --- a/acinclude.m4	Wed Feb 23 13:37:10 2011 -0500
> +++ b/acinclude.m4	Thu Feb 24 19:34:38 2011 -0500
> @@ -122,6 +122,13 @@
>    fi
>  ])
>  
> +AC_DEFUN([IT_FIND_JAVA])
> +[
> +  AC_REQUIRE([IT_CHECK_FOR_JDK])
> +  JAVA=${SYSTEM_JDK_DIR}/bin/java
> +  AC_SUBS(JAVA)
> +]
> +

This isn't the one from IcedTea.  It's a lot more complicated...
BTW, AC_SUBS should be AC_SUBST?

>  AC_DEFUN([IT_FIND_JAVAC],
>  [
>    AC_ARG_WITH([javac],
> @@ -250,6 +257,56 @@
>    AC_SUBST(ECJ_JAR)
>  ])
>  
> +AC_DEFUN([IT_FIND_RHINO_JAR],
> +[
> +  AC_MSG_CHECKING([whether to include Javascript support via Rhino])
> +  AC_ARG_WITH([rhino],
> +              [AS_HELP_STRING(--with-rhino,specify location of the rhino jar)],
> +  [
> +    case "${withval}" in
> +      yes)
> +        RHINO_JAR=yes
> +        ;;
> +      no)
> +        RHINO_JAR=no
> +        ;;
> +      *)
> +        if test -f "${withval}"; then
> +          RHINO_JAR="${withval}"
> +        elif test -z "${withval}"; then
> +          RHINO_JAR=yes
> +        else
> +          AC_MSG_RESULT([not found])
> +          AC_MSG_ERROR("The rhino jar ${withval} was not found.")
> +        fi
> +    ;;
> +     esac
> +  ],
> +  [
> +    RHINO_JAR=yes
> +  ])
> +  if test x"${RHINO_JAR}" = "xyes"; then
> +    if test -e "/usr/share/java/rhino.jar"; then
> +      RHINO_JAR=/usr/share/java/rhino.jar
> +    elif test -e "/usr/share/java/js.jar"; then
> +      RHINO_JAR=/usr/share/java/js.jar
> +    elif test -e "/usr/share/rhino-1.6/lib/js.jar"; then
> +      RHINO_JAR=/usr/share/rhino-1.6/lib/js.jar
> +    fi
> +    if test x"${RHINO_JAR}" = "xyes"; then
> +      AC_MSG_RESULT([not found])
> +      AC_MSG_ERROR("A rhino jar was not found in /usr/share/java as either rhino.jar or js.jar.")
> +    fi
> +  fi
> +  AC_MSG_RESULT(${RHINO_JAR})
> +  AM_CONDITIONAL(WITH_RHINO, test x"${RHINO_JAR}" != "xno")
> +dnl Clear RHINO_JAR if it doesn't contain a valid filename
> +  if test x"${RHINO_JAR}" = "xno"; then
> +    RHINO_JAR=
> +  fi
> +  AC_SUBST(RHINO_JAR)
> +])
> +
>  AC_DEFUN_ONCE([IT_CHECK_PLUGIN],
>  [
>  AC_MSG_CHECKING([whether to build the browser plugin])
> diff -r d7fee305bd4f configure.ac
> --- a/configure.ac	Wed Feb 23 13:37:10 2011 -0500
> +++ b/configure.ac	Thu Feb 24 19:34:38 2011 -0500
> @@ -32,7 +32,9 @@
>  FIND_JAVAC
>  FIND_JAR
>  FIND_ECJ_JAR
> +IT_FIND_JAVA
>  IT_FIND_JAVADOC
> +IT_FIND_RHINO_JAR
>  AC_CONFIG_FILES([javac], [chmod +x javac])
>  
>  IT_SET_VERSION
> diff -r d7fee305bd4f netx/net/sourceforge/jnlp/browser/BrowserAwareProxySelector.java
> --- a/netx/net/sourceforge/jnlp/browser/BrowserAwareProxySelector.java	Wed Feb 23 13:37:10 2011 -0500
> +++ b/netx/net/sourceforge/jnlp/browser/BrowserAwareProxySelector.java	Thu Feb 24 19:34:38 2011 -0500
> @@ -54,6 +54,8 @@
>  
>  import net.sourceforge.jnlp.runtime.JNLPProxySelector;
>  import net.sourceforge.jnlp.runtime.JNLPRuntime;
> +import net.sourceforge.jnlp.runtime.PacEvaluator;
> +import net.sourceforge.jnlp.runtime.PacEvaluatorFactory;
>  
>  /**
>   * A ProxySelector which can read proxy settings from a browser's
> @@ -85,6 +87,8 @@
>      private String browserSocks4ProxyHost;
>      private int browserSocks4ProxyPort;
>  
> +    private PacEvaluator browserProxyAutoConfig = null;
> +
>      /**
>       * Create a new instance of this class, reading configuration fropm the browser
>       */
> @@ -128,6 +132,12 @@
>              e.printStackTrace();
>          }
>  
> +        if (browserProxyType == BROWSER_PROXY_TYPE_PAC) {
> +            if (browserAutoConfigUrl != null) {
> +                browserProxyAutoConfig = PacEvaluatorFactory.getPacEvaluator(browserAutoConfigUrl);
> +            }
> +        }
> +
>          browserUseSameProxy = Boolean.valueOf(prefs.get("network.proxy.share_proxy_settings"));
>  
>          browserHttpProxyHost = prefs.get("network.proxy.http");
> @@ -216,8 +226,21 @@
>       * browser.
>       */
>      private List<Proxy> getFromBrowserPAC(URI uri) {
> -        System.err.println(R("RPRoxyPacNotImplemented"));
> -        return Arrays.asList(new Proxy[] { Proxy.NO_PROXY });
> +        if (browserAutoConfigUrl == null || uri.getScheme().equals("socket")) {
> +            return Arrays.asList(new Proxy[] { Proxy.NO_PROXY });
> +        }
> +
> +        List<Proxy> proxies = new ArrayList<Proxy>();
> +
> +        try {
> +            String proxiesString = browserProxyAutoConfig.getProxies(uri.toURL());
> +            proxies.addAll(getProxiesFromPacResult(proxiesString));
> +        } catch (MalformedURLException e) {
> +            e.printStackTrace();
> +            proxies.add(Proxy.NO_PROXY);
> +        }
> +
> +        return proxies;
>      }
>  
>      /**
> diff -r d7fee305bd4f netx/net/sourceforge/jnlp/resources/Messages.properties
> --- a/netx/net/sourceforge/jnlp/resources/Messages.properties	Wed Feb 23 13:37:10 2011 -0500
> +++ b/netx/net/sourceforge/jnlp/resources/Messages.properties	Thu Feb 24 19:34:38 2011 -0500
> @@ -142,7 +142,7 @@
>  RUnexpected=Unexpected {0} at {1}
>  RConfigurationError=Fatal error while reading the configuration
>  RConfigurationFatal=ERROR: a fatal error has occurred while loading configuration. Perhaps a global configuration was required but could not be found
> -RPRoxyPacNotImplemented=Using Proxy Auto Config (PAC) files is not supported yet.
> +RPRoxyPacNotSupported=Using Proxy Auto Config (PAC) files is not supported.
>  RProxyFirefoxNotFound=Unable to use Firefox's proxy settings. Using "DIRECT" as proxy type.
>  RProxyFirefoxOptionNotImplemented=Browser proxy option "{0}" ({1}) not supported yet.
>  
> diff -r d7fee305bd4f netx/net/sourceforge/jnlp/runtime/FakePacEvaluator.java
> --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
> +++ b/netx/net/sourceforge/jnlp/runtime/FakePacEvaluator.java	Thu Feb 24 19:34:38 2011 -0500
> @@ -0,0 +1,54 @@
> +/* FakePacEvaluator.java
> +   Copyright (C) 2011 Red Hat, Inc.
> +
> +This file is part of IcedTea.
> +
> +IcedTea 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, version 2.
> +
> +IcedTea 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 IcedTea; see the file COPYING.  If not, write to
> +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> +02110-1301 USA.
> +
> +Linking this library statically or dynamically with other modules is
> +making a combined work based on this library.  Thus, the terms and
> +conditions of the GNU General Public License cover the whole
> +combination.
> +
> +As a special exception, the copyright holders of this library give you
> +permission to link this library with independent modules to produce an
> +executable, regardless of the license terms of these independent
> +modules, and to copy and distribute the resulting executable under
> +terms of your choice, provided that you also meet, for each linked
> +independent module, the terms and conditions of the license of that
> +module.  An independent module is a module which is not derived from
> +or based on this library.  If you modify this library, you may extend
> +this exception to your version of the library, but you are not
> +obligated to do so.  If you do not wish to do so, delete this
> +exception statement from your version.
> +*/
> +
> +package net.sourceforge.jnlp.runtime;
> +
> +import static net.sourceforge.jnlp.runtime.Translator.R;
> +import java.net.URL;
> +
> +/**
> + * A dummy PacEvaluator that always returns "DIRECT"
> + */
> +public class FakePacEvaluator implements PacEvaluator {
> +    @Override
> +    public String getProxies(URL url) {
> +        if (JNLPRuntime.isDebug()) {
> +            System.err.println(R("RPRoxyPacNotSupported"));
> +        }
> +        return "DIRECT";
> +    }
> +}
> diff -r d7fee305bd4f netx/net/sourceforge/jnlp/runtime/JNLPProxySelector.java
> --- a/netx/net/sourceforge/jnlp/runtime/JNLPProxySelector.java	Wed Feb 23 13:37:10 2011 -0500
> +++ b/netx/net/sourceforge/jnlp/runtime/JNLPProxySelector.java	Thu Feb 24 19:34:38 2011 -0500
> @@ -16,7 +16,6 @@
>  
>  package net.sourceforge.jnlp.runtime;
>  
> -import static net.sourceforge.jnlp.runtime.Translator.R;
>  import java.io.IOException;
>  import java.net.InetAddress;
>  import java.net.InetSocketAddress;
> @@ -52,6 +51,8 @@
>      /** The default port to use as a fallback. Currently squid's default port */
>      public static final int FALLBACK_PROXY_PORT = 3128;
>  
> +    private PacEvaluator pacEvaluator = null;
> +
>      /** The proxy type. See PROXY_TYPE_* constants */
>      private int proxyType = PROXY_TYPE_UNKNOWN;
>  
> @@ -96,8 +97,7 @@
>  
>          proxyType = Integer.valueOf(config.getProperty(DeploymentConfiguration.KEY_PROXY_TYPE));
>  
> -        String autoConfigString = config
> -                .getProperty(DeploymentConfiguration.KEY_PROXY_AUTO_CONFIG_URL);
> +        String autoConfigString = config.getProperty(DeploymentConfiguration.KEY_PROXY_AUTO_CONFIG_URL);
>          if (autoConfigString != null) {
>              try {
>                  autoConfigUrl = new URL(autoConfigString);
> @@ -106,6 +106,10 @@
>              }
>          }
>  
> +        if (autoConfigUrl != null) {
> +            pacEvaluator = PacEvaluatorFactory.getPacEvaluator(autoConfigUrl);
> +        }
> +
>          bypassList = new ArrayList<String>();
>          String proxyBypass = config.getProperty(DeploymentConfiguration.KEY_PROXY_BYPASS_LIST);
>          if (proxyBypass != null) {
> @@ -333,14 +337,22 @@
>       *
>       * @return a List of valid Proxy objects
>       */
> -    private List<Proxy> getFromPAC(URI uri) {
> -        if (autoConfigUrl == null) {
> +    protected List<Proxy> getFromPAC(URI uri) {
> +        if (autoConfigUrl == null || uri.getScheme().equals("socket")) {
>              return Arrays.asList(new Proxy[] { Proxy.NO_PROXY });
>          }
> -        // TODO implement this by reading and using the PAC file
> -        System.err.println(R("RPRoxyPacNotImplemented"));
>  
> -        return Arrays.asList(new Proxy[] { Proxy.NO_PROXY });
> +        List<Proxy> proxies = new ArrayList<Proxy>();
> +
> +        try {
> +            String proxiesString = pacEvaluator.getProxies(uri.toURL());
> +            proxies.addAll(getProxiesFromPacResult(proxiesString));
> +        } catch (MalformedURLException e) {
> +            e.printStackTrace();
> +            proxies.add(Proxy.NO_PROXY);
> +        }
> +
> +        return proxies;
>      }
>  
>      /**
> @@ -351,5 +363,56 @@
>       */
>      protected abstract List<Proxy> getFromBrowser(URI uri);
>  
> +    /**
> +     * Converts a proxy string from a browser into a List of Proxy objects
> +     * suitable for java.
> +     * @param pacString a string indicating proxies. For example
> +     * "PROXY foo.bar:3128; DIRECT"
> +     * @return a list of Proxy objects represeting the parsed string.
> +     */
> +    public static List<Proxy> getProxiesFromPacResult(String pacString) {
> +        List<Proxy> proxies = new ArrayList<Proxy>();
> +
> +        String[] tokens = pacString.split(";");
> +        for (String token: tokens) {
> +            if (token.startsWith("PROXY")) {
> +                String hostPortPair = token.substring("PROXY".length()).trim();
> +                if (!hostPortPair.contains(":")) {
> +                    continue;
> +                }
> +                String host = hostPortPair.split(":")[0];
> +                int port;
> +                try {
> +                    port = Integer.valueOf(hostPortPair.split(":")[1]);
> +                } catch (NumberFormatException nfe) {
> +                    continue;
> +                }
> +                SocketAddress sa = new InetSocketAddress(host, port);
> +                proxies.add(new Proxy(Type.HTTP, sa));
> +            } else if (token.startsWith("SOCKS")) {
> +                String hostPortPair = token.substring("SOCKS".length()).trim();
> +                if (!hostPortPair.contains(":")) {
> +                    continue;
> +                }
> +                String host = hostPortPair.split(":")[0];
> +                int port;
> +                try {
> +                    port = Integer.valueOf(hostPortPair.split(":")[1]);
> +                } catch (NumberFormatException nfe) {
> +                    continue;
> +                }
> +                SocketAddress sa = new InetSocketAddress(host, port);
> +                proxies.add(new Proxy(Type.SOCKS, sa));
> +            } else if (token.startsWith("DIRECT")) {
> +                proxies.add(Proxy.NO_PROXY);
> +            } else {
> +                if (JNLPRuntime.isDebug()) {
> +                    System.out.println("Unrecognized proxy token: " + token);
> +                }
> +            }
> +        }
> +
> +        return proxies;
> +    }
>  
>  }
> diff -r d7fee305bd4f netx/net/sourceforge/jnlp/runtime/PacEvaluator.java
> --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
> +++ b/netx/net/sourceforge/jnlp/runtime/PacEvaluator.java	Thu Feb 24 19:34:38 2011 -0500
> @@ -0,0 +1,56 @@
> +/* PacEvaluator.java
> +   Copyright (C) 2011 Red Hat, Inc.
> +
> +This file is part of IcedTea.
> +
> +IcedTea 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, version 2.
> +
> +IcedTea 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 IcedTea; see the file COPYING.  If not, write to
> +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> +02110-1301 USA.
> +
> +Linking this library statically or dynamically with other modules is
> +making a combined work based on this library.  Thus, the terms and
> +conditions of the GNU General Public License cover the whole
> +combination.
> +
> +As a special exception, the copyright holders of this library give you
> +permission to link this library with independent modules to produce an
> +executable, regardless of the license terms of these independent
> +modules, and to copy and distribute the resulting executable under
> +terms of your choice, provided that you also meet, for each linked
> +independent module, the terms and conditions of the license of that
> +module.  An independent module is a module which is not derived from
> +or based on this library.  If you modify this library, you may extend
> +this exception to your version of the library, but you are not
> +obligated to do so.  If you do not wish to do so, delete this
> +exception statement from your version.
> +*/
> +
> +package net.sourceforge.jnlp.runtime;
> +
> +import java.net.URL;
> +
> +/**
> + * This interface represents an object which can evaluate Proxy Auto Config
> + * files.
> + */
> +public interface PacEvaluator {
> +    /**
> +     * Get the proxies for accessing a given URL. The result is obtained by
> +     * evaluating the PAC file with the given url (and the host) as input.
> +     *
> +     * @param url the url for which a proxy is desired
> +     * @return a list of proxies in a string like
> +     * <pre>"PROXY foo.example.com:8080; PROXY bar.example.com:8080; DIRECT"</pre>
> +     */
> +    public String getProxies(URL url);
> +}
> diff -r d7fee305bd4f netx/net/sourceforge/jnlp/runtime/PacEvaluatorFactory.java
> --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
> +++ b/netx/net/sourceforge/jnlp/runtime/PacEvaluatorFactory.java	Thu Feb 24 19:34:38 2011 -0500
> @@ -0,0 +1,107 @@
> +/* PacEvaluatorFactory.java
> +   Copyright (C) 2011 Red Hat, Inc.
> +
> +This file is part of IcedTea.
> +
> +IcedTea 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, version 2.
> +
> +IcedTea 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 IcedTea; see the file COPYING.  If not, write to
> +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> +02110-1301 USA.
> +
> +Linking this library statically or dynamically with other modules is
> +making a combined work based on this library.  Thus, the terms and
> +conditions of the GNU General Public License cover the whole
> +combination.
> +
> +As a special exception, the copyright holders of this library give you
> +permission to link this library with independent modules to produce an
> +executable, regardless of the license terms of these independent
> +modules, and to copy and distribute the resulting executable under
> +terms of your choice, provided that you also meet, for each linked
> +independent module, the terms and conditions of the license of that
> +module.  An independent module is a module which is not derived from
> +or based on this library.  If you modify this library, you may extend
> +this exception to your version of the library, but you are not
> +obligated to do so.  If you do not wish to do so, delete this
> +exception statement from your version.
> +*/
> +
> +package net.sourceforge.jnlp.runtime;
> +
> +import java.io.IOException;
> +import java.io.InputStream;
> +import java.lang.reflect.Constructor;
> +import java.lang.reflect.InvocationTargetException;
> +import java.net.URL;
> +import java.util.Properties;
> +
> +
> +public class PacEvaluatorFactory {
> +
> +    public static PacEvaluator getPacEvaluator(URL pacUrl) {
> +        boolean useRhino = false;
> +
> +        ClassLoader cl = PacEvaluatorFactory.class.getClassLoader();
> +        if (cl == null) {
> +            cl = ClassLoader.getSystemClassLoader();
> +        }
> +        InputStream in = cl.getResourceAsStream("net/sourceforge/jnlp/build.properties");
> +        Properties properties = null;
> +        try {
> +            properties = new Properties();
> +            properties.load(in);
> +        } catch (IOException e) {
> +            if (JNLPRuntime.isDebug()) {
> +                e.printStackTrace();
> +            }
> +        } finally {
> +            try {
> +                in.close();
> +            } catch (IOException e) {
> +                if (JNLPRuntime.isDebug()) {
> +                    e.printStackTrace();
> +                }
> +            }
> +        }
> +
> +        if (properties == null) {
> +            return new FakePacEvaluator();
> +        }
> +
> +        String available = properties.getProperty("rhino.available");
> +        useRhino = Boolean.valueOf(available);
> +
> +        if (useRhino) {
> +            try {
> +                Class<?> evaluator = Class.forName("net.sourceforge.jnlp.runtime.RhinoBasedPacEvaluator");
> +                Constructor<?> constructor = evaluator.getConstructor(URL.class);
> +                return (PacEvaluator) constructor.newInstance(pacUrl);
> +            } catch (ClassNotFoundException e) {
> +                // ignore
> +            } catch (InstantiationException e) {
> +                e.printStackTrace();
> +            } catch (IllegalAccessException e) {
> +                e.printStackTrace();
> +            } catch (NoSuchMethodException e) {
> +                e.printStackTrace();
> +            } catch (IllegalArgumentException e) {
> +                e.printStackTrace();
> +            } catch (InvocationTargetException e) {
> +                if (e.getCause() != null) {
> +                    e.getCause().printStackTrace();
> +                }
> +            }
> +        }
> +
> +        return new FakePacEvaluator();
> +    }
> +}
> diff -r d7fee305bd4f netx/net/sourceforge/jnlp/runtime/RhinoBasedPacEvaluator.java
> --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
> +++ b/netx/net/sourceforge/jnlp/runtime/RhinoBasedPacEvaluator.java	Thu Feb 24 19:34:38 2011 -0500
> @@ -0,0 +1,256 @@
> +/* RhinoBasedPacEvaluator.java
> +   Copyright (C) 2011 Red Hat, Inc.
> +
> +This file is part of IcedTea.
> +
> +IcedTea 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, version 2.
> +
> +IcedTea 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 IcedTea; see the file COPYING.  If not, write to
> +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> +02110-1301 USA.
> +
> +Linking this library statically or dynamically with other modules is
> +making a combined work based on this library.  Thus, the terms and
> +conditions of the GNU General Public License cover the whole
> +combination.
> +
> +As a special exception, the copyright holders of this library give you
> +permission to link this library with independent modules to produce an
> +executable, regardless of the license terms of these independent
> +modules, and to copy and distribute the resulting executable under
> +terms of your choice, provided that you also meet, for each linked
> +independent module, the terms and conditions of the license of that
> +module.  An independent module is a module which is not derived from
> +or based on this library.  If you modify this library, you may extend
> +this exception to your version of the library, but you are not
> +obligated to do so.  If you do not wish to do so, delete this
> +exception statement from your version.
> +*/
> +
> +package net.sourceforge.jnlp.runtime;
> +
> +import java.io.BufferedReader;
> +import java.io.IOException;
> +import java.io.InputStream;
> +import java.io.InputStreamReader;
> +import java.net.SocketPermission;
> +import java.net.URL;
> +import java.security.AccessControlContext;
> +import java.security.AccessController;
> +import java.security.Permissions;
> +import java.security.PrivilegedAction;
> +import java.security.ProtectionDomain;
> +
> +import net.sourceforge.jnlp.util.TimedHashMap;
> +
> +import org.mozilla.javascript.Context;
> +import org.mozilla.javascript.Function;
> +import org.mozilla.javascript.Scriptable;
> +
> +/**
> + * Represents a Proxy Auto Config file. This object can be used to evaluate the
> + * proxy file to find the proxy for a given url.
> + *
> + * @see http://en.wikipedia.org/wiki/Proxy_auto-config#The_PAC_file
> + */
> +public class RhinoBasedPacEvaluator implements PacEvaluator {
> +
> +    private final String pacHelperFunctionContents;
> +    private final String pacContents;
> +    private final URL pacUrl;
> +    private final TimedHashMap<String, String> cache;
> +
> +    /**
> +     * Initialize a new object by using the PAC file located at the given URL.
> +     *
> +     * @param pacUrl the url of the PAC file to use
> +     */
> +    public RhinoBasedPacEvaluator(URL pacUrl) {
> +        if (JNLPRuntime.isDebug()) {
> +            System.err.println("Using the Rhino based PAC evaluator for url " + pacUrl);
> +        }
> +        pacHelperFunctionContents = getHelperFunctionContents();
> +        this.pacUrl = pacUrl;
> +        pacContents = getPacContents(pacUrl);
> +        cache = new TimedHashMap<String, String>();
> +    }
> +
> +    /**
> +     * Get the proxies for accessing a given URL. The result is obtained by
> +     * evaluating the PAC file with the given url (and the host) as input.
> +     *
> +     * This method performs caching of the result.
> +     *
> +     * @param url the url for which a proxy is desired
> +     * @return a list of proxies in a string like
> +     * <pre>"PROXY foo.example.com:8080; PROXY bar.example.com:8080; DIRECT"</pre>
> +     *
> +     * @see #getProxiesWithoutCaching(URL)
> +     */
> +    public String getProxies(URL url) {
> +        String cachedResult = getFromCache(url);
> +        if (cachedResult != null) {
> +            return cachedResult;
> +        }
> +
> +        String result = getProxiesWithoutCaching(url);
> +        addToCache(url, cachedResult);
> +        return result;
> +    }
> +
> +    /**
> +     * Get the proxies for accessing a given URL. The result is obtained by
> +     * evaluating the PAC file with the given url (and the host) as input.
> +     *
> +     * @param url the url for which a proxy is desired
> +     * @return a list of proxies in a string like
> +     * <pre>"PROXY example.com:3128; DIRECT"</pre>
> +     *
> +     * @see #getProxies(URL)
> +     */
> +    private String getProxiesWithoutCaching(URL url) {
> +        if (pacHelperFunctionContents == null) {
> +            System.err.println("Error loading pac functions");
> +            return "DIRECT";
> +        }
> +
> +        EvaluatePacAction evaluatePacAction = new EvaluatePacAction(pacContents, pacUrl.toString(),
> +                pacHelperFunctionContents, url);
> +        Permissions p = new Permissions();
> +        p.add(new RuntimePermission("accessClassInPackage.org.mozilla.javascript"));
> +        p.add(new SocketPermission("*", "resolve"));
> +        ProtectionDomain pd = new ProtectionDomain(null, p);
> +        AccessControlContext context = new AccessControlContext(new ProtectionDomain[] { pd });
> +
> +        return AccessController.doPrivileged(evaluatePacAction, context);
> +    }
> +
> +    /**
> +     * Returns the contents of file at pacUrl as a String.
> +     */
> +    private String getPacContents(URL pacUrl) {
> +        StringBuilder contents = null;
> +        try {
> +            String line = null;
> +            BufferedReader pacReader = new BufferedReader(new InputStreamReader(pacUrl.openStream()));
> +            contents = new StringBuilder();
> +            while ((line = pacReader.readLine()) != null) {
> +                // System.out.println(line);
> +                contents = contents.append(line).append("\n");
> +            }
> +        } catch (IOException e) {
> +            contents = null;
> +        }
> +
> +        System.out.println(contents);
> +        return (contents != null) ? contents.toString() : null;
> +    }
> +
> +    /**
> +     * Returns the pac helper functions as a String. The functions are read
> +     * from net/sourceforge/jnlp/resources/pac-funcs.js
> +     */
> +    private String getHelperFunctionContents() {
> +        StringBuilder contents = null;
> +        try {
> +            String line;
> +            ClassLoader cl = this.getClass().getClassLoader();
> +            if (cl == null) {
> +                cl = ClassLoader.getSystemClassLoader();
> +            }
> +            InputStream in = cl.getResourceAsStream("net/sourceforge/jnlp/runtime/pac-funcs.js");
> +            BufferedReader pacFuncsReader = new BufferedReader(new InputStreamReader(in));
> +            contents = new StringBuilder();
> +            while ((line = pacFuncsReader.readLine()) != null) {
> +                // System.out.println(line);
> +                contents = contents.append(line).append("\n");
> +            }
> +        } catch (IOException e) {
> +            e.printStackTrace();
> +            contents = null;
> +        }
> +
> +        return (contents != null) ? contents.toString() : null;
> +    }
> +
> +    /**
> +     * Gets an entry from the cache
> +     */
> +    private String getFromCache(URL url) {
> +        String lookupString = url.getProtocol() + "://" + url.getHost();
> +        String result = cache.get(lookupString);
> +        return result;
> +    }
> +
> +    /**
> +     * Adds an entry to the cache
> +     */
> +    private void addToCache(URL url, String proxyResult) {
> +        String lookupString = url.getAuthority() + "://" + url.getHost();
> +        cache.put(lookupString, proxyResult);
> +    }
> +
> +    /**
> +     * Helper classs to run remote javascript code (specified by the user as
> +     * PAC URL) inside a sandbox.
> +     */
> +    private static class EvaluatePacAction implements PrivilegedAction<String> {
> +
> +        private String pacContents;
> +        private String pacUrl;
> +        private String pacFuncsContents;
> +        private URL url;
> +
> +        public EvaluatePacAction(String pacContents, String pacUrl, String pacFuncsContents, URL url) {
> +            this.pacContents = pacContents;
> +            this.pacUrl = pacUrl;
> +            this.pacFuncsContents = pacFuncsContents;
> +            this.url = url;
> +        }
> +
> +        public String run() {
> +            Context cx = Context.enter();
> +            try {
> +                /*
> +                 * TODO defense in depth.
> +                 *
> +                 * This is already running within a sandbox, but we can (and we
> +                 * should) lock it down further. Look into ClassShutter.
> +                 */
> +                Scriptable scope = cx.initStandardObjects();
> +                // any optimization level greater than -1 will trigger code generation
> +                // and this block will then need classloader permissions
> +                cx.setOptimizationLevel(-1);
> +                Object result = null;
> +                result = cx.evaluateString(scope, pacFuncsContents, "internal", 1, null);
> +                result = cx.evaluateString(scope, pacContents, pacUrl, 1, null);
> +
> +                Object functionObj = scope.get("FindProxyForURL", scope);
> +                if (!(functionObj instanceof Function)) {
> +                    System.err.println("FindProxyForURL not found");
> +                    return null;
> +                } else {
> +                    Function findProxyFunction = (Function) functionObj;
> +
> +                    Object[] args = { url.toString(), url.getHost() };
> +                    result = findProxyFunction.call(cx, scope, scope, args);
> +                    return (String) result;
> +                }
> +            } catch (Exception e) {
> +                e.printStackTrace();
> +                return "DIRECT";
> +            } finally {
> +                Context.exit();
> +            }
> +        }
> +    }
> +
> +}
> diff -r d7fee305bd4f netx/net/sourceforge/jnlp/runtime/pac-funcs.js
> --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
> +++ b/netx/net/sourceforge/jnlp/runtime/pac-funcs.js	Thu Feb 24 19:34:38 2011 -0500
> @@ -0,0 +1,830 @@
> +/* pac-funcs.js
> +   Copyright (C) 2011 Red Hat, Inc.
> +
> +This file is part of IcedTea.
> +
> +IcedTea 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, version 2.
> +
> +IcedTea 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 IcedTea; see the file COPYING.  If not, write to
> +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> +02110-1301 USA.
> +
> +Linking this library statically or dynamically with other modules is
> +making a combined work based on this library.  Thus, the terms and
> +conditions of the GNU General Public License cover the whole
> +combination.
> +
> +As a special exception, the copyright holders of this library give you
> +permission to link this library with independent modules to produce an
> +executable, regardless of the license terms of these independent
> +modules, and to copy and distribute the resulting executable under
> +terms of your choice, provided that you also meet, for each linked
> +independent module, the terms and conditions of the license of that
> +module.  An independent module is a module which is not derived from
> +or based on this library.  If you modify this library, you may extend
> +this exception to your version of the library, but you are not
> +obligated to do so.  If you do not wish to do so, delete this
> +exception statement from your version.
> +*/
> +
> +/*
> + * These helper functions are required to be able to parse Proxy Auto Config
> + * (PAC) files. PAC files will use these helper functions to decide the best
> + * proxy for connecting to a host.
> + *
> + * This implementation is based on the description of the functions at:
> + * http://web.archive.org/web/20060424005037/wp.netscape.com/eng/mozilla/2.0/relnotes/demo/proxy-live.html
> + */
> +
> +/**
> + * Returns true if the host does not contain a domain (there are no dots)
> + */
> +function isPlainHostName(host) {
> +    if (host.indexOf(".") === -1) {
> +        return true;
> +    } else {
> +        return false;
> +    }
> +}
> +
> +/**
> + * Returns true if the host is part of the domain (the host ends with domain)
> + */
> +function dnsDomainIs(host, domain) {
> +    var loc = host.lastIndexOf(domain);
> +    if (loc === -1) {
> +        return false;
> +    }
> +    if (loc + domain.length === host.length) {
> +        // host ends with domain
> +        return true;
> +    }
> +    return false;
> +}
> +
> +/**
> + * Returns true if the host is an exact match of hostdom or if host is not a
> + * fully qualified name but has the same hostname as hostdom
> + */
> +function localHostOrDomainIs(host, hostdom) {
> +    if (host === hostdom) {
> +        // exact match
> +        return true;
> +    }
> +    var firstdot = hostdom.indexOf(".");
> +    if (firstdot === -1) {
> +        // hostdom has no dots
> +        return false;
> +    }
> +    if (host === hostdom.substring(0, firstdot)) {
> +        // hostname matches
> +        return true;
> +    }
> +    return false;
> +}
> +
> +/**
> + * Returns true if the host name can be resolved.
> + */
> +function isResolvable(host) {
> +    try {
> +        java.net.InetAddress.getByName(host);
> +        return true;
> +    } catch (e) {
> +        //if (e.javaException instanceof java.net.UnknownHostException) {
> +        	return false;
> +        //} else {
> +        // 	throw e;
> +        //}
> +    }
> +}
> +
> +/**
> + * Return true if the ip address of the host matches the pattern given the mask.
> + */
> +function isInNet(host, pattern, mask) {
> +    if (!isResolvable(host)) {
> +        return false;
> +    }
> +
> +    var hostIp = dnsResolve(host);
> +    var hostParts = hostIp.split(".");
> +    var patternParts = pattern.split(".");
> +    var maskParts = mask.split(".");
> +
> +    if (hostParts.length !== 4 ||
> +        patternParts.length !== hostParts.length ||
> +        maskParts.length !== hostParts.length) {
> +        return false;
> +    }
> +
> +    var matched = true;
> +    for (var i = 0; i < hostParts.length; i++) {
> +        var partMatches = (hostParts[i] & maskParts[i]) === (patternParts[i] & maskParts[i]);
> +        matched = matched && partMatches;
> +    }
> +
> +    return matched;
> +}
> +
> +/**
> + * Returns the IP address of the host as a string
> + */
> +function dnsResolve(host) {
> +    return java.net.InetAddress.getByName(host).getHostAddress() + "";
> +}
> +
> +/**
> + * Returns the local IP address
> + */
> +function myIpAddress() {
> +    return java.net.InetAddress.getLocalHost().getHostAddress() + "";
> +}
> +
> +/**
> + * Returns the number of domains in a hostname
> + */
> +function dnsDomainLevels(host) {
> +    var levels = 0;
> +    for (var i = 0; i < host.length; i++) {
> +        if (host[i] === '.') {
> +            levels++;
> +        }
> +    }
> +    return levels;
> +}
> +
> +/**
> + * Returns true if the shell expression matches the given input string
> + */
> +function shExpMatch(str, shExp) {
> +
> +    // TODO support all special characters
> +    // right now we support only * and ?
> +
> +
> +    try {
> +
> +        // turn shExp into a regular expression
> +
> +        var work = "";
> +
> +        // escape characters
> +        for (var i = 0; i < shExp.length; i++) {
> +            var ch = shExp[i];
> +            switch (ch) {
> +                case "\\": work = work + "\\\\"; break;
> +                case "^": work = work + "\\^"; break;
> +                case "$": work = work + "\\$"; break;
> +                case "+": work = work + "\\+"; break;
> +                case ".": work = work + "\\."; break;
> +                case "(": work = work + "\\("; break;
> +                case ")": work = work + "\\)"; break;
> +                case "{": work = work + "\\{"; break;
> +                case "}": work = work + "\\}"; break;
> +                case "[": work = work + "\\["; break;
> +                case "]": work = work + "\\]"; break;
> +
> +                case "?": work = work + ".{1}"; break;
> +                case "*": work = work + ".*"; break;
> +
> +                default:
> +                    work = work + ch;
> +            }
> +
> +        }
> +
> +        var regExp = "^" +  work + "$";
> +
> +        // match
> +        //java.lang.System.out.println("")
> +        //java.lang.System.out.println("Input String  : " + str);
> +        //java.lang.System.out.println("Input Pattern : " + shExp);
> +        //java.lang.System.out.println("RegExp        : " + regExp.toString());
> +        var match = str.match(regExp);
> +
> +        if (match === null) {
> +            return false;
> +        } else {
> +            return true;
> +        }
> +
> +
> +    } catch (e) {
> +        return false;
> +    }
> +
> +}
> +
> +
> +/**
> + * Returns true if the current weekday matches the desired weekday(s)
> + *
> + * Possible ways of calling:
> + *   weekdayRange(wd1);
> + *   weekdayRange(wd1, "GMT");
> + *   weekdayRange(wd1, wd2);
> + *   weekdayRange(wd1, wd2, "GMT");
> + *
> + * Where wd1 and wd2 are one of "SUN", "MON", "TUE", "WED", "THU", "FRI" and
> + * "SAT"
> + *
> + * The argument "GMT", if present, is always the last argument
> + */
> +function weekdayRange() {
> +	var wd1;
> +	var wd2;
> +	var gmt = false;
> +
> +	function isWeekDay(day) {
> +		if (day === "SUN" || day === "MON" || day === "TUE" || day === "WED" ||
> +            day === "THU" || day === "FRI" || day === "SAT") {
> +			return true;
> +		}
> +		return false;
> +	}
> +
> +    function strToWeekDay(str) {
> +        switch (str) {
> +            case "SUN": return 0;
> +            case "MON": return 1;
> +            case "TUE": return 2;
> +            case "WED": return 3;
> +            case "THU": return 4;
> +            case "FRI": return 5;
> +            case "SAT": return 6;
> +            default: return 0;
> +        }
> +    }
> +
> +	if (arguments.length > 1) {
> +		if (arguments[arguments.length-1] === "GMT") {
> +			gmt = true;
> +            arguments.splice(0,arguments.length-1);
> +        }
> +	}
> +
> +    if (arguments.length === 0) { return false; }
> +
> +    wd1 = arguments[0];
> +
> +	if (!isWeekDay(wd1)) { return false; }
> +
> +    var today = new Date().getDay();
> +    if (arguments.length >= 2) {
> +        // return true if current weekday is between wd1 and wd2 (inclusive)
> +        wd2 = arguments[1];
> +        if (!isWeekDay(wd2)) { return false; }
> +
> +        var day1 = strToWeekDay(wd1);
> +        var day2 = strToWeekDay(wd2);
> +
> +        if (day1 <= day2) {
> +            if ( day1 <= today && today <= day2) {
> +                return true;
> +            }
> +            return false;
> +        } else {
> +            if (day1 <= today || today <= day2) {
> +                return true;
> +            }
> +            return false;
> +        }
> +    } else {
> +        // return true if the current weekday is wd1
> +        if (strToWeekDay(wd1) === today) {
> +            return true;
> +        }
> +        return false;
> +    }
> +}
> +
> +/**
> + * Returns true if the current date matches the given date(s)
> + *
> + * Possible ways of calling:
> + *   dateRange(day)
> + *   dateRange(day1, day2)
> + *   dateRange(month)
> + *   dateRange(month1, month2)
> + *   dateRange(year)
> + *   dateRange(year1, year2)
> + *   dateRange(day1, month1, day2, month2)
> + *   dateRange(month1, year1, month2, year2)
> + *   dateRange(day1, month1, year1, day2, month2, year2)
> + *
> + * The parameter "GMT" may additionally be passed as the last argument in any
> + * of the above ways of calling.
> + */
> +function dateRange() {
> +
> +    // note: watch out for wrapping around of dates. date ranges, like
> +    // month=9 to month=8, wrap around and cover the entire year. this
> +    // makes everything more interesting
> +
> +    var gmt;
> +	if (arguments.length > 1) {
> +		if (arguments[arguments.length-1] === "GMT") {
> +			gmt = true;
> +            arguments.splice(0,arguments.length-1);
> +        }
> +	}
> +
> +    function isDate(date) {
> +        if (typeof(date) === 'number' && (date <= 31 && date >= 1)) {
> +            return true;
> +        }
> +        return false;
> +    }
> +
> +    function strToMonth(month) {
> +        switch (month) {
> +            case "JAN": return 0;
> +            case "FEB": return 1;
> +            case "MAR": return 2;
> +            case "APR": return 3;
> +            case "MAY": return 4;
> +            case "JUN": return 5;
> +            case "JUL": return 6;
> +            case "AUG": return 7;
> +            case "SEP": return 8;
> +            case "OCT": return 9;
> +            case "NOV": return 10;
> +            case "DEC": return 11;
> +            default: return 0;
> +        }
> +    }
> +
> +    function isMonth(month) {
> +        if (month === "JAN" || month === "FEB" || month === "MAR" ||
> +                month === "APR" || month === "MAY" || month === "JUN" ||
> +                month === "JUL" || month === "AUG" || month === "SEP" ||
> +                month === "OCT" || month === "NOV" || month === "DEC") {
> +            return true;
> +        }
> +        return false;
> +    }
> +
> +    function isYear(year) {
> +        if (typeof(year) === 'number') {
> +            return true;
> +        }
> +        return false;
> +    }
> +
> +    function inDateRange(today, date1, date2) {
> +        if (date1 <= date2) {
> +            if (date1 <= today.getDate() && today.getDate() <= date2) {
> +                return true;
> +            } else {
> +                return false;
> +            }
> +        } else {
> +            if (date1 <= today.getDate() || today.getDate() <= date2) {
> +                return true;
> +            } else {
> +                return false;
> +            }
> +        }
> +    }
> +
> +    function inMonthRange(today, month1, month2) {
> +        if (month1 <= month2) {
> +            if (month1 <= today.getMonth() && today.getMonth() <= month2) {
> +                return true;
> +            } else {
> +                return false;
> +            }
> +        } else {
> +            if (month1 <= today.getMonth() || today.getMonth() <= month2) {
> +                return true;
> +            } else {
> +                return false;
> +            }
> +        }
> +    }
> +
> +    function inYearRange(today, year1, year2) {
> +        if (year1 <= today.getYear() && today.getYear() <= year2) {
> +            return true;
> +        } else {
> +            return false;
> +        }
> +    }
> +
> +    function inMonthDateRange(today, date1, month1, date2, month2) {
> +        if (month1 === month2) {
> +            if (today.getMonth() === month1) {
> +                if (date1 <= today.getDate() && today.getDate() <= date2) {
> +                    return true;
> +                } else {
> +                    return false;
> +                }
> +            } else {
> +                if (date1 <= date2) {
> +                    return false;
> +                } else {
> +                    return true;
> +                }
> +            }
> +        } else if (month1 < month2) {
> +            if (month1 <= today.getMonth() && today.getMonth() <= month2) {
> +                if (today.getMonth() === month1) {
> +                    if (today.getDate() >= date1) {
> +                        return true;
> +                    } else {
> +                        return false;
> +                    }
> +                } else if (today.getMonth() === month2) {
> +                    if (today.getDate() <= date2) {
> +                        return true;
> +                    } else {
> +                        return false;
> +                    }
> +                } else {
> +                    return true;
> +                }
> +            } else {
> +                return false;
> +            }
> +        } else {
> +            if (month1 <= today.getMonth() || today.getMonth() <= month2) {
> +                if (today.getMonth() === month1) {
> +                    if (today.getDate() >= date1) {
> +                        return true;
> +                    } else {
> +                        return false;
> +                    }
> +                } else if (today.getMonth() === month2) {
> +                    if (today.getDate() <= date2) {
> +                        return true;
> +                    } else {
> +                        return false;
> +                    }
> +                } else {
> +                    return true;
> +                }
> +            } else {
> +                return false;
> +            }
> +        }
> +    }
> +
> +    function inYearMonthRange(today, month1, year1, month2, year2) {
> +        if (year1 === year2) {
> +            if (today.getYear() === year1) {
> +               if (month1 <= today.getMonth() && today.getMonth() <= month2) {
> +                   return true;
> +               } else {
> +                   return false;
> +               }
> +            } else {
> +                return false;
> +            }
> +        }
> +        if (year1 < year2) {
> +            if (year1 <= today.getYear() && today.getYear() <= year2) {
> +                if (today.getYear() === year1) {
> +                    if (today.getMonth() >= month1) {
> +                        return true;
> +                    } else {
> +                        return false;
> +                    }
> +                } else if (today.getYear() === year2) {
> +                    if (today.getMonth() <= month2) {
> +                        return true;
> +                    } else {
> +                        return false;
> +                    }
> +                } else {
> +                    return true;
> +                }
> +            } else {
> +                return false;
> +            }
> +        } else {
> +            return false;
> +        }
> +
> +    }
> +
> +    function inYearMonthDateRange(today, date1, month1, year1, date2, month2, year2) {
> +        if (year1 === year2) {
> +            if (year1 === today.getYear()) {
> +                if ((month1 <= today.getMonth()) && (today.getMonth() <= month2)) {
> +                    if (month1 === month2) {
> +                        if (date1 <= today.getDate() && today.getDate() <= date2) {
> +                            return true;
> +                        } else  {
> +                            return false;
> +                        }
> +                    } else if (today.getMonth() === month1) {
> +                        if (today.getDate() >= date1) {
> +                            return true;
> +                        } else {
> +                            return false;
> +                        }
> +                    } else if (today.getMonth() === month2) {
> +                        if (today.getDate() <= date2) {
> +                            return true;
> +                        } else {
> +                            return false;
> +                        }
> +                    } else  {
> +                        return true;
> +                    }
> +                } else {
> +                    return false;
> +                }
> +            } else {
> +                return false;
> +            }
> +        } else if (year1 < year2) {
> +            if (year1 <= today.getYear() && today.getYear() <= year2) {
> +                if (today.getYear() === year1) {
> +                    if (today.getMonth() === month1) {
> +                        if (today.getDate() >= date1) {
> +                            return true;
> +                        } else {
> +                            return false;
> +                        }
> +                    } else if (today.getMonth() > month1) {
> +                        return true;
> +                    } else {
> +                        return false;
> +                    }
> +                } else if (today.getYear() === year2) {
> +                    if (today.getMonth() <= month2) {
> +
> +                    } else {
> +                        return true;
> +                    }
> +                } else {
> +                    return true;
> +                }
> +            } else {
> +                return false;
> +            }
> +        } else {
> +            return false;
> +        }
> +    }
> +
> +    // TODO: change date to gmt, whatever
> +    var today = new Date();
> +
> +    var arg1;
> +    var arg2;
> +    var arg3;
> +    var arg4;
> +    var arg5;
> +    var arg6;
> +
> +    switch (arguments.length) {
> +        case 1:
> +            var arg = arguments[0];
> +            if (isDate(arg)) {
> +                if (today.getDate() === arg) {
> +                    return true;
> +                } else {
> +                    return false;
> +                }
> +            } else if (isMonth(arg)) {
> +                if (strToMonth(arg) === today.getMonth()) {
> +                    return true;
> +                } else {
> +                    return false;
> +                }
> +            } else { // year
> +                if (today.getYear() === arg) {
> +                    return true;
> +                } else {
> +                    return false;
> +                }
> +            }
> +        case 2:
> +            arg1 = arguments[0];
> +            arg2 = arguments[1];
> +            if (isDate(arg1) && isDate(arg2)) {
> +                var date1 = arg1;
> +                var date2 = arg2;
> +
> +                return inDateRange(today, date1, date2);
> +
> +            } else if (isMonth(arg1) && isMonth(arg2)) {
> +                var month1 = strToMonth(arg1);
> +                var month2 = strToMonth(arg2);
> +
> +                return inMonthRange(today, month1, month2);
> +
> +            } else if (isYear(arg1) && isYear(arg2)) {
> +                var year1 = arg1;
> +                var year2 = arg2;
> +
> +                return inYearRange(today, year1, year2);
> +            } else {
> +                return false;
> +            }
> +        case 4:
> +            arg1 = arguments[0];
> +            arg2 = arguments[1];
> +            arg3 = arguments[2];
> +            arg4 = arguments[3];
> +
> +            if (isDate(arg1) && isMonth(arg2) && isDate(arg3) && isMonth(arg4)) {
> +                var date1 = arg1;
> +                var month1 = strToMonth(arg2);
> +                var date2 = arg3;
> +                var month2 = strToMonth(arg4);
> +
> +                return inMonthDateRange(today, date1, month1, date2, month2);
> +
> +            } else if (isMonth(arg1) && isYear(arg2) && isMonth(arg3) && isYear(arg4)) {
> +                var month1 = strToMonth(arg1);
> +                var year1 = arg2;
> +                var month2 = strToMonth(arg3);
> +                var year2 = arg4;
> +
> +                return inYearMonthRange(today, month1, year1, month2, year2);
> +            } else {
> +                return false;
> +            }
> +        case 6:
> +            arg1 = arguments[0];
> +            arg2 = arguments[1];
> +            arg3 = arguments[2];
> +            arg4 = arguments[3];
> +            arg5 = arguments[4];
> +            arg6 = arguments[5];
> +            if (isDate(arg1) && isMonth(arg2) && isYear(arg3) &&
> +                isDate(arg4) && isMonth(arg5) && isYear(arg6)) {
> +                var day1 = arg1;
> +                var month1 = strToMonth(arg2);
> +                var year1 = arg3;
> +                var day2 = arg4;
> +                var month2 = strToMonth(arg5);
> +                var year2 = arg6;
> +
> +                return inYearMonthDateRange(today, day1, month1, year1, day2, month2, year2);
> +            } else {
> +                return false;
> +            }
> +        default:
> +            return false;
> +    }
> +
> +}
> +
> +/**
> + * Returns true if the current time matches the range given
> + *
> + * timeRange(hour)
> + * timeRange(hour1, hour2)
> + * timeRange(hour1, min1, hour2, min2)
> + * timeRange(hour1, min1, sec1, hour2, min2, sec2)
> + *
> + * The string "GMT" can be used as the last additional parameter in addition to
> + * the methods listed above.
> + */
> +function timeRange() {
> +
> +    // watch out for wrap around of times
> +
> +    var gmt;
> +	if (arguments.length > 1) {
> +		if (arguments[arguments.length-1] === "GMT") {
> +			gmt = true;
> +            arguments.splice(0,arguments.length-1);
> +        }
> +	}
> +
> +    function isHour(hour) {
> +        if (typeof(hour) === "number" && ( 0 <= hour && hour <= 23)) {
> +            return true;
> +        } else {
> +            return false;
> +        }
> +    }
> +
> +    function isMin(minute) {
> +        if (typeof(minute) === "number" && (0 <= minute && minute <= 59)) {
> +            return true;
> +        } else {
> +            return false;
> +        }
> +    }
> +
> +    function inHourRange(now, hour1, hour2) {
> +        if (hour1 === hour2) {
> +            if (now.getHours() === hour1) {
> +                return true;
> +            } else {
> +                return false;
> +            }
> +        } else if (hour1 < hour2) {
> +           if (hour1 <= now.getHours() && now.getHours() <= hour2) {
> +                return true;
> +           } else {
> +               return false;
> +           }
> +        } else {
> +            if (hour1 <= now.getHours() || now.getHours() <= hour2) {
> +                return true;
> +            } else {
> +                return false;
> +            }
> +        }
> +    }
> +
> +    function inHourMinuteRange(now, hour1, min1, hour2, min2) {
> +        if (hour1 == hour2) {
> +            if (now.getHours() == hour1) {
> +                if (min1 <= min2) {
> +                    if (min1 <= now.getMinutes() && now.getMinutes() <= min2) {
> +                        return true;
> +                    } else {
> +                        return false;
> +                    }
> +                } else {
> +                    if (min1 <= now.getMinutes() || now.getMinutes() <= min2) {
> +                        return true;
> +                    } else {
> +                        return false;
> +                    }
> +                }
> +            } else {
> +                if (min1 <= min2) {
> +                    return false;
> +                } else {
> +                    return true;
> +                }
> +            }
> +        } else if (hour1 < hour2) {
> +            if (hour1 <= now.getHours() && now.getHours() <= hour2) {
> +                return true;
> +            } else {
> +                return false;
> +            }
> +        } else {
> +            if (hour1 <= now.getHours() || now.getHours() <= hour2) {
> +                return true;
> +            } else {
> +                return false;
> +            }
> +        }
> +    }
> +
> +    var today = new Date();
> +
> +    switch (arguments.length) {
> +        case 1:
> +            var hour = arguments[0];
> +            if (today.getHours() === hour) {
> +                return true;
> +            } else {
> +                return false;
> +            }
> +        case 2:
> +            var hour1 = arguments[0];
> +            var hour2 = arguments[1];
> +            if (isHour(hour1) && isHour(hour2)) {
> +                return inHourRange(today, hour1, hour2);
> +            } else {
> +                return false;
> +            }
> +        case 4:
> +            var hour1 = arguments[0];
> +            var min1 = arguments[1];
> +            var hour2 = arguments[2];
> +            var min2 = arguments[3];
> +
> +            if (isHour(hour1) && isMin(min1) && isHour(hour2) && isMin(min2)) {
> +                return inHourMinuteRange(today, hour1, min1, hour2, min2);
> +            } else {
> +                return false;
> +            }
> +
> +        case 6:
> +            var hour1 = arguments[0];
> +            var min1 = arguments[1];
> +            var sec1 = arguments[2];
> +            var hour2 = arguments[3];
> +            var min2 = arguments[4];
> +            var sec2 = arguments[5];
> +
> +            // TODO handle seconds properly
> +
> +            return inHourMinuteRange(today, hour1, min1, hour2, min2);
> +        default:
> +            return false;
> +    }
> +}
> +
> diff -r d7fee305bd4f tests/netx/pac/pac-funcs-test.js
> --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
> +++ b/tests/netx/pac/pac-funcs-test.js	Thu Feb 24 19:34:38 2011 -0500
> @@ -0,0 +1,446 @@
> +
> +var ICEDTEA_CLASSPATH_ORG_IP = "208.78.240.231";
> +var CLASSPATH_ORG_IP = "199.232.41.10";
> +
> +var testsFailed = 0;
> +var testsPassed = 0;
> +
> +print("loading needed files\n");
> +file = arguments[0] + "";
> +load(file)
> +print("finished loaded needed files\n");
> +
> +
> +function main() {
> +
> +	testIsPlainHostName();
> +	testDnsDomainIs();
> +	testLocalHostOrDomainIs();
> +	testIsResolvable();
> +	testIsInNet();
> +	testDnsResolve();
> +	testDnsDomainLevels();
> +	testShExpMatch();
> +	testWeekdayRange();
> +	testDateRange();
> +	testTimeRange();
> +
> +	java.lang.System.out.println(testsFailed + " of " + (testsFailed + testsPassed) + " tests failed");
> +}
> +
> +function runTests(name, tests) {
> +	java.lang.System.out.println("Testing: " + name.name);
> +
> +	var undefined_var;
> +
> +	for ( var i = 0; i < tests.length; i++) {
> +
> +		java.lang.System.out.print("Test " + (i + 1) + ": ");
> +		var expectedVal = tests[i][0];
> +		var args = tests[i].slice(1);
> +		var returnVal;
> +		try {
> +			returnVal = name.apply(null, args);
> +		} catch (e) {
> +			returnVal = e;
> +		}
> +		if (returnVal === expectedVal) {
> +			java.lang.System.out.println("Passed.");
> +			testsPassed++;
> +		} else {
> +			java.lang.System.out.println("FAILED.");
> +            java.lang.System.out.println(name.name + "(" + args.join(", ") + ")");
> +			java.lang.System.out.println("Expected '" + expectedVal + "' but got '" + returnVal + "'");
> +			testsFailed++;
> +		}
> +	}
> +}
> +
> +function testIsPlainHostName() {
> +    var tests = [
> +        [ false, "icedtea.classpath.org" ],
> +        [ false, "classpath.org" ],
> +        [ true, "org" ],
> +        [ true, "icedtea" ],
> +        [ false, ".icedtea.classpath.org" ],
> +        [ false, "icedtea." ],
> +        [ false, "icedtea.classpath." ]
> +    ];
> +
> +    runTests(isPlainHostName, tests);
> +}
> +
> +function testDnsDomainIs() {
> +    var tests = [
> +        [ true, "icedtea.classpath.org", "icedtea.classpath.org" ],
> +        [ true, "icedtea.classpath.org", ".classpath.org" ],
> +        [ true, "icedtea.classpath.org", ".org" ],
> +        [ false, "icedtea.classpath.org", "icedtea.classpath.com" ],
> +        [ false, "icedtea.classpath.org", "icedtea.classpath" ],
> +        [ false, "icedtea.classpath", "icedtea.classpath.org" ],
> +        [ false, "icedtea", "icedtea.classpath.org" ]
> +    ];
> +
> +    runTests(dnsDomainIs, tests);
> +}
> +
> +function testLocalHostOrDomainIs() {
> +
> +    var tests = [
> +        [ true, "icedtea.classpath.org", "icedtea.classpath.org" ],
> +        [ true, "icedtea", "icedtea.classpath.org" ],
> +        [ false, "icedtea.classpath.org", "icedtea.classpath.com" ],
> +        [ false, "icedtea.classpath", "icedtea.classpath.org" ],
> +        [ false, "foo.classpath.org", "icedtea.classpath.org" ],
> +        [ false, "foo", "icedtea.classpath.org" ]
> +    ];
> +
> +    runTests(localHostOrDomainIs, tests);
> +}
> +
> +function testIsResolvable() {
> +
> +    var tests = [
> +        [ true, "icedtea.classpath.org", "icedtea.classpath.org" ],
> +        [ true, "classpath.org" ],
> +        [ false, "icedtea" ],
> +        [ false, "foobar.classpath.org" ],
> +        [ false, "icedtea.classpath.com" ]
> +    ];
> +
> +    runTests(isResolvable, tests);
> +}
> +
> +function testIsInNet() {
> +
> +	var parts = ICEDTEA_CLASSPATH_ORG_IP.split("\.");
> +
> +	var fakeParts = ICEDTEA_CLASSPATH_ORG_IP.split("\.");
> +	fakeParts[0] = fakeParts[0] + 1;
> +
> +	function createIp(array) {
> +		return array[0] + "." + array[1] + "." + array[2] + "." + array[3];
> +	}
> +
> +	var tests = [
> +	    [ true, "icedtea.classpath.org", ICEDTEA_CLASSPATH_ORG_IP, "255.255.255.255"],
> +	    [ true, "icedtea.classpath.org", ICEDTEA_CLASSPATH_ORG_IP, "255.255.255.0"],
> +	    [ true, "icedtea.classpath.org", ICEDTEA_CLASSPATH_ORG_IP, "255.255.0.0"],
> +	    [ true, "icedtea.classpath.org", ICEDTEA_CLASSPATH_ORG_IP, "255.0.0.0"],
> +	    [ true, "icedtea.classpath.org", ICEDTEA_CLASSPATH_ORG_IP, "0.0.0.0"],
> +	    [ true, "icedtea.classpath.org", ICEDTEA_CLASSPATH_ORG_IP, "255.255.255.255"],
> +	    [ true, "icedtea.classpath.org", ICEDTEA_CLASSPATH_ORG_IP, "0.0.0.0"],
> +	    [ true, "icedtea.classpath.org", createIp(parts), "255.255.255.255" ],
> +	    [ false, "icedtea.classpath.org", createIp(fakeParts), "255.255.255.255"],
> +	    [ false, "icedtea.classpath.org", createIp(fakeParts), "255.255.255.0"],
> +	    [ false, "icedtea.classpath.org", createIp(fakeParts), "255.255.0.0"],
> +	    [ false, "icedtea.classpath.org", createIp(fakeParts), "255.0.0.0"],
> +	    [ true, "icedtea.classpath.org", createIp(fakeParts), "0.0.0.0"]
> +	];
> +
> +	runTests(isInNet, tests);
> +}
> +
> +function testDnsResolve() {
> +    var tests = [
> +        [ ICEDTEA_CLASSPATH_ORG_IP, "icedtea.classpath.org" ],
> +        //[ CLASSPATH_ORG_IP, "classpath.org" ],
> +        [ "127.0.0.1", "localhost" ]
> +    ];
> +
> +    runTests(dnsResolve, tests);
> +}
> +
> +function testDnsDomainLevels() {
> +    var tests = [
> +        [ 0, "org" ],
> +        [ 1, "classpath.org" ],
> +        [ 2, "icedtea.classpath.org" ],
> +        [ 3, "foo.icedtea.classpath.org" ]
> +    ];
> +
> +    runTests(dnsDomainLevels, tests);
> +
> +}
> +function testShExpMatch() {
> +    var tests = [
> +         [ true, "icedtea.classpath.org", "icedtea.classpath.org"],
> +         [ false, "icedtea.classpath.org", ".org"],
> +         [ false, "icedtea.classpath.org", "icedtea."],
> +         [ false, "icedtea", "icedtea.classpath.org"],
> +
> +         [ true, "icedtea.classpath.org", "*" ],
> +         [ true, "icedtea.classpath.org", "*.classpath.org" ],
> +         [ true, "http://icedtea.classpath.org", "*.classpath.org" ],
> +         [ true, "http://icedtea.classpath.org/foobar/", "*.classpath.org/*" ],
> +         [ true, "http://icedtea.classpath.org/foobar/", "*/foobar/*" ],
> +         [ true, "http://icedtea.classpath.org/foobar/", "*foobar*" ],
> +         [ true, "http://icedtea.classpath.org/foobar/", "*foo*" ],
> +         [ false, "http://icedtea.classpath.org/foobar/", "*/foo/*" ],
> +         [ false, "http://icedtea.classpath.org/foobar/", "*/foob/*" ],
> +         [ false, "http://icedtea.classpath.org/foobar/", "*/fooba/*" ],
> +         [ false, "http://icedtea.classpath.org/foo/", "*foobar*" ],
> +
> +         [ true, "1", "?" ],
> +         [ true, "12", "??" ],
> +         [ true, "123", "1?3" ],
> +         [ true, "123", "?23" ],
> +         [ true, "123", "12?" ],
> +         [ true, "1234567890", "??????????" ],
> +         [ false, "1234567890", "?????????" ],
> +         [ false, "123", "1?1" ],
> +         [ false, "123", "??" ],
> +
> +         [ true, "http://icedtea.classpath.org/f1/", "*/f?/*" ],
> +         [ true, "http://icedtea1.classpath.org/f1/", "*icedtea?.classpath*/f?/*" ],
> +         [ false, "http://icedtea.classpath.org/f1/", "*/f2/*" ],
> +         [ true, "http://icedtea.classpath.org/f1/", "*/f?/*" ],
> +         [ false, "http://icedtea.classpath.org/f1", "f?*"],
> +         [ false, "http://icedtea.classpath.org/f1", "f?*"],
> +         [ false, "http://icedtea.classpath.org/f1", "f?*"],
> +
> +         [ true, "http://icedtea.classpath.org/foobar/", "*.classpath.org/*" ],
> +         [ true, "http://icedtea.classpath.org/foobar/", "*.classpath.org/*" ],
> +         [ true, "http://icedtea.classpath.org/foobar/", "*.classpath.org/*" ],
> +
> +         [ true, "http://icedtea.classpath.org/foo.php?id=bah", "*foo.php*" ],
> +         [ false, "http://icedtea.classpath.org/foo_php?id=bah", "*foo.php*" ]
> +     ];
> +
> +     runTests(shExpMatch, tests);
> +}
> +
> +function testWeekdayRange() {
> +
> +    var today = new Date();
> +    var day = today.getDay();
> +
> +    function dayToStr(day) {
> +        switch (day) {
> +            case -2: return "FRI";
> +            case -1: return "SAT";
> +            case 0: return "SUN";
> +            case 1: return "MON";
> +            case 2: return "TUE";
> +            case 3: return "WED";
> +            case 4: return "THU";
> +            case 5: return "FRI";
> +            case 6: return "SAT";
> +            case 7: return "SUN";
> +            case 8: return "MON";
> +            default: return "FRI";
> +        }
> +
> +    }
> +
> +    var tests = [
> +       [ true, dayToStr(day) ],
> +       [ false, dayToStr(day+1) ],
> +       [ false, dayToStr(day-1) ],
> +    ];
> +}
> +
> +function testDateRange() {
> +
> +    function incDate(date) {
> +        return (date + 1 - 1) % 31 +1 ;
> +    }
> +
> +    function decDate(date) {
> +        return (date - 1 - 1 + 31) % 31 + 1;
> +    }
> +
> +    function monthToStr(month) {
> +        switch (month) {
> +            case -1: return "DEC";
> +            case 0: return "JAN";
> +            case 1: return "FEB";
> +            case 2: return "MAR";
> +            case 3: return "APR";
> +            case 4: return "MAY";
> +            case 5: return "JUN";
> +            case 6: return "JUL";
> +            case 7: return "AUG";
> +            case 8: return "SEP";
> +            case 9: return "OCT";
> +            case 10: return "NOV";
> +            case 11: return "DEC";
> +            case 12: return "JAN";
> +            default: throw "Invalid Month";
> +        }
> +    }
> +
> +    var today = new Date();
> +    var date = today.getDate();
> +    var month = today.getMonth();
> +    var year = today.getYear();
> +
> +    var tests = [
> +        [ true, date ],
> +        [ false, incDate(date) ],
> +        [ false, decDate(date) ],
> +
> +        [ true, monthToStr(month) ],
> +        [ false, monthToStr(month+1) ],
> +        [ false, monthToStr(month-1) ],
> +
> +        [ true, year ],
> +        [ false, year - 1],
> +        [ false, year + 1],
> +
> +        [ true, date, date ],
> +        [ true, date, incDate(date) ],
> +        [ true, decDate(date), date ],
> +        [ true, decDate(date), incDate(date) ],
> +        [ false, incDate(date), decDate(date) ],
> +        [ false, decDate(decDate(date)), decDate(date) ],
> +        [ false, incDate(date), incDate(incDate(date)) ],
> +
> +        [ true, monthToStr(month), monthToStr(month) ],
> +        [ true, monthToStr(month), monthToStr(month+1) ],
> +        [ true, monthToStr(month-1), monthToStr(month) ],
> +        [ true, monthToStr(month-1), monthToStr(month+1) ],
> +        [ true, "JAN", "DEC" ],
> +        [ true, "DEC", "NOV" ],
> +        [ true, "JUL", "JUN"],
> +        [ false, monthToStr(month+1), monthToStr(month+1) ],
> +        [ false, monthToStr(month-1), monthToStr(month-1) ],
> +        [ false, monthToStr(month+1), monthToStr(month-1) ],
> +
> +        [ true, year, year ],
> +        [ true, year, year+1 ],
> +        [ true, year-1, year ],
> +        [ true, year-1, year+1 ],
> +        [ false, year-2, year-1 ],
> +        [ false, year+1, year+1 ],
> +        [ false, year+1, year+2 ],
> +        [ false, year+1, year-1 ],
> +
> +        [ true, date, monthToStr(month) , date, monthToStr(month) ],
> +        [ true, decDate(date), monthToStr(month) , date, monthToStr(month) ],
> +        [ false, decDate(date), monthToStr(month) , decDate(date), monthToStr(month) ],
> +        [ true, date, monthToStr(month) , incDate(date), monthToStr(month) ],
> +        [ false, incDate(date), monthToStr(month) , incDate(date), monthToStr(month) ],
> +        [ true, decDate(date), monthToStr(month) , incDate(date), monthToStr(month) ],
> +        [ false, incDate(date), monthToStr(month) , decDate(date), monthToStr(month) ],
> +        [ true, date, monthToStr(month-1) , date, monthToStr(month) ],
> +        [ true, date, monthToStr(month) , date, monthToStr(month+1) ],
> +        [ true, date, monthToStr(month-1) , date, monthToStr(month+1) ],
> +        [ true, incDate(date), monthToStr(month-1) , date, monthToStr(month+1) ],
> +        [ true, date, monthToStr(month-1) , decDate(date), monthToStr(month+1) ],
> +        [ false, date, monthToStr(month+1) , date, monthToStr(month-1) ],
> +        [ false, incDate(date), monthToStr(month+1) , incDate(date), monthToStr(month-1) ],
> +        [ false, decDate(date), monthToStr(month+1) , decDate(date), monthToStr(month-1) ],
> +        [ true, 1, "JAN", 31, "DEC" ],
> +        [ true, 2, "JAN", 1, "JAN" ],
> +        [ false, 1, monthToStr(month+1), 31, monthToStr(month+1) ],
> +        [ false, 1, monthToStr(month-1), 31, monthToStr(month-1) ],
> +
> +        [ true, monthToStr(month), year, monthToStr(month), year ],
> +        [ true, monthToStr(month-1), year, monthToStr(month), year ],
> +        [ true, monthToStr(month), year, monthToStr(month+1), year ],
> +        [ true, monthToStr(month-1), year, monthToStr(month+1), year ],
> +        [ true, monthToStr(0), year, monthToStr(11), year ],
> +        [ false, monthToStr(month+1), year, monthToStr(month-1), year ],
> +        [ false, monthToStr(month+1), year, monthToStr(month+1), year ],
> +        [ false, monthToStr(month-1), year, monthToStr(month-1), year ],
> +        [ false, monthToStr(month), year-1, monthToStr(month-1), year ],
> +        [ true, monthToStr(month), year, monthToStr(month), year + 1 ],
> +        [ true, monthToStr(month), year-1, monthToStr(month), year ],
> +        [ true, monthToStr(month), year-1, monthToStr(month), year+1 ],
> +        [ true, monthToStr(0), year, monthToStr(0), year+1 ],
> +        [ true, monthToStr(0), year-1, monthToStr(0), year+1 ],
> +        [ false, monthToStr(0), year-1, monthToStr(11), year-1 ],
> +        [ false, monthToStr(0), year+1, monthToStr(11), year+1 ],
> +
> +        [ true, date, monthToStr(month), year, date, monthToStr(month), year ],
> +        [ true, decDate(date), monthToStr(month), year, incDate(date), monthToStr(month), year ],
> +        [ true, decDate(date), monthToStr(month-1), year, incDate(date), monthToStr(month+1), year ],
> +        [ true, decDate(date), monthToStr(month-1), year-1, incDate(date), monthToStr(month+1), year+1 ],
> +        [ true, incDate(date), monthToStr(month-1), year-1, incDate(date), monthToStr(month+1), year+1 ],
> +        [ false, incDate(date), monthToStr(month), year, incDate(date), monthToStr(month+1), year+1 ],
> +        [ false, date, monthToStr(month+1), year, incDate(date), monthToStr(month+1), year+1 ],
> +        [ true, 1, monthToStr(0), 0, 31, monthToStr(11), 100000 ],
> +        [ true, 1, monthToStr(0), year, 31, monthToStr(11), year ],
> +        [ true, 1, monthToStr(0), year-1, 31, monthToStr(11), year+1 ],
> +        [ false, 1, monthToStr(0), year-1, 31, monthToStr(11), year-1 ],
> +        [ false, 1, monthToStr(0), year+1, 31, monthToStr(11), year+1 ],
> +
> +    ];
> +
> +    runTests(dateRange, tests);
> +
> +}
> +
> +function testTimeRange() {
> +    var now = new Date();
> +
> +    var hour = now.getHours();
> +    var min = now.getMinutes();
> +    var sec = now.getSeconds();
> +
> +    function toHour(input) {
> +        if (input < 0) {
> +            while (input < 0) {
> +                input = input + 24;
> +            }
> +            return (input % 24);
> +        } else {
> +            return (input % 24);
> +        }
> +    }
> +
> +    function toMin(input) {
> +        if (input < 0) {
> +            while (input < 0) {
> +                input = input + 60;
> +            }
> +            return (input % 60);
> +        } else {
> +            return (input % 60);
> +        }
> +    }
> +
> +    tests = [
> +        [ true, hour ],
> +        [ false, toHour(hour+1)],
> +        [ false, toHour(hour-1)],
> +
> +        [ true, hour, hour ],
> +        [ true, toHour(hour-1), hour ],
> +        [ true, hour, toHour(hour+1)],
> +        [ true, toHour(hour-1), toHour(hour+1)],
> +        [ true, toHour(hour+1), hour ],
> +        [ true, hour, toHour(hour-1) ],
> +        [ false, toHour(hour-2), toHour(hour-1)],
> +        [ false, toHour(hour+1), toHour(hour+2)],
> +        [ false, toHour(hour+1), toHour(hour-1) ],
> +        [ true, 0, 23 ],
> +        [ true, 12, 11 ],
> +
> +        [ true, hour, min, hour, min ],
> +        [ true, hour, min, hour, toMin(min+1) ],
> +        [ true, hour, toMin(min-1), hour, min ],
> +        [ true, hour, toMin(min-1), hour, toMin(min+1) ],
> +        [ true, hour, toMin(min+2), hour, toMin(min+1) ],
> +        [ false, hour, toMin(min+1), hour, toMin(min+1) ],
> +        [ false, hour, toMin(min-1), hour, toMin(min-1) ],
> +        [ false, hour, toMin(min+1), hour, toMin(min-1) ],
> +        [ true, toHour(hour-1), min, hour, min ],
> +        [ true, hour, min, toHour(hour+1), min ],
> +        [ true, toHour(hour-1), min, toHour(hour+1), min ],
> +        [ true, 0, 0, 23, 59 ],
> +        [ true, 0, 1, 0, 0 ],
> +
> +        [ true, 0, 1, 0, 0, 0, 0 ],
> +        [ true, hour, min, sec, hour, min, sec ],
> +        [ true, hour, min, sec, hour, min + 10, sec ],
> +        [ true, hour, min, sec - 10, hour, min, sec ],
> +        [ true, hour, min, sec, hour, min-1 , sec ],
> +
> +    ];
> +
> +    runTests(timeRange, tests);
> +}
> +
> +main();


-- 
Andrew :)

Free Java Software Engineer
Red Hat, Inc. (http://www.redhat.com)

Support Free Java!
Contribute to GNU Classpath and IcedTea
http://www.gnu.org/software/classpath
http://icedtea.classpath.org
PGP Key: F5862A37 (https://keys.indymedia.org/)
Fingerprint = EA30 D855 D50F 90CD F54D  0698 0713 C3ED F586 2A37



More information about the distro-pkg-dev mailing list